2 * Copyright (C) 2017 Netronome Systems, Inc.
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.
9 * The BSD 2-Clause License:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
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.
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
34 #include <linux/ethtool.h>
35 #include <linux/vmalloc.h>
39 #include "nfpcore/nfp.h"
40 #include "nfpcore/nfp_nffw.h"
41 #include "nfpcore/nfp6000/nfp6000.h"
43 #define NFP_DUMP_SPEC_RTSYM "_abi_dump_spec"
45 #define ALIGN8(x) ALIGN(x, 8)
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,
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
65 /* generic type plus length */
68 __be32 length
; /* chunk length to follow, aligned to 8 bytes */
72 /* NFP CPP parameters */
73 struct nfp_dumpspec_cpp_isl_id
{
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 */
87 struct nfp_dumpspec_csr
{
88 struct nfp_dump_tl tl
;
89 struct nfp_dump_common_cpp cpp
;
90 __be32 register_width
; /* in bits */
93 struct nfp_dumpspec_rtsym
{
94 struct nfp_dump_tl tl
;
98 /* header for register dumpable */
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 */
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 */
113 /* after padded_name_length, there is dump_length data */
116 struct nfp_dump_prolog
{
117 struct nfp_dump_tl tl
;
121 struct nfp_dump_error
{
122 struct nfp_dump_tl tl
;
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 */
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 */
142 typedef int (*nfp_tlv_visit
)(struct nfp_pf
*pf
, struct nfp_dump_tl
*tl
,
146 nfp_traverse_tlvs(struct nfp_pf
*pf
, void *data
, u32 data_length
, void *param
,
147 nfp_tlv_visit tlv_visit
)
149 long long remaining
= data_length
;
150 struct nfp_dump_tl
*tl
;
155 while (remaining
>= sizeof(*tl
)) {
157 if (!tl
->type
&& !tl
->length
)
160 if (be32_to_cpu(tl
->length
) > remaining
- sizeof(*tl
))
163 total_tlv_size
= sizeof(*tl
) + be32_to_cpu(tl
->length
);
165 /* Spec TLVs should be aligned to 4 bytes. */
166 if (total_tlv_size
% 4 != 0)
170 remaining
-= total_tlv_size
;
171 err
= tlv_visit(pf
, tl
, param
);
179 static u32
nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id
*cpp_id
)
181 return NFP_CPP_ISLAND_ID(cpp_id
->target
, cpp_id
->action
, cpp_id
->token
,
185 struct nfp_dumpspec
*
186 nfp_net_dump_load_dumpspec(struct nfp_cpp
*cpp
, struct nfp_rtsym_table
*rtbl
)
188 const struct nfp_rtsym
*specsym
;
189 struct nfp_dumpspec
*dumpspec
;
193 specsym
= nfp_rtsym_lookup(rtbl
, NFP_DUMP_SPEC_RTSYM
);
197 /* expected size of this buffer is in the order of tens of kilobytes */
198 dumpspec
= vmalloc(sizeof(*dumpspec
) + specsym
->size
);
202 dumpspec
->size
= specsym
->size
;
204 cpp_id
= NFP_CPP_ISLAND_ID(specsym
->target
, NFP_CPP_ACTION_RW
, 0,
207 bytes_read
= nfp_cpp_read(cpp
, cpp_id
, specsym
->addr
, dumpspec
->data
,
209 if (bytes_read
!= specsym
->size
) {
211 nfp_warn(cpp
, "Debug dump specification read failed.\n");
218 static int nfp_dump_error_tlv_size(struct nfp_dump_tl
*spec
)
220 return ALIGN8(sizeof(struct nfp_dump_error
) + sizeof(*spec
) +
221 be32_to_cpu(spec
->length
));
224 static int nfp_calc_fwname_tlv_size(struct nfp_pf
*pf
)
226 u32 fwname_len
= strlen(nfp_mip_name(pf
->mip
));
228 return sizeof(struct nfp_dump_tl
) + ALIGN8(fwname_len
+ 1);
231 static int nfp_calc_hwinfo_field_sz(struct nfp_pf
*pf
, struct nfp_dump_tl
*spec
)
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
);
241 value
= nfp_hwinfo_lookup(pf
->hwinfo
, spec
->data
);
243 return nfp_dump_error_tlv_size(spec
);
245 return sizeof(struct nfp_dump_tl
) + ALIGN8(key_len
+ strlen(value
) + 2);
248 static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr
*spec_csr
)
250 u32 required_read_sz
= sizeof(*spec_csr
) - sizeof(spec_csr
->tl
);
251 u32 available_sz
= be32_to_cpu(spec_csr
->tl
.length
);
254 if (available_sz
< required_read_sz
)
257 reg_width
= be32_to_cpu(spec_csr
->register_width
);
259 return reg_width
== 32 || reg_width
== 64;
263 nfp_calc_rtsym_dump_sz(struct nfp_pf
*pf
, struct nfp_dump_tl
*spec
)
265 struct nfp_rtsym_table
*rtbl
= pf
->rtbl
;
266 struct nfp_dumpspec_rtsym
*spec_rtsym
;
267 const struct nfp_rtsym
*sym
;
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
);
277 sym
= nfp_rtsym_lookup(rtbl
, spec_rtsym
->rtsym
);
279 return nfp_dump_error_tlv_size(spec
);
281 if (sym
->type
== NFP_RTSYM_TYPE_ABS
)
282 size
= sizeof(sym
->addr
);
286 return ALIGN8(offsetof(struct nfp_dump_rtsym
, rtsym
) + key_len
+ 1) +
291 nfp_add_tlv_size(struct nfp_pf
*pf
, struct nfp_dump_tl
*tl
, void *param
)
293 struct nfp_dumpspec_csr
*spec_csr
;
297 switch (be32_to_cpu(tl
->type
)) {
298 case NFP_DUMPSPEC_TYPE_FWNAME
:
299 *size
+= nfp_calc_fwname_tlv_size(pf
);
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
);
308 *size
+= ALIGN8(sizeof(struct nfp_dump_csr
)) +
309 ALIGN8(be32_to_cpu(spec_csr
->cpp
.dump_length
));
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
);
316 *size
+= ALIGN8(sizeof(struct nfp_dump_csr
)) +
317 ALIGN8(be32_to_cpu(spec_csr
->cpp
.dump_length
) *
318 NFP_IND_NUM_CONTEXTS
);
320 case NFP_DUMPSPEC_TYPE_RTSYM
:
321 *size
+= nfp_calc_rtsym_dump_sz(pf
, tl
);
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
);
327 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD
:
328 *size
+= nfp_calc_hwinfo_field_sz(pf
, tl
);
331 *size
+= nfp_dump_error_tlv_size(tl
);
339 nfp_calc_specific_level_size(struct nfp_pf
*pf
, struct nfp_dump_tl
*dump_level
,
342 struct nfp_level_size
*lev_sz
= param
;
344 if (dump_level
->type
!= lev_sz
->requested_level
)
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
);
352 s64
nfp_net_dump_calculate_size(struct nfp_pf
*pf
, struct nfp_dumpspec
*spec
,
355 struct nfp_level_size lev_sz
;
358 lev_sz
.requested_level
= cpu_to_be32(flag
);
359 lev_sz
.total_size
= ALIGN8(sizeof(struct nfp_dump_prolog
));
361 err
= nfp_traverse_tlvs(pf
, spec
->data
, spec
->size
, &lev_sz
,
362 nfp_calc_specific_level_size
);
366 return lev_sz
.total_size
;
369 static int nfp_add_tlv(u32 type
, u32 total_tlv_sz
, struct nfp_dump_state
*dump
)
371 struct nfp_dump_tl
*tl
= dump
->p
;
373 if (total_tlv_sz
> dump
->buf_size
)
376 if (dump
->buf_size
- total_tlv_sz
< dump
->dumped_size
)
379 tl
->type
= cpu_to_be32(type
);
380 tl
->length
= cpu_to_be32(total_tlv_sz
- sizeof(*tl
));
382 dump
->dumped_size
+= total_tlv_sz
;
383 dump
->p
+= total_tlv_sz
;
389 nfp_dump_error_tlv(struct nfp_dump_tl
*spec
, int error
,
390 struct nfp_dump_state
*dump
)
392 struct nfp_dump_error
*dump_header
= dump
->p
;
393 u32 total_spec_size
, total_size
;
396 total_spec_size
= sizeof(*spec
) + be32_to_cpu(spec
->length
);
397 total_size
= ALIGN8(sizeof(*dump_header
) + total_spec_size
);
399 err
= nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR
, total_size
, dump
);
403 dump_header
->error
= cpu_to_be32(error
);
404 memcpy(dump_header
->spec
, spec
, total_spec_size
);
409 static int nfp_dump_fwname(struct nfp_pf
*pf
, struct nfp_dump_state
*dump
)
411 struct nfp_dump_tl
*dump_header
= dump
->p
;
412 u32 fwname_len
, total_size
;
416 fwname
= nfp_mip_name(pf
->mip
);
417 fwname_len
= strlen(fwname
);
418 total_size
= sizeof(*dump_header
) + ALIGN8(fwname_len
+ 1);
420 err
= nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME
, total_size
, dump
);
424 memcpy(dump_header
->data
, fwname
, fwname_len
);
430 nfp_dump_hwinfo(struct nfp_pf
*pf
, struct nfp_dump_tl
*spec
,
431 struct nfp_dump_state
*dump
)
433 struct nfp_dump_tl
*dump_header
= dump
->p
;
434 u32 hwinfo_size
, total_size
;
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
);
442 err
= nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO
, total_size
, dump
);
446 memcpy(dump_header
->data
, hwinfo
, hwinfo_size
);
451 static int nfp_dump_hwinfo_field(struct nfp_pf
*pf
, struct nfp_dump_tl
*spec
,
452 struct nfp_dump_state
*dump
)
454 struct nfp_dump_tl
*dump_header
= dump
->p
;
455 u32 tl_len
, key_len
, val_len
;
456 const char *key
, *value
;
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
);
466 value
= nfp_hwinfo_lookup(pf
->hwinfo
, key
);
468 return nfp_dump_error_tlv(spec
, -ENOENT
, dump
);
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
);
476 memcpy(dump_header
->data
, key
, key_len
+ 1);
477 memcpy(dump_header
->data
+ key_len
+ 1, value
, val_len
+ 1);
482 static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id
*cpp_id
)
484 return cpp_id
->target
== NFP_CPP_TARGET_ISLAND_XPB
&&
485 cpp_id
->action
== 0 && cpp_id
->token
== 0;
489 nfp_dump_csr_range(struct nfp_pf
*pf
, struct nfp_dumpspec_csr
*spec_csr
,
490 struct nfp_dump_state
*dump
)
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
;
500 if (!nfp_csr_spec_valid(spec_csr
))
501 return nfp_dump_error_tlv(&spec_csr
->tl
, -EINVAL
, dump
);
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
;
509 err
= nfp_add_tlv(be32_to_cpu(spec_csr
->tl
.type
), total_size
, dump
);
513 dump_header
->cpp
= spec_csr
->cpp
;
514 dump_header
->register_width
= spec_csr
->register_width
;
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
);
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
);
524 bytes_read
= nfp_cpp_read(pf
->cpp
, cpp_id
, cpp_rd_addr
,
526 err
= bytes_read
== reg_sz
? 0 : -EIO
;
529 dump_header
->error
= cpu_to_be32(err
);
530 dump_header
->error_offset
= cpu_to_be32(cpp_rd_addr
);
533 cpp_rd_addr
+= reg_sz
;
540 /* Write context to CSRCtxPtr, then read from it. Then the value can be read
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
)
548 u32 csr_ctx_ptr_offs
;
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
);
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
;
565 result
= nfp_cpp_read(cpp
, cpp_id
, offset
, dest
, reg_sz
);
566 if (result
!= reg_sz
)
567 return result
< 0 ? result
: -EIO
;
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
)
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
);
591 nfp_dump_indirect_csr_range(struct nfp_pf
*pf
,
592 struct nfp_dumpspec_csr
*spec_csr
,
593 struct nfp_dump_state
*dump
)
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
;
602 if (!nfp_csr_spec_valid(spec_csr
))
603 return nfp_dump_error_tlv(&spec_csr
->tl
, -EINVAL
, dump
);
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
;
612 err
= nfp_add_tlv(be32_to_cpu(spec_csr
->tl
.type
), total_size
, dump
);
616 dump_header
->cpp
= spec_csr
->cpp
;
617 dump_header
->register_width
= spec_csr
->register_width
;
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
);
625 dump_header
->error
= cpu_to_be32(err
);
626 dump_header
->error_offset
= cpu_to_be32(cpp_rd_addr
);
629 cpp_rd_addr
+= reg_sz
;
630 dest
+= reg_sz
* NFP_IND_NUM_CONTEXTS
;
637 nfp_dump_single_rtsym(struct nfp_pf
*pf
, struct nfp_dumpspec_rtsym
*spec
,
638 struct nfp_dump_state
*dump
)
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
;
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
);
656 sym
= nfp_rtsym_lookup(rtbl
, spec
->rtsym
);
658 return nfp_dump_error_tlv(&spec
->tl
, -ENOENT
, dump
);
660 if (sym
->type
== NFP_RTSYM_TYPE_ABS
)
661 sym_size
= sizeof(sym
->addr
);
663 sym_size
= sym
->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
;
670 err
= nfp_add_tlv(be32_to_cpu(spec
->tl
.type
), total_size
, dump
);
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
);
679 if (sym
->type
== NFP_RTSYM_TYPE_ABS
) {
680 *(u64
*)dest
= sym
->addr
;
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
,
691 if (bytes_read
!= sym_size
) {
694 dump_header
->error
= cpu_to_be32(bytes_read
);
702 nfp_dump_for_tlv(struct nfp_pf
*pf
, struct nfp_dump_tl
*tl
, void *param
)
704 struct nfp_dumpspec_rtsym
*spec_rtsym
;
705 struct nfp_dump_state
*dump
= param
;
706 struct nfp_dumpspec_csr
*spec_csr
;
709 switch (be32_to_cpu(tl
->type
)) {
710 case NFP_DUMPSPEC_TYPE_FWNAME
:
711 err
= nfp_dump_fwname(pf
, dump
);
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
);
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
);
729 case NFP_DUMPSPEC_TYPE_RTSYM
:
730 spec_rtsym
= (struct nfp_dumpspec_rtsym
*)tl
;
731 err
= nfp_dump_single_rtsym(pf
, spec_rtsym
, dump
);
735 case NFP_DUMPSPEC_TYPE_HWINFO
:
736 err
= nfp_dump_hwinfo(pf
, tl
, dump
);
740 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD
:
741 err
= nfp_dump_hwinfo_field(pf
, tl
, dump
);
746 err
= nfp_dump_error_tlv(tl
, -EOPNOTSUPP
, dump
);
755 nfp_dump_specific_level(struct nfp_pf
*pf
, struct nfp_dump_tl
*dump_level
,
758 struct nfp_dump_state
*dump
= param
;
760 if (dump_level
->type
!= dump
->requested_level
)
763 return nfp_traverse_tlvs(pf
, dump_level
->data
,
764 be32_to_cpu(dump_level
->length
), dump
,
768 static int nfp_dump_populate_prolog(struct nfp_dump_state
*dump
)
770 struct nfp_dump_prolog
*prolog
= dump
->p
;
774 total_size
= ALIGN8(sizeof(*prolog
));
776 err
= nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG
, total_size
, dump
);
780 prolog
->dump_level
= dump
->requested_level
;
785 int nfp_net_dump_populate_buffer(struct nfp_pf
*pf
, struct nfp_dumpspec
*spec
,
786 struct ethtool_dump
*dump_param
, void *dest
)
788 struct nfp_dump_state dump
;
791 dump
.requested_level
= cpu_to_be32(dump_param
->flag
);
792 dump
.dumped_size
= 0;
794 dump
.buf_size
= dump_param
->len
;
796 err
= nfp_dump_populate_prolog(&dump
);
800 err
= nfp_traverse_tlvs(pf
, spec
->data
, spec
->size
, &dump
,
801 nfp_dump_specific_level
);
805 /* Set size of actual dump, to trigger warning if different from
808 dump_param
->len
= dump
.dumped_size
;