775 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */3 4#include <linux/ethtool.h>5#include <linux/vmalloc.h>6 7#include "nfp_asm.h"8#include "nfp_main.h"9#include "nfpcore/nfp.h"10#include "nfpcore/nfp_nffw.h"11#include "nfpcore/nfp6000/nfp6000.h"12 13#define NFP_DUMP_SPEC_RTSYM "_abi_dump_spec"14 15#define ALIGN8(x) ALIGN(x, 8)16 17enum nfp_dumpspec_type {18 NFP_DUMPSPEC_TYPE_CPP_CSR = 0,19 NFP_DUMPSPEC_TYPE_XPB_CSR = 1,20 NFP_DUMPSPEC_TYPE_ME_CSR = 2,21 NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR = 3,22 NFP_DUMPSPEC_TYPE_RTSYM = 4,23 NFP_DUMPSPEC_TYPE_HWINFO = 5,24 NFP_DUMPSPEC_TYPE_FWNAME = 6,25 NFP_DUMPSPEC_TYPE_HWINFO_FIELD = 7,26 NFP_DUMPSPEC_TYPE_PROLOG = 10000,27 NFP_DUMPSPEC_TYPE_ERROR = 10001,28};29 30/* The following structs must be carefully aligned so that they can be used to31 * interpret the binary dumpspec and populate the dump data in a deterministic32 * way.33 */34 35/* generic type plus length */36struct nfp_dump_tl {37 /* New members must be added within the struct_group() macro below. */38 struct_group_tagged(nfp_dump_tl_hdr, hdr,39 __be32 type;40 __be32 length; /* chunk length to follow, aligned to 8 bytes */41 );42 char data[];43};44static_assert(offsetof(struct nfp_dump_tl, data) == sizeof(struct nfp_dump_tl_hdr),45 "struct member likely outside of struct_group_tagged()");46 47/* NFP CPP parameters */48struct nfp_dumpspec_cpp_isl_id {49 u8 target;50 u8 action;51 u8 token;52 u8 island;53};54 55struct nfp_dump_common_cpp {56 struct nfp_dumpspec_cpp_isl_id cpp_id;57 __be32 offset; /* address to start dump */58 __be32 dump_length; /* total bytes to dump, aligned to reg size */59};60 61/* CSR dumpables */62struct nfp_dumpspec_csr {63 struct nfp_dump_tl_hdr tl;64 struct nfp_dump_common_cpp cpp;65 __be32 register_width; /* in bits */66};67 68struct nfp_dumpspec_rtsym {69 struct nfp_dump_tl_hdr tl;70 char rtsym[];71};72 73/* header for register dumpable */74struct nfp_dump_csr {75 struct nfp_dump_tl_hdr tl;76 struct nfp_dump_common_cpp cpp;77 __be32 register_width; /* in bits */78 __be32 error; /* error code encountered while reading */79 __be32 error_offset; /* offset being read when error occurred */80};81 82struct nfp_dump_rtsym {83 struct nfp_dump_tl_hdr tl;84 struct nfp_dump_common_cpp cpp;85 __be32 error; /* error code encountered while reading */86 u8 padded_name_length; /* pad so data starts at 8 byte boundary */87 char rtsym[];88 /* after padded_name_length, there is dump_length data */89};90 91struct nfp_dump_prolog {92 struct nfp_dump_tl_hdr tl;93 __be32 dump_level;94};95 96struct nfp_dump_error {97 struct nfp_dump_tl_hdr tl;98 __be32 error;99 char padding[4];100 char spec[];101};102 103/* to track state through debug size calculation TLV traversal */104struct nfp_level_size {105 __be32 requested_level; /* input */106 u32 total_size; /* output */107};108 109/* to track state during debug dump creation TLV traversal */110struct nfp_dump_state {111 __be32 requested_level; /* input param */112 u32 dumped_size; /* adds up to size of dumped data */113 u32 buf_size; /* size of buffer pointer to by p */114 void *p; /* current point in dump buffer */115};116 117typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl,118 void *param);119 120static int121nfp_traverse_tlvs(struct nfp_pf *pf, void *data, u32 data_length, void *param,122 nfp_tlv_visit tlv_visit)123{124 long long remaining = data_length;125 struct nfp_dump_tl *tl;126 u32 total_tlv_size;127 void *p = data;128 int err;129 130 while (remaining >= sizeof(*tl)) {131 tl = p;132 if (!tl->type && !tl->length)133 break;134 135 if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))136 return -EINVAL;137 138 total_tlv_size = sizeof(*tl) + be32_to_cpu(tl->length);139 140 /* Spec TLVs should be aligned to 4 bytes. */141 if (total_tlv_size % 4 != 0)142 return -EINVAL;143 144 p += total_tlv_size;145 remaining -= total_tlv_size;146 err = tlv_visit(pf, tl, param);147 if (err)148 return err;149 }150 151 return 0;152}153 154static u32 nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id *cpp_id)155{156 return NFP_CPP_ISLAND_ID(cpp_id->target, cpp_id->action, cpp_id->token,157 cpp_id->island);158}159 160struct nfp_dumpspec *161nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)162{163 const struct nfp_rtsym *specsym;164 struct nfp_dumpspec *dumpspec;165 int bytes_read;166 u64 sym_size;167 168 specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);169 if (!specsym)170 return NULL;171 sym_size = nfp_rtsym_size(specsym);172 173 /* expected size of this buffer is in the order of tens of kilobytes */174 dumpspec = vmalloc(sizeof(*dumpspec) + sym_size);175 if (!dumpspec)176 return NULL;177 dumpspec->size = sym_size;178 179 bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size);180 if (bytes_read != sym_size) {181 vfree(dumpspec);182 nfp_warn(cpp, "Debug dump specification read failed.\n");183 return NULL;184 }185 186 return dumpspec;187}188 189static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec)190{191 return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) +192 be32_to_cpu(spec->length));193}194 195static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf)196{197 u32 fwname_len = strlen(nfp_mip_name(pf->mip));198 199 return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1);200}201 202static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)203{204 u32 tl_len, key_len;205 const char *value;206 207 tl_len = be32_to_cpu(spec->length);208 key_len = strnlen(spec->data, tl_len);209 if (key_len == tl_len)210 return nfp_dump_error_tlv_size(spec);211 212 value = nfp_hwinfo_lookup(pf->hwinfo, spec->data);213 if (!value)214 return nfp_dump_error_tlv_size(spec);215 216 return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2);217}218 219static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr)220{221 u32 required_read_sz = sizeof(*spec_csr) - sizeof(spec_csr->tl);222 u32 available_sz = be32_to_cpu(spec_csr->tl.length);223 u32 reg_width;224 225 if (available_sz < required_read_sz)226 return false;227 228 reg_width = be32_to_cpu(spec_csr->register_width);229 230 return reg_width == 32 || reg_width == 64;231}232 233static int234nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)235{236 struct nfp_rtsym_table *rtbl = pf->rtbl;237 struct nfp_dumpspec_rtsym *spec_rtsym;238 const struct nfp_rtsym *sym;239 u32 tl_len, key_len;240 241 spec_rtsym = (struct nfp_dumpspec_rtsym *)spec;242 tl_len = be32_to_cpu(spec->length);243 key_len = strnlen(spec_rtsym->rtsym, tl_len);244 if (key_len == tl_len)245 return nfp_dump_error_tlv_size(spec);246 247 sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym);248 if (!sym)249 return nfp_dump_error_tlv_size(spec);250 251 return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +252 ALIGN8(nfp_rtsym_size(sym));253}254 255static int256nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)257{258 struct nfp_dumpspec_csr *spec_csr;259 u32 *size = param;260 u32 hwinfo_size;261 262 switch (be32_to_cpu(tl->type)) {263 case NFP_DUMPSPEC_TYPE_FWNAME:264 *size += nfp_calc_fwname_tlv_size(pf);265 break;266 case NFP_DUMPSPEC_TYPE_CPP_CSR:267 case NFP_DUMPSPEC_TYPE_XPB_CSR:268 case NFP_DUMPSPEC_TYPE_ME_CSR:269 spec_csr = (struct nfp_dumpspec_csr *)tl;270 if (!nfp_csr_spec_valid(spec_csr))271 *size += nfp_dump_error_tlv_size(tl);272 else273 *size += ALIGN8(sizeof(struct nfp_dump_csr)) +274 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));275 break;276 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:277 spec_csr = (struct nfp_dumpspec_csr *)tl;278 if (!nfp_csr_spec_valid(spec_csr))279 *size += nfp_dump_error_tlv_size(tl);280 else281 *size += ALIGN8(sizeof(struct nfp_dump_csr)) +282 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length) *283 NFP_IND_NUM_CONTEXTS);284 break;285 case NFP_DUMPSPEC_TYPE_RTSYM:286 *size += nfp_calc_rtsym_dump_sz(pf, tl);287 break;288 case NFP_DUMPSPEC_TYPE_HWINFO:289 hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);290 *size += sizeof(struct nfp_dump_tl) + ALIGN8(hwinfo_size);291 break;292 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:293 *size += nfp_calc_hwinfo_field_sz(pf, tl);294 break;295 default:296 *size += nfp_dump_error_tlv_size(tl);297 break;298 }299 300 return 0;301}302 303static int304nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,305 void *param)306{307 struct nfp_level_size *lev_sz = param;308 309 if (dump_level->type != lev_sz->requested_level)310 return 0;311 312 return nfp_traverse_tlvs(pf, dump_level->data,313 be32_to_cpu(dump_level->length),314 &lev_sz->total_size, nfp_add_tlv_size);315}316 317s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,318 u32 flag)319{320 struct nfp_level_size lev_sz;321 int err;322 323 lev_sz.requested_level = cpu_to_be32(flag);324 lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog));325 326 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz,327 nfp_calc_specific_level_size);328 if (err)329 return err;330 331 return lev_sz.total_size;332}333 334static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump)335{336 struct nfp_dump_tl *tl = dump->p;337 338 if (total_tlv_sz > dump->buf_size)339 return -ENOSPC;340 341 if (dump->buf_size - total_tlv_sz < dump->dumped_size)342 return -ENOSPC;343 344 tl->type = cpu_to_be32(type);345 tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl));346 347 dump->dumped_size += total_tlv_sz;348 dump->p += total_tlv_sz;349 350 return 0;351}352 353static int354nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error,355 struct nfp_dump_state *dump)356{357 struct nfp_dump_error *dump_header = dump->p;358 u32 total_spec_size, total_size;359 int err;360 361 total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length);362 total_size = ALIGN8(sizeof(*dump_header) + total_spec_size);363 364 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump);365 if (err)366 return err;367 368 dump_header->error = cpu_to_be32(error);369 memcpy(dump_header->spec, spec, total_spec_size);370 371 return 0;372}373 374static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump)375{376 struct nfp_dump_tl *dump_header = dump->p;377 u32 fwname_len, total_size;378 const char *fwname;379 int err;380 381 fwname = nfp_mip_name(pf->mip);382 fwname_len = strlen(fwname);383 total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1);384 385 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump);386 if (err)387 return err;388 389 memcpy(dump_header->data, fwname, fwname_len);390 391 return 0;392}393 394static int395nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec,396 struct nfp_dump_state *dump)397{398 struct nfp_dump_tl *dump_header = dump->p;399 u32 hwinfo_size, total_size;400 char *hwinfo;401 int err;402 403 hwinfo = nfp_hwinfo_get_packed_strings(pf->hwinfo);404 hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);405 total_size = sizeof(*dump_header) + ALIGN8(hwinfo_size);406 407 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump);408 if (err)409 return err;410 411 memcpy(dump_header->data, hwinfo, hwinfo_size);412 413 return 0;414}415 416static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec,417 struct nfp_dump_state *dump)418{419 struct nfp_dump_tl *dump_header = dump->p;420 u32 tl_len, key_len, val_len;421 const char *key, *value;422 u32 total_size;423 int err;424 425 tl_len = be32_to_cpu(spec->length);426 key_len = strnlen(spec->data, tl_len);427 if (key_len == tl_len)428 return nfp_dump_error_tlv(spec, -EINVAL, dump);429 430 key = spec->data;431 value = nfp_hwinfo_lookup(pf->hwinfo, key);432 if (!value)433 return nfp_dump_error_tlv(spec, -ENOENT, dump);434 435 val_len = strlen(value);436 total_size = sizeof(*dump_header) + ALIGN8(key_len + val_len + 2);437 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO_FIELD, total_size, dump);438 if (err)439 return err;440 441 memcpy(dump_header->data, key, key_len + 1);442 memcpy(dump_header->data + key_len + 1, value, val_len + 1);443 444 return 0;445}446 447static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id)448{449 return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB &&450 cpp_id->action == 0 && cpp_id->token == 0;451}452 453static int454nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,455 struct nfp_dump_state *dump)456{457 struct nfp_dump_tl *spec_csr_tl =458 container_of(&spec_csr->tl, struct nfp_dump_tl, hdr);459 struct nfp_dump_csr *dump_header = dump->p;460 u32 reg_sz, header_size, total_size;461 u32 cpp_rd_addr, max_rd_addr;462 int bytes_read;463 void *dest;464 u32 cpp_id;465 int err;466 467 if (!nfp_csr_spec_valid(spec_csr))468 return nfp_dump_error_tlv(spec_csr_tl, -EINVAL, dump);469 470 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;471 header_size = ALIGN8(sizeof(*dump_header));472 total_size = header_size +473 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));474 dest = dump->p + header_size;475 476 err = nfp_add_tlv(be32_to_cpu(spec_csr_tl->type), total_size, dump);477 if (err)478 return err;479 480 dump_header->cpp = spec_csr->cpp;481 dump_header->register_width = spec_csr->register_width;482 483 cpp_id = nfp_get_numeric_cpp_id(&spec_csr->cpp.cpp_id);484 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);485 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);486 487 while (cpp_rd_addr < max_rd_addr) {488 if (is_xpb_read(&spec_csr->cpp.cpp_id)) {489 err = nfp_xpb_readl(pf->cpp, cpp_rd_addr, (u32 *)dest);490 } else {491 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr,492 dest, reg_sz);493 err = bytes_read == reg_sz ? 0 : -EIO;494 }495 if (err) {496 dump_header->error = cpu_to_be32(err);497 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);498 break;499 }500 cpp_rd_addr += reg_sz;501 dest += reg_sz;502 }503 504 return 0;505}506 507/* Write context to CSRCtxPtr, then read from it. Then the value can be read508 * from IndCtxStatus.509 */510static int511nfp_read_indirect_csr(struct nfp_cpp *cpp,512 struct nfp_dumpspec_cpp_isl_id cpp_params, u32 offset,513 u32 reg_sz, u32 context, void *dest)514{515 u32 csr_ctx_ptr_offs;516 u32 cpp_id;517 int result;518 519 csr_ctx_ptr_offs = nfp_get_ind_csr_ctx_ptr_offs(offset);520 cpp_id = NFP_CPP_ISLAND_ID(cpp_params.target,521 NFP_IND_ME_REFL_WR_SIG_INIT,522 cpp_params.token, cpp_params.island);523 result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context);524 if (result)525 return result;526 527 cpp_id = nfp_get_numeric_cpp_id(&cpp_params);528 result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz);529 if (result != reg_sz)530 return result < 0 ? result : -EIO;531 532 result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz);533 if (result != reg_sz)534 return result < 0 ? result : -EIO;535 536 return 0;537}538 539static int540nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp,541 struct nfp_dumpspec_csr *spec_csr, u32 address,542 u32 reg_sz, void *dest)543{544 u32 ctx;545 int err;546 547 for (ctx = 0; ctx < NFP_IND_NUM_CONTEXTS; ctx++) {548 err = nfp_read_indirect_csr(cpp, spec_csr->cpp.cpp_id, address,549 reg_sz, ctx, dest + ctx * reg_sz);550 if (err)551 return err;552 }553 554 return 0;555}556 557static int558nfp_dump_indirect_csr_range(struct nfp_pf *pf,559 struct nfp_dumpspec_csr *spec_csr,560 struct nfp_dump_state *dump)561{562 struct nfp_dump_tl *spec_csr_tl =563 container_of(&spec_csr->tl, struct nfp_dump_tl, hdr);564 struct nfp_dump_csr *dump_header = dump->p;565 u32 reg_sz, header_size, total_size;566 u32 cpp_rd_addr, max_rd_addr;567 u32 reg_data_length;568 void *dest;569 int err;570 571 if (!nfp_csr_spec_valid(spec_csr))572 return nfp_dump_error_tlv(spec_csr_tl, -EINVAL, dump);573 574 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;575 header_size = ALIGN8(sizeof(*dump_header));576 reg_data_length = be32_to_cpu(spec_csr->cpp.dump_length) *577 NFP_IND_NUM_CONTEXTS;578 total_size = header_size + ALIGN8(reg_data_length);579 dest = dump->p + header_size;580 581 err = nfp_add_tlv(be32_to_cpu(spec_csr_tl->type), total_size, dump);582 if (err)583 return err;584 585 dump_header->cpp = spec_csr->cpp;586 dump_header->register_width = spec_csr->register_width;587 588 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);589 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);590 while (cpp_rd_addr < max_rd_addr) {591 err = nfp_read_all_indirect_csr_ctx(pf->cpp, spec_csr,592 cpp_rd_addr, reg_sz, dest);593 if (err) {594 dump_header->error = cpu_to_be32(err);595 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);596 break;597 }598 cpp_rd_addr += reg_sz;599 dest += reg_sz * NFP_IND_NUM_CONTEXTS;600 }601 602 return 0;603}604 605static int606nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,607 struct nfp_dump_state *dump)608{609 struct nfp_dump_tl *spec_tl =610 container_of(&spec->tl, struct nfp_dump_tl, hdr);611 struct nfp_dump_rtsym *dump_header = dump->p;612 struct nfp_dumpspec_cpp_isl_id cpp_params;613 struct nfp_rtsym_table *rtbl = pf->rtbl;614 u32 header_size, total_size, sym_size;615 const struct nfp_rtsym *sym;616 u32 tl_len, key_len;617 int bytes_read;618 void *dest;619 int err;620 621 tl_len = be32_to_cpu(spec_tl->length);622 key_len = strnlen(spec->rtsym, tl_len);623 if (key_len == tl_len)624 return nfp_dump_error_tlv(spec_tl, -EINVAL, dump);625 626 sym = nfp_rtsym_lookup(rtbl, spec->rtsym);627 if (!sym)628 return nfp_dump_error_tlv(spec_tl, -ENOENT, dump);629 630 sym_size = nfp_rtsym_size(sym);631 header_size =632 ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1);633 total_size = header_size + ALIGN8(sym_size);634 dest = dump->p + header_size;635 636 err = nfp_add_tlv(be32_to_cpu(spec_tl->type), total_size, dump);637 if (err)638 return err;639 640 dump_header->padded_name_length =641 header_size - offsetof(struct nfp_dump_rtsym, rtsym);642 memcpy(dump_header->rtsym, spec->rtsym, key_len + 1);643 dump_header->cpp.dump_length = cpu_to_be32(sym_size);644 645 if (sym->type != NFP_RTSYM_TYPE_ABS) {646 cpp_params.target = sym->target;647 cpp_params.action = NFP_CPP_ACTION_RW;648 cpp_params.token = 0;649 cpp_params.island = sym->domain;650 dump_header->cpp.cpp_id = cpp_params;651 dump_header->cpp.offset = cpu_to_be32(sym->addr);652 }653 654 bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size);655 if (bytes_read != sym_size) {656 if (bytes_read >= 0)657 bytes_read = -EIO;658 dump_header->error = cpu_to_be32(bytes_read);659 }660 661 return 0;662}663 664static int665nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)666{667 struct nfp_dumpspec_rtsym *spec_rtsym;668 struct nfp_dump_state *dump = param;669 struct nfp_dumpspec_csr *spec_csr;670 int err;671 672 switch (be32_to_cpu(tl->type)) {673 case NFP_DUMPSPEC_TYPE_FWNAME:674 err = nfp_dump_fwname(pf, dump);675 if (err)676 return err;677 break;678 case NFP_DUMPSPEC_TYPE_CPP_CSR:679 case NFP_DUMPSPEC_TYPE_XPB_CSR:680 case NFP_DUMPSPEC_TYPE_ME_CSR:681 spec_csr = (struct nfp_dumpspec_csr *)tl;682 err = nfp_dump_csr_range(pf, spec_csr, dump);683 if (err)684 return err;685 break;686 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:687 spec_csr = (struct nfp_dumpspec_csr *)tl;688 err = nfp_dump_indirect_csr_range(pf, spec_csr, dump);689 if (err)690 return err;691 break;692 case NFP_DUMPSPEC_TYPE_RTSYM:693 spec_rtsym = (struct nfp_dumpspec_rtsym *)tl;694 err = nfp_dump_single_rtsym(pf, spec_rtsym, dump);695 if (err)696 return err;697 break;698 case NFP_DUMPSPEC_TYPE_HWINFO:699 err = nfp_dump_hwinfo(pf, tl, dump);700 if (err)701 return err;702 break;703 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:704 err = nfp_dump_hwinfo_field(pf, tl, dump);705 if (err)706 return err;707 break;708 default:709 err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump);710 if (err)711 return err;712 }713 714 return 0;715}716 717static int718nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,719 void *param)720{721 struct nfp_dump_state *dump = param;722 723 if (dump_level->type != dump->requested_level)724 return 0;725 726 return nfp_traverse_tlvs(pf, dump_level->data,727 be32_to_cpu(dump_level->length), dump,728 nfp_dump_for_tlv);729}730 731static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)732{733 struct nfp_dump_prolog *prolog = dump->p;734 u32 total_size;735 int err;736 737 total_size = ALIGN8(sizeof(*prolog));738 739 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);740 if (err)741 return err;742 743 prolog->dump_level = dump->requested_level;744 745 return 0;746}747 748int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,749 struct ethtool_dump *dump_param, void *dest)750{751 struct nfp_dump_state dump;752 int err;753 754 dump.requested_level = cpu_to_be32(dump_param->flag);755 dump.dumped_size = 0;756 dump.p = dest;757 dump.buf_size = dump_param->len;758 759 err = nfp_dump_populate_prolog(&dump);760 if (err)761 return err;762 763 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,764 nfp_dump_specific_level);765 if (err)766 return err;767 768 /* Set size of actual dump, to trigger warning if different from769 * calculated size.770 */771 dump_param->len = dump.dumped_size;772 773 return 0;774}775