Merge branch 'mlx5-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox...
[sfrench/cifs-2.6.git] / drivers / net / ethernet / netronome / nfp / nfpcore / nfp_hwinfo.c
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 }