File Index
Files and directories
Sign in
FILE

nfp_rtsym.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c C
  1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
  3
  4/*
  5 * nfp_rtsym.c
  6 * Interface for accessing run-time symbol table
  7 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
  8 *          Jason McMullan <jason.mcmullan@netronome.com>
  9 *          Espen Skoglund <espen.skoglund@netronome.com>
 10 *          Francois H. Theron <francois.theron@netronome.com>
 11 */
 12
 13#include <linux/unaligned.h>
 14#include <linux/kernel.h>
 15#include <linux/module.h>
 16#include <linux/slab.h>
 17#include <linux/io-64-nonatomic-hi-lo.h>
 18
 19#include "nfp.h"
 20#include "nfp_cpp.h"
 21#include "nfp_nffw.h"
 22#include "nfp6000/nfp6000.h"
 23
 24/* These need to match the linker */
 25#define SYM_TGT_LMEM		0
 26#define SYM_TGT_EMU_CACHE	0x17
 27
 28struct nfp_rtsym_entry {
 29	u8	type;
 30	u8	target;
 31	u8	island;
 32	u8	addr_hi;
 33	__le32	addr_lo;
 34	__le16	name;
 35	u8	menum;
 36	u8	size_hi;
 37	__le32	size_lo;
 38};
 39
 40struct nfp_rtsym_table {
 41	struct nfp_cpp *cpp;
 42	int num;
 43	char *strtab;
 44	struct nfp_rtsym symtab[];
 45};
 46
 47static int nfp_meid(u8 island_id, u8 menum)
 48{
 49	return (island_id & 0x3F) == island_id && menum < 12 ?
 50		(island_id << 4) | (menum + 4) : -1;
 51}
 52
 53static void
 54nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size,
 55			struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw)
 56{
 57	sw->type = fw->type;
 58	sw->name = cache->strtab + le16_to_cpu(fw->name) % strtab_size;
 59	sw->addr = ((u64)fw->addr_hi << 32) | le32_to_cpu(fw->addr_lo);
 60	sw->size = ((u64)fw->size_hi << 32) | le32_to_cpu(fw->size_lo);
 61
 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
 82struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp)
 83{
 84	struct nfp_rtsym_table *rtbl;
 85	const struct nfp_mip *mip;
 86
 87	mip = nfp_mip_open(cpp);
 88	rtbl = __nfp_rtsym_table_read(cpp, mip);
 89	nfp_mip_close(mip);
 90
 91	return rtbl;
 92}
 93
 94struct nfp_rtsym_table *
 95__nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip)
 96{
 97	const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) |
 98		NFP_ISL_EMEM0;
 99	u32 strtab_addr, symtab_addr, strtab_size, symtab_size;
