xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3d79e19f5SCarl Heymann 
4d79e19f5SCarl Heymann #include <linux/ethtool.h>
58a925303SCarl Heymann #include <linux/vmalloc.h>
6d79e19f5SCarl Heymann 
760b84a9bSCarl Heymann #include "nfp_asm.h"
8d79e19f5SCarl Heymann #include "nfp_main.h"
98a925303SCarl Heymann #include "nfpcore/nfp.h"
108a925303SCarl Heymann #include "nfpcore/nfp_nffw.h"
1128b2d7d0SCarl Heymann #include "nfpcore/nfp6000/nfp6000.h"
128a925303SCarl Heymann 
138a925303SCarl Heymann #define NFP_DUMP_SPEC_RTSYM	"_abi_dump_spec"
14d79e19f5SCarl Heymann 
15f7852b8eSCarl Heymann #define ALIGN8(x)	ALIGN(x, 8)
16f7852b8eSCarl Heymann 
17f7852b8eSCarl Heymann enum nfp_dumpspec_type {
180e6c4955SCarl Heymann 	NFP_DUMPSPEC_TYPE_CPP_CSR = 0,
190e6c4955SCarl Heymann 	NFP_DUMPSPEC_TYPE_XPB_CSR = 1,
200e6c4955SCarl Heymann 	NFP_DUMPSPEC_TYPE_ME_CSR = 2,
2160b84a9bSCarl Heymann 	NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR = 3,
22e1e798e3SCarl Heymann 	NFP_DUMPSPEC_TYPE_RTSYM = 4,
2324ff8455SCarl Heymann 	NFP_DUMPSPEC_TYPE_HWINFO = 5,
24e9364d30SCarl Heymann 	NFP_DUMPSPEC_TYPE_FWNAME = 6,
2510144de3SCarl Heymann 	NFP_DUMPSPEC_TYPE_HWINFO_FIELD = 7,
26f7852b8eSCarl Heymann 	NFP_DUMPSPEC_TYPE_PROLOG = 10000,
27f3682c78SCarl Heymann 	NFP_DUMPSPEC_TYPE_ERROR = 10001,
28f7852b8eSCarl Heymann };
29f7852b8eSCarl Heymann 
30f7852b8eSCarl Heymann /* The following structs must be carefully aligned so that they can be used to
31f7852b8eSCarl Heymann  * interpret the binary dumpspec and populate the dump data in a deterministic
32f7852b8eSCarl Heymann  * way.
33f7852b8eSCarl Heymann  */
34f7852b8eSCarl Heymann 
35f7852b8eSCarl Heymann /* generic type plus length */
36f7852b8eSCarl Heymann struct nfp_dump_tl {
37f7852b8eSCarl Heymann 	__be32 type;
38f7852b8eSCarl Heymann 	__be32 length;	/* chunk length to follow, aligned to 8 bytes */
39*3f6e9633SGustavo A. R. Silva 	char data[];
40f7852b8eSCarl Heymann };
41f7852b8eSCarl Heymann 
42e1e798e3SCarl Heymann /* NFP CPP parameters */
43e1e798e3SCarl Heymann struct nfp_dumpspec_cpp_isl_id {
44e1e798e3SCarl Heymann 	u8 target;
45e1e798e3SCarl Heymann 	u8 action;
46e1e798e3SCarl Heymann 	u8 token;
47e1e798e3SCarl Heymann 	u8 island;
48e1e798e3SCarl Heymann };
49e1e798e3SCarl Heymann 
50e1e798e3SCarl Heymann struct nfp_dump_common_cpp {
51e1e798e3SCarl Heymann 	struct nfp_dumpspec_cpp_isl_id cpp_id;
52e1e798e3SCarl Heymann 	__be32 offset;		/* address to start dump */
53e1e798e3SCarl Heymann 	__be32 dump_length;	/* total bytes to dump, aligned to reg size */
54e1e798e3SCarl Heymann };
55e1e798e3SCarl Heymann 
560e6c4955SCarl Heymann /* CSR dumpables */
570e6c4955SCarl Heymann struct nfp_dumpspec_csr {
580e6c4955SCarl Heymann 	struct nfp_dump_tl tl;
590e6c4955SCarl Heymann 	struct nfp_dump_common_cpp cpp;
600e6c4955SCarl Heymann 	__be32 register_width;	/* in bits */
610e6c4955SCarl Heymann };
620e6c4955SCarl Heymann 
63e1e798e3SCarl Heymann struct nfp_dumpspec_rtsym {
64e1e798e3SCarl Heymann 	struct nfp_dump_tl tl;
65*3f6e9633SGustavo A. R. Silva 	char rtsym[];
66e1e798e3SCarl Heymann };
67e1e798e3SCarl Heymann 
680e6c4955SCarl Heymann /* header for register dumpable */
690e6c4955SCarl Heymann struct nfp_dump_csr {
700e6c4955SCarl Heymann 	struct nfp_dump_tl tl;
710e6c4955SCarl Heymann 	struct nfp_dump_common_cpp cpp;
720e6c4955SCarl Heymann 	__be32 register_width;	/* in bits */
730e6c4955SCarl Heymann 	__be32 error;		/* error code encountered while reading */
740e6c4955SCarl Heymann 	__be32 error_offset;	/* offset being read when error occurred */
750e6c4955SCarl Heymann };
760e6c4955SCarl Heymann 
77e1e798e3SCarl Heymann struct nfp_dump_rtsym {
78e1e798e3SCarl Heymann 	struct nfp_dump_tl tl;
79e1e798e3SCarl Heymann 	struct nfp_dump_common_cpp cpp;
80e1e798e3SCarl Heymann 	__be32 error;		/* error code encountered while reading */
81e1e798e3SCarl Heymann 	u8 padded_name_length;	/* pad so data starts at 8 byte boundary */
82*3f6e9633SGustavo A. R. Silva 	char rtsym[];
83e1e798e3SCarl Heymann 	/* after padded_name_length, there is dump_length data */
84e1e798e3SCarl Heymann };
85e1e798e3SCarl Heymann 
86f7852b8eSCarl Heymann struct nfp_dump_prolog {
87f7852b8eSCarl Heymann 	struct nfp_dump_tl tl;
88f7852b8eSCarl Heymann 	__be32 dump_level;
89f7852b8eSCarl Heymann };
90f7852b8eSCarl Heymann 
91f3682c78SCarl Heymann struct nfp_dump_error {
92f3682c78SCarl Heymann 	struct nfp_dump_tl tl;
93f3682c78SCarl Heymann 	__be32 error;
94f3682c78SCarl Heymann 	char padding[4];
95*3f6e9633SGustavo A. R. Silva 	char spec[];
96f3682c78SCarl Heymann };
97f3682c78SCarl Heymann 
98f3682c78SCarl Heymann /* to track state through debug size calculation TLV traversal */
99f3682c78SCarl Heymann struct nfp_level_size {
10092a54f4aSCarl Heymann 	__be32 requested_level;	/* input */
101f3682c78SCarl Heymann 	u32 total_size;		/* output */
102f3682c78SCarl Heymann };
103f3682c78SCarl Heymann 
104f7852b8eSCarl Heymann /* to track state during debug dump creation TLV traversal */
105f7852b8eSCarl Heymann struct nfp_dump_state {
10692a54f4aSCarl Heymann 	__be32 requested_level;	/* input param */
107f7852b8eSCarl Heymann 	u32 dumped_size;	/* adds up to size of dumped data */
108f7852b8eSCarl Heymann 	u32 buf_size;		/* size of buffer pointer to by p */
109f7852b8eSCarl Heymann 	void *p;		/* current point in dump buffer */
110f7852b8eSCarl Heymann };
111f7852b8eSCarl Heymann 
112f3682c78SCarl Heymann typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl,
113f3682c78SCarl Heymann 			     void *param);
114f3682c78SCarl Heymann 
115f3682c78SCarl Heymann static int
nfp_traverse_tlvs(struct nfp_pf * pf,void * data,u32 data_length,void * param,nfp_tlv_visit tlv_visit)116f3682c78SCarl Heymann nfp_traverse_tlvs(struct nfp_pf *pf, void *data, u32 data_length, void *param,
117f3682c78SCarl Heymann 		  nfp_tlv_visit tlv_visit)
118f3682c78SCarl Heymann {
119f3682c78SCarl Heymann 	long long remaining = data_length;
120f3682c78SCarl Heymann 	struct nfp_dump_tl *tl;
121f3682c78SCarl Heymann 	u32 total_tlv_size;
122f3682c78SCarl Heymann 	void *p = data;
123f3682c78SCarl Heymann 	int err;
124f3682c78SCarl Heymann 
125f3682c78SCarl Heymann 	while (remaining >= sizeof(*tl)) {
126f3682c78SCarl Heymann 		tl = p;
127f3682c78SCarl Heymann 		if (!tl->type && !tl->length)
128f3682c78SCarl Heymann 			break;
129f3682c78SCarl Heymann 
130f3682c78SCarl Heymann 		if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))
131f3682c78SCarl Heymann 			return -EINVAL;
132f3682c78SCarl Heymann 
133f3682c78SCarl Heymann 		total_tlv_size = sizeof(*tl) + be32_to_cpu(tl->length);
134f3682c78SCarl Heymann 
135f3682c78SCarl Heymann 		/* Spec TLVs should be aligned to 4 bytes. */
136f3682c78SCarl Heymann 		if (total_tlv_size % 4 != 0)
137f3682c78SCarl Heymann 			return -EINVAL;
138f3682c78SCarl Heymann 
139f3682c78SCarl Heymann 		p += total_tlv_size;
140f3682c78SCarl Heymann 		remaining -= total_tlv_size;
141f3682c78SCarl Heymann 		err = tlv_visit(pf, tl, param);
142f3682c78SCarl Heymann 		if (err)
143f3682c78SCarl Heymann 			return err;
144f3682c78SCarl Heymann 	}
145f3682c78SCarl Heymann 
146f3682c78SCarl Heymann 	return 0;
147f3682c78SCarl Heymann }
148f3682c78SCarl Heymann 
nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id * cpp_id)149e1e798e3SCarl Heymann static u32 nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id *cpp_id)
150e1e798e3SCarl Heymann {
151e1e798e3SCarl Heymann 	return NFP_CPP_ISLAND_ID(cpp_id->target, cpp_id->action, cpp_id->token,
152e1e798e3SCarl Heymann 				 cpp_id->island);
153e1e798e3SCarl Heymann }
154e1e798e3SCarl Heymann 
155d79e19f5SCarl Heymann struct nfp_dumpspec *
nfp_net_dump_load_dumpspec(struct nfp_cpp * cpp,struct nfp_rtsym_table * rtbl)156d79e19f5SCarl Heymann nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
157d79e19f5SCarl Heymann {
1588a925303SCarl Heymann 	const struct nfp_rtsym *specsym;
1598a925303SCarl Heymann 	struct nfp_dumpspec *dumpspec;
1608a925303SCarl Heymann 	int bytes_read;
1614152e58cSJakub Kicinski 	u64 sym_size;
1628a925303SCarl Heymann 
1638a925303SCarl Heymann 	specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
1648a925303SCarl Heymann 	if (!specsym)
165d79e19f5SCarl Heymann 		return NULL;
1664152e58cSJakub Kicinski 	sym_size = nfp_rtsym_size(specsym);
1678a925303SCarl Heymann 
1688a925303SCarl Heymann 	/* expected size of this buffer is in the order of tens of kilobytes */
1694152e58cSJakub Kicinski 	dumpspec = vmalloc(sizeof(*dumpspec) + sym_size);
1708a925303SCarl Heymann 	if (!dumpspec)
1718a925303SCarl Heymann 		return NULL;
1724152e58cSJakub Kicinski 	dumpspec->size = sym_size;
1738a925303SCarl Heymann 
1744152e58cSJakub Kicinski 	bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size);
1754152e58cSJakub Kicinski 	if (bytes_read != sym_size) {
1768a925303SCarl Heymann 		vfree(dumpspec);
1778a925303SCarl Heymann 		nfp_warn(cpp, "Debug dump specification read failed.\n");
1788a925303SCarl Heymann 		return NULL;
1798a925303SCarl Heymann 	}
1808a925303SCarl Heymann 
1818a925303SCarl Heymann 	return dumpspec;
182d79e19f5SCarl Heymann }
183d79e19f5SCarl Heymann 
nfp_dump_error_tlv_size(struct nfp_dump_tl * spec)184f3682c78SCarl Heymann static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec)
185f3682c78SCarl Heymann {
186f3682c78SCarl Heymann 	return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) +
187f3682c78SCarl Heymann 		      be32_to_cpu(spec->length));
188f3682c78SCarl Heymann }
189f3682c78SCarl Heymann 
nfp_calc_fwname_tlv_size(struct nfp_pf * pf)190e9364d30SCarl Heymann static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf)
191e9364d30SCarl Heymann {
192e9364d30SCarl Heymann 	u32 fwname_len = strlen(nfp_mip_name(pf->mip));
193e9364d30SCarl Heymann 
194e9364d30SCarl Heymann 	return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1);
195e9364d30SCarl Heymann }
196e9364d30SCarl Heymann 
nfp_calc_hwinfo_field_sz(struct nfp_pf * pf,struct nfp_dump_tl * spec)19710144de3SCarl Heymann static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
19810144de3SCarl Heymann {
19910144de3SCarl Heymann 	u32 tl_len, key_len;
20010144de3SCarl Heymann 	const char *value;
20110144de3SCarl Heymann 
20210144de3SCarl Heymann 	tl_len = be32_to_cpu(spec->length);
20310144de3SCarl Heymann 	key_len = strnlen(spec->data, tl_len);
20410144de3SCarl Heymann 	if (key_len == tl_len)
20510144de3SCarl Heymann 		return nfp_dump_error_tlv_size(spec);
20610144de3SCarl Heymann 
20710144de3SCarl Heymann 	value = nfp_hwinfo_lookup(pf->hwinfo, spec->data);
20810144de3SCarl Heymann 	if (!value)
20910144de3SCarl Heymann 		return nfp_dump_error_tlv_size(spec);
21010144de3SCarl Heymann 
21110144de3SCarl Heymann 	return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2);
21210144de3SCarl Heymann }
21310144de3SCarl Heymann 
nfp_csr_spec_valid(struct nfp_dumpspec_csr * spec_csr)2140e6c4955SCarl Heymann static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr)
2150e6c4955SCarl Heymann {
2160e6c4955SCarl Heymann 	u32 required_read_sz = sizeof(*spec_csr) - sizeof(spec_csr->tl);
2170e6c4955SCarl Heymann 	u32 available_sz = be32_to_cpu(spec_csr->tl.length);
2180e6c4955SCarl Heymann 	u32 reg_width;
2190e6c4955SCarl Heymann 
2200e6c4955SCarl Heymann 	if (available_sz < required_read_sz)
2210e6c4955SCarl Heymann 		return false;
2220e6c4955SCarl Heymann 
2230e6c4955SCarl Heymann 	reg_width = be32_to_cpu(spec_csr->register_width);
2240e6c4955SCarl Heymann 
2250e6c4955SCarl Heymann 	return reg_width == 32 || reg_width == 64;
2260e6c4955SCarl Heymann }
2270e6c4955SCarl Heymann 
228f3682c78SCarl Heymann static int
nfp_calc_rtsym_dump_sz(struct nfp_pf * pf,struct nfp_dump_tl * spec)229e1e798e3SCarl Heymann nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
230e1e798e3SCarl Heymann {
231e1e798e3SCarl Heymann 	struct nfp_rtsym_table *rtbl = pf->rtbl;
232e1e798e3SCarl Heymann 	struct nfp_dumpspec_rtsym *spec_rtsym;
233e1e798e3SCarl Heymann 	const struct nfp_rtsym *sym;
234e1e798e3SCarl Heymann 	u32 tl_len, key_len;
235e1e798e3SCarl Heymann 
236e1e798e3SCarl Heymann 	spec_rtsym = (struct nfp_dumpspec_rtsym *)spec;
237e1e798e3SCarl Heymann 	tl_len = be32_to_cpu(spec->length);
238e1e798e3SCarl Heymann 	key_len = strnlen(spec_rtsym->rtsym, tl_len);
239e1e798e3SCarl Heymann 	if (key_len == tl_len)
240e1e798e3SCarl Heymann 		return nfp_dump_error_tlv_size(spec);
241e1e798e3SCarl Heymann 
242e1e798e3SCarl Heymann 	sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym);
243e1e798e3SCarl Heymann 	if (!sym)
244e1e798e3SCarl Heymann 		return nfp_dump_error_tlv_size(spec);
245e1e798e3SCarl Heymann 
246e1e798e3SCarl Heymann 	return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
2474152e58cSJakub Kicinski 	       ALIGN8(nfp_rtsym_size(sym));
248e1e798e3SCarl Heymann }
249e1e798e3SCarl Heymann 
250e1e798e3SCarl Heymann static int
nfp_add_tlv_size(struct nfp_pf * pf,struct nfp_dump_tl * tl,void * param)251f3682c78SCarl Heymann nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
252f3682c78SCarl Heymann {
2530e6c4955SCarl Heymann 	struct nfp_dumpspec_csr *spec_csr;
254f3682c78SCarl Heymann 	u32 *size = param;
25524ff8455SCarl Heymann 	u32 hwinfo_size;
256f3682c78SCarl Heymann 
257f3682c78SCarl Heymann 	switch (be32_to_cpu(tl->type)) {
258e9364d30SCarl Heymann 	case NFP_DUMPSPEC_TYPE_FWNAME:
259e9364d30SCarl Heymann 		*size += nfp_calc_fwname_tlv_size(pf);
260e9364d30SCarl Heymann 		break;
2610e6c4955SCarl Heymann 	case NFP_DUMPSPEC_TYPE_CPP_CSR:
2620e6c4955SCarl Heymann 	case NFP_DUMPSPEC_TYPE_XPB_CSR:
2630e6c4955SCarl Heymann 	case NFP_DUMPSPEC_TYPE_ME_CSR:
2640e6c4955SCarl Heymann 		spec_csr = (struct nfp_dumpspec_csr *)tl;
2650e6c4955SCarl Heymann 		if (!nfp_csr_spec_valid(spec_csr))
2660e6c4955SCarl Heymann 			*size += nfp_dump_error_tlv_size(tl);
2670e6c4955SCarl Heymann 		else
2680e6c4955SCarl Heymann 			*size += ALIGN8(sizeof(struct nfp_dump_csr)) +
2690e6c4955SCarl Heymann 				 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
2700e6c4955SCarl Heymann 		break;
27160b84a9bSCarl Heymann 	case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:
27260b84a9bSCarl Heymann 		spec_csr = (struct nfp_dumpspec_csr *)tl;
27360b84a9bSCarl Heymann 		if (!nfp_csr_spec_valid(spec_csr))
27460b84a9bSCarl Heymann 			*size += nfp_dump_error_tlv_size(tl);
27560b84a9bSCarl Heymann 		else
27660b84a9bSCarl Heymann 			*size += ALIGN8(sizeof(struct nfp_dump_csr)) +
27760b84a9bSCarl Heymann 				 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length) *
27860b84a9bSCarl Heymann 					NFP_IND_NUM_CONTEXTS);
27960b84a9bSCarl Heymann 		break;
280e1e798e3SCarl Heymann 	case NFP_DUMPSPEC_TYPE_RTSYM:
281e1e798e3SCarl Heymann 		*size += nfp_calc_rtsym_dump_sz(pf, tl);
282e1e798e3SCarl Heymann 		break;
28324ff8455SCarl Heymann 	case NFP_DUMPSPEC_TYPE_HWINFO:
28424ff8455SCarl Heymann 		hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);
28524ff8455SCarl Heymann 		*size += sizeof(struct nfp_dump_tl) + ALIGN8(hwinfo_size);
28624ff8455SCarl Heymann 		break;
28710144de3SCarl Heymann 	case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
28810144de3SCarl Heymann 		*size += nfp_calc_hwinfo_field_sz(pf, tl);
28910144de3SCarl Heymann 		break;
290f3682c78SCarl Heymann 	default:
291f3682c78SCarl Heymann 		*size += nfp_dump_error_tlv_size(tl);
292f3682c78SCarl Heymann 		break;
293f3682c78SCarl Heymann 	}
294f3682c78SCarl Heymann 
295f3682c78SCarl Heymann 	return 0;
296f3682c78SCarl Heymann }
297f3682c78SCarl Heymann 
298f3682c78SCarl Heymann static int
nfp_calc_specific_level_size(struct nfp_pf * pf,struct nfp_dump_tl * dump_level,void * param)299f3682c78SCarl Heymann nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
300f3682c78SCarl Heymann 			     void *param)
301f3682c78SCarl Heymann {
302f3682c78SCarl Heymann 	struct nfp_level_size *lev_sz = param;
303f3682c78SCarl Heymann 
30492a54f4aSCarl Heymann 	if (dump_level->type != lev_sz->requested_level)
305f3682c78SCarl Heymann 		return 0;
306f3682c78SCarl Heymann 
307f3682c78SCarl Heymann 	return nfp_traverse_tlvs(pf, dump_level->data,
308f3682c78SCarl Heymann 				 be32_to_cpu(dump_level->length),
309f3682c78SCarl Heymann 				 &lev_sz->total_size, nfp_add_tlv_size);
310f3682c78SCarl Heymann }
311f3682c78SCarl Heymann 
nfp_net_dump_calculate_size(struct nfp_pf * pf,struct nfp_dumpspec * spec,u32 flag)312d79e19f5SCarl Heymann s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
313d79e19f5SCarl Heymann 				u32 flag)
314d79e19f5SCarl Heymann {
315f3682c78SCarl Heymann 	struct nfp_level_size lev_sz;
316f3682c78SCarl Heymann 	int err;
317f3682c78SCarl Heymann 
31892a54f4aSCarl Heymann 	lev_sz.requested_level = cpu_to_be32(flag);
319f3682c78SCarl Heymann 	lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog));
320f3682c78SCarl Heymann 
321f3682c78SCarl Heymann 	err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz,
322f3682c78SCarl Heymann 				nfp_calc_specific_level_size);
323f3682c78SCarl Heymann 	if (err)
324f3682c78SCarl Heymann 		return err;
325f3682c78SCarl Heymann 
326f3682c78SCarl Heymann 	return lev_sz.total_size;
327f7852b8eSCarl Heymann }
328f7852b8eSCarl Heymann 
nfp_add_tlv(u32 type,u32 total_tlv_sz,struct nfp_dump_state * dump)329f7852b8eSCarl Heymann static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump)
330f7852b8eSCarl Heymann {
331f7852b8eSCarl Heymann 	struct nfp_dump_tl *tl = dump->p;
332f7852b8eSCarl Heymann 
333f7852b8eSCarl Heymann 	if (total_tlv_sz > dump->buf_size)
334f7852b8eSCarl Heymann 		return -ENOSPC;
335f7852b8eSCarl Heymann 
336f7852b8eSCarl Heymann 	if (dump->buf_size - total_tlv_sz < dump->dumped_size)
337f7852b8eSCarl Heymann 		return -ENOSPC;
338f7852b8eSCarl Heymann 
339f7852b8eSCarl Heymann 	tl->type = cpu_to_be32(type);
340f7852b8eSCarl Heymann 	tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl));
341f7852b8eSCarl Heymann 
342f7852b8eSCarl Heymann 	dump->dumped_size += total_tlv_sz;
343f7852b8eSCarl Heymann 	dump->p += total_tlv_sz;
344f7852b8eSCarl Heymann 
345f7852b8eSCarl Heymann 	return 0;
346f7852b8eSCarl Heymann }
347f7852b8eSCarl Heymann 
348f3682c78SCarl Heymann static int
nfp_dump_error_tlv(struct nfp_dump_tl * spec,int error,struct nfp_dump_state * dump)349f3682c78SCarl Heymann nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error,
350f3682c78SCarl Heymann 		   struct nfp_dump_state *dump)
351f3682c78SCarl Heymann {
352f3682c78SCarl Heymann 	struct nfp_dump_error *dump_header = dump->p;
353f3682c78SCarl Heymann 	u32 total_spec_size, total_size;
354f3682c78SCarl Heymann 	int err;
355f3682c78SCarl Heymann 
356f3682c78SCarl Heymann 	total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length);
357f3682c78SCarl Heymann 	total_size = ALIGN8(sizeof(*dump_header) + total_spec_size);
358f3682c78SCarl Heymann 
359f3682c78SCarl Heymann 	err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump);
360f3682c78SCarl Heymann 	if (err)
361f3682c78SCarl Heymann 		return err;
362f3682c78SCarl Heymann 
363f3682c78SCarl Heymann 	dump_header->error = cpu_to_be32(error);
364f3682c78SCarl Heymann 	memcpy(dump_header->spec, spec, total_spec_size);
365f3682c78SCarl Heymann 
366f3682c78SCarl Heymann 	return 0;
367f3682c78SCarl Heymann }
368f3682c78SCarl Heymann 
nfp_dump_fwname(struct nfp_pf * pf,struct nfp_dump_state * dump)369e9364d30SCarl Heymann static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump)
370e9364d30SCarl Heymann {
371e9364d30SCarl Heymann 	struct nfp_dump_tl *dump_header = dump->p;
372e9364d30SCarl Heymann 	u32 fwname_len, total_size;
373e9364d30SCarl Heymann 	const char *fwname;
374e9364d30SCarl Heymann 	int err;
375e9364d30SCarl Heymann 
376e9364d30SCarl Heymann 	fwname = nfp_mip_name(pf->mip);
377e9364d30SCarl Heymann 	fwname_len = strlen(fwname);
378e9364d30SCarl Heymann 	total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1);
379e9364d30SCarl Heymann 
380e9364d30SCarl Heymann 	err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump);
381e9364d30SCarl Heymann 	if (err)
382e9364d30SCarl Heymann 		return err;
383e9364d30SCarl Heymann 
384e9364d30SCarl Heymann 	memcpy(dump_header->data, fwname, fwname_len);
385e9364d30SCarl Heymann 
386e9364d30SCarl Heymann 	return 0;
387e9364d30SCarl Heymann }
388e9364d30SCarl Heymann 
389f3682c78SCarl Heymann static int
nfp_dump_hwinfo(struct nfp_pf * pf,struct nfp_dump_tl * spec,struct nfp_dump_state * dump)39024ff8455SCarl Heymann nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec,
39124ff8455SCarl Heymann 		struct nfp_dump_state *dump)
39224ff8455SCarl Heymann {
39324ff8455SCarl Heymann 	struct nfp_dump_tl *dump_header = dump->p;
39424ff8455SCarl Heymann 	u32 hwinfo_size, total_size;
39524ff8455SCarl Heymann 	char *hwinfo;
39624ff8455SCarl Heymann 	int err;
39724ff8455SCarl Heymann 
39824ff8455SCarl Heymann 	hwinfo = nfp_hwinfo_get_packed_strings(pf->hwinfo);
39924ff8455SCarl Heymann 	hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);
40024ff8455SCarl Heymann 	total_size = sizeof(*dump_header) + ALIGN8(hwinfo_size);
40124ff8455SCarl Heymann 
40224ff8455SCarl Heymann 	err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump);
40324ff8455SCarl Heymann 	if (err)
40424ff8455SCarl Heymann 		return err;
40524ff8455SCarl Heymann 
40624ff8455SCarl Heymann 	memcpy(dump_header->data, hwinfo, hwinfo_size);
40724ff8455SCarl Heymann 
40824ff8455SCarl Heymann 	return 0;
40924ff8455SCarl Heymann }
41024ff8455SCarl Heymann 
nfp_dump_hwinfo_field(struct nfp_pf * pf,struct nfp_dump_tl * spec,struct nfp_dump_state * dump)41110144de3SCarl Heymann static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec,
41210144de3SCarl Heymann 				 struct nfp_dump_state *dump)
41310144de3SCarl Heymann {
41410144de3SCarl Heymann 	struct nfp_dump_tl *dump_header = dump->p;
41510144de3SCarl Heymann 	u32 tl_len, key_len, val_len;
41610144de3SCarl Heymann 	const char *key, *value;
41710144de3SCarl Heymann 	u32 total_size;
41810144de3SCarl Heymann 	int err;
41910144de3SCarl Heymann 
42010144de3SCarl Heymann 	tl_len = be32_to_cpu(spec->length);
42110144de3SCarl Heymann 	key_len = strnlen(spec->data, tl_len);
42210144de3SCarl Heymann 	if (key_len == tl_len)
42310144de3SCarl Heymann 		return nfp_dump_error_tlv(spec, -EINVAL, dump);
42410144de3SCarl Heymann 
42510144de3SCarl Heymann 	key = spec->data;
42610144de3SCarl Heymann 	value = nfp_hwinfo_lookup(pf->hwinfo, key);
42710144de3SCarl Heymann 	if (!value)
42810144de3SCarl Heymann 		return nfp_dump_error_tlv(spec, -ENOENT, dump);
42910144de3SCarl Heymann 
43010144de3SCarl Heymann 	val_len = strlen(value);
43110144de3SCarl Heymann 	total_size = sizeof(*dump_header) + ALIGN8(key_len + val_len + 2);
43210144de3SCarl Heymann 	err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO_FIELD, total_size, dump);
43310144de3SCarl Heymann 	if (err)
43410144de3SCarl Heymann 		return err;
43510144de3SCarl Heymann 
43610144de3SCarl Heymann 	memcpy(dump_header->data, key, key_len + 1);
43710144de3SCarl Heymann 	memcpy(dump_header->data + key_len + 1, value, val_len + 1);
43810144de3SCarl Heymann 
43910144de3SCarl Heymann 	return 0;
44010144de3SCarl Heymann }
44110144de3SCarl Heymann 
is_xpb_read(struct nfp_dumpspec_cpp_isl_id * cpp_id)44228b2d7d0SCarl Heymann static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id)
44328b2d7d0SCarl Heymann {
44428b2d7d0SCarl Heymann 	return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB &&
44528b2d7d0SCarl Heymann 	       cpp_id->action == 0 && cpp_id->token == 0;
44628b2d7d0SCarl Heymann }
44728b2d7d0SCarl Heymann 
44824ff8455SCarl Heymann static int
nfp_dump_csr_range(struct nfp_pf * pf,struct nfp_dumpspec_csr * spec_csr,struct nfp_dump_state * dump)4490e6c4955SCarl Heymann nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,
4500e6c4955SCarl Heymann 		   struct nfp_dump_state *dump)
4510e6c4955SCarl Heymann {
4520e6c4955SCarl Heymann 	struct nfp_dump_csr *dump_header = dump->p;
4530e6c4955SCarl Heymann 	u32 reg_sz, header_size, total_size;
4540e6c4955SCarl Heymann 	u32 cpp_rd_addr, max_rd_addr;
4550e6c4955SCarl Heymann 	int bytes_read;
4560e6c4955SCarl Heymann 	void *dest;
4570e6c4955SCarl Heymann 	u32 cpp_id;
4580e6c4955SCarl Heymann 	int err;
4590e6c4955SCarl Heymann 
4600e6c4955SCarl Heymann 	if (!nfp_csr_spec_valid(spec_csr))
4610e6c4955SCarl Heymann 		return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
4620e6c4955SCarl Heymann 
4630e6c4955SCarl Heymann 	reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;
4640e6c4955SCarl Heymann 	header_size = ALIGN8(sizeof(*dump_header));
4650e6c4955SCarl Heymann 	total_size = header_size +
4660e6c4955SCarl Heymann 		     ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
4670e6c4955SCarl Heymann 	dest = dump->p + header_size;
4680e6c4955SCarl Heymann 
4690e6c4955SCarl Heymann 	err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
4700e6c4955SCarl Heymann 	if (err)
4710e6c4955SCarl Heymann 		return err;
4720e6c4955SCarl Heymann 
4730e6c4955SCarl Heymann 	dump_header->cpp = spec_csr->cpp;
4740e6c4955SCarl Heymann 	dump_header->register_width = spec_csr->register_width;
4750e6c4955SCarl Heymann 
4760e6c4955SCarl Heymann 	cpp_id = nfp_get_numeric_cpp_id(&spec_csr->cpp.cpp_id);
4770e6c4955SCarl Heymann 	cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);
4780e6c4955SCarl Heymann 	max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
4790e6c4955SCarl Heymann 
4800e6c4955SCarl Heymann 	while (cpp_rd_addr < max_rd_addr) {
481aa3f4b69SJakub Kicinski 		if (is_xpb_read(&spec_csr->cpp.cpp_id)) {
482aa3f4b69SJakub Kicinski 			err = nfp_xpb_readl(pf->cpp, cpp_rd_addr, (u32 *)dest);
483aa3f4b69SJakub Kicinski 		} else {
48428b2d7d0SCarl Heymann 			bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr,
48528b2d7d0SCarl Heymann 						  dest, reg_sz);
486aa3f4b69SJakub Kicinski 			err = bytes_read == reg_sz ? 0 : -EIO;
487aa3f4b69SJakub Kicinski 		}
488aa3f4b69SJakub Kicinski 		if (err) {
489aa3f4b69SJakub Kicinski 			dump_header->error = cpu_to_be32(err);
4900e6c4955SCarl Heymann 			dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
4910e6c4955SCarl Heymann 			break;
4920e6c4955SCarl Heymann 		}
4930e6c4955SCarl Heymann 		cpp_rd_addr += reg_sz;
4940e6c4955SCarl Heymann 		dest += reg_sz;
4950e6c4955SCarl Heymann 	}
4960e6c4955SCarl Heymann 
4970e6c4955SCarl Heymann 	return 0;
4980e6c4955SCarl Heymann }
4990e6c4955SCarl Heymann 
50060b84a9bSCarl Heymann /* Write context to CSRCtxPtr, then read from it. Then the value can be read
50160b84a9bSCarl Heymann  * from IndCtxStatus.
50260b84a9bSCarl Heymann  */
50360b84a9bSCarl Heymann static int
nfp_read_indirect_csr(struct nfp_cpp * cpp,struct nfp_dumpspec_cpp_isl_id cpp_params,u32 offset,u32 reg_sz,u32 context,void * dest)50460b84a9bSCarl Heymann nfp_read_indirect_csr(struct nfp_cpp *cpp,
50560b84a9bSCarl Heymann 		      struct nfp_dumpspec_cpp_isl_id cpp_params, u32 offset,
50660b84a9bSCarl Heymann 		      u32 reg_sz, u32 context, void *dest)
50760b84a9bSCarl Heymann {
50860b84a9bSCarl Heymann 	u32 csr_ctx_ptr_offs;
50960b84a9bSCarl Heymann 	u32 cpp_id;
51060b84a9bSCarl Heymann 	int result;
51160b84a9bSCarl Heymann 
51260b84a9bSCarl Heymann 	csr_ctx_ptr_offs = nfp_get_ind_csr_ctx_ptr_offs(offset);
51360b84a9bSCarl Heymann 	cpp_id = NFP_CPP_ISLAND_ID(cpp_params.target,
51460b84a9bSCarl Heymann 				   NFP_IND_ME_REFL_WR_SIG_INIT,
51560b84a9bSCarl Heymann 				   cpp_params.token, cpp_params.island);
51660b84a9bSCarl Heymann 	result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context);
517aa3f4b69SJakub Kicinski 	if (result)
518aa3f4b69SJakub Kicinski 		return result;
51960b84a9bSCarl Heymann 
52060b84a9bSCarl Heymann 	cpp_id = nfp_get_numeric_cpp_id(&cpp_params);
52160b84a9bSCarl Heymann 	result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz);
52260b84a9bSCarl Heymann 	if (result != reg_sz)
52360b84a9bSCarl Heymann 		return result < 0 ? result : -EIO;
52460b84a9bSCarl Heymann 
52560b84a9bSCarl Heymann 	result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz);
52660b84a9bSCarl Heymann 	if (result != reg_sz)
52760b84a9bSCarl Heymann 		return result < 0 ? result : -EIO;
52860b84a9bSCarl Heymann 
52960b84a9bSCarl Heymann 	return 0;
53060b84a9bSCarl Heymann }
53160b84a9bSCarl Heymann 
53260b84a9bSCarl Heymann static int
nfp_read_all_indirect_csr_ctx(struct nfp_cpp * cpp,struct nfp_dumpspec_csr * spec_csr,u32 address,u32 reg_sz,void * dest)53360b84a9bSCarl Heymann nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp,
53460b84a9bSCarl Heymann 			      struct nfp_dumpspec_csr *spec_csr, u32 address,
53560b84a9bSCarl Heymann 			      u32 reg_sz, void *dest)
53660b84a9bSCarl Heymann {
53760b84a9bSCarl Heymann 	u32 ctx;
53860b84a9bSCarl Heymann 	int err;
53960b84a9bSCarl Heymann 
54060b84a9bSCarl Heymann 	for (ctx = 0; ctx < NFP_IND_NUM_CONTEXTS; ctx++) {
54160b84a9bSCarl Heymann 		err = nfp_read_indirect_csr(cpp, spec_csr->cpp.cpp_id, address,
54260b84a9bSCarl Heymann 					    reg_sz, ctx, dest + ctx * reg_sz);
54360b84a9bSCarl Heymann 		if (err)
54460b84a9bSCarl Heymann 			return err;
54560b84a9bSCarl Heymann 	}
54660b84a9bSCarl Heymann 
54760b84a9bSCarl Heymann 	return 0;
54860b84a9bSCarl Heymann }
54960b84a9bSCarl Heymann 
55060b84a9bSCarl Heymann static int
nfp_dump_indirect_csr_range(struct nfp_pf * pf,struct nfp_dumpspec_csr * spec_csr,struct nfp_dump_state * dump)55160b84a9bSCarl Heymann nfp_dump_indirect_csr_range(struct nfp_pf *pf,
55260b84a9bSCarl Heymann 			    struct nfp_dumpspec_csr *spec_csr,
55360b84a9bSCarl Heymann 			    struct nfp_dump_state *dump)
55460b84a9bSCarl Heymann {
55560b84a9bSCarl Heymann 	struct nfp_dump_csr *dump_header = dump->p;
55660b84a9bSCarl Heymann 	u32 reg_sz, header_size, total_size;
55760b84a9bSCarl Heymann 	u32 cpp_rd_addr, max_rd_addr;
55860b84a9bSCarl Heymann 	u32 reg_data_length;
55960b84a9bSCarl Heymann 	void *dest;
56060b84a9bSCarl Heymann 	int err;
56160b84a9bSCarl Heymann 
56260b84a9bSCarl Heymann 	if (!nfp_csr_spec_valid(spec_csr))
56360b84a9bSCarl Heymann 		return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
56460b84a9bSCarl Heymann 
56560b84a9bSCarl Heymann 	reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;
56660b84a9bSCarl Heymann 	header_size = ALIGN8(sizeof(*dump_header));
56760b84a9bSCarl Heymann 	reg_data_length = be32_to_cpu(spec_csr->cpp.dump_length) *
56860b84a9bSCarl Heymann 			  NFP_IND_NUM_CONTEXTS;
56960b84a9bSCarl Heymann 	total_size = header_size + ALIGN8(reg_data_length);
57060b84a9bSCarl Heymann 	dest = dump->p + header_size;
57160b84a9bSCarl Heymann 
57260b84a9bSCarl Heymann 	err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
57360b84a9bSCarl Heymann 	if (err)
57460b84a9bSCarl Heymann 		return err;
57560b84a9bSCarl Heymann 
57660b84a9bSCarl Heymann 	dump_header->cpp = spec_csr->cpp;
57760b84a9bSCarl Heymann 	dump_header->register_width = spec_csr->register_width;
57860b84a9bSCarl Heymann 
57960b84a9bSCarl Heymann 	cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);
58060b84a9bSCarl Heymann 	max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
58160b84a9bSCarl Heymann 	while (cpp_rd_addr < max_rd_addr) {
58260b84a9bSCarl Heymann 		err = nfp_read_all_indirect_csr_ctx(pf->cpp, spec_csr,
58360b84a9bSCarl Heymann 						    cpp_rd_addr, reg_sz, dest);
58460b84a9bSCarl Heymann 		if (err) {
58560b84a9bSCarl Heymann 			dump_header->error = cpu_to_be32(err);
58660b84a9bSCarl Heymann 			dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
58760b84a9bSCarl Heymann 			break;
58860b84a9bSCarl Heymann 		}
58960b84a9bSCarl Heymann 		cpp_rd_addr += reg_sz;
59060b84a9bSCarl Heymann 		dest += reg_sz * NFP_IND_NUM_CONTEXTS;
59160b84a9bSCarl Heymann 	}
59260b84a9bSCarl Heymann 
59360b84a9bSCarl Heymann 	return 0;
59460b84a9bSCarl Heymann }
59560b84a9bSCarl Heymann 
5960e6c4955SCarl Heymann static int
nfp_dump_single_rtsym(struct nfp_pf * pf,struct nfp_dumpspec_rtsym * spec,struct nfp_dump_state * dump)597e1e798e3SCarl Heymann nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
598e1e798e3SCarl Heymann 		      struct nfp_dump_state *dump)
599e1e798e3SCarl Heymann {
600e1e798e3SCarl Heymann 	struct nfp_dump_rtsym *dump_header = dump->p;
601e1e798e3SCarl Heymann 	struct nfp_dumpspec_cpp_isl_id cpp_params;
602e1e798e3SCarl Heymann 	struct nfp_rtsym_table *rtbl = pf->rtbl;
603e71494aeSCarl Heymann 	u32 header_size, total_size, sym_size;
604e1e798e3SCarl Heymann 	const struct nfp_rtsym *sym;
605e1e798e3SCarl Heymann 	u32 tl_len, key_len;
606e1e798e3SCarl Heymann 	int bytes_read;
607e1e798e3SCarl Heymann 	void *dest;
608e1e798e3SCarl Heymann 	int err;
609e1e798e3SCarl Heymann 
610e1e798e3SCarl Heymann 	tl_len = be32_to_cpu(spec->tl.length);
611e1e798e3SCarl Heymann 	key_len = strnlen(spec->rtsym, tl_len);
612e1e798e3SCarl Heymann 	if (key_len == tl_len)
613e1e798e3SCarl Heymann 		return nfp_dump_error_tlv(&spec->tl, -EINVAL, dump);
614e1e798e3SCarl Heymann 
615e1e798e3SCarl Heymann 	sym = nfp_rtsym_lookup(rtbl, spec->rtsym);
616e1e798e3SCarl Heymann 	if (!sym)
617e1e798e3SCarl Heymann 		return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
618e1e798e3SCarl Heymann 
6194152e58cSJakub Kicinski 	sym_size = nfp_rtsym_size(sym);
620e1e798e3SCarl Heymann 	header_size =
621e1e798e3SCarl Heymann 		ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1);
622e71494aeSCarl Heymann 	total_size = header_size + ALIGN8(sym_size);
623e1e798e3SCarl Heymann 	dest = dump->p + header_size;
624e1e798e3SCarl Heymann 
625e1e798e3SCarl Heymann 	err = nfp_add_tlv(be32_to_cpu(spec->tl.type), total_size, dump);
626e1e798e3SCarl Heymann 	if (err)
627e1e798e3SCarl Heymann 		return err;
628e1e798e3SCarl Heymann 
629e1e798e3SCarl Heymann 	dump_header->padded_name_length =
630e1e798e3SCarl Heymann 		header_size - offsetof(struct nfp_dump_rtsym, rtsym);
631e1e798e3SCarl Heymann 	memcpy(dump_header->rtsym, spec->rtsym, key_len + 1);
632e71494aeSCarl Heymann 	dump_header->cpp.dump_length = cpu_to_be32(sym_size);
633e1e798e3SCarl Heymann 
6344152e58cSJakub Kicinski 	if (sym->type != NFP_RTSYM_TYPE_ABS) {
635e1e798e3SCarl Heymann 		cpp_params.target = sym->target;
636e1e798e3SCarl Heymann 		cpp_params.action = NFP_CPP_ACTION_RW;
637e1e798e3SCarl Heymann 		cpp_params.token  = 0;
638e1e798e3SCarl Heymann 		cpp_params.island = sym->domain;
639e1e798e3SCarl Heymann 		dump_header->cpp.cpp_id = cpp_params;
640e1e798e3SCarl Heymann 		dump_header->cpp.offset = cpu_to_be32(sym->addr);
6414152e58cSJakub Kicinski 	}
6424152e58cSJakub Kicinski 
6431240989cSJakub Kicinski 	bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size);
644e71494aeSCarl Heymann 	if (bytes_read != sym_size) {
645e1e798e3SCarl Heymann 		if (bytes_read >= 0)
646e1e798e3SCarl Heymann 			bytes_read = -EIO;
647e1e798e3SCarl Heymann 		dump_header->error = cpu_to_be32(bytes_read);
648e1e798e3SCarl Heymann 	}
649e1e798e3SCarl Heymann 
650e1e798e3SCarl Heymann 	return 0;
651e1e798e3SCarl Heymann }
652e1e798e3SCarl Heymann 
653e1e798e3SCarl Heymann static int
nfp_dump_for_tlv(struct nfp_pf * pf,struct nfp_dump_tl * tl,void * param)654f3682c78SCarl Heymann nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
655f3682c78SCarl Heymann {
656e1e798e3SCarl Heymann 	struct nfp_dumpspec_rtsym *spec_rtsym;
657f3682c78SCarl Heymann 	struct nfp_dump_state *dump = param;
6580e6c4955SCarl Heymann 	struct nfp_dumpspec_csr *spec_csr;
659f3682c78SCarl Heymann 	int err;
660f3682c78SCarl Heymann 
661f3682c78SCarl Heymann 	switch (be32_to_cpu(tl->type)) {
662e9364d30SCarl Heymann 	case NFP_DUMPSPEC_TYPE_FWNAME:
663e9364d30SCarl Heymann 		err = nfp_dump_fwname(pf, dump);
664e9364d30SCarl Heymann 		if (err)
665e9364d30SCarl Heymann 			return err;
666e9364d30SCarl Heymann 		break;
6670e6c4955SCarl Heymann 	case NFP_DUMPSPEC_TYPE_CPP_CSR:
6680e6c4955SCarl Heymann 	case NFP_DUMPSPEC_TYPE_XPB_CSR:
6690e6c4955SCarl Heymann 	case NFP_DUMPSPEC_TYPE_ME_CSR:
6700e6c4955SCarl Heymann 		spec_csr = (struct nfp_dumpspec_csr *)tl;
6710e6c4955SCarl Heymann 		err = nfp_dump_csr_range(pf, spec_csr, dump);
6720e6c4955SCarl Heymann 		if (err)
6730e6c4955SCarl Heymann 			return err;
6740e6c4955SCarl Heymann 		break;
67560b84a9bSCarl Heymann 	case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:
67660b84a9bSCarl Heymann 		spec_csr = (struct nfp_dumpspec_csr *)tl;
67760b84a9bSCarl Heymann 		err = nfp_dump_indirect_csr_range(pf, spec_csr, dump);
67860b84a9bSCarl Heymann 		if (err)
67960b84a9bSCarl Heymann 			return err;
68060b84a9bSCarl Heymann 		break;
681e1e798e3SCarl Heymann 	case NFP_DUMPSPEC_TYPE_RTSYM:
682e1e798e3SCarl Heymann 		spec_rtsym = (struct nfp_dumpspec_rtsym *)tl;
683e1e798e3SCarl Heymann 		err = nfp_dump_single_rtsym(pf, spec_rtsym, dump);
684e1e798e3SCarl Heymann 		if (err)
685e1e798e3SCarl Heymann 			return err;
686e1e798e3SCarl Heymann 		break;
68724ff8455SCarl Heymann 	case NFP_DUMPSPEC_TYPE_HWINFO:
68824ff8455SCarl Heymann 		err = nfp_dump_hwinfo(pf, tl, dump);
68924ff8455SCarl Heymann 		if (err)
69024ff8455SCarl Heymann 			return err;
69124ff8455SCarl Heymann 		break;
69210144de3SCarl Heymann 	case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
69310144de3SCarl Heymann 		err = nfp_dump_hwinfo_field(pf, tl, dump);
69410144de3SCarl Heymann 		if (err)
69510144de3SCarl Heymann 			return err;
69610144de3SCarl Heymann 		break;
697f3682c78SCarl Heymann 	default:
698f3682c78SCarl Heymann 		err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump);
699f3682c78SCarl Heymann 		if (err)
700f3682c78SCarl Heymann 			return err;
701f3682c78SCarl Heymann 	}
702f3682c78SCarl Heymann 
703f3682c78SCarl Heymann 	return 0;
704f3682c78SCarl Heymann }
705f3682c78SCarl Heymann 
706f3682c78SCarl Heymann static int
nfp_dump_specific_level(struct nfp_pf * pf,struct nfp_dump_tl * dump_level,void * param)707f3682c78SCarl Heymann nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
708f3682c78SCarl Heymann 			void *param)
709f3682c78SCarl Heymann {
710f3682c78SCarl Heymann 	struct nfp_dump_state *dump = param;
711f3682c78SCarl Heymann 
71292a54f4aSCarl Heymann 	if (dump_level->type != dump->requested_level)
713f3682c78SCarl Heymann 		return 0;
714f3682c78SCarl Heymann 
715f3682c78SCarl Heymann 	return nfp_traverse_tlvs(pf, dump_level->data,
716f3682c78SCarl Heymann 				 be32_to_cpu(dump_level->length), dump,
717f3682c78SCarl Heymann 				 nfp_dump_for_tlv);
718f3682c78SCarl Heymann }
719f3682c78SCarl Heymann 
nfp_dump_populate_prolog(struct nfp_dump_state * dump)720f7852b8eSCarl Heymann static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)
721f7852b8eSCarl Heymann {
722f7852b8eSCarl Heymann 	struct nfp_dump_prolog *prolog = dump->p;
723f7852b8eSCarl Heymann 	u32 total_size;
724f7852b8eSCarl Heymann 	int err;
725f7852b8eSCarl Heymann 
726f7852b8eSCarl Heymann 	total_size = ALIGN8(sizeof(*prolog));
727f7852b8eSCarl Heymann 
728f7852b8eSCarl Heymann 	err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);
729f7852b8eSCarl Heymann 	if (err)
730f7852b8eSCarl Heymann 		return err;
731f7852b8eSCarl Heymann 
73292a54f4aSCarl Heymann 	prolog->dump_level = dump->requested_level;
733f7852b8eSCarl Heymann 
734f7852b8eSCarl Heymann 	return 0;
735d79e19f5SCarl Heymann }
736d79e19f5SCarl Heymann 
nfp_net_dump_populate_buffer(struct nfp_pf * pf,struct nfp_dumpspec * spec,struct ethtool_dump * dump_param,void * dest)737d79e19f5SCarl Heymann int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
738d79e19f5SCarl Heymann 				 struct ethtool_dump *dump_param, void *dest)
739d79e19f5SCarl Heymann {
740f7852b8eSCarl Heymann 	struct nfp_dump_state dump;
741f7852b8eSCarl Heymann 	int err;
742f7852b8eSCarl Heymann 
74392a54f4aSCarl Heymann 	dump.requested_level = cpu_to_be32(dump_param->flag);
744f7852b8eSCarl Heymann 	dump.dumped_size = 0;
745f7852b8eSCarl Heymann 	dump.p = dest;
746f7852b8eSCarl Heymann 	dump.buf_size = dump_param->len;
747f7852b8eSCarl Heymann 
748f7852b8eSCarl Heymann 	err = nfp_dump_populate_prolog(&dump);
749f7852b8eSCarl Heymann 	if (err)
750f7852b8eSCarl Heymann 		return err;
751f7852b8eSCarl Heymann 
752f3682c78SCarl Heymann 	err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,
753f3682c78SCarl Heymann 				nfp_dump_specific_level);
754f3682c78SCarl Heymann 	if (err)
755f3682c78SCarl Heymann 		return err;
756f3682c78SCarl Heymann 
757f7852b8eSCarl Heymann 	/* Set size of actual dump, to trigger warning if different from
758f7852b8eSCarl Heymann 	 * calculated size.
759f7852b8eSCarl Heymann 	 */
760f7852b8eSCarl Heymann 	dump_param->len = dump.dumped_size;
761f7852b8eSCarl Heymann 
762f7852b8eSCarl Heymann 	return 0;
763d79e19f5SCarl Heymann }
764