0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <asm/unaligned.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 #include <linux/io-64-nonatomic-hi-lo.h>
0018
0019 #include "nfp.h"
0020 #include "nfp_cpp.h"
0021 #include "nfp_nffw.h"
0022 #include "nfp6000/nfp6000.h"
0023
0024
0025 #define SYM_TGT_LMEM 0
0026 #define SYM_TGT_EMU_CACHE 0x17
0027
0028 struct nfp_rtsym_entry {
0029 u8 type;
0030 u8 target;
0031 u8 island;
0032 u8 addr_hi;
0033 __le32 addr_lo;
0034 __le16 name;
0035 u8 menum;
0036 u8 size_hi;
0037 __le32 size_lo;
0038 };
0039
0040 struct nfp_rtsym_table {
0041 struct nfp_cpp *cpp;
0042 int num;
0043 char *strtab;
0044 struct nfp_rtsym symtab[];
0045 };
0046
0047 static int nfp_meid(u8 island_id, u8 menum)
0048 {
0049 return (island_id & 0x3F) == island_id && menum < 12 ?
0050 (island_id << 4) | (menum + 4) : -1;
0051 }
0052
0053 static void
0054 nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size,
0055 struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw)
0056 {
0057 sw->type = fw->type;
0058 sw->name = cache->strtab + le16_to_cpu(fw->name) % strtab_size;
0059 sw->addr = ((u64)fw->addr_hi << 32) | le32_to_cpu(fw->addr_lo);
0060 sw->size = ((u64)fw->size_hi << 32) | le32_to_cpu(fw->size_lo);
0061
0062 switch (fw->target) {
0063 case SYM_TGT_LMEM:
0064 sw->target = NFP_RTSYM_TARGET_LMEM;
0065 break;
0066 case SYM_TGT_EMU_CACHE:
0067 sw->target = NFP_RTSYM_TARGET_EMU_CACHE;
0068 break;
0069 default:
0070 sw->target = fw->target;
0071 break;
0072 }
0073
0074 if (fw->menum != 0xff)
0075 sw->domain = nfp_meid(fw->island, fw->menum);
0076 else if (fw->island != 0xff)
0077 sw->domain = fw->island;
0078 else
0079 sw->domain = -1;
0080 }
0081
0082 struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp)
0083 {
0084 struct nfp_rtsym_table *rtbl;
0085 const struct nfp_mip *mip;
0086
0087 mip = nfp_mip_open(cpp);
0088 rtbl = __nfp_rtsym_table_read(cpp, mip);
0089 nfp_mip_close(mip);
0090
0091 return rtbl;
0092 }
0093
0094 struct nfp_rtsym_table *
0095 __nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip)
0096 {
0097 const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) |
0098 NFP_ISL_EMEM0;
0099 u32 strtab_addr, symtab_addr, strtab_size, symtab_size;
0100 struct nfp_rtsym_entry *rtsymtab;
0101 struct nfp_rtsym_table *cache;
0102 int err, n, size;
0103
0104 if (!mip)
0105 return NULL;
0106
0107 nfp_mip_strtab(mip, &strtab_addr, &strtab_size);
0108 nfp_mip_symtab(mip, &symtab_addr, &symtab_size);
0109
0110 if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab))
0111 return NULL;
0112
0113
0114 symtab_size = round_up(symtab_size, 8);
0115 strtab_size = round_up(strtab_size, 8);
0116
0117 rtsymtab = kmalloc(symtab_size, GFP_KERNEL);
0118 if (!rtsymtab)
0119 return NULL;
0120
0121 size = sizeof(*cache);
0122 size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym);
0123 size += strtab_size + 1;
0124 cache = kmalloc(size, GFP_KERNEL);
0125 if (!cache)
0126 goto exit_free_rtsym_raw;
0127
0128 cache->cpp = cpp;
0129 cache->num = symtab_size / sizeof(*rtsymtab);
0130 cache->strtab = (void *)&cache->symtab[cache->num];
0131
0132 err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size);
0133 if (err != symtab_size)
0134 goto exit_free_cache;
0135
0136 err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size);
0137 if (err != strtab_size)
0138 goto exit_free_cache;
0139 cache->strtab[strtab_size] = '\0';
0140
0141 for (n = 0; n < cache->num; n++)
0142 nfp_rtsym_sw_entry_init(cache, strtab_size,
0143 &cache->symtab[n], &rtsymtab[n]);
0144
0145 kfree(rtsymtab);
0146
0147 return cache;
0148
0149 exit_free_cache:
0150 kfree(cache);
0151 exit_free_rtsym_raw:
0152 kfree(rtsymtab);
0153 return NULL;
0154 }
0155
0156
0157
0158
0159
0160
0161
0162 int nfp_rtsym_count(struct nfp_rtsym_table *rtbl)
0163 {
0164 if (!rtbl)
0165 return -EINVAL;
0166 return rtbl->num;
0167 }
0168
0169
0170
0171
0172
0173
0174
0175
0176 const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx)
0177 {
0178 if (!rtbl)
0179 return NULL;
0180 if (idx >= rtbl->num)
0181 return NULL;
0182
0183 return &rtbl->symtab[idx];
0184 }
0185
0186
0187
0188
0189
0190
0191
0192
0193 const struct nfp_rtsym *
0194 nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
0195 {
0196 int n;
0197
0198 if (!rtbl)
0199 return NULL;
0200
0201 for (n = 0; n < rtbl->num; n++)
0202 if (strcmp(name, rtbl->symtab[n].name) == 0)
0203 return &rtbl->symtab[n];
0204
0205 return NULL;
0206 }
0207
0208 u64 nfp_rtsym_size(const struct nfp_rtsym *sym)
0209 {
0210 switch (sym->type) {
0211 case NFP_RTSYM_TYPE_NONE:
0212 pr_err("rtsym '%s': type NONE\n", sym->name);
0213 return 0;
0214 default:
0215 pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type);
0216 fallthrough;
0217 case NFP_RTSYM_TYPE_OBJECT:
0218 case NFP_RTSYM_TYPE_FUNCTION:
0219 return sym->size;
0220 case NFP_RTSYM_TYPE_ABS:
0221 return sizeof(u64);
0222 }
0223 }
0224
0225 static int
0226 nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0227 u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr)
0228 {
0229 if (sym->type != NFP_RTSYM_TYPE_OBJECT) {
0230 nfp_err(cpp, "rtsym '%s': direct access to non-object rtsym\n",
0231 sym->name);
0232 return -EINVAL;
0233 }
0234
0235 *addr = sym->addr + off;
0236
0237 if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) {
0238 int locality_off = nfp_cpp_mu_locality_lsb(cpp);
0239
0240 *addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
0241 *addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
0242
0243 *cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token,
0244 sym->domain);
0245 } else if (sym->target < 0) {
0246 nfp_err(cpp, "rtsym '%s': unhandled target encoding: %d\n",
0247 sym->name, sym->target);
0248 return -EINVAL;
0249 } else {
0250 *cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token,
0251 sym->domain);
0252 }
0253
0254 return 0;
0255 }
0256
0257 int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0258 u8 action, u8 token, u64 off, void *buf, size_t len)
0259 {
0260 u64 sym_size = nfp_rtsym_size(sym);
0261 u32 cpp_id;
0262 u64 addr;
0263 int err;
0264
0265 if (off > sym_size) {
0266 nfp_err(cpp, "rtsym '%s': read out of bounds: off: %lld + len: %zd > size: %lld\n",
0267 sym->name, off, len, sym_size);
0268 return -ENXIO;
0269 }
0270 len = min_t(size_t, len, sym_size - off);
0271
0272 if (sym->type == NFP_RTSYM_TYPE_ABS) {
0273 u8 tmp[8];
0274
0275 put_unaligned_le64(sym->addr, tmp);
0276 memcpy(buf, &tmp[off], len);
0277
0278 return len;
0279 }
0280
0281 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
0282 if (err)
0283 return err;
0284
0285 return nfp_cpp_read(cpp, cpp_id, addr, buf, len);
0286 }
0287
0288 int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
0289 void *buf, size_t len)
0290 {
0291 return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
0292 }
0293
0294 int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0295 u8 action, u8 token, u64 off, u32 *value)
0296 {
0297 u32 cpp_id;
0298 u64 addr;
0299 int err;
0300
0301 if (off + 4 > nfp_rtsym_size(sym)) {
0302 nfp_err(cpp, "rtsym '%s': readl out of bounds: off: %lld + 4 > size: %lld\n",
0303 sym->name, off, nfp_rtsym_size(sym));
0304 return -ENXIO;
0305 }
0306
0307 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
0308 if (err)
0309 return err;
0310
0311 return nfp_cpp_readl(cpp, cpp_id, addr, value);
0312 }
0313
0314 int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
0315 u32 *value)
0316 {
0317 return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
0318 }
0319
0320 int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0321 u8 action, u8 token, u64 off, u64 *value)
0322 {
0323 u32 cpp_id;
0324 u64 addr;
0325 int err;
0326
0327 if (off + 8 > nfp_rtsym_size(sym)) {
0328 nfp_err(cpp, "rtsym '%s': readq out of bounds: off: %lld + 8 > size: %lld\n",
0329 sym->name, off, nfp_rtsym_size(sym));
0330 return -ENXIO;
0331 }
0332
0333 if (sym->type == NFP_RTSYM_TYPE_ABS) {
0334 *value = sym->addr;
0335 return 0;
0336 }
0337
0338 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
0339 if (err)
0340 return err;
0341
0342 return nfp_cpp_readq(cpp, cpp_id, addr, value);
0343 }
0344
0345 int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
0346 u64 *value)
0347 {
0348 return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
0349 }
0350
0351 int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0352 u8 action, u8 token, u64 off, void *buf, size_t len)
0353 {
0354 u64 sym_size = nfp_rtsym_size(sym);
0355 u32 cpp_id;
0356 u64 addr;
0357 int err;
0358
0359 if (off > sym_size) {
0360 nfp_err(cpp, "rtsym '%s': write out of bounds: off: %lld + len: %zd > size: %lld\n",
0361 sym->name, off, len, sym_size);
0362 return -ENXIO;
0363 }
0364 len = min_t(size_t, len, sym_size - off);
0365
0366 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
0367 if (err)
0368 return err;
0369
0370 return nfp_cpp_write(cpp, cpp_id, addr, buf, len);
0371 }
0372
0373 int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
0374 void *buf, size_t len)
0375 {
0376 return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
0377 }
0378
0379 int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0380 u8 action, u8 token, u64 off, u32 value)
0381 {
0382 u32 cpp_id;
0383 u64 addr;
0384 int err;
0385
0386 if (off + 4 > nfp_rtsym_size(sym)) {
0387 nfp_err(cpp, "rtsym '%s': writel out of bounds: off: %lld + 4 > size: %lld\n",
0388 sym->name, off, nfp_rtsym_size(sym));
0389 return -ENXIO;
0390 }
0391
0392 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
0393 if (err)
0394 return err;
0395
0396 return nfp_cpp_writel(cpp, cpp_id, addr, value);
0397 }
0398
0399 int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
0400 u32 value)
0401 {
0402 return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
0403 }
0404
0405 int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
0406 u8 action, u8 token, u64 off, u64 value)
0407 {
0408 u32 cpp_id;
0409 u64 addr;
0410 int err;
0411
0412 if (off + 8 > nfp_rtsym_size(sym)) {
0413 nfp_err(cpp, "rtsym '%s': writeq out of bounds: off: %lld + 8 > size: %lld\n",
0414 sym->name, off, nfp_rtsym_size(sym));
0415 return -ENXIO;
0416 }
0417
0418 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
0419 if (err)
0420 return err;
0421
0422 return nfp_cpp_writeq(cpp, cpp_id, addr, value);
0423 }
0424
0425 int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
0426 u64 value)
0427 {
0428 return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
0429 }
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443 u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
0444 int *error)
0445 {
0446 const struct nfp_rtsym *sym;
0447 u32 val32;
0448 u64 val;
0449 int err;
0450
0451 sym = nfp_rtsym_lookup(rtbl, name);
0452 if (!sym) {
0453 err = -ENOENT;
0454 goto exit;
0455 }
0456
0457 switch (nfp_rtsym_size(sym)) {
0458 case 4:
0459 err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32);
0460 val = val32;
0461 break;
0462 case 8:
0463 err = nfp_rtsym_readq(rtbl->cpp, sym, 0, &val);
0464 break;
0465 default:
0466 nfp_err(rtbl->cpp,
0467 "rtsym '%s': unsupported or non-scalar size: %lld\n",
0468 name, nfp_rtsym_size(sym));
0469 err = -EINVAL;
0470 break;
0471 }
0472
0473 exit:
0474 if (error)
0475 *error = err;
0476
0477 if (err)
0478 return ~0ULL;
0479 return val;
0480 }
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494 int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
0495 u64 value)
0496 {
0497 const struct nfp_rtsym *sym;
0498 int err;
0499
0500 sym = nfp_rtsym_lookup(rtbl, name);
0501 if (!sym)
0502 return -ENOENT;
0503
0504 switch (nfp_rtsym_size(sym)) {
0505 case 4:
0506 err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value);
0507 break;
0508 case 8:
0509 err = nfp_rtsym_writeq(rtbl->cpp, sym, 0, value);
0510 break;
0511 default:
0512 nfp_err(rtbl->cpp,
0513 "rtsym '%s': unsupported or non-scalar size: %lld\n",
0514 name, nfp_rtsym_size(sym));
0515 err = -EINVAL;
0516 break;
0517 }
0518
0519 return err;
0520 }
0521
0522 u8 __iomem *
0523 nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
0524 unsigned int min_size, struct nfp_cpp_area **area)
0525 {
0526 const struct nfp_rtsym *sym;
0527 u8 __iomem *mem;
0528 u32 cpp_id;
0529 u64 addr;
0530 int err;
0531
0532 sym = nfp_rtsym_lookup(rtbl, name);
0533 if (!sym)
0534 return (u8 __iomem *)ERR_PTR(-ENOENT);
0535
0536 err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0,
0537 &cpp_id, &addr);
0538 if (err) {
0539 nfp_err(rtbl->cpp, "rtsym '%s': mapping failed\n", name);
0540 return (u8 __iomem *)ERR_PTR(err);
0541 }
0542
0543 if (sym->size < min_size) {
0544 nfp_err(rtbl->cpp, "rtsym '%s': too small\n", name);
0545 return (u8 __iomem *)ERR_PTR(-EINVAL);
0546 }
0547
0548 mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area);
0549 if (IS_ERR(mem)) {
0550 nfp_err(rtbl->cpp, "rtysm '%s': failed to map: %ld\n",
0551 name, PTR_ERR(mem));
0552 return mem;
0553 }
0554
0555 return mem;
0556 }