100	struct nfp_rtsym_entry *rtsymtab;
101	struct nfp_rtsym_table *cache;
102	int err, n, size;
103
104	if (!mip)
105		return NULL;
106
107	nfp_mip_strtab(mip, &strtab_addr, &strtab_size);
108	nfp_mip_symtab(mip, &symtab_addr, &symtab_size);
109
110	if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab))
111		return NULL;
112
113	/* Align to 64 bits */
114	symtab_size = round_up(symtab_size, 8);
115	strtab_size = round_up(strtab_size, 8);
116
117	rtsymtab = kmalloc(symtab_size, GFP_KERNEL);
118	if (!rtsymtab)
119		return NULL;
120
121	size = sizeof(*cache);
122	size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym);
123	size +=	strtab_size + 1;
124	cache = kmalloc(size, GFP_KERNEL);
125	if (!cache)
126		goto exit_free_rtsym_raw;
127
128	cache->cpp = cpp;
129	cache->num = symtab_size / sizeof(*rtsymtab);
130	cache->strtab = (void *)&cache->symtab[cache->num];
131
132	err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size);
133	if (err != symtab_size)
134		goto exit_free_cache;
135
136	err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size);
137	if (err != strtab_size)
138		goto exit_free_cache;
139	cache->strtab[strtab_size] = '\0';
140
141	for (n = 0; n < cache->num; n++)
142		nfp_rtsym_sw_entry_init(cache, strtab_size,
143					&cache->symtab[n], &rtsymtab[n]);
144
145	kfree(rtsymtab);
146
147	return cache;
148
149exit_free_cache:
150	kfree(cache);
151exit_free_rtsym_raw:
152	kfree(rtsymtab);
153	return NULL;
154}
155
156/**
157 * nfp_rtsym_count() - Get the number of RTSYM descriptors
158 * @rtbl:	NFP RTsym table
159 *
160 * Return: Number of RTSYM descriptors
161 */
162int nfp_rtsym_count(struct nfp_rtsym_table *rtbl)
163{
164	if (!rtbl)
165		return -EINVAL;
166	return rtbl->num;
167}
168
169/**
170 * nfp_rtsym_get() - Get the Nth RTSYM descriptor
171 * @rtbl:	NFP RTsym table
172 * @idx:	Index (0-based) of the RTSYM descriptor
173 *
174 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
175 */
176const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx)
177{
178	if (!rtbl)
179		return NULL;
180	if (idx >= rtbl->num)
181		return NULL;
182
183	return &rtbl->symtab[idx];
184}
185
186/**
187 * nfp_rtsym_lookup() - Return the RTSYM descriptor for a symbol name
188 * @rtbl:	NFP RTsym table
189 * @name:	Symbol name
190 *
191 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
192 */
193const struct nfp_rtsym *
194nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
195{
196	int n;
197
198	if (!rtbl)
199		return NULL;
200
201	for (n = 0; n < rtbl->num; n++)
202		if (strcmp(name, rtbl->symtab[n].name) == 0)
203			return &rtbl->symtab[n];
204
205	return NULL;
206}
207
208u64 nfp_rtsym_size(const struct nfp_rtsym *sym)
209{
210	switch (sym->type) {
211	case NFP_RTSYM_TYPE_NONE:
212		pr_err("rtsym '%s': type NONE\n", sym->name);
213		return 0;
214	default:
215		pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type);
216		fallthrough;
217	case NFP_RTSYM_TYPE_OBJECT:
218	case NFP_RTSYM_TYPE_FUNCTION:
219		return sym->size;
220	case NFP_RTSYM_TYPE_ABS:
221		return sizeof(u64);
222	}
223}
224
225static int
226nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
227		  u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr)
228{
229	if (sym->type != NFP_RTSYM_TYPE_OBJECT) {
230		nfp_err(cpp, "rtsym '%s': direct access to non-object rtsym\n",
231			sym->name);
232		return -EINVAL;
233	}
234
235	*addr = sym->addr + off;
236
237	if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) {
238		int locality_off = nfp_cpp_mu_locality_lsb(cpp);
239
240		*addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
241		*addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
242
243		*cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token,
244					    sym->domain);
245	} else if (sym->target < 0) {
246		nfp_err(cpp, "rtsym '%s': unhandled target encoding: %d\n",
247			sym->name, sym->target);
248		return -EINVAL;
249	} else {
250		*cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token,
251					    sym->domain);
252	}
253
254	return 0;
255}
256
257int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
258		     u8 action, u8 token, u64 off, void *buf, size_t len)
259{
260	u64 sym_size = nfp_rtsym_size(sym);
261	u32 cpp_id;
262	u64 addr;
263	int err;
264
265	if (off > sym_size) {
266		nfp_err(cpp, "rtsym '%s': read out of bounds: off: %lld + len: %zd > size: %lld\n",
267			sym->name, off, len, sym_size);
268		return -ENXIO;
269	}
270	len = min_t(size_t, len, sym_size - off);
271
272	if (sym->type == NFP_RTSYM_TYPE_ABS) {
273		u8 tmp[8];
274
275		put_unaligned_le64(sym->addr, tmp);
276		memcpy(buf, &tmp[off], len);
277
278		return len;
279	}
280
281	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
282	if (err)
283		return err;
284
285	return nfp_cpp_read(cpp, cpp_id, addr, buf, len);
286}
287
288int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
289		   void *buf, size_t len)
290{
291	return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
292}
293
294int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
295		      u8 action, u8 token, u64 off, u32 *value)
296{
297	u32 cpp_id;
298	u64 addr;
299	int err;
300
301	if (off + 4 > nfp_rtsym_size(sym)) {
302		nfp_err(cpp, "rtsym '%s': readl out of bounds: off: %lld + 4 > size: %lld\n",
303			sym->name, off, nfp_rtsym_size(sym));
304		return -ENXIO;
305	}
306
307	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
308	if (err)
309		return err;
310
311	return nfp_cpp_readl(cpp, cpp_id, addr, value);
312}
313
314int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
315		    u32 *value)
316{
317	return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
318}
319
320int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
321		      u8 action, u8 token, u64 off, u64 *value)
322{
323	u32 cpp_id;
324	u64 addr;
325	int err;
326
327	if (off + 8 > nfp_rtsym_size(sym)) {
328		nfp_err(cpp, "rtsym '%s': readq out of bounds: off: %lld + 8 > size: %lld\n",
329			sym->name, off, nfp_rtsym_size(sym));
330		return -ENXIO;
331	}
332
333	if (sym->type == NFP_RTSYM_TYPE_ABS) {
334		*value = sym->addr;
335		return 0;
336	}
337
338	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
339	if (err)
340		return err;
341
342	return nfp_cpp_readq(cpp, cpp_id, addr, value);
343}
344
345int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
346		    u64 *value)
347{
348	return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
349}
350
351int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
352		      u8 action, u8 token, u64 off, void *buf, size_t len)
353{
354	u64 sym_size = nfp_rtsym_size(sym);
355	u32 cpp_id;
356	u64 addr;
357	int err;
358
359	if (off > sym_size) {
360		nfp_err(cpp, "rtsym '%s': write out of bounds: off: %lld + len: %zd > size: %lld\n",
361			sym->name, off, len, sym_size);
362		return -ENXIO;
363	}
364	len = min_t(size_t, len, sym_size - off);
365
366	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
367	if (err)
368		return err;
369
370	return nfp_cpp_write(cpp, cpp_id, addr, buf, len);
371}
372
373int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
374		    void *buf, size_t len)
375{
376	return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
377}
378
379int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
380		       u8 action, u8 token, u64 off, u32 value)
381{
382	u32 cpp_id;
383	u64 addr;
384	int err;
385
386	if (off + 4 > nfp_rtsym_size(sym)) {
387		nfp_err(cpp, "rtsym '%s': writel out of bounds: off: %lld + 4 > size: %lld\n",
388			sym->name, off, nfp_rtsym_size(sym));
389		return -ENXIO;
390	}
391
392	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
393	if (err)
394		return err;
395
396	return nfp_cpp_writel(cpp, cpp_id, addr, value);
397}
398
399int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
400		     u32 value)
401{
402	return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
403}
404
405int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
406		       u8 action, u8 token, u64 off, u64 value)
407{
408	u32 cpp_id;
409	u64 addr;
410	int err;
411
412	if (off + 8 > nfp_rtsym_size(sym)) {
413		nfp_err(cpp, "rtsym '%s': writeq out of bounds: off: %lld + 8 > size: %lld\n",
414			sym->name, off, nfp_rtsym_size(sym));
415		return -ENXIO;
416	}
417
418	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
419	if (err)
420		return err;
421
422	return nfp_cpp_writeq(cpp, cpp_id, addr, value);
423}
424
425int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
426		     u64 value)
427{
428	return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
429}
430
431/**
432 * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol
433 * @rtbl:	NFP RTsym table
434 * @name:	Symbol name
435 * @error:	Poniter to error code (optional)
436 *
437 * Lookup a symbol, map, read it and return it's value. Value of the symbol
438 * will be interpreted as a simple little-endian unsigned value. Symbol can
439 * be 4 or 8 bytes in size.
440 *
441 * Return: value read, on error sets the error and returns ~0ULL.
442 */
443u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
444		      int *error)
445{
446	const struct nfp_rtsym *sym;
447	u32 val32;
448	u64 val;
449	int err;
450
451	sym = nfp_rtsym_lookup(rtbl, name);
452	if (!sym) {
453		err = -ENOENT;
454		goto exit;
455	}
456
457	switch (nfp_rtsym_size(sym)) {
458	case 4:
459		err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32);
460		val = val32;
461		break;
462	case 8:
463		err = nfp_rtsym_readq(rtbl->cpp, sym, 0, &val);
464		break;
465	default:
466		nfp_err(rtbl->cpp,
467			"rtsym '%s': unsupported or non-scalar size: %lld\n",
468			name, nfp_rtsym_size(sym));
469		err = -EINVAL;
470		break;
471	}
472
473exit:
474	if (error)
475		*error = err;
476
477	if (err)
478		return ~0ULL;
479	return val;
480}
481
482/**
483 * nfp_rtsym_write_le() - Write an unsigned scalar value to a symbol
484 * @rtbl:	NFP RTsym table
485 * @name:	Symbol name
486 * @value:	Value to write
487 *
488 * Lookup a symbol and write a value to it. Symbol can be 4 or 8 bytes in size.
489 * If 4 bytes then the lower 32-bits of 'value' are used. Value will be
490 * written as simple little-endian unsigned value.
491 *
492 * Return: 0 on success or error code.
493 */
494int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
495		       u64 value)
496{
497	const struct nfp_rtsym *sym;
498	int err;
499
500	sym = nfp_rtsym_lookup(rtbl, name);
501	if (!sym)
502		return -ENOENT;
503
504	switch (nfp_rtsym_size(sym)) {
505	case 4:
506		err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value);
507		break;
508	case 8:
509		err = nfp_rtsym_writeq(rtbl->cpp, sym, 0, value);
510		break;
511	default:
512		nfp_err(rtbl->cpp,
513			"rtsym '%s': unsupported or non-scalar size: %lld\n",
514			name, nfp_rtsym_size(sym));
515		err = -EINVAL;
516		break;
517	}
518
519	return err;
520}
521
522u8 __iomem *
523nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
524	      unsigned int min_size, struct nfp_cpp_area **area)
525{
526	const struct nfp_rtsym *sym;
527	u8 __iomem *mem;
528	u32 cpp_id;
529	u64 addr;
530	int err;
531
532	sym = nfp_rtsym_lookup(rtbl, name);
533	if (!sym)
534		return (u8 __iomem *)ERR_PTR(-ENOENT);
535
536	err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0,
537				&cpp_id, &addr);
538	if (err) {
539		nfp_err(rtbl->cpp, "rtsym '%s': mapping failed\n", name);
540		return (u8 __iomem *)ERR_PTR(err);
541	}
542
543	if (sym->size < min_size) {
544		nfp_err(rtbl->cpp, "rtsym '%s': too small\n", name);
545		return (u8 __iomem *)ERR_PTR(-EINVAL);
546	}
547
548	mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area);
549	if (IS_ERR(mem)) {
550		nfp_err(rtbl->cpp, "rtysm '%s': failed to map: %ld\n",
551			name, PTR_ERR(mem));
552		return mem;
553	}
554
555	return mem;
556}
~/ Read-only file preview.