root/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfp_traverse_tlvs
  2. nfp_get_numeric_cpp_id
  3. nfp_net_dump_load_dumpspec
  4. nfp_dump_error_tlv_size
  5. nfp_calc_fwname_tlv_size
  6. nfp_calc_hwinfo_field_sz
  7. nfp_csr_spec_valid
  8. nfp_calc_rtsym_dump_sz
  9. nfp_add_tlv_size
  10. nfp_calc_specific_level_size
  11. nfp_net_dump_calculate_size
  12. nfp_add_tlv
  13. nfp_dump_error_tlv
  14. nfp_dump_fwname
  15. nfp_dump_hwinfo
  16. nfp_dump_hwinfo_field
  17. is_xpb_read
  18. nfp_dump_csr_range
  19. nfp_read_indirect_csr
  20. nfp_read_all_indirect_csr_ctx
  21. nfp_dump_indirect_csr_range
  22. nfp_dump_single_rtsym
  23. nfp_dump_for_tlv
  24. nfp_dump_specific_level
  25. nfp_dump_populate_prolog
  26. nfp_net_dump_populate_buffer

   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[0];
  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[0];
  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[0];
  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[0];
  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 }

/* [<][>][^][v][top][bottom][index][help] */