Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2015-2017 Netronome Systems, Inc. */
0003 
0004 /* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM
0005  * after chip reset.
0006  *
0007  * Examples of the fields:
0008  *   me.count = 40
0009  *   me.mask = 0x7f_ffff_ffff
0010  *
0011  *   me.count is the total number of MEs on the system.
0012  *   me.mask is the bitmask of MEs that are available for application usage.
0013  *
0014  *   (ie, in this example, ME 39 has been reserved by boardconfig.)
0015  */
0016 
0017 #include <asm/byteorder.h>
0018 #include <asm/unaligned.h>
0019 #include <linux/delay.h>
0020 #include <linux/log2.h>
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 #include <linux/slab.h>
0024 
0025 #define NFP_SUBSYS "nfp_hwinfo"
0026 
0027 #include "crc32.h"
0028 #include "nfp.h"
0029 #include "nfp_cpp.h"
0030 #include "nfp6000/nfp6000.h"
0031 
0032 #define HWINFO_SIZE_MIN 0x100
0033 #define HWINFO_WAIT 20  /* seconds */
0034 
0035 /* The Hardware Info Table defines the properties of the system.
0036  *
0037  * HWInfo v1 Table (fixed size)
0038  *
0039  * 0x0000: u32 version          Hardware Info Table version (1.0)
0040  * 0x0004: u32 size         Total size of the table, including
0041  *                  the CRC32 (IEEE 802.3)
0042  * 0x0008: u32 jumptab          Offset of key/value table
0043  * 0x000c: u32 keys         Total number of keys in the key/value table
0044  * NNNNNN:              Key/value jump table and string data
0045  * (size - 4): u32 crc32    CRC32 (same as IEEE 802.3, POSIX csum, etc)
0046  *              CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
0047  *
0048  * HWInfo v2 Table (variable size)
0049  *
0050  * 0x0000: u32 version          Hardware Info Table version (2.0)
0051  * 0x0004: u32 size         Current size of the data area, excluding CRC32
0052  * 0x0008: u32 limit            Maximum size of the table
0053  * 0x000c: u32 reserved         Unused, set to zero
0054  * NNNNNN:          Key/value data
0055  * (size - 4): u32 crc32    CRC32 (same as IEEE 802.3, POSIX csum, etc)
0056  *              CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
0057  *
0058  * If the HWInfo table is in the process of being updated, the low bit
0059  * of version will be set.
0060  *
0061  * HWInfo v1 Key/Value Table
0062  * -------------------------
0063  *
0064  *  The key/value table is a set of offsets to ASCIIZ strings which have
0065  *  been strcmp(3) sorted (yes, please use bsearch(3) on the table).
0066  *
0067  *  All keys are guaranteed to be unique.
0068  *
0069  * N+0: u32 key_1       Offset to the first key
0070  * N+4: u32 val_1       Offset to the first value
0071  * N+8: u32 key_2       Offset to the second key
0072  * N+c: u32 val_2       Offset to the second value
0073  * ...
0074  *
0075  * HWInfo v2 Key/Value Table
0076  * -------------------------
0077  *
0078  * Packed UTF8Z strings, ie 'key1\000value1\000key2\000value2\000'
0079  *
0080  * Unsorted.
0081  */
0082 
0083 #define NFP_HWINFO_VERSION_1 ('H' << 24 | 'I' << 16 | 1 << 8 | 0 << 1 | 0)
0084 #define NFP_HWINFO_VERSION_2 ('H' << 24 | 'I' << 16 | 2 << 8 | 0 << 1 | 0)
0085 #define NFP_HWINFO_VERSION_UPDATING BIT(0)
0086 
0087 struct nfp_hwinfo {
0088     u8 start[0];
0089 
0090     __le32 version;
0091     __le32 size;
0092 
0093     /* v2 specific fields */
0094     __le32 limit;
0095     __le32 resv;
0096 
0097     char data[];
0098 };
0099 
0100 static bool nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
0101 {
0102     return le32_to_cpu(hwinfo->version) & NFP_HWINFO_VERSION_UPDATING;
0103 }
0104 
0105 static int
0106 hwinfo_db_walk(struct nfp_cpp *cpp, struct nfp_hwinfo *hwinfo, u32 size)
0107 {
0108     const char *key, *val, *end = hwinfo->data + size;
0109 
0110     for (key = hwinfo->data; *key && key < end;
0111          key = val + strlen(val) + 1) {
0112 
0113         val = key + strlen(key) + 1;
0114         if (val >= end) {
0115             nfp_warn(cpp, "Bad HWINFO - overflowing key\n");
0116             return -EINVAL;
0117         }
0118 
0119         if (val + strlen(val) + 1 > end) {
0120             nfp_warn(cpp, "Bad HWINFO - overflowing value\n");
0121             return -EINVAL;
0122         }
0123     }
0124 
0125     return 0;
0126 }
0127 
0128 static int
0129 hwinfo_db_validate(struct nfp_cpp *cpp, struct nfp_hwinfo *db, u32 len)
0130 {
0131     u32 size, crc;
0132 
0133     size = le32_to_cpu(db->size);
0134     if (size > len) {
0135         nfp_err(cpp, "Unsupported hwinfo size %u > %u\n", size, len);
0136         return -EINVAL;
0137     }
0138 
0139     size -= sizeof(u32);
0140     crc = crc32_posix(db, size);
0141     if (crc != get_unaligned_le32(db->start + size)) {
0142         nfp_err(cpp, "Corrupt hwinfo table (CRC mismatch), calculated 0x%x, expected 0x%x\n",
0143             crc, get_unaligned_le32(db->start + size));
0144 
0145         return -EINVAL;
0146     }
0147 
0148     return hwinfo_db_walk(cpp, db, size);
0149 }
0150 
0151 static struct nfp_hwinfo *
0152 hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size)
0153 {
0154     struct nfp_hwinfo *header;
0155     struct nfp_resource *res;
0156     u64 cpp_addr;
0157     u32 cpp_id;
0158     int err;
0159     u8 *db;
0160 
0161     res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO);
0162     if (!IS_ERR(res)) {
0163         cpp_id = nfp_resource_cpp_id(res);
0164         cpp_addr = nfp_resource_address(res);
0165         *cpp_size = nfp_resource_size(res);
0166 
0167         nfp_resource_release(res);
0168 
0169         if (*cpp_size < HWINFO_SIZE_MIN)
0170             return NULL;
0171     } else if (PTR_ERR(res) == -ENOENT) {
0172         /* Try getting the HWInfo table from the 'classic' location */
0173         cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU,
0174                        NFP_CPP_ACTION_RW, 0, 1);
0175         cpp_addr = 0x30000;
0176         *cpp_size = 0x0e000;
0177     } else {
0178         return NULL;
0179     }
0180 
0181     db = kmalloc(*cpp_size + 1, GFP_KERNEL);
0182     if (!db)
0183         return NULL;
0184 
0185     err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size);
0186     if (err != *cpp_size)
0187         goto exit_free;
0188 
0189     header = (void *)db;
0190     if (nfp_hwinfo_is_updating(header))
0191         goto exit_free;
0192 
0193     if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) {
0194         nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n",
0195             le32_to_cpu(header->version));
0196         goto exit_free;
0197     }
0198 
0199     /* NULL-terminate for safety */
0200     db[*cpp_size] = '\0';
0201 
0202     return (void *)db;
0203 exit_free:
0204     kfree(db);
0205     return NULL;
0206 }
0207 
0208 static struct nfp_hwinfo *hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size)
0209 {
0210     const unsigned long wait_until = jiffies + HWINFO_WAIT * HZ;
0211     struct nfp_hwinfo *db;
0212     int err;
0213 
0214     for (;;) {
0215         const unsigned long start_time = jiffies;
0216 
0217         db = hwinfo_try_fetch(cpp, hwdb_size);
0218         if (db)
0219             return db;
0220 
0221         err = msleep_interruptible(100);
0222         if (err || time_after(start_time, wait_until)) {
0223             nfp_err(cpp, "NFP access error\n");
0224             return NULL;
0225         }
0226     }
0227 }
0228 
0229 struct nfp_hwinfo *nfp_hwinfo_read(struct nfp_cpp *cpp)
0230 {
0231     struct nfp_hwinfo *db;
0232     size_t hwdb_size = 0;
0233     int err;
0234 
0235     db = hwinfo_fetch(cpp, &hwdb_size);
0236     if (!db)
0237         return NULL;
0238 
0239     err = hwinfo_db_validate(cpp, db, hwdb_size);
0240     if (err) {
0241         kfree(db);
0242         return NULL;
0243     }
0244 
0245     return db;
0246 }
0247 
0248 /**
0249  * nfp_hwinfo_lookup() - Find a value in the HWInfo table by name
0250  * @hwinfo: NFP HWinfo table
0251  * @lookup: HWInfo name to search for
0252  *
0253  * Return: Value of the HWInfo name, or NULL
0254  */
0255 const char *nfp_hwinfo_lookup(struct nfp_hwinfo *hwinfo, const char *lookup)
0256 {
0257     const char *key, *val, *end;
0258 
0259     if (!hwinfo || !lookup)
0260         return NULL;
0261 
0262     end = hwinfo->data + le32_to_cpu(hwinfo->size) - sizeof(u32);
0263 
0264     for (key = hwinfo->data; *key && key < end;
0265          key = val + strlen(val) + 1) {
0266 
0267         val = key + strlen(key) + 1;
0268 
0269         if (strcmp(key, lookup) == 0)
0270             return val;
0271     }
0272 
0273     return NULL;
0274 }
0275 
0276 char *nfp_hwinfo_get_packed_strings(struct nfp_hwinfo *hwinfo)
0277 {
0278     return hwinfo->data;
0279 }
0280 
0281 u32 nfp_hwinfo_get_packed_str_size(struct nfp_hwinfo *hwinfo)
0282 {
0283     return le32_to_cpu(hwinfo->size) - sizeof(u32);
0284 }