root/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfp_hwinfo_is_updating
  2. hwinfo_db_walk
  3. hwinfo_db_validate
  4. hwinfo_try_fetch
  5. hwinfo_fetch
  6. nfp_hwinfo_read
  7. nfp_hwinfo_lookup
  8. nfp_hwinfo_get_packed_strings
  9. nfp_hwinfo_get_packed_str_size

   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 
  87 struct 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 
 100 static bool nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
 101 {
 102         return le32_to_cpu(hwinfo->version) & NFP_HWINFO_VERSION_UPDATING;
 103 }
 104 
 105 static int
 106 hwinfo_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 
 128 static int
 129 hwinfo_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 
 151 static struct nfp_hwinfo *
 152 hwinfo_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;
 203 exit_free:
 204         kfree(db);
 205         return NULL;
 206 }
 207 
 208 static 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 
 229 struct 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  */
 255 const 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 
 276 char *nfp_hwinfo_get_packed_strings(struct nfp_hwinfo *hwinfo)
 277 {
 278         return hwinfo->data;
 279 }
 280 
 281 u32 nfp_hwinfo_get_packed_str_size(struct nfp_hwinfo *hwinfo)
 282 {
 283         return le32_to_cpu(hwinfo->size) - sizeof(u32);
 284 }

/* [<][>][^][v][top][bottom][index][help] */