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