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 u32 cpp_id; 192 193 specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM); 194 if (!specsym) 195 return NULL; 196 197 /* expected size of this buffer is in the order of tens of kilobytes */ 198 dumpspec = vmalloc(sizeof(*dumpspec) + specsym->size); 199 if (!dumpspec) 200 return NULL; 201 202 dumpspec->size = specsym->size; 203 204 cpp_id = NFP_CPP_ISLAND_ID(specsym->target, NFP_CPP_ACTION_RW, 0, 205 specsym->domain); 206 207 bytes_read = nfp_cpp_read(cpp, cpp_id, specsym->addr, dumpspec->data, 208 specsym->size); 209 if (bytes_read != specsym->size) { 210 vfree(dumpspec); 211 nfp_warn(cpp, "Debug dump specification read failed.\n"); 212 return NULL; 213 } 214 215 return dumpspec; 216 } 217 218 static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec) 219 { 220 return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) + 221 be32_to_cpu(spec->length)); 222 } 223 224 static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf) 225 { 226 u32 fwname_len = strlen(nfp_mip_name(pf->mip)); 227 228 return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1); 229 } 230 231 static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec) 232 { 233 u32 tl_len, key_len; 234 const char *value; 235 236 tl_len = be32_to_cpu(spec->length); 237 key_len = strnlen(spec->data, tl_len); 238 if (key_len == tl_len) 239 return nfp_dump_error_tlv_size(spec); 240 241 value = nfp_hwinfo_lookup(pf->hwinfo, spec->data); 242 if (!value) 243 return nfp_dump_error_tlv_size(spec); 244 245 return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2); 246 } 247 248 static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr) 249 { 250 u32 required_read_sz = sizeof(*spec_csr) - sizeof(spec_csr->tl); 251 u32 available_sz = be32_to_cpu(spec_csr->tl.length); 252 u32 reg_width; 253 254 if (available_sz < required_read_sz) 255 return false; 256 257 reg_width = be32_to_cpu(spec_csr->register_width); 258 259 return reg_width == 32 || reg_width == 64; 260 } 261 262 static int 263 nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec) 264 { 265 struct nfp_rtsym_table *rtbl = pf->rtbl; 266 struct nfp_dumpspec_rtsym *spec_rtsym; 267 const struct nfp_rtsym *sym; 268 u32 tl_len, key_len; 269 u32 size; 270 271 spec_rtsym = (struct nfp_dumpspec_rtsym *)spec; 272 tl_len = be32_to_cpu(spec->length); 273 key_len = strnlen(spec_rtsym->rtsym, tl_len); 274 if (key_len == tl_len) 275 return nfp_dump_error_tlv_size(spec); 276 277 sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym); 278 if (!sym) 279 return nfp_dump_error_tlv_size(spec); 280 281 if (sym->type == NFP_RTSYM_TYPE_ABS) 282 size = sizeof(sym->addr); 283 else 284 size = sym->size; 285 286 return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) + 287 ALIGN8(size); 288 } 289 290 static int 291 nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param) 292 { 293 struct nfp_dumpspec_csr *spec_csr; 294 u32 *size = param; 295 u32 hwinfo_size; 296 297 switch (be32_to_cpu(tl->type)) { 298 case NFP_DUMPSPEC_TYPE_FWNAME: 299 *size += nfp_calc_fwname_tlv_size(pf); 300 break; 301 case NFP_DUMPSPEC_TYPE_CPP_CSR: 302 case NFP_DUMPSPEC_TYPE_XPB_CSR: 303 case NFP_DUMPSPEC_TYPE_ME_CSR: 304 spec_csr = (struct nfp_dumpspec_csr *)tl; 305 if (!nfp_csr_spec_valid(spec_csr)) 306 *size += nfp_dump_error_tlv_size(tl); 307 else 308 *size += ALIGN8(sizeof(struct nfp_dump_csr)) + 309 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length)); 310 break; 311 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR: 312 spec_csr = (struct nfp_dumpspec_csr *)tl; 313 if (!nfp_csr_spec_valid(spec_csr)) 314 *size += nfp_dump_error_tlv_size(tl); 315 else 316 *size += ALIGN8(sizeof(struct nfp_dump_csr)) + 317 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length) * 318 NFP_IND_NUM_CONTEXTS); 319 break; 320 case NFP_DUMPSPEC_TYPE_RTSYM: 321 *size += nfp_calc_rtsym_dump_sz(pf, tl); 322 break; 323 case NFP_DUMPSPEC_TYPE_HWINFO: 324 hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo); 325 *size += sizeof(struct nfp_dump_tl) + ALIGN8(hwinfo_size); 326 break; 327 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD: 328 *size += nfp_calc_hwinfo_field_sz(pf, tl); 329 break; 330 default: 331 *size += nfp_dump_error_tlv_size(tl); 332 break; 333 } 334 335 return 0; 336 } 337 338 static int 339 nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level, 340 void *param) 341 { 342 struct nfp_level_size *lev_sz = param; 343 344 if (dump_level->type != lev_sz->requested_level) 345 return 0; 346 347 return nfp_traverse_tlvs(pf, dump_level->data, 348 be32_to_cpu(dump_level->length), 349 &lev_sz->total_size, nfp_add_tlv_size); 350 } 351 352 s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec, 353 u32 flag) 354 { 355 struct nfp_level_size lev_sz; 356 int err; 357 358 lev_sz.requested_level = cpu_to_be32(flag); 359 lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog)); 360 361 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz, 362 nfp_calc_specific_level_size); 363 if (err) 364 return err; 365 366 return lev_sz.total_size; 367 } 368 369 static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump) 370 { 371 struct nfp_dump_tl *tl = dump->p; 372 373 if (total_tlv_sz > dump->buf_size) 374 return -ENOSPC; 375 376 if (dump->buf_size - total_tlv_sz < dump->dumped_size) 377 return -ENOSPC; 378 379 tl->type = cpu_to_be32(type); 380 tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl)); 381 382 dump->dumped_size += total_tlv_sz; 383 dump->p += total_tlv_sz; 384 385 return 0; 386 } 387 388 static int 389 nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error, 390 struct nfp_dump_state *dump) 391 { 392 struct nfp_dump_error *dump_header = dump->p; 393 u32 total_spec_size, total_size; 394 int err; 395 396 total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length); 397 total_size = ALIGN8(sizeof(*dump_header) + total_spec_size); 398 399 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump); 400 if (err) 401 return err; 402 403 dump_header->error = cpu_to_be32(error); 404 memcpy(dump_header->spec, spec, total_spec_size); 405 406 return 0; 407 } 408 409 static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump) 410 { 411 struct nfp_dump_tl *dump_header = dump->p; 412 u32 fwname_len, total_size; 413 const char *fwname; 414 int err; 415 416 fwname = nfp_mip_name(pf->mip); 417 fwname_len = strlen(fwname); 418 total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1); 419 420 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump); 421 if (err) 422 return err; 423 424 memcpy(dump_header->data, fwname, fwname_len); 425 426 return 0; 427 } 428 429 static int 430 nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec, 431 struct nfp_dump_state *dump) 432 { 433 struct nfp_dump_tl *dump_header = dump->p; 434 u32 hwinfo_size, total_size; 435 char *hwinfo; 436 int err; 437 438 hwinfo = nfp_hwinfo_get_packed_strings(pf->hwinfo); 439 hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo); 440 total_size = sizeof(*dump_header) + ALIGN8(hwinfo_size); 441 442 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump); 443 if (err) 444 return err; 445 446 memcpy(dump_header->data, hwinfo, hwinfo_size); 447 448 return 0; 449 } 450 451 static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec, 452 struct nfp_dump_state *dump) 453 { 454 struct nfp_dump_tl *dump_header = dump->p; 455 u32 tl_len, key_len, val_len; 456 const char *key, *value; 457 u32 total_size; 458 int err; 459 460 tl_len = be32_to_cpu(spec->length); 461 key_len = strnlen(spec->data, tl_len); 462 if (key_len == tl_len) 463 return nfp_dump_error_tlv(spec, -EINVAL, dump); 464 465 key = spec->data; 466 value = nfp_hwinfo_lookup(pf->hwinfo, key); 467 if (!value) 468 return nfp_dump_error_tlv(spec, -ENOENT, dump); 469 470 val_len = strlen(value); 471 total_size = sizeof(*dump_header) + ALIGN8(key_len + val_len + 2); 472 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO_FIELD, total_size, dump); 473 if (err) 474 return err; 475 476 memcpy(dump_header->data, key, key_len + 1); 477 memcpy(dump_header->data + key_len + 1, value, val_len + 1); 478 479 return 0; 480 } 481 482 static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id) 483 { 484 return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB && 485 cpp_id->action == 0 && cpp_id->token == 0; 486 } 487 488 static int 489 nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr, 490 struct nfp_dump_state *dump) 491 { 492 struct nfp_dump_csr *dump_header = dump->p; 493 u32 reg_sz, header_size, total_size; 494 u32 cpp_rd_addr, max_rd_addr; 495 int bytes_read; 496 void *dest; 497 u32 cpp_id; 498 int err; 499 500 if (!nfp_csr_spec_valid(spec_csr)) 501 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump); 502 503 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE; 504 header_size = ALIGN8(sizeof(*dump_header)); 505 total_size = header_size + 506 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length)); 507 dest = dump->p + header_size; 508 509 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump); 510 if (err) 511 return err; 512 513 dump_header->cpp = spec_csr->cpp; 514 dump_header->register_width = spec_csr->register_width; 515 516 cpp_id = nfp_get_numeric_cpp_id(&spec_csr->cpp.cpp_id); 517 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset); 518 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length); 519 520 while (cpp_rd_addr < max_rd_addr) { 521 if (is_xpb_read(&spec_csr->cpp.cpp_id)) { 522 err = nfp_xpb_readl(pf->cpp, cpp_rd_addr, (u32 *)dest); 523 } else { 524 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr, 525 dest, reg_sz); 526 err = bytes_read == reg_sz ? 0 : -EIO; 527 } 528 if (err) { 529 dump_header->error = cpu_to_be32(err); 530 dump_header->error_offset = cpu_to_be32(cpp_rd_addr); 531 break; 532 } 533 cpp_rd_addr += reg_sz; 534 dest += reg_sz; 535 } 536 537 return 0; 538 } 539 540 /* Write context to CSRCtxPtr, then read from it. Then the value can be read 541 * from IndCtxStatus. 542 */ 543 static int 544 nfp_read_indirect_csr(struct nfp_cpp *cpp, 545 struct nfp_dumpspec_cpp_isl_id cpp_params, u32 offset, 546 u32 reg_sz, u32 context, void *dest) 547 { 548 u32 csr_ctx_ptr_offs; 549 u32 cpp_id; 550 int result; 551 552 csr_ctx_ptr_offs = nfp_get_ind_csr_ctx_ptr_offs(offset); 553 cpp_id = NFP_CPP_ISLAND_ID(cpp_params.target, 554 NFP_IND_ME_REFL_WR_SIG_INIT, 555 cpp_params.token, cpp_params.island); 556 result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context); 557 if (result) 558 return result; 559 560 cpp_id = nfp_get_numeric_cpp_id(&cpp_params); 561 result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz); 562 if (result != reg_sz) 563 return result < 0 ? result : -EIO; 564 565 result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz); 566 if (result != reg_sz) 567 return result < 0 ? result : -EIO; 568 569 return 0; 570 } 571 572 static int 573 nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp, 574 struct nfp_dumpspec_csr *spec_csr, u32 address, 575 u32 reg_sz, void *dest) 576 { 577 u32 ctx; 578 int err; 579 580 for (ctx = 0; ctx < NFP_IND_NUM_CONTEXTS; ctx++) { 581 err = nfp_read_indirect_csr(cpp, spec_csr->cpp.cpp_id, address, 582 reg_sz, ctx, dest + ctx * reg_sz); 583 if (err) 584 return err; 585 } 586 587 return 0; 588 } 589 590 static int 591 nfp_dump_indirect_csr_range(struct nfp_pf *pf, 592 struct nfp_dumpspec_csr *spec_csr, 593 struct nfp_dump_state *dump) 594 { 595 struct nfp_dump_csr *dump_header = dump->p; 596 u32 reg_sz, header_size, total_size; 597 u32 cpp_rd_addr, max_rd_addr; 598 u32 reg_data_length; 599 void *dest; 600 int err; 601 602 if (!nfp_csr_spec_valid(spec_csr)) 603 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump); 604 605 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE; 606 header_size = ALIGN8(sizeof(*dump_header)); 607 reg_data_length = be32_to_cpu(spec_csr->cpp.dump_length) * 608 NFP_IND_NUM_CONTEXTS; 609 total_size = header_size + ALIGN8(reg_data_length); 610 dest = dump->p + header_size; 611 612 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump); 613 if (err) 614 return err; 615 616 dump_header->cpp = spec_csr->cpp; 617 dump_header->register_width = spec_csr->register_width; 618 619 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset); 620 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length); 621 while (cpp_rd_addr < max_rd_addr) { 622 err = nfp_read_all_indirect_csr_ctx(pf->cpp, spec_csr, 623 cpp_rd_addr, reg_sz, dest); 624 if (err) { 625 dump_header->error = cpu_to_be32(err); 626 dump_header->error_offset = cpu_to_be32(cpp_rd_addr); 627 break; 628 } 629 cpp_rd_addr += reg_sz; 630 dest += reg_sz * NFP_IND_NUM_CONTEXTS; 631 } 632 633 return 0; 634 } 635 636 static int 637 nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec, 638 struct nfp_dump_state *dump) 639 { 640 struct nfp_dump_rtsym *dump_header = dump->p; 641 struct nfp_dumpspec_cpp_isl_id cpp_params; 642 struct nfp_rtsym_table *rtbl = pf->rtbl; 643 u32 header_size, total_size, sym_size; 644 const struct nfp_rtsym *sym; 645 u32 tl_len, key_len; 646 int bytes_read; 647 u32 cpp_id; 648 void *dest; 649 int err; 650 651 tl_len = be32_to_cpu(spec->tl.length); 652 key_len = strnlen(spec->rtsym, tl_len); 653 if (key_len == tl_len) 654 return nfp_dump_error_tlv(&spec->tl, -EINVAL, dump); 655 656 sym = nfp_rtsym_lookup(rtbl, spec->rtsym); 657 if (!sym) 658 return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump); 659 660 if (sym->type == NFP_RTSYM_TYPE_ABS) 661 sym_size = sizeof(sym->addr); 662 else 663 sym_size = sym->size; 664 665 header_size = 666 ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1); 667 total_size = header_size + ALIGN8(sym_size); 668 dest = dump->p + header_size; 669 670 err = nfp_add_tlv(be32_to_cpu(spec->tl.type), total_size, dump); 671 if (err) 672 return err; 673 674 dump_header->padded_name_length = 675 header_size - offsetof(struct nfp_dump_rtsym, rtsym); 676 memcpy(dump_header->rtsym, spec->rtsym, key_len + 1); 677 dump_header->cpp.dump_length = cpu_to_be32(sym_size); 678 679 if (sym->type == NFP_RTSYM_TYPE_ABS) { 680 *(u64 *)dest = sym->addr; 681 } else { 682 cpp_params.target = sym->target; 683 cpp_params.action = NFP_CPP_ACTION_RW; 684 cpp_params.token = 0; 685 cpp_params.island = sym->domain; 686 cpp_id = nfp_get_numeric_cpp_id(&cpp_params); 687 dump_header->cpp.cpp_id = cpp_params; 688 dump_header->cpp.offset = cpu_to_be32(sym->addr); 689 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, sym->addr, dest, 690 sym_size); 691 if (bytes_read != sym_size) { 692 if (bytes_read >= 0) 693 bytes_read = -EIO; 694 dump_header->error = cpu_to_be32(bytes_read); 695 } 696 } 697 698 return 0; 699 } 700 701 static int 702 nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param) 703 { 704 struct nfp_dumpspec_rtsym *spec_rtsym; 705 struct nfp_dump_state *dump = param; 706 struct nfp_dumpspec_csr *spec_csr; 707 int err; 708 709 switch (be32_to_cpu(tl->type)) { 710 case NFP_DUMPSPEC_TYPE_FWNAME: 711 err = nfp_dump_fwname(pf, dump); 712 if (err) 713 return err; 714 break; 715 case NFP_DUMPSPEC_TYPE_CPP_CSR: 716 case NFP_DUMPSPEC_TYPE_XPB_CSR: 717 case NFP_DUMPSPEC_TYPE_ME_CSR: 718 spec_csr = (struct nfp_dumpspec_csr *)tl; 719 err = nfp_dump_csr_range(pf, spec_csr, dump); 720 if (err) 721 return err; 722 break; 723 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR: 724 spec_csr = (struct nfp_dumpspec_csr *)tl; 725 err = nfp_dump_indirect_csr_range(pf, spec_csr, dump); 726 if (err) 727 return err; 728 break; 729 case NFP_DUMPSPEC_TYPE_RTSYM: 730 spec_rtsym = (struct nfp_dumpspec_rtsym *)tl; 731 err = nfp_dump_single_rtsym(pf, spec_rtsym, dump); 732 if (err) 733 return err; 734 break; 735 case NFP_DUMPSPEC_TYPE_HWINFO: 736 err = nfp_dump_hwinfo(pf, tl, dump); 737 if (err) 738 return err; 739 break; 740 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD: 741 err = nfp_dump_hwinfo_field(pf, tl, dump); 742 if (err) 743 return err; 744 break; 745 default: 746 err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump); 747 if (err) 748 return err; 749 } 750 751 return 0; 752 } 753 754 static int 755 nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level, 756 void *param) 757 { 758 struct nfp_dump_state *dump = param; 759 760 if (dump_level->type != dump->requested_level) 761 return 0; 762 763 return nfp_traverse_tlvs(pf, dump_level->data, 764 be32_to_cpu(dump_level->length), dump, 765 nfp_dump_for_tlv); 766 } 767 768 static int nfp_dump_populate_prolog(struct nfp_dump_state *dump) 769 { 770 struct nfp_dump_prolog *prolog = dump->p; 771 u32 total_size; 772 int err; 773 774 total_size = ALIGN8(sizeof(*prolog)); 775 776 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump); 777 if (err) 778 return err; 779 780 prolog->dump_level = dump->requested_level; 781 782 return 0; 783 } 784 785 int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec, 786 struct ethtool_dump *dump_param, void *dest) 787 { 788 struct nfp_dump_state dump; 789 int err; 790 791 dump.requested_level = cpu_to_be32(dump_param->flag); 792 dump.dumped_size = 0; 793 dump.p = dest; 794 dump.buf_size = dump_param->len; 795 796 err = nfp_dump_populate_prolog(&dump); 797 if (err) 798 return err; 799 800 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump, 801 nfp_dump_specific_level); 802 if (err) 803 return err; 804 805 /* Set size of actual dump, to trigger warning if different from 806 * calculated size. 807 */ 808 dump_param->len = dump.dumped_size; 809 810 return 0; 811 } 812