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>
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
35 /* generic type plus length */
38 __be32 length
; /* chunk length to follow, aligned to 8 bytes */
42 /* NFP CPP parameters */
43 struct nfp_dumpspec_cpp_isl_id
{
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 */
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
;
68 /* header for register dumpable */
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 */
83 /* after padded_name_length, there is dump_length data */
86 struct nfp_dump_prolog
{
87 struct nfp_dump_tl tl
;
91 struct nfp_dump_error
{
92 struct nfp_dump_tl tl
;
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
,
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
;
125 while (remaining
>= sizeof(*tl
)) {
127 if (!tl
->type
&& !tl
->length
)
130 if (be32_to_cpu(tl
->length
) > remaining
- sizeof(*tl
))
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)
140 remaining
-= total_tlv_size
;
141 err
= tlv_visit(pf
, tl
, param
);
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
,
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
;
163 specsym
= nfp_rtsym_lookup(rtbl
, NFP_DUMP_SPEC_RTSYM
);
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
);
172 dumpspec
->size
= sym_size
;
174 bytes_read
= nfp_rtsym_read(cpp
, specsym
, 0, dumpspec
->data
, sym_size
);
175 if (bytes_read
!= sym_size
) {
177 nfp_warn(cpp
, "Debug dump specification read failed.\n");
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
)
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
);
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
);
220 if (available_sz
< required_read_sz
)
223 reg_width
= be32_to_cpu(spec_csr
->register_width
);
225 return reg_width
== 32 || reg_width
== 64;
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
;
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
);
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
));
251 nfp_add_tlv_size(struct nfp_pf
*pf
, struct nfp_dump_tl
*tl
, void *param
)
253 struct nfp_dumpspec_csr
*spec_csr
;
257 switch (be32_to_cpu(tl
->type
)) {
258 case NFP_DUMPSPEC_TYPE_FWNAME
:
259 *size
+= nfp_calc_fwname_tlv_size(pf
);
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
);
268 *size
+= ALIGN8(sizeof(struct nfp_dump_csr
)) +
269 ALIGN8(be32_to_cpu(spec_csr
->cpp
.dump_length
));
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
);
276 *size
+= ALIGN8(sizeof(struct nfp_dump_csr
)) +
277 ALIGN8(be32_to_cpu(spec_csr
->cpp
.dump_length
) *
278 NFP_IND_NUM_CONTEXTS
);
280 case NFP_DUMPSPEC_TYPE_RTSYM
:
281 *size
+= nfp_calc_rtsym_dump_sz(pf
, tl
);
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
);
287 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD
:
288 *size
+= nfp_calc_hwinfo_field_sz(pf
, tl
);
291 *size
+= nfp_dump_error_tlv_size(tl
);
299 nfp_calc_specific_level_size(struct nfp_pf
*pf
, struct nfp_dump_tl
*dump_level
,
302 struct nfp_level_size
*lev_sz
= param
;
304 if (dump_level
->type
!= lev_sz
->requested_level
)
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
,
315 struct nfp_level_size lev_sz
;
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
);
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
)
336 if (dump
->buf_size
- total_tlv_sz
< dump
->dumped_size
)
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
;
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
;
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
);
363 dump_header
->error
= cpu_to_be32(error
);
364 memcpy(dump_header
->spec
, spec
, total_spec_size
);
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
;
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
);
384 memcpy(dump_header
->data
, fwname
, fwname_len
);
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
;
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
);
406 memcpy(dump_header
->data
, hwinfo
, hwinfo_size
);
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
;
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
);
426 value
= nfp_hwinfo_lookup(pf
->hwinfo
, key
);
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
);
436 memcpy(dump_header
->data
, key
, key_len
+ 1);
437 memcpy(dump_header
->data
+ key_len
+ 1, value
, val_len
+ 1);
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;
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
;
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
);
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
);
484 bytes_read
= nfp_cpp_read(pf
->cpp
, cpp_id
, cpp_rd_addr
,
486 err
= bytes_read
== reg_sz
? 0 : -EIO
;
489 dump_header
->error
= cpu_to_be32(err
);
490 dump_header
->error_offset
= cpu_to_be32(cpp_rd_addr
);
493 cpp_rd_addr
+= reg_sz
;
500 /* Write context to CSRCtxPtr, then read from it. Then the value can be read
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
;
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
);
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
;
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
)
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
);
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
;
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
);
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
);
585 dump_header
->error
= cpu_to_be32(err
);
586 dump_header
->error_offset
= cpu_to_be32(cpp_rd_addr
);
589 cpp_rd_addr
+= reg_sz
;
590 dest
+= reg_sz
* NFP_IND_NUM_CONTEXTS
;
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
;
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
);
617 return nfp_dump_error_tlv(&spec
->tl
, -ENOENT
, dump
);
619 sym_size
= nfp_rtsym_size(sym
);
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
);
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
) {
647 dump_header
->error
= cpu_to_be32(bytes_read
);
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
;
661 switch (be32_to_cpu(tl
->type
)) {
662 case NFP_DUMPSPEC_TYPE_FWNAME
:
663 err
= nfp_dump_fwname(pf
, dump
);
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
);
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
);
681 case NFP_DUMPSPEC_TYPE_RTSYM
:
682 spec_rtsym
= (struct nfp_dumpspec_rtsym
*)tl
;
683 err
= nfp_dump_single_rtsym(pf
, spec_rtsym
, dump
);
687 case NFP_DUMPSPEC_TYPE_HWINFO
:
688 err
= nfp_dump_hwinfo(pf
, tl
, dump
);
692 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD
:
693 err
= nfp_dump_hwinfo_field(pf
, tl
, dump
);
698 err
= nfp_dump_error_tlv(tl
, -EOPNOTSUPP
, dump
);
707 nfp_dump_specific_level(struct nfp_pf
*pf
, struct nfp_dump_tl
*dump_level
,
710 struct nfp_dump_state
*dump
= param
;
712 if (dump_level
->type
!= dump
->requested_level
)
715 return nfp_traverse_tlvs(pf
, dump_level
->data
,
716 be32_to_cpu(dump_level
->length
), dump
,
720 static int nfp_dump_populate_prolog(struct nfp_dump_state
*dump
)
722 struct nfp_dump_prolog
*prolog
= dump
->p
;
726 total_size
= ALIGN8(sizeof(*prolog
));
728 err
= nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG
, total_size
, dump
);
732 prolog
->dump_level
= dump
->requested_level
;
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
;
743 dump
.requested_level
= cpu_to_be32(dump_param
->flag
);
744 dump
.dumped_size
= 0;
746 dump
.buf_size
= dump_param
->len
;
748 err
= nfp_dump_populate_prolog(&dump
);
752 err
= nfp_traverse_tlvs(pf
, spec
->data
, spec
->size
, &dump
,
753 nfp_dump_specific_level
);
757 /* Set size of actual dump, to trigger warning if different from
760 dump_param
->len
= dump
.dumped_size
;