xref: /dpdk/drivers/net/nfp/nfpcore/nfp_rtsym.c (revision 665b49c51639a10c553433bc2bcd85c7331c631e)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Netronome Systems, Inc.
3  * All rights reserved.
4  */
5 
6 /*
7  * nfp_rtsym.c
8  * Interface for accessing run-time symbol table
9  */
10 
11 #include <stdio.h>
12 #include <rte_byteorder.h>
13 #include "nfp_cpp.h"
14 #include "nfp_logs.h"
15 #include "nfp_mip.h"
16 #include "nfp_rtsym.h"
17 #include "nfp6000/nfp6000.h"
18 
19 /* These need to match the linker */
20 #define SYM_TGT_LMEM		0
21 #define SYM_TGT_EMU_CACHE	0x17
22 
23 struct nfp_rtsym_entry {
24 	uint8_t	type;
25 	uint8_t	target;
26 	uint8_t	island;
27 	uint8_t	addr_hi;
28 	uint32_t addr_lo;
29 	uint16_t name;
30 	uint8_t	menum;
31 	uint8_t	size_hi;
32 	uint32_t size_lo;
33 };
34 
35 struct nfp_rtsym_table {
36 	struct nfp_cpp *cpp;
37 	int num;
38 	char *strtab;
39 	struct nfp_rtsym symtab[];
40 };
41 
42 static int
43 nfp_meid(uint8_t island_id, uint8_t menum)
44 {
45 	return (island_id & 0x3F) == island_id && menum < 12 ?
46 		(island_id << 4) | (menum + 4) : -1;
47 }
48 
49 static void
50 nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, uint32_t strtab_size,
51 			struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw)
52 {
53 	sw->type = fw->type;
54 	sw->name = cache->strtab + rte_le_to_cpu_16(fw->name) % strtab_size;
55 	sw->addr = ((uint64_t)fw->addr_hi << 32) |
56 		   rte_le_to_cpu_32(fw->addr_lo);
57 	sw->size = ((uint64_t)fw->size_hi << 32) |
58 		   rte_le_to_cpu_32(fw->size_lo);
59 
60 	PMD_INIT_LOG(DEBUG, "rtsym_entry_init name=%s, addr=%" PRIx64 ", size=%" PRIu64 ", target=%d",
61 		     sw->name, sw->addr, sw->size, sw->target);
62 	switch (fw->target) {
63 	case SYM_TGT_LMEM:
64 		sw->target = NFP_RTSYM_TARGET_LMEM;
65 		break;
66 	case SYM_TGT_EMU_CACHE:
67 		sw->target = NFP_RTSYM_TARGET_EMU_CACHE;
68 		break;
69 	default:
70 		sw->target = fw->target;
71 		break;
72 	}
73 
74 	if (fw->menum != 0xff)
75 		sw->domain = nfp_meid(fw->island, fw->menum);
76 	else if (fw->island != 0xff)
77 		sw->domain = fw->island;
78 	else
79 		sw->domain = -1;
80 }
81 
82 struct nfp_rtsym_table *
83 nfp_rtsym_table_read(struct nfp_cpp *cpp)
84 {
85 	struct nfp_rtsym_table *rtbl;
86 	struct nfp_mip *mip;
87 
88 	mip = nfp_mip_open(cpp);
89 	rtbl = __nfp_rtsym_table_read(cpp, mip);
90 	nfp_mip_close(mip);
91 
92 	return rtbl;
93 }
94 
95 struct nfp_rtsym_table *
96 __nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip)
97 {
98 	uint32_t strtab_addr, symtab_addr, strtab_size, symtab_size;
99 	struct nfp_rtsym_entry *rtsymtab;
100 	struct nfp_rtsym_table *cache;
101 	const uint32_t dram =
102 		NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) |
103 		NFP_ISL_EMEM0;
104 	int err, n, size;
105 
106 	if (mip == NULL)
107 		return NULL;
108 
109 	nfp_mip_strtab(mip, &strtab_addr, &strtab_size);
110 	nfp_mip_symtab(mip, &symtab_addr, &symtab_size);
111 
112 	if (symtab_size == 0 || strtab_size == 0 || symtab_size % sizeof(*rtsymtab) != 0)
113 		return NULL;
114 
115 	/* Align to 64 bits */
116 	symtab_size = round_up(symtab_size, 8);
117 	strtab_size = round_up(strtab_size, 8);
118 
119 	rtsymtab = malloc(symtab_size);
120 	if (rtsymtab == NULL)
121 		return NULL;
122 
123 	size = sizeof(*cache);
124 	size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym);
125 	size +=	strtab_size + 1;
126 	cache = malloc(size);
127 	if (cache == NULL)
128 		goto exit_free_rtsym_raw;
129 
130 	cache->cpp = cpp;
131 	cache->num = symtab_size / sizeof(*rtsymtab);
132 	cache->strtab = (void *)&cache->symtab[cache->num];
133 
134 	err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size);
135 	if (err != (int)symtab_size)
136 		goto exit_free_cache;
137 
138 	err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size);
139 	if (err != (int)strtab_size)
140 		goto exit_free_cache;
141 	cache->strtab[strtab_size] = '\0';
142 
143 	for (n = 0; n < cache->num; n++)
144 		nfp_rtsym_sw_entry_init(cache, strtab_size,
145 					&cache->symtab[n], &rtsymtab[n]);
146 
147 	free(rtsymtab);
148 
149 	return cache;
150 
151 exit_free_cache:
152 	free(cache);
153 exit_free_rtsym_raw:
154 	free(rtsymtab);
155 	return NULL;
156 }
157 
158 /*
159  * nfp_rtsym_count() - Get the number of RTSYM descriptors
160  * @rtbl:	NFP RTsym table
161  *
162  * Return: Number of RTSYM descriptors
163  */
164 int
165 nfp_rtsym_count(struct nfp_rtsym_table *rtbl)
166 {
167 	if (rtbl == NULL)
168 		return -EINVAL;
169 
170 	return rtbl->num;
171 }
172 
173 /*
174  * nfp_rtsym_get() - Get the Nth RTSYM descriptor
175  * @rtbl:	NFP RTsym table
176  * @idx:	Index (0-based) of the RTSYM descriptor
177  *
178  * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
179  */
180 const struct nfp_rtsym *
181 nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx)
182 {
183 	if (rtbl == NULL)
184 		return NULL;
185 
186 	if (idx >= rtbl->num)
187 		return NULL;
188 
189 	return &rtbl->symtab[idx];
190 }
191 
192 /*
193  * nfp_rtsym_lookup() - Return the RTSYM descriptor for a symbol name
194  * @rtbl:	NFP RTsym table
195  * @name:	Symbol name
196  *
197  * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
198  */
199 const struct nfp_rtsym *
200 nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
201 {
202 	int n;
203 
204 	if (rtbl == NULL)
205 		return NULL;
206 
207 	for (n = 0; n < rtbl->num; n++)
208 		if (strcmp(name, rtbl->symtab[n].name) == 0)
209 			return &rtbl->symtab[n];
210 
211 	return NULL;
212 }
213 
214 /*
215  * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol
216  * @rtbl:	NFP RTsym table
217  * @name:	Symbol name
218  * @error:	Pointer to error code (optional)
219  *
220  * Lookup a symbol, map, read it and return it's value. Value of the symbol
221  * will be interpreted as a simple little-endian unsigned value. Symbol can
222  * be 4 or 8 bytes in size.
223  *
224  * Return: value read, on error sets the error and returns ~0ULL.
225  */
226 uint64_t
227 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, int *error)
228 {
229 	const struct nfp_rtsym *sym;
230 	uint32_t val32, id;
231 	uint64_t val;
232 	int err;
233 
234 	sym = nfp_rtsym_lookup(rtbl, name);
235 	if (sym == NULL) {
236 		err = -ENOENT;
237 		goto exit;
238 	}
239 
240 	id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
241 
242 	PMD_DRV_LOG(DEBUG, "Reading symbol %s with size %" PRIu64 " at %" PRIx64 "",
243 		name, sym->size, sym->addr);
244 	switch (sym->size) {
245 	case 4:
246 		err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32);
247 		val = val32;
248 		break;
249 	case 8:
250 		err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val);
251 		break;
252 	default:
253 		PMD_DRV_LOG(ERR, "rtsym '%s' unsupported size: %" PRId64,
254 			name, sym->size);
255 		err = -EINVAL;
256 		break;
257 	}
258 
259 	if (err)
260 		err = -EIO;
261 exit:
262 	if (error)
263 		*error = err;
264 
265 	if (err)
266 		return ~0ULL;
267 
268 	return val;
269 }
270 
271 uint8_t *
272 nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name,
273 	      unsigned int min_size, struct nfp_cpp_area **area)
274 {
275 	const struct nfp_rtsym *sym;
276 	uint8_t *mem;
277 
278 	PMD_DRV_LOG(DEBUG, "mapping symbol %s", name);
279 	sym = nfp_rtsym_lookup(rtbl, name);
280 	if (sym == NULL) {
281 		PMD_INIT_LOG(ERR, "symbol lookup fails for %s", name);
282 		return NULL;
283 	}
284 
285 	if (sym->size < min_size) {
286 		PMD_DRV_LOG(ERR, "Symbol %s too small (%" PRIu64 " < %u)", name,
287 			sym->size, min_size);
288 		return NULL;
289 	}
290 
291 	mem = nfp_cpp_map_area(rtbl->cpp, sym->domain, sym->target, sym->addr,
292 			       sym->size, area);
293 	if (mem == NULL) {
294 		PMD_INIT_LOG(ERR, "Failed to map symbol %s", name);
295 		return NULL;
296 	}
297 	PMD_DRV_LOG(DEBUG, "symbol %s with address %p", name, mem);
298 
299 	return mem;
300 }
301