dpdk/drivers/net/nfp/nfpcore/nfp_hwinfo.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Netronome Systems, Inc.
   3 * All rights reserved.
   4 */
   5
   6/* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM
   7 * after chip reset.
   8 *
   9 * Examples of the fields:
  10 *   me.count = 40
  11 *   me.mask = 0x7f_ffff_ffff
  12 *
  13 *   me.count is the total number of MEs on the system.
  14 *   me.mask is the bitmask of MEs that are available for application usage.
  15 *
  16 *   (ie, in this example, ME 39 has been reserved by boardconfig.)
  17 */
  18
  19#include <stdio.h>
  20#include <time.h>
  21
  22#include "nfp_cpp.h"
  23#include "nfp6000/nfp6000.h"
  24#include "nfp_resource.h"
  25#include "nfp_hwinfo.h"
  26#include "nfp_crc.h"
  27
  28static int
  29nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
  30{
  31        return hwinfo->version & NFP_HWINFO_VERSION_UPDATING;
  32}
  33
  34static int
  35nfp_hwinfo_db_walk(struct nfp_hwinfo *hwinfo, uint32_t size)
  36{
  37        const char *key, *val, *end = hwinfo->data + size;
  38
  39        for (key = hwinfo->data; *key && key < end;
  40             key = val + strlen(val) + 1) {
  41                val = key + strlen(key) + 1;
  42                if (val >= end) {
  43                        printf("Bad HWINFO - overflowing key\n");
  44                        return -EINVAL;
  45                }
  46
  47                if (val + strlen(val) + 1 > end) {
  48                        printf("Bad HWINFO - overflowing value\n");
  49                        return -EINVAL;
  50                }
  51        }
  52        return 0;
  53}
  54
  55static int
  56nfp_hwinfo_db_validate(struct nfp_hwinfo *db, uint32_t len)
  57{
  58        uint32_t size, new_crc, *crc;
  59
  60        size = db->size;
  61        if (size > len) {
  62                printf("Unsupported hwinfo size %u > %u\n", size, len);
  63                return -EINVAL;
  64        }
  65
  66        size -= sizeof(uint32_t);
  67        new_crc = nfp_crc32_posix((char *)db, size);
  68        crc = (uint32_t *)(db->start + size);
  69        if (new_crc != *crc) {
  70                printf("Corrupt hwinfo table (CRC mismatch)\n");
  71                printf("\tcalculated 0x%x, expected 0x%x\n", new_crc, *crc);
  72                return -EINVAL;
  73        }
  74
  75        return nfp_hwinfo_db_walk(db, size);
  76}
  77
  78static struct nfp_hwinfo *
  79nfp_hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size)
  80{
  81        struct nfp_hwinfo *header;
  82        void *res;
  83        uint64_t cpp_addr;
  84        uint32_t cpp_id;
  85        int err;
  86        uint8_t *db;
  87
  88        res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO);
  89        if (res) {
  90                cpp_id = nfp_resource_cpp_id(res);
  91                cpp_addr = nfp_resource_address(res);
  92                *cpp_size = nfp_resource_size(res);
  93
  94                nfp_resource_release(res);
  95
  96                if (*cpp_size < HWINFO_SIZE_MIN)
  97                        return NULL;
  98        } else {
  99                return NULL;
 100        }
 101
 102        db = malloc(*cpp_size + 1);
 103        if (!db)
 104                return NULL;
 105
 106        err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size);
 107        if (err != (int)*cpp_size)
 108                goto exit_free;
 109
 110        header = (void *)db;
 111        printf("NFP HWINFO header: %08x\n", *(uint32_t *)header);
 112        if (nfp_hwinfo_is_updating(header))
 113                goto exit_free;
 114
 115        if (header->version != NFP_HWINFO_VERSION_2) {
 116                printf("Unknown HWInfo version: 0x%08x\n",
 117                        header->version);
 118                goto exit_free;
 119        }
 120
 121        /* NULL-terminate for safety */
 122        db[*cpp_size] = '\0';
 123
 124        return (void *)db;
 125exit_free:
 126        free(db);
 127        return NULL;
 128}
 129
 130static struct nfp_hwinfo *
 131nfp_hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size)
 132{
 133        struct timespec wait;
 134        struct nfp_hwinfo *db;
 135        int count;
 136
 137        wait.tv_sec = 0;
 138        wait.tv_nsec = 10000000;
 139        count = 0;
 140
 141        for (;;) {
 142                db = nfp_hwinfo_try_fetch(cpp, hwdb_size);
 143                if (db)
 144                        return db;
 145
 146                nanosleep(&wait, NULL);
 147                if (count++ > 200) {
 148                        printf("NFP access error\n");
 149                        return NULL;
 150                }
 151        }
 152}
 153
 154struct nfp_hwinfo *
 155nfp_hwinfo_read(struct nfp_cpp *cpp)
 156{
 157        struct nfp_hwinfo *db;
 158        size_t hwdb_size = 0;
 159        int err;
 160
 161        db = nfp_hwinfo_fetch(cpp, &hwdb_size);
 162        if (!db)
 163                return NULL;
 164
 165        err = nfp_hwinfo_db_validate(db, hwdb_size);
 166        if (err) {
 167                free(db);
 168                return NULL;
 169        }
 170        return db;
 171}
 172
 173/*
 174 * nfp_hwinfo_lookup() - Find a value in the HWInfo table by name
 175 * @hwinfo:     NFP HWinfo table
 176 * @lookup:     HWInfo name to search for
 177 *
 178 * Return: Value of the HWInfo name, or NULL
 179 */
 180const char *
 181nfp_hwinfo_lookup(struct nfp_hwinfo *hwinfo, const char *lookup)
 182{
 183        const char *key, *val, *end;
 184
 185        if (!hwinfo || !lookup)
 186                return NULL;
 187
 188        end = hwinfo->data + hwinfo->size - sizeof(uint32_t);
 189
 190        for (key = hwinfo->data; *key && key < end;
 191             key = val + strlen(val) + 1) {
 192                val = key + strlen(key) + 1;
 193
 194                if (strcmp(key, lookup) == 0)
 195                        return val;
 196        }
 197
 198        return NULL;
 199}
 200