gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / net / ethernet / netronome / nfp / nfp_net_debugdump.c
bloba614df095b08c02c82c474db079078c094f481ec
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
4 #include <linux/ethtool.h>
5 #include <linux/vmalloc.h>
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"
13 #define NFP_DUMP_SPEC_RTSYM "_abi_dump_spec"
15 #define ALIGN8(x) ALIGN(x, 8)
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,
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.
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[];
42 /* NFP CPP parameters */
43 struct nfp_dumpspec_cpp_isl_id {
44 u8 target;
45 u8 action;
46 u8 token;
47 u8 island;
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 */
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 */
63 struct nfp_dumpspec_rtsym {
64 struct nfp_dump_tl tl;
65 char rtsym[];
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 */
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[];
83 /* after padded_name_length, there is dump_length data */
86 struct nfp_dump_prolog {
87 struct nfp_dump_tl tl;
88 __be32 dump_level;
91 struct nfp_dump_error {
92 struct nfp_dump_tl tl;
93 __be32 error;
94 char padding[4];
95 char spec[];
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 */
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 */
112 typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl,
113 void *param);
115 static int
116 nfp_traverse_tlvs(struct nfp_pf *pf, void *data, u32 data_length, void *param,
117 nfp_tlv_visit tlv_visit)
119 long long remaining = data_length;
120 struct nfp_dump_tl *tl;
121 u32 total_tlv_size;
122 void *p = data;
123 int err;
125 while (remaining >= sizeof(*tl)) {
126 tl = p;
127 if (!tl->type && !tl->length)
128 break;
130 if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))
131 return -EINVAL;
133 total_tlv_size = sizeof(*tl) + be32_to_cpu(tl->length);
135 /* Spec TLVs should be aligned to 4 bytes. */
136 if (total_tlv_size % 4 != 0)
137 return -EINVAL;
139 p += total_tlv_size;
140 remaining -= total_tlv_size;
141 err = tlv_visit(pf, tl, param);
142 if (err)
143 return err;
146 return 0;
149 static u32 nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id *cpp_id)
151 return NFP_CPP_ISLAND_ID(cpp_id->target, cpp_id->action, cpp_id->token,
152 cpp_id->island);
155 struct nfp_dumpspec *
156 nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
158 const struct nfp_rtsym *specsym;
159 struct nfp_dumpspec *dumpspec;
160 int bytes_read;
161 u64 sym_size;
163 specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
164 if (!specsym)
165 return NULL;
166 sym_size = nfp_rtsym_size(specsym);
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;
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;
181 return dumpspec;
184 static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec)
186 return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) +
187 be32_to_cpu(spec->length));
190 static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf)
192 u32 fwname_len = strlen(nfp_mip_name(pf->mip));
194 return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1);
197 static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
199 u32 tl_len, key_len;
200 const char *value;
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);
207 value = nfp_hwinfo_lookup(pf->hwinfo, spec->data);
208 if (!value)
209 return nfp_dump_error_tlv_size(spec);
211 return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2);
214 static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr)
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;
220 if (available_sz < required_read_sz)
221 return false;
223 reg_width = be32_to_cpu(spec_csr->register_width);
225 return reg_width == 32 || reg_width == 64;
228 static int
229 nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
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;
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);
242 sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym);
243 if (!sym)
244 return nfp_dump_error_tlv_size(spec);
246 return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
247 ALIGN8(nfp_rtsym_size(sym));
250 static int
251 nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
253 struct nfp_dumpspec_csr *spec_csr;
254 u32 *size = param;
255 u32 hwinfo_size;
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;
295 return 0;
298 static int
299 nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
300 void *param)
302 struct nfp_level_size *lev_sz = param;
304 if (dump_level->type != lev_sz->requested_level)
305 return 0;
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);
312 s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
313 u32 flag)
315 struct nfp_level_size lev_sz;
316 int err;
318 lev_sz.requested_level = cpu_to_be32(flag);
319 lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog));
321 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz,
322 nfp_calc_specific_level_size);
323 if (err)
324 return err;
326 return lev_sz.total_size;
329 static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump)
331 struct nfp_dump_tl *tl = dump->p;
333 if (total_tlv_sz > dump->buf_size)
334 return -ENOSPC;
336 if (dump->buf_size - total_tlv_sz < dump->dumped_size)
337 return -ENOSPC;
339 tl->type = cpu_to_be32(type);
340 tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl));
342 dump->dumped_size += total_tlv_sz;
343 dump->p += total_tlv_sz;
345 return 0;
348 static int
349 nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error,
350 struct nfp_dump_state *dump)
352 struct nfp_dump_error *dump_header = dump->p;
353 u32 total_spec_size, total_size;
354 int err;
356 total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length);
357 total_size = ALIGN8(sizeof(*dump_header) + total_spec_size);
359 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump);
360 if (err)
361 return err;
363 dump_header->error = cpu_to_be32(error);
364 memcpy(dump_header->spec, spec, total_spec_size);
366 return 0;
369 static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump)
371 struct nfp_dump_tl *dump_header = dump->p;
372 u32 fwname_len, total_size;
373 const char *fwname;
374 int err;
376 fwname = nfp_mip_name(pf->mip);
377 fwname_len = strlen(fwname);
378 total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1);
380 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump);
381 if (err)
382 return err;
384 memcpy(dump_header->data, fwname, fwname_len);
386 return 0;
389 static int
390 nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec,
391 struct nfp_dump_state *dump)
393 struct nfp_dump_tl *dump_header = dump->p;
394 u32 hwinfo_size, total_size;
395 char *hwinfo;
396 int err;
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);
402 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump);
403 if (err)
404 return err;
406 memcpy(dump_header->data, hwinfo, hwinfo_size);
408 return 0;
411 static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec,
412 struct nfp_dump_state *dump)
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;
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);
425 key = spec->data;
426 value = nfp_hwinfo_lookup(pf->hwinfo, key);
427 if (!value)
428 return nfp_dump_error_tlv(spec, -ENOENT, dump);
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;
436 memcpy(dump_header->data, key, key_len + 1);
437 memcpy(dump_header->data + key_len + 1, value, val_len + 1);
439 return 0;
442 static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id)
444 return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB &&
445 cpp_id->action == 0 && cpp_id->token == 0;
448 static int
449 nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,
450 struct nfp_dump_state *dump)
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;
460 if (!nfp_csr_spec_valid(spec_csr))
461 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
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;
469 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
470 if (err)
471 return err;
473 dump_header->cpp = spec_csr->cpp;
474 dump_header->register_width = spec_csr->register_width;
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);
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;
488 if (err) {
489 dump_header->error = cpu_to_be32(err);
490 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
491 break;
493 cpp_rd_addr += reg_sz;
494 dest += reg_sz;
497 return 0;
500 /* Write context to CSRCtxPtr, then read from it. Then the value can be read
501 * from IndCtxStatus.
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)
508 u32 csr_ctx_ptr_offs;
509 u32 cpp_id;
510 int result;
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;
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;
525 result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz);
526 if (result != reg_sz)
527 return result < 0 ? result : -EIO;
529 return 0;
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)
537 u32 ctx;
538 int err;
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;
547 return 0;
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)
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;
562 if (!nfp_csr_spec_valid(spec_csr))
563 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
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;
572 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
573 if (err)
574 return err;
576 dump_header->cpp = spec_csr->cpp;
577 dump_header->register_width = spec_csr->register_width;
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;
589 cpp_rd_addr += reg_sz;
590 dest += reg_sz * NFP_IND_NUM_CONTEXTS;
593 return 0;
596 static int
597 nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
598 struct nfp_dump_state *dump)
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;
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);
615 sym = nfp_rtsym_lookup(rtbl, spec->rtsym);
616 if (!sym)
617 return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
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;
625 err = nfp_add_tlv(be32_to_cpu(spec->tl.type), total_size, dump);
626 if (err)
627 return err;
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);
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);
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);
650 return 0;
653 static int
654 nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
656 struct nfp_dumpspec_rtsym *spec_rtsym;
657 struct nfp_dump_state *dump = param;
658 struct nfp_dumpspec_csr *spec_csr;
659 int err;
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;
703 return 0;
706 static int
707 nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
708 void *param)
710 struct nfp_dump_state *dump = param;
712 if (dump_level->type != dump->requested_level)
713 return 0;
715 return nfp_traverse_tlvs(pf, dump_level->data,
716 be32_to_cpu(dump_level->length), dump,
717 nfp_dump_for_tlv);
720 static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)
722 struct nfp_dump_prolog *prolog = dump->p;
723 u32 total_size;
724 int err;
726 total_size = ALIGN8(sizeof(*prolog));
728 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);
729 if (err)
730 return err;
732 prolog->dump_level = dump->requested_level;
734 return 0;
737 int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
738 struct ethtool_dump *dump_param, void *dest)
740 struct nfp_dump_state dump;
741 int err;
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;
748 err = nfp_dump_populate_prolog(&dump);
749 if (err)
750 return err;
752 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,
753 nfp_dump_specific_level);
754 if (err)
755 return err;
757 /* Set size of actual dump, to trigger warning if different from
758 * calculated size.
760 dump_param->len = dump.dumped_size;
762 return 0;