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 17 enum 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 to 31 * interpret the binary dumpspec and populate the dump data in a deterministic 32 * way. 33 */ 34 35 /* generic type plus length */ 36 struct 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 }; 44 static_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 */ 48 struct nfp_dumpspec_cpp_isl_id { 49 u8 target; 50 u8 action; 51 u8 token; 52 u8 island; 53 }; 54 55 struct 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 */ 62 struct 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 68 struct nfp_dumpspec_rtsym { 69 struct nfp_dump_tl_hdr tl; 70 char rtsym[]; 71 }; 72 73 /* header for register dumpable */ 74 struct 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 82 struct 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 91 struct nfp_dump_prolog { 92 struct nfp_dump_tl_hdr tl; 93 __be32 dump_level; 94 }; 95 96 struct 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 */ 104 struct 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 */ 110 struct 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 117 typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl, 118 void *param); 119 120 static int 121 nfp_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 154 static 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 160 struct nfp_dumpspec * 161 nfp_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 189 static 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 195 static 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 202 static 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 219 static 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 233 static int 234 nfp_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 255 static int 256 nfp_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 else 273 *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 else 281 *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 303 static int 304 nfp_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 317 s64 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 334 static 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 353 static int 354 nfp_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 374 static 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 394 static int 395 nfp_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 416 static 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 447 static 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 453 static int 454 nfp_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 read 508 * from IndCtxStatus. 509 */ 510 static int 511 nfp_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 539 static int 540 nfp_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 557 static int 558 nfp_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 605 static int 606 nfp_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 664 static int 665 nfp_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 717 static int 718 nfp_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 731 static 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 748 int 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 from 769 * calculated size. 770 */ 771 dump_param->len = dump.dumped_size; 772 773 return 0; 774 } 775