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