0001
0002
0003
0004 #include <linux/ethtool.h>
0005 #include <linux/vmalloc.h>
0006
0007 #include "nfp_asm.h"
0008 #include "nfp_main.h"
0009 #include "nfpcore/nfp.h"
0010 #include "nfpcore/nfp_nffw.h"
0011 #include "nfpcore/nfp6000/nfp6000.h"
0012
0013 #define NFP_DUMP_SPEC_RTSYM "_abi_dump_spec"
0014
0015 #define ALIGN8(x) ALIGN(x, 8)
0016
0017 enum nfp_dumpspec_type {
0018 NFP_DUMPSPEC_TYPE_CPP_CSR = 0,
0019 NFP_DUMPSPEC_TYPE_XPB_CSR = 1,
0020 NFP_DUMPSPEC_TYPE_ME_CSR = 2,
0021 NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR = 3,
0022 NFP_DUMPSPEC_TYPE_RTSYM = 4,
0023 NFP_DUMPSPEC_TYPE_HWINFO = 5,
0024 NFP_DUMPSPEC_TYPE_FWNAME = 6,
0025 NFP_DUMPSPEC_TYPE_HWINFO_FIELD = 7,
0026 NFP_DUMPSPEC_TYPE_PROLOG = 10000,
0027 NFP_DUMPSPEC_TYPE_ERROR = 10001,
0028 };
0029
0030
0031
0032
0033
0034
0035
0036 struct nfp_dump_tl {
0037 __be32 type;
0038 __be32 length;
0039 char data[];
0040 };
0041
0042
0043 struct nfp_dumpspec_cpp_isl_id {
0044 u8 target;
0045 u8 action;
0046 u8 token;
0047 u8 island;
0048 };
0049
0050 struct nfp_dump_common_cpp {
0051 struct nfp_dumpspec_cpp_isl_id cpp_id;
0052 __be32 offset;
0053 __be32 dump_length;
0054 };
0055
0056
0057 struct nfp_dumpspec_csr {
0058 struct nfp_dump_tl tl;
0059 struct nfp_dump_common_cpp cpp;
0060 __be32 register_width;
0061 };
0062
0063 struct nfp_dumpspec_rtsym {
0064 struct nfp_dump_tl tl;
0065 char rtsym[];
0066 };
0067
0068
0069 struct nfp_dump_csr {
0070 struct nfp_dump_tl tl;
0071 struct nfp_dump_common_cpp cpp;
0072 __be32 register_width;
0073 __be32 error;
0074 __be32 error_offset;
0075 };
0076
0077 struct nfp_dump_rtsym {
0078 struct nfp_dump_tl tl;
0079 struct nfp_dump_common_cpp cpp;
0080 __be32 error;
0081 u8 padded_name_length;
0082 char rtsym[];
0083
0084 };
0085
0086 struct nfp_dump_prolog {
0087 struct nfp_dump_tl tl;
0088 __be32 dump_level;
0089 };
0090
0091 struct nfp_dump_error {
0092 struct nfp_dump_tl tl;
0093 __be32 error;
0094 char padding[4];
0095 char spec[];
0096 };
0097
0098
0099 struct nfp_level_size {
0100 __be32 requested_level;
0101 u32 total_size;
0102 };
0103
0104
0105 struct nfp_dump_state {
0106 __be32 requested_level;
0107 u32 dumped_size;
0108 u32 buf_size;
0109 void *p;
0110 };
0111
0112 typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl,
0113 void *param);
0114
0115 static int
0116 nfp_traverse_tlvs(struct nfp_pf *pf, void *data, u32 data_length, void *param,
0117 nfp_tlv_visit tlv_visit)
0118 {
0119 long long remaining = data_length;
0120 struct nfp_dump_tl *tl;
0121 u32 total_tlv_size;
0122 void *p = data;
0123 int err;
0124
0125 while (remaining >= sizeof(*tl)) {
0126 tl = p;
0127 if (!tl->type && !tl->length)
0128 break;
0129
0130 if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))
0131 return -EINVAL;
0132
0133 total_tlv_size = sizeof(*tl) + be32_to_cpu(tl->length);
0134
0135
0136 if (total_tlv_size % 4 != 0)
0137 return -EINVAL;
0138
0139 p += total_tlv_size;
0140 remaining -= total_tlv_size;
0141 err = tlv_visit(pf, tl, param);
0142 if (err)
0143 return err;
0144 }
0145
0146 return 0;
0147 }
0148
0149 static u32 nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id *cpp_id)
0150 {
0151 return NFP_CPP_ISLAND_ID(cpp_id->target, cpp_id->action, cpp_id->token,
0152 cpp_id->island);
0153 }
0154
0155 struct nfp_dumpspec *
0156 nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
0157 {
0158 const struct nfp_rtsym *specsym;
0159 struct nfp_dumpspec *dumpspec;
0160 int bytes_read;
0161 u64 sym_size;
0162
0163 specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
0164 if (!specsym)
0165 return NULL;
0166 sym_size = nfp_rtsym_size(specsym);
0167
0168
0169 dumpspec = vmalloc(sizeof(*dumpspec) + sym_size);
0170 if (!dumpspec)
0171 return NULL;
0172 dumpspec->size = sym_size;
0173
0174 bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size);
0175 if (bytes_read != sym_size) {
0176 vfree(dumpspec);
0177 nfp_warn(cpp, "Debug dump specification read failed.\n");
0178 return NULL;
0179 }
0180
0181 return dumpspec;
0182 }
0183
0184 static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec)
0185 {
0186 return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) +
0187 be32_to_cpu(spec->length));
0188 }
0189
0190 static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf)
0191 {
0192 u32 fwname_len = strlen(nfp_mip_name(pf->mip));
0193
0194 return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1);
0195 }
0196
0197 static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
0198 {
0199 u32 tl_len, key_len;
0200 const char *value;
0201
0202 tl_len = be32_to_cpu(spec->length);
0203 key_len = strnlen(spec->data, tl_len);
0204 if (key_len == tl_len)
0205 return nfp_dump_error_tlv_size(spec);
0206
0207 value = nfp_hwinfo_lookup(pf->hwinfo, spec->data);
0208 if (!value)
0209 return nfp_dump_error_tlv_size(spec);
0210
0211 return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2);
0212 }
0213
0214 static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr)
0215 {
0216 u32 required_read_sz = sizeof(*spec_csr) - sizeof(spec_csr->tl);
0217 u32 available_sz = be32_to_cpu(spec_csr->tl.length);
0218 u32 reg_width;
0219
0220 if (available_sz < required_read_sz)
0221 return false;
0222
0223 reg_width = be32_to_cpu(spec_csr->register_width);
0224
0225 return reg_width == 32 || reg_width == 64;
0226 }
0227
0228 static int
0229 nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
0230 {
0231 struct nfp_rtsym_table *rtbl = pf->rtbl;
0232 struct nfp_dumpspec_rtsym *spec_rtsym;
0233 const struct nfp_rtsym *sym;
0234 u32 tl_len, key_len;
0235
0236 spec_rtsym = (struct nfp_dumpspec_rtsym *)spec;
0237 tl_len = be32_to_cpu(spec->length);
0238 key_len = strnlen(spec_rtsym->rtsym, tl_len);
0239 if (key_len == tl_len)
0240 return nfp_dump_error_tlv_size(spec);
0241
0242 sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym);
0243 if (!sym)
0244 return nfp_dump_error_tlv_size(spec);
0245
0246 return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
0247 ALIGN8(nfp_rtsym_size(sym));
0248 }
0249
0250 static int
0251 nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
0252 {
0253 struct nfp_dumpspec_csr *spec_csr;
0254 u32 *size = param;
0255 u32 hwinfo_size;
0256
0257 switch (be32_to_cpu(tl->type)) {
0258 case NFP_DUMPSPEC_TYPE_FWNAME:
0259 *size += nfp_calc_fwname_tlv_size(pf);
0260 break;
0261 case NFP_DUMPSPEC_TYPE_CPP_CSR:
0262 case NFP_DUMPSPEC_TYPE_XPB_CSR:
0263 case NFP_DUMPSPEC_TYPE_ME_CSR:
0264 spec_csr = (struct nfp_dumpspec_csr *)tl;
0265 if (!nfp_csr_spec_valid(spec_csr))
0266 *size += nfp_dump_error_tlv_size(tl);
0267 else
0268 *size += ALIGN8(sizeof(struct nfp_dump_csr)) +
0269 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
0270 break;
0271 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:
0272 spec_csr = (struct nfp_dumpspec_csr *)tl;
0273 if (!nfp_csr_spec_valid(spec_csr))
0274 *size += nfp_dump_error_tlv_size(tl);
0275 else
0276 *size += ALIGN8(sizeof(struct nfp_dump_csr)) +
0277 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length) *
0278 NFP_IND_NUM_CONTEXTS);
0279 break;
0280 case NFP_DUMPSPEC_TYPE_RTSYM:
0281 *size += nfp_calc_rtsym_dump_sz(pf, tl);
0282 break;
0283 case NFP_DUMPSPEC_TYPE_HWINFO:
0284 hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);
0285 *size += sizeof(struct nfp_dump_tl) + ALIGN8(hwinfo_size);
0286 break;
0287 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
0288 *size += nfp_calc_hwinfo_field_sz(pf, tl);
0289 break;
0290 default:
0291 *size += nfp_dump_error_tlv_size(tl);
0292 break;
0293 }
0294
0295 return 0;
0296 }
0297
0298 static int
0299 nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
0300 void *param)
0301 {
0302 struct nfp_level_size *lev_sz = param;
0303
0304 if (dump_level->type != lev_sz->requested_level)
0305 return 0;
0306
0307 return nfp_traverse_tlvs(pf, dump_level->data,
0308 be32_to_cpu(dump_level->length),
0309 &lev_sz->total_size, nfp_add_tlv_size);
0310 }
0311
0312 s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
0313 u32 flag)
0314 {
0315 struct nfp_level_size lev_sz;
0316 int err;
0317
0318 lev_sz.requested_level = cpu_to_be32(flag);
0319 lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog));
0320
0321 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz,
0322 nfp_calc_specific_level_size);
0323 if (err)
0324 return err;
0325
0326 return lev_sz.total_size;
0327 }
0328
0329 static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump)
0330 {
0331 struct nfp_dump_tl *tl = dump->p;
0332
0333 if (total_tlv_sz > dump->buf_size)
0334 return -ENOSPC;
0335
0336 if (dump->buf_size - total_tlv_sz < dump->dumped_size)
0337 return -ENOSPC;
0338
0339 tl->type = cpu_to_be32(type);
0340 tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl));
0341
0342 dump->dumped_size += total_tlv_sz;
0343 dump->p += total_tlv_sz;
0344
0345 return 0;
0346 }
0347
0348 static int
0349 nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error,
0350 struct nfp_dump_state *dump)
0351 {
0352 struct nfp_dump_error *dump_header = dump->p;
0353 u32 total_spec_size, total_size;
0354 int err;
0355
0356 total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length);
0357 total_size = ALIGN8(sizeof(*dump_header) + total_spec_size);
0358
0359 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump);
0360 if (err)
0361 return err;
0362
0363 dump_header->error = cpu_to_be32(error);
0364 memcpy(dump_header->spec, spec, total_spec_size);
0365
0366 return 0;
0367 }
0368
0369 static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump)
0370 {
0371 struct nfp_dump_tl *dump_header = dump->p;
0372 u32 fwname_len, total_size;
0373 const char *fwname;
0374 int err;
0375
0376 fwname = nfp_mip_name(pf->mip);
0377 fwname_len = strlen(fwname);
0378 total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1);
0379
0380 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump);
0381 if (err)
0382 return err;
0383
0384 memcpy(dump_header->data, fwname, fwname_len);
0385
0386 return 0;
0387 }
0388
0389 static int
0390 nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec,
0391 struct nfp_dump_state *dump)
0392 {
0393 struct nfp_dump_tl *dump_header = dump->p;
0394 u32 hwinfo_size, total_size;
0395 char *hwinfo;
0396 int err;
0397
0398 hwinfo = nfp_hwinfo_get_packed_strings(pf->hwinfo);
0399 hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);
0400 total_size = sizeof(*dump_header) + ALIGN8(hwinfo_size);
0401
0402 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump);
0403 if (err)
0404 return err;
0405
0406 memcpy(dump_header->data, hwinfo, hwinfo_size);
0407
0408 return 0;
0409 }
0410
0411 static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec,
0412 struct nfp_dump_state *dump)
0413 {
0414 struct nfp_dump_tl *dump_header = dump->p;
0415 u32 tl_len, key_len, val_len;
0416 const char *key, *value;
0417 u32 total_size;
0418 int err;
0419
0420 tl_len = be32_to_cpu(spec->length);
0421 key_len = strnlen(spec->data, tl_len);
0422 if (key_len == tl_len)
0423 return nfp_dump_error_tlv(spec, -EINVAL, dump);
0424
0425 key = spec->data;
0426 value = nfp_hwinfo_lookup(pf->hwinfo, key);
0427 if (!value)
0428 return nfp_dump_error_tlv(spec, -ENOENT, dump);
0429
0430 val_len = strlen(value);
0431 total_size = sizeof(*dump_header) + ALIGN8(key_len + val_len + 2);
0432 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO_FIELD, total_size, dump);
0433 if (err)
0434 return err;
0435
0436 memcpy(dump_header->data, key, key_len + 1);
0437 memcpy(dump_header->data + key_len + 1, value, val_len + 1);
0438
0439 return 0;
0440 }
0441
0442 static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id)
0443 {
0444 return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB &&
0445 cpp_id->action == 0 && cpp_id->token == 0;
0446 }
0447
0448 static int
0449 nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,
0450 struct nfp_dump_state *dump)
0451 {
0452 struct nfp_dump_csr *dump_header = dump->p;
0453 u32 reg_sz, header_size, total_size;
0454 u32 cpp_rd_addr, max_rd_addr;
0455 int bytes_read;
0456 void *dest;
0457 u32 cpp_id;
0458 int err;
0459
0460 if (!nfp_csr_spec_valid(spec_csr))
0461 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
0462
0463 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;
0464 header_size = ALIGN8(sizeof(*dump_header));
0465 total_size = header_size +
0466 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
0467 dest = dump->p + header_size;
0468
0469 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
0470 if (err)
0471 return err;
0472
0473 dump_header->cpp = spec_csr->cpp;
0474 dump_header->register_width = spec_csr->register_width;
0475
0476 cpp_id = nfp_get_numeric_cpp_id(&spec_csr->cpp.cpp_id);
0477 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);
0478 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
0479
0480 while (cpp_rd_addr < max_rd_addr) {
0481 if (is_xpb_read(&spec_csr->cpp.cpp_id)) {
0482 err = nfp_xpb_readl(pf->cpp, cpp_rd_addr, (u32 *)dest);
0483 } else {
0484 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr,
0485 dest, reg_sz);
0486 err = bytes_read == reg_sz ? 0 : -EIO;
0487 }
0488 if (err) {
0489 dump_header->error = cpu_to_be32(err);
0490 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
0491 break;
0492 }
0493 cpp_rd_addr += reg_sz;
0494 dest += reg_sz;
0495 }
0496
0497 return 0;
0498 }
0499
0500
0501
0502
0503 static int
0504 nfp_read_indirect_csr(struct nfp_cpp *cpp,
0505 struct nfp_dumpspec_cpp_isl_id cpp_params, u32 offset,
0506 u32 reg_sz, u32 context, void *dest)
0507 {
0508 u32 csr_ctx_ptr_offs;
0509 u32 cpp_id;
0510 int result;
0511
0512 csr_ctx_ptr_offs = nfp_get_ind_csr_ctx_ptr_offs(offset);
0513 cpp_id = NFP_CPP_ISLAND_ID(cpp_params.target,
0514 NFP_IND_ME_REFL_WR_SIG_INIT,
0515 cpp_params.token, cpp_params.island);
0516 result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context);
0517 if (result)
0518 return result;
0519
0520 cpp_id = nfp_get_numeric_cpp_id(&cpp_params);
0521 result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz);
0522 if (result != reg_sz)
0523 return result < 0 ? result : -EIO;
0524
0525 result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz);
0526 if (result != reg_sz)
0527 return result < 0 ? result : -EIO;
0528
0529 return 0;
0530 }
0531
0532 static int
0533 nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp,
0534 struct nfp_dumpspec_csr *spec_csr, u32 address,
0535 u32 reg_sz, void *dest)
0536 {
0537 u32 ctx;
0538 int err;
0539
0540 for (ctx = 0; ctx < NFP_IND_NUM_CONTEXTS; ctx++) {
0541 err = nfp_read_indirect_csr(cpp, spec_csr->cpp.cpp_id, address,
0542 reg_sz, ctx, dest + ctx * reg_sz);
0543 if (err)
0544 return err;
0545 }
0546
0547 return 0;
0548 }
0549
0550 static int
0551 nfp_dump_indirect_csr_range(struct nfp_pf *pf,
0552 struct nfp_dumpspec_csr *spec_csr,
0553 struct nfp_dump_state *dump)
0554 {
0555 struct nfp_dump_csr *dump_header = dump->p;
0556 u32 reg_sz, header_size, total_size;
0557 u32 cpp_rd_addr, max_rd_addr;
0558 u32 reg_data_length;
0559 void *dest;
0560 int err;
0561
0562 if (!nfp_csr_spec_valid(spec_csr))
0563 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
0564
0565 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;
0566 header_size = ALIGN8(sizeof(*dump_header));
0567 reg_data_length = be32_to_cpu(spec_csr->cpp.dump_length) *
0568 NFP_IND_NUM_CONTEXTS;
0569 total_size = header_size + ALIGN8(reg_data_length);
0570 dest = dump->p + header_size;
0571
0572 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
0573 if (err)
0574 return err;
0575
0576 dump_header->cpp = spec_csr->cpp;
0577 dump_header->register_width = spec_csr->register_width;
0578
0579 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);
0580 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
0581 while (cpp_rd_addr < max_rd_addr) {
0582 err = nfp_read_all_indirect_csr_ctx(pf->cpp, spec_csr,
0583 cpp_rd_addr, reg_sz, dest);
0584 if (err) {
0585 dump_header->error = cpu_to_be32(err);
0586 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
0587 break;
0588 }
0589 cpp_rd_addr += reg_sz;
0590 dest += reg_sz * NFP_IND_NUM_CONTEXTS;
0591 }
0592
0593 return 0;
0594 }
0595
0596 static int
0597 nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
0598 struct nfp_dump_state *dump)
0599 {
0600 struct nfp_dump_rtsym *dump_header = dump->p;
0601 struct nfp_dumpspec_cpp_isl_id cpp_params;
0602 struct nfp_rtsym_table *rtbl = pf->rtbl;
0603 u32 header_size, total_size, sym_size;
0604 const struct nfp_rtsym *sym;
0605 u32 tl_len, key_len;
0606 int bytes_read;
0607 void *dest;
0608 int err;
0609
0610 tl_len = be32_to_cpu(spec->tl.length);
0611 key_len = strnlen(spec->rtsym, tl_len);
0612 if (key_len == tl_len)
0613 return nfp_dump_error_tlv(&spec->tl, -EINVAL, dump);
0614
0615 sym = nfp_rtsym_lookup(rtbl, spec->rtsym);
0616 if (!sym)
0617 return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
0618
0619 sym_size = nfp_rtsym_size(sym);
0620 header_size =
0621 ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1);
0622 total_size = header_size + ALIGN8(sym_size);
0623 dest = dump->p + header_size;
0624
0625 err = nfp_add_tlv(be32_to_cpu(spec->tl.type), total_size, dump);
0626 if (err)
0627 return err;
0628
0629 dump_header->padded_name_length =
0630 header_size - offsetof(struct nfp_dump_rtsym, rtsym);
0631 memcpy(dump_header->rtsym, spec->rtsym, key_len + 1);
0632 dump_header->cpp.dump_length = cpu_to_be32(sym_size);
0633
0634 if (sym->type != NFP_RTSYM_TYPE_ABS) {
0635 cpp_params.target = sym->target;
0636 cpp_params.action = NFP_CPP_ACTION_RW;
0637 cpp_params.token = 0;
0638 cpp_params.island = sym->domain;
0639 dump_header->cpp.cpp_id = cpp_params;
0640 dump_header->cpp.offset = cpu_to_be32(sym->addr);
0641 }
0642
0643 bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size);
0644 if (bytes_read != sym_size) {
0645 if (bytes_read >= 0)
0646 bytes_read = -EIO;
0647 dump_header->error = cpu_to_be32(bytes_read);
0648 }
0649
0650 return 0;
0651 }
0652
0653 static int
0654 nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
0655 {
0656 struct nfp_dumpspec_rtsym *spec_rtsym;
0657 struct nfp_dump_state *dump = param;
0658 struct nfp_dumpspec_csr *spec_csr;
0659 int err;
0660
0661 switch (be32_to_cpu(tl->type)) {
0662 case NFP_DUMPSPEC_TYPE_FWNAME:
0663 err = nfp_dump_fwname(pf, dump);
0664 if (err)
0665 return err;
0666 break;
0667 case NFP_DUMPSPEC_TYPE_CPP_CSR:
0668 case NFP_DUMPSPEC_TYPE_XPB_CSR:
0669 case NFP_DUMPSPEC_TYPE_ME_CSR:
0670 spec_csr = (struct nfp_dumpspec_csr *)tl;
0671 err = nfp_dump_csr_range(pf, spec_csr, dump);
0672 if (err)
0673 return err;
0674 break;
0675 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:
0676 spec_csr = (struct nfp_dumpspec_csr *)tl;
0677 err = nfp_dump_indirect_csr_range(pf, spec_csr, dump);
0678 if (err)
0679 return err;
0680 break;
0681 case NFP_DUMPSPEC_TYPE_RTSYM:
0682 spec_rtsym = (struct nfp_dumpspec_rtsym *)tl;
0683 err = nfp_dump_single_rtsym(pf, spec_rtsym, dump);
0684 if (err)
0685 return err;
0686 break;
0687 case NFP_DUMPSPEC_TYPE_HWINFO:
0688 err = nfp_dump_hwinfo(pf, tl, dump);
0689 if (err)
0690 return err;
0691 break;
0692 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
0693 err = nfp_dump_hwinfo_field(pf, tl, dump);
0694 if (err)
0695 return err;
0696 break;
0697 default:
0698 err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump);
0699 if (err)
0700 return err;
0701 }
0702
0703 return 0;
0704 }
0705
0706 static int
0707 nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
0708 void *param)
0709 {
0710 struct nfp_dump_state *dump = param;
0711
0712 if (dump_level->type != dump->requested_level)
0713 return 0;
0714
0715 return nfp_traverse_tlvs(pf, dump_level->data,
0716 be32_to_cpu(dump_level->length), dump,
0717 nfp_dump_for_tlv);
0718 }
0719
0720 static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)
0721 {
0722 struct nfp_dump_prolog *prolog = dump->p;
0723 u32 total_size;
0724 int err;
0725
0726 total_size = ALIGN8(sizeof(*prolog));
0727
0728 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);
0729 if (err)
0730 return err;
0731
0732 prolog->dump_level = dump->requested_level;
0733
0734 return 0;
0735 }
0736
0737 int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
0738 struct ethtool_dump *dump_param, void *dest)
0739 {
0740 struct nfp_dump_state dump;
0741 int err;
0742
0743 dump.requested_level = cpu_to_be32(dump_param->flag);
0744 dump.dumped_size = 0;
0745 dump.p = dest;
0746 dump.buf_size = dump_param->len;
0747
0748 err = nfp_dump_populate_prolog(&dump);
0749 if (err)
0750 return err;
0751
0752 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,
0753 nfp_dump_specific_level);
0754 if (err)
0755 return err;
0756
0757
0758
0759
0760 dump_param->len = dump.dumped_size;
0761
0762 return 0;
0763 }