linux/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
   3
   4/* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM
   5 * after chip reset.
   6 *
   7 * Examples of the fields:
   8 *   me.count = 40
   9 *   me.mask = 0x7f_ffff_ffff
  10 *
  11 *   me.count is the total number of MEs on the system.
  12 *   me.mask is the bitmask of MEs that are available for application usage.
  13 *
  14 *   (ie, in this example, ME 39 has been reserved by boardconfig.)
  15 */
  16
  17#include <asm/byteorder.h>
  18#include <asm/unaligned.h>
  19#include <linux/delay.h>
  20#include <linux/log2.h>
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/slab.h>
  24
  25#define NFP_SUBSYS "nfp_hwinfo"
  26
  27#include "crc32.h"
  28#include "nfp.h"
  29#include "nfp_cpp.h"
  30#include "nfp6000/nfp6000.h"
  31
  32#define HWINFO_SIZE_MIN 0x100
  33#define HWINFO_WAIT     20      /* seconds */
  34
  35/* The Hardware Info Table defines the properties of the system.
  36 *
  37 * HWInfo v1 Table (fixed size)
  38 *
  39 * 0x0000: u32 version          Hardware Info Table version (1.0)
  40 * 0x0004: u32 size             Total size of the table, including
  41 *                              the CRC32 (IEEE 802.3)
  42 * 0x0008: u32 jumptab          Offset of key/value table
  43 * 0x000c: u32 keys             Total number of keys in the key/value table
  44 * NNNNNN:                      Key/value jump table and string data
  45 * (size - 4): u32 crc32        CRC32 (same as IEEE 802.3, POSIX csum, etc)
  46 *                              CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
  47 *
  48 * HWInfo v2 Table (variable size)
  49 *
  50 * 0x0000: u32 version          Hardware Info Table version (2.0)
  51 * 0x0004: u32 size             Current size of the data area, excluding CRC32
  52 * 0x0008: u32 limit            Maximum size of the table
  53 * 0x000c: u32 reserved         Unused, set to zero
  54 * NNNNNN:                      Key/value data
  55 * (size - 4): u32 crc32        CRC32 (same as IEEE 802.3, POSIX csum, etc)
  56 *                              CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
  57 *
  58 * If the HWInfo table is in the process of being updated, the low bit
  59 * of version will be set.
  60 *
  61 * HWInfo v1 Key/Value Table
  62 * -------------------------
  63 *
  64 *  The key/value table is a set of offsets to ASCIIZ strings which have
  65 *  been strcmp(3) sorted (yes, please use bsearch(3) on the table).
  66 *
  67 *  All keys are guaranteed to be unique.
  68 *
  69 * N+0: u32 key_1               Offset to the first key
  70 * N+4: u32 val_1               Offset to the first value
  71 * N+8: u32 key_2               Offset to the second key
  72 * N+c: u32 val_2               Offset to the second value
  73 * ...
  74 *
  75 * HWInfo v2 Key/Value Table
  76 * -------------------------
  77 *
  78 * Packed UTF8Z strings, ie 'key1\000value1\000key2\000value2\000'
  79 *
  80 * Unsorted.
  81 */
  82
  83#define NFP_HWINFO_VERSION_1 ('H' << 24 | 'I' << 16 | 1 << 8 | 0 << 1 | 0)
  84#define NFP_HWINFO_VERSION_2 ('H' << 24 | 'I' << 16 | 2 << 8 | 0 << 1 | 0)
  85#define NFP_HWINFO_VERSION_UPDATING     BIT(0)
  86
  87struct nfp_hwinfo {
  88        u8 start[0];
  89
  90        __le32 version;
  91        __le32 size;
  92
  93        /* v2 specific fields */
  94        __le32 limit;
  95        __le32 resv;
  96
  97        char data[];
  98};
  99
 100static bool nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
 101{
 102        return le32_to_cpu(hwinfo->version) & NFP_HWINFO_VERSION_UPDATING;
 103}
 104
 105static int
 106hwinfo_db_walk(struct nfp_cpp *cpp, struct nfp_hwinfo *hwinfo, u32 size)
 107{
 108        const char *key, *val, *end = hwinfo->data + size;
 109
 110        for (key = hwinfo->data; *key && key < end;
 111             key = val + strlen(val) + 1) {
 112
 113                val = key + strlen(key) + 1;
 114                if (val >= end) {
 115                        nfp_warn(cpp, "Bad HWINFO - overflowing key\n");
 116                        return -EINVAL;
 117                }
 118
 119                if (val + strlen(val) + 1 > end) {
 120                        nfp_warn(cpp, "Bad HWINFO - overflowing value\n");
 121                        return -EINVAL;
 122                }
 123        }
 124
 125        return 0;
 126}
 127
 128static int
 129hwinfo_db_validate(struct nfp_cpp *cpp, struct nfp_hwinfo *db, u32 len)
 130{
 131        u32 size, crc;
 132
 133        size = le32_to_cpu(db->size);
 134        if (size > len) {
 135                nfp_err(cpp, "Unsupported hwinfo size %u > %u\n", size, len);
 136                return -EINVAL;
 137        }
 138
 139        size -= sizeof(u32);
 140        crc = crc32_posix(db, size);
 141        if (crc != get_unaligned_le32(db->start + size)) {
 142                nfp_err(cpp, "Corrupt hwinfo table (CRC mismatch), calculated 0x%x, expected 0x%x\n",
 143                        crc, get_unaligned_le32(db->start + size));
 144
 145                return -EINVAL;
 146        }
 147
 148        return hwinfo_db_walk(cpp, db, size);
 149}
 150
 151static struct nfp_hwinfo *
 152hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size)
 153{
 154        struct nfp_hwinfo *header;
 155        struct nfp_resource *res;
 156        u64 cpp_addr;
 157        u32 cpp_id;
 158        int err;
 159        u8 *db;
 160
 161        res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO);
 162        if (!IS_ERR(res)) {
 163                cpp_id = nfp_resource_cpp_id(res);
 164                cpp_addr = nfp_resource_address(res);
 165                *cpp_size = nfp_resource_size(res);
 166
 167                nfp_resource_release(res);
 168
 169                if (*cpp_size < HWINFO_SIZE_MIN)
 170                        return NULL;
 171        } else if (PTR_ERR(res) == -ENOENT) {
 172                /* Try getting the HWInfo table from the 'classic' location */
 173                cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU,
 174                                           NFP_CPP_ACTION_RW, 0, 1);
 175                cpp_addr = 0x30000;
 176                *cpp_size = 0x0e000;
 177        } else {
 178                return NULL;
 179        }
 180
 181        db = kmalloc(*cpp_size + 1, GFP_KERNEL);
 182        if (!db)
 183                return NULL;
 184
 185        err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size);
 186        if (err != *cpp_size)
 187                goto exit_free;
 188
 189        header = (void *)db;
 190        if (nfp_hwinfo_is_updating(header))
 191                goto exit_free;
 192
 193        if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) {
 194                nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n",
 195                        le32_to_cpu(header->version));
 196                goto exit_free;
 197        }
 198
 199        /* NULL-terminate for safety */
 200        db[*cpp_size] = '\0';
 201
 202        return (void *)db;
 203exit_free:
 204        kfree(db);
 205        return NULL;
 206}
 207
 208static struct nfp_hwinfo *hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size)
 209{
 210        const unsigned long wait_until = jiffies + HWINFO_WAIT * HZ;
 211        struct nfp_hwinfo *db;
 212        int err;
 213
 214        for (;;) {
 215                const unsigned long start_time = jiffies;
 216
 217                db = hwinfo_try_fetch(cpp, hwdb_size);
 218                if (db)
 219                        return db;
 220
 221                err = msleep_interruptible(100);
 222                if (err || time_after(start_time, wait_until)) {
 223                        nfp_err(cpp, "NFP access error\n");
 224                        return NULL;
 225                }
 226        }
 227}
 228
 229struct nfp_hwinfo *nfp_hwinfo_read(struct nfp_cpp *cpp)
 230{
 231        struct nfp_hwinfo *db;
 232        size_t hwdb_size = 0;
 233        int err;
 234
 235        db = hwinfo_fetch(cpp, &hwdb_size);
 236        if (!db)
 237                return NULL;
 238
 239        err = hwinfo_db_validate(cpp, db, hwdb_size);
 240        if (err) {
 241                kfree(db);
 242                return NULL;
 243        }
 244
 245        return db;
 246}
 247
 248/**
 249 * nfp_hwinfo_lookup() - Find a value in the HWInfo table by name
 250 * @hwinfo:     NFP HWinfo table
 251 * @lookup:     HWInfo name to search for
 252 *
 253 * Return: Value of the HWInfo name, or NULL
 254 */
 255const char *nfp_hwinfo_lookup(struct nfp_hwinfo *hwinfo, const char *lookup)
 256{
 257        const char *key, *val, *end;
 258
 259        if (!hwinfo || !lookup)
 260                return NULL;
 261
 262        end = hwinfo->data + le32_to_cpu(hwinfo->size) - sizeof(u32);
 263
 264        for (key = hwinfo->data; *key && key < end;
 265             key = val + strlen(val) + 1) {
 266
 267                val = key + strlen(key) + 1;
 268
 269                if (strcmp(key, lookup) == 0)
 270                        return val;
 271        }
 272
 273        return NULL;
 274}
 275
 276char *nfp_hwinfo_get_packed_strings(struct nfp_hwinfo *hwinfo)
 277{
 278        return hwinfo->data;
 279}
 280
 281u32 nfp_hwinfo_get_packed_str_size(struct nfp_hwinfo *hwinfo)
 282{
 283        return le32_to_cpu(hwinfo->size) - sizeof(u32);
 284}
 285