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