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
28 static int
nfp_hwinfo_is_updating(struct nfp_hwinfo * hwinfo)29 nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
30 {
31 return hwinfo->version & NFP_HWINFO_VERSION_UPDATING;
32 }
33
34 static int
nfp_hwinfo_db_walk(struct nfp_hwinfo * hwinfo,uint32_t size)35 nfp_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
55 static int
nfp_hwinfo_db_validate(struct nfp_hwinfo * db,uint32_t len)56 nfp_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
78 static struct nfp_hwinfo *
nfp_hwinfo_try_fetch(struct nfp_cpp * cpp,size_t * cpp_size)79 nfp_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;
125 exit_free:
126 free(db);
127 return NULL;
128 }
129
130 static struct nfp_hwinfo *
nfp_hwinfo_fetch(struct nfp_cpp * cpp,size_t * hwdb_size)131 nfp_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
154 struct nfp_hwinfo *
nfp_hwinfo_read(struct nfp_cpp * cpp)155 nfp_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 */
180 const char *
nfp_hwinfo_lookup(struct nfp_hwinfo * hwinfo,const char * lookup)181 nfp_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