Linux 4.16.11
[linux/fpc-iii.git] / drivers / net / ethernet / netronome / nfp / nfp_net_debugdump.c
blobbb8ed460086e6c6e9b5129785d4d119eb547b858
1 /*
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
13 * conditions are met:
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
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
31 * SOFTWARE.
34 #include <linux/ethtool.h>
35 #include <linux/vmalloc.h>
37 #include "nfp_asm.h"
38 #include "nfp_main.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
62 * way.
65 /* generic type plus length */
66 struct nfp_dump_tl {
67 __be32 type;
68 __be32 length; /* chunk length to follow, aligned to 8 bytes */
69 char data[0];
72 /* NFP CPP parameters */
73 struct nfp_dumpspec_cpp_isl_id {
74 u8 target;
75 u8 action;
76 u8 token;
77 u8 island;
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 */
86 /* CSR dumpables */
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;
95 char rtsym[0];
98 /* header for register dumpable */
99 struct nfp_dump_csr {
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 */
112 char rtsym[0];
113 /* after padded_name_length, there is dump_length data */
116 struct nfp_dump_prolog {
117 struct nfp_dump_tl tl;
118 __be32 dump_level;
121 struct nfp_dump_error {
122 struct nfp_dump_tl tl;
123 __be32 error;
124 char padding[4];
125 char spec[0];
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,
143 void *param);
145 static int
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;
151 u32 total_tlv_size;
152 void *p = data;
153 int err;
155 while (remaining >= sizeof(*tl)) {
156 tl = p;
157 if (!tl->type && !tl->length)
158 break;
160 if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))
161 return -EINVAL;
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)
167 return -EINVAL;
169 p += total_tlv_size;
170 remaining -= total_tlv_size;
171 err = tlv_visit(pf, tl, param);
172 if (err)
173 return err;
176 return 0;
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,
182 cpp_id->island);
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;
190 int bytes_read;
191 u32 cpp_id;
193 specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
194 if (!specsym)
195 return NULL;
197 /* expected size of this buffer is in the order of tens of kilobytes */
198 dumpspec = vmalloc(sizeof(*dumpspec) + specsym->size);
199 if (!dumpspec)
200 return NULL;
202 dumpspec->size = specsym->size;
204 cpp_id = NFP_CPP_ISLAND_ID(specsym->target, NFP_CPP_ACTION_RW, 0,
205 specsym->domain);
207 bytes_read = nfp_cpp_read(cpp, cpp_id, specsym->addr, dumpspec->data,
208 specsym->size);
209 if (bytes_read != specsym->size) {
210 vfree(dumpspec);
211 nfp_warn(cpp, "Debug dump specification read failed.\n");
212 return NULL;
215 return dumpspec;
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)
233 u32 tl_len, key_len;
234 const char *value;
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);
242 if (!value)
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);
252 u32 reg_width;
254 if (available_sz < required_read_sz)
255 return false;
257 reg_width = be32_to_cpu(spec_csr->register_width);
259 return reg_width == 32 || reg_width == 64;
262 static int
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;
268 u32 tl_len, key_len;
269 u32 size;
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);
278 if (!sym)
279 return nfp_dump_error_tlv_size(spec);
281 if (sym->type == NFP_RTSYM_TYPE_ABS)
282 size = sizeof(sym->addr);
283 else
284 size = sym->size;
286 return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
287 ALIGN8(size);
290 static int
291 nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
293 struct nfp_dumpspec_csr *spec_csr;
294 u32 *size = param;
295 u32 hwinfo_size;
297 switch (be32_to_cpu(tl->type)) {
298 case NFP_DUMPSPEC_TYPE_FWNAME:
299 *size += nfp_calc_fwname_tlv_size(pf);
300 break;
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);
307 else
308 *size += ALIGN8(sizeof(struct nfp_dump_csr)) +
309 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
310 break;
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);
315 else
316 *size += ALIGN8(sizeof(struct nfp_dump_csr)) +
317 ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length) *
318 NFP_IND_NUM_CONTEXTS);
319 break;
320 case NFP_DUMPSPEC_TYPE_RTSYM:
321 *size += nfp_calc_rtsym_dump_sz(pf, tl);
322 break;
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);
326 break;
327 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
328 *size += nfp_calc_hwinfo_field_sz(pf, tl);
329 break;
330 default:
331 *size += nfp_dump_error_tlv_size(tl);
332 break;
335 return 0;
338 static int
339 nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
340 void *param)
342 struct nfp_level_size *lev_sz = param;
344 if (dump_level->type != lev_sz->requested_level)
345 return 0;
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,
353 u32 flag)
355 struct nfp_level_size lev_sz;
356 int err;
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);
363 if (err)
364 return err;
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)
374 return -ENOSPC;
376 if (dump->buf_size - total_tlv_sz < dump->dumped_size)
377 return -ENOSPC;
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;
385 return 0;
388 static int
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;
394 int err;
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);
400 if (err)
401 return err;
403 dump_header->error = cpu_to_be32(error);
404 memcpy(dump_header->spec, spec, total_spec_size);
406 return 0;
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;
413 const char *fwname;
414 int err;
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);
421 if (err)
422 return err;
424 memcpy(dump_header->data, fwname, fwname_len);
426 return 0;
429 static int
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;
435 char *hwinfo;
436 int err;
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);
443 if (err)
444 return err;
446 memcpy(dump_header->data, hwinfo, hwinfo_size);
448 return 0;
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;
457 u32 total_size;
458 int err;
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);
465 key = spec->data;
466 value = nfp_hwinfo_lookup(pf->hwinfo, key);
467 if (!value)
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);
473 if (err)
474 return err;
476 memcpy(dump_header->data, key, key_len + 1);
477 memcpy(dump_header->data + key_len + 1, value, val_len + 1);
479 return 0;
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;
488 static int
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;
495 int bytes_read;
496 void *dest;
497 u32 cpp_id;
498 int err;
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);
510 if (err)
511 return err;
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);
523 } else {
524 bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr,
525 dest, reg_sz);
526 err = bytes_read == reg_sz ? 0 : -EIO;
528 if (err) {
529 dump_header->error = cpu_to_be32(err);
530 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
531 break;
533 cpp_rd_addr += reg_sz;
534 dest += reg_sz;
537 return 0;
540 /* Write context to CSRCtxPtr, then read from it. Then the value can be read
541 * from IndCtxStatus.
543 static int
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;
549 u32 cpp_id;
550 int result;
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);
557 if (result)
558 return result;
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;
569 return 0;
572 static int
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)
577 u32 ctx;
578 int err;
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);
583 if (err)
584 return err;
587 return 0;
590 static int
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;
598 u32 reg_data_length;
599 void *dest;
600 int err;
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);
613 if (err)
614 return err;
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);
624 if (err) {
625 dump_header->error = cpu_to_be32(err);
626 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
627 break;
629 cpp_rd_addr += reg_sz;
630 dest += reg_sz * NFP_IND_NUM_CONTEXTS;
633 return 0;
636 static int
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;
645 u32 tl_len, key_len;
646 int bytes_read;
647 u32 cpp_id;
648 void *dest;
649 int err;
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);
657 if (!sym)
658 return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
660 if (sym->type == NFP_RTSYM_TYPE_ABS)
661 sym_size = sizeof(sym->addr);
662 else
663 sym_size = sym->size;
665 header_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);
671 if (err)
672 return err;
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;
681 } else {
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,
690 sym_size);
691 if (bytes_read != sym_size) {
692 if (bytes_read >= 0)
693 bytes_read = -EIO;
694 dump_header->error = cpu_to_be32(bytes_read);
698 return 0;
701 static int
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;
707 int err;
709 switch (be32_to_cpu(tl->type)) {
710 case NFP_DUMPSPEC_TYPE_FWNAME:
711 err = nfp_dump_fwname(pf, dump);
712 if (err)
713 return err;
714 break;
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);
720 if (err)
721 return err;
722 break;
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);
726 if (err)
727 return err;
728 break;
729 case NFP_DUMPSPEC_TYPE_RTSYM:
730 spec_rtsym = (struct nfp_dumpspec_rtsym *)tl;
731 err = nfp_dump_single_rtsym(pf, spec_rtsym, dump);
732 if (err)
733 return err;
734 break;
735 case NFP_DUMPSPEC_TYPE_HWINFO:
736 err = nfp_dump_hwinfo(pf, tl, dump);
737 if (err)
738 return err;
739 break;
740 case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
741 err = nfp_dump_hwinfo_field(pf, tl, dump);
742 if (err)
743 return err;
744 break;
745 default:
746 err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump);
747 if (err)
748 return err;
751 return 0;
754 static int
755 nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
756 void *param)
758 struct nfp_dump_state *dump = param;
760 if (dump_level->type != dump->requested_level)
761 return 0;
763 return nfp_traverse_tlvs(pf, dump_level->data,
764 be32_to_cpu(dump_level->length), dump,
765 nfp_dump_for_tlv);
768 static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)
770 struct nfp_dump_prolog *prolog = dump->p;
771 u32 total_size;
772 int err;
774 total_size = ALIGN8(sizeof(*prolog));
776 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);
777 if (err)
778 return err;
780 prolog->dump_level = dump->requested_level;
782 return 0;
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;
789 int err;
791 dump.requested_level = cpu_to_be32(dump_param->flag);
792 dump.dumped_size = 0;
793 dump.p = dest;
794 dump.buf_size = dump_param->len;
796 err = nfp_dump_populate_prolog(&dump);
797 if (err)
798 return err;
800 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,
801 nfp_dump_specific_level);
802 if (err)
803 return err;
805 /* Set size of actual dump, to trigger warning if different from
806 * calculated size.
808 dump_param->len = dump.dumped_size;
810 return 0;