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 bytes_read = nfp_xpb_readl(pf->cpp, cpp_rd_addr, 523 (u32 *)dest); 524 else 525 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr, 526 dest, reg_sz); 527 if (bytes_read != reg_sz) { 528 if (bytes_read >= 0) 529 bytes_read = -EIO; 530 dump_header->error = cpu_to_be32(bytes_read); 531 dump_header->error_offset = cpu_to_be32(cpp_rd_addr); 532 break; 533 } 534 cpp_rd_addr += reg_sz; 535 dest += reg_sz; 536 } 537 538 return 0; 539 } 540 541 /* Write context to CSRCtxPtr, then read from it. Then the value can be read 542 * from IndCtxStatus. 543 */ 544 static int 545 nfp_read_indirect_csr(struct nfp_cpp *cpp, 546 struct nfp_dumpspec_cpp_isl_id cpp_params, u32 offset, 547 u32 reg_sz, u32 context, void *dest) 548 { 549 u32 csr_ctx_ptr_offs; 550 u32 cpp_id; 551 int result; 552 553 csr_ctx_ptr_offs = nfp_get_ind_csr_ctx_ptr_offs(offset); 554 cpp_id = NFP_CPP_ISLAND_ID(cpp_params.target, 555 NFP_IND_ME_REFL_WR_SIG_INIT, 556 cpp_params.token, cpp_params.island); 557 result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context); 558 if (result != sizeof(context)) 559 return result < 0 ? result : -EIO; 560 561 cpp_id = nfp_get_numeric_cpp_id(&cpp_params); 562 result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz); 563 if (result != reg_sz) 564 return result < 0 ? result : -EIO; 565 566 result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz); 567 if (result != reg_sz) 568 return result < 0 ? result : -EIO; 569 570 return 0; 571 } 572 573 static int 574 nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp, 575 struct nfp_dumpspec_csr *spec_csr, u32 address, 576 u32 reg_sz, void *dest) 577 { 578 u32 ctx; 579 int err; 580 581 for (ctx = 0; ctx < NFP_IND_NUM_CONTEXTS; ctx++) { 582 err = nfp_read_indirect_csr(cpp, spec_csr->cpp.cpp_id, address, 583 reg_sz, ctx, dest + ctx * reg_sz); 584 if (err) 585 return err; 586 } 587 588 return 0; 589 } 590 591 static int 592 nfp_dump_indirect_csr_range(struct nfp_pf *pf, 593 struct nfp_dumpspec_csr *spec_csr, 594 struct nfp_dump_state *dump) 595 { 596 struct nfp_dump_csr *dump_header = dump->p; 597 u32 reg_sz, header_size, total_size; 598 u32 cpp_rd_addr, max_rd_addr; 599 u32 reg_data_length; 600 void *dest; 601 int err; 602 603 if (!nfp_csr_spec_valid(spec_csr)) 604 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump); 605 606 reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE; 607 header_size = ALIGN8(sizeof(*dump_header)); 608 reg_data_length = be32_to_cpu(spec_csr->cpp.dump_length) * 609 NFP_IND_NUM_CONTEXTS; 610 total_size = header_size + ALIGN8(reg_data_length); 611 dest = dump->p + header_size; 612 613 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump); 614 if (err) 615 return err; 616 617 dump_header->cpp = spec_csr->cpp; 618 dump_header->register_width = spec_csr->register_width; 619 620 cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset); 621 max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length); 622 while (cpp_rd_addr < max_rd_addr) { 623 err = nfp_read_all_indirect_csr_ctx(pf->cpp, spec_csr, 624 cpp_rd_addr, reg_sz, dest); 625 if (err) { 626 dump_header->error = cpu_to_be32(err); 627 dump_header->error_offset = cpu_to_be32(cpp_rd_addr); 628 break; 629 } 630 cpp_rd_addr += reg_sz; 631 dest += reg_sz * NFP_IND_NUM_CONTEXTS; 632 } 633 634 return 0; 635 } 636 637 static int 638 nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec, 639 struct nfp_dump_state *dump) 640 { 641 struct nfp_dump_rtsym *dump_header = dump->p; 642 struct nfp_dumpspec_cpp_isl_id cpp_params; 643 struct nfp_rtsym_table *rtbl = pf->rtbl; 644 const struct nfp_rtsym *sym; 645 u32 header_size, total_size; 646 u32 tl_len, key_len; 647 int bytes_read; 648 u32 cpp_id; 649 void *dest; 650 int err; 651 652 tl_len = be32_to_cpu(spec->tl.length); 653 key_len = strnlen(spec->rtsym, tl_len); 654 if (key_len == tl_len) 655 return nfp_dump_error_tlv(&spec->tl, -EINVAL, dump); 656 657 sym = nfp_rtsym_lookup(rtbl, spec->rtsym); 658 if (!sym) 659 return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump); 660 661 header_size = 662 ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1); 663 total_size = header_size + ALIGN8(sym->size); 664 dest = dump->p + header_size; 665 666 err = nfp_add_tlv(be32_to_cpu(spec->tl.type), total_size, dump); 667 if (err) 668 return err; 669 670 dump_header->padded_name_length = 671 header_size - offsetof(struct nfp_dump_rtsym, rtsym); 672 memcpy(dump_header->rtsym, spec->rtsym, key_len + 1); 673 674 if (sym->type == NFP_RTSYM_TYPE_ABS) { 675 dump_header->cpp.dump_length = cpu_to_be32(sizeof(sym->addr)); 676 *(u64 *)dest = sym->addr; 677 } else { 678 cpp_params.target = sym->target; 679 cpp_params.action = NFP_CPP_ACTION_RW; 680 cpp_params.token = 0; 681 cpp_params.island = sym->domain; 682 cpp_id = nfp_get_numeric_cpp_id(&cpp_params); 683 dump_header->cpp.cpp_id = cpp_params; 684 dump_header->cpp.offset = cpu_to_be32(sym->addr); 685 dump_header->cpp.dump_length = cpu_to_be32(sym->size); 686 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, sym->addr, dest, 687 sym->size); 688 if (bytes_read != sym->size) { 689 if (bytes_read >= 0) 690 bytes_read = -EIO; 691 dump_header->error = cpu_to_be32(bytes_read); 692 } 693 } 694 695 return 0; 696 } 697 698 static int 699 nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param) 700 { 701 struct nfp_dumpspec_rtsym *spec_rtsym; 702 struct nfp_dump_state *dump = param; 703 struct nfp_dumpspec_csr *spec_csr; 704 int err; 705 706 switch (be32_to_cpu(tl->type)) { 707 case NFP_DUMPSPEC_TYPE_FWNAME: 708 err = nfp_dump_fwname(pf, dump); 709 if (err) 710 return err; 711 break; 712 case NFP_DUMPSPEC_TYPE_CPP_CSR: 713 case NFP_DUMPSPEC_TYPE_XPB_CSR: 714 case NFP_DUMPSPEC_TYPE_ME_CSR: 715 spec_csr = (struct nfp_dumpspec_csr *)tl; 716 err = nfp_dump_csr_range(pf, spec_csr, dump); 717 if (err) 718 return err; 719 break; 720 case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR: 721 spec_csr = (struct nfp_dumpspec_csr *)tl; 722 err = nfp_dump_indirect_csr_range(pf, spec_csr, dump); 723 if (err) 724 return err; 725 break; 726 case NFP_DUMPSPEC_TYPE_RTSYM: 727 spec_rtsym = (struct nfp_dumpspec_rtsym *)tl; 728 err = nfp_dump_single_rtsym(pf, spec_rtsym, dump); 729 if (err) 730 return err; 731 break; 732 case NFP_DUMPSPEC_TYPE_HWINFO: 733 err = nfp_dump_hwinfo(pf, tl, dump); 734 if (err) 735 return err; 736 break; 737 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD: 738 err = nfp_dump_hwinfo_field(pf, tl, dump); 739 if (err) 740 return err; 741 break; 742 default: 743 err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump); 744 if (err) 745 return err; 746 } 747 748 return 0; 749 } 750 751 static int 752 nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level, 753 void *param) 754 { 755 struct nfp_dump_state *dump = param; 756 757 if (dump_level->type != dump->requested_level) 758 return 0; 759 760 return nfp_traverse_tlvs(pf, dump_level->data, 761 be32_to_cpu(dump_level->length), dump, 762 nfp_dump_for_tlv); 763 } 764 765 static int nfp_dump_populate_prolog(struct nfp_dump_state *dump) 766 { 767 struct nfp_dump_prolog *prolog = dump->p; 768 u32 total_size; 769 int err; 770 771 total_size = ALIGN8(sizeof(*prolog)); 772 773 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump); 774 if (err) 775 return err; 776 777 prolog->dump_level = dump->requested_level; 778 779 return 0; 780 } 781 782 int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec, 783 struct ethtool_dump *dump_param, void *dest) 784 { 785 struct nfp_dump_state dump; 786 int err; 787 788 dump.requested_level = cpu_to_be32(dump_param->flag); 789 dump.dumped_size = 0; 790 dump.p = dest; 791 dump.buf_size = dump_param->len; 792 793 err = nfp_dump_populate_prolog(&dump); 794 if (err) 795 return err; 796 797 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump, 798 nfp_dump_specific_level); 799 if (err) 800 return err; 801 802 /* Set size of actual dump, to trigger warning if different from 803 * calculated size. 804 */ 805 dump_param->len = dump.dumped_size; 806 807 return 0; 808 } 809