1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
28static int
29nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
30{
31 return hwinfo->version & NFP_HWINFO_VERSION_UPDATING;
32}
33
34static int
35nfp_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
55static int
56nfp_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
78static struct nfp_hwinfo *
79nfp_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
122 db[*cpp_size] = '\0';
123
124 return (void *)db;
125exit_free:
126 free(db);
127 return NULL;
128}
129
130static struct nfp_hwinfo *
131nfp_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
154struct nfp_hwinfo *
155nfp_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
175
176
177
178
179
180const char *
181nfp_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