1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/ethtool.h>
35#include <linux/vmalloc.h>
36
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"
42
43#define NFP_DUMP_SPEC_RTSYM "_abi_dump_spec"
44
45#define ALIGN8(x) ALIGN(x, 8)
46
47enum 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,
58};
59
60
61
62
63
64
65
66struct nfp_dump_tl {
67 __be32 type;
68 __be32 length;
69 char data[0];
70};
71
72
73struct nfp_dumpspec_cpp_isl_id {
74 u8 target;
75 u8 action;
76 u8 token;
77 u8 island;
78};
79
80struct nfp_dump_common_cpp {
81 struct nfp_dumpspec_cpp_isl_id cpp_id;
82 __be32 offset;
83 __be32 dump_length;
84};
85
86
87struct nfp_dumpspec_csr {
88 struct nfp_dump_tl tl;
89 struct nfp_dump_common_cpp cpp;
90 __be32 register_width;
91};
92
93struct nfp_dumpspec_rtsym {
94 struct nfp_dump_tl tl;
95 char rtsym[0];
96};
97
98
99struct nfp_dump_csr {
100 struct nfp_dump_tl tl;
101 struct nfp_dump_common_cpp cpp;
102 __be32 register_width;
103 __be32 error;
104 __be32 error_offset;
105};
106
107struct nfp_dump_rtsym {
108 struct nfp_dump_tl tl;
109 struct nfp_dump_common_cpp cpp;
110 __be32 error;
111 u8 padded_name_length;
112 char rtsym[0];
113
114};
115
116struct nfp_dump_prolog {
117 struct nfp_dump_tl tl;
118 __be32 dump_level;
119};
120
121struct nfp_dump_error {
122 struct nfp_dump_tl tl;
123 __be32 error;
124 char padding[4];
125 char spec[0];
126};
127
128
129struct nfp_level_size {
130 __be32 requested_level;
131 u32 total_size;
132};
133
134
135struct nfp_dump_state {
136 __be32 requested_level;
137 u32 dumped_size;
138 u32 buf_size;
139 void *p;
140};
141
142typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl,
143 void *param);
144
145static int
146nfp_traverse_tlvs(struct nfp_pf *pf, void *data, u32 data_length, void *param,
147 nfp_tlv_visit tlv_visit)
148{
149 long long remaining = data_length;
150 struct nfp_dump_tl *tl;
151 u32 total_tlv_size;
152 void *p = data;
153 int err;
154
155 while (remaining >= sizeof(*tl)) {
156 tl = p;
157 if (!tl->type && !tl->length)
158 break;
159
160 if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))
161 return -EINVAL;
162
163 total_tlv_size = sizeof(*tl) + be32_to_cpu(tl->length);
164
165
166 if (total_tlv_size % 4 != 0)
167 return -EINVAL;
168
169 p += total_tlv_size;
170 remaining -= total_tlv_size;
171 err = tlv_visit(pf, tl, param);
172 if (err)
173 return err;
174 }
175
176 return 0;
177}
178
179static u32 nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id *cpp_id)
180{
181 return NFP_CPP_ISLAND_ID(cpp_id->target, cpp_id->action, cpp_id->token,
182 cpp_id->island);
183}
184
185struct nfp_dumpspec *
186nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
187{
188 const struct nfp_rtsym *specsym;
189 struct nfp_dumpspec *dumpspec;
190 int bytes_read;
191 u32 cpp_id;
192
193 specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
194 if (!specsym)
195 return NULL;
196
197
198 dumpspec = vmalloc(sizeof(*dumpspec) + specsym->size);
199 if (!dumpspec)
200 return NULL;
201
202 dumpspec->size = specsym->size;
203
204 cpp_id = NFP_CPP_ISLAND_ID(specsym->target, NFP_CPP_ACTION_RW, 0,
205 specsym->domain);
206
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;
213 }
214
215 return dumpspec;
216}
217
218static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec)
219{
220 return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) +
221 be32_to_cpu(spec->length));
222}
223
224static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf)
225{
226 u32 fwname_len = strlen(nfp_mip_name(pf->mip));
227
228 return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1);
229}
230
231static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
232{
233 u32 tl_len, key_len;
234 const char *value;
235
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);
240
241 value = nfp_hwinfo_lookup(pf->hwinfo, spec->data);
242 if (!value)
243 return nfp_dump_error_tlv_size(spec);
244
245 return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2);
246}
247
248static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr)
249{
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;
253
254 if (available_sz < required_read_sz)
255 return false;
256
257 reg_width = be32_to_cpu(spec_csr->register_width);
258
259 return reg_width == 32 || reg_width == 64;
260}
261
262static int
263nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
264{
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;
270
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);
276
277 sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym);
278 if (!sym)
279 return nfp_dump_error_tlv_size(spec);
280
281 if (sym->type == NFP_RTSYM_TYPE_ABS)
282 size = sizeof(sym->addr);
283 else
284 size = sym->size;
285
286 return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
287 ALIGN8(size);
288}
289
290static int
291nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
292{
293 struct nfp_dumpspec_csr *spec_csr;
294 u32 *size = param;
295 u32 hwinfo_size;
296
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;
333 }
334
335 return 0;
336}
337
338static int
339nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
340 void *param)
341{
342 struct nfp_level_size *lev_sz = param;
343
344 if (dump_level->type != lev_sz->requested_level)
345 return 0;
346
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);
350}
351
352s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
353 u32 flag)
354{
355 struct nfp_level_size lev_sz;
356 int err;
357
358 lev_sz.requested_level = cpu_to_be32(flag);
359 lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog));
360
361 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz,
362 nfp_calc_specific_level_size);
363 if (err)
364 return err;
365
366 return lev_sz.total_size;
367}
368
369static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump)
370{
371 struct nfp_dump_tl *tl = dump->p;
372
373 if (total_tlv_sz > dump->buf_size)
374 return -ENOSPC;
375
376 if (dump->buf_size - total_tlv_sz < dump->dumped_size)
377 return -ENOSPC;
378
379 tl->type = cpu_to_be32(type);
380 tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl));
381
382 dump->dumped_size += total_tlv_sz;
383 dump->p += total_tlv_sz;
384
385 return 0;
386}
387
388static int
389nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error,
390 struct nfp_dump_state *dump)
391{
392 struct nfp_dump_error *dump_header = dump->p;
393 u32 total_spec_size, total_size;
394 int err;
395
396 total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length);
397 total_size = ALIGN8(sizeof(*dump_header) + total_spec_size);
398
399 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump);
400 if (err)
401 return err;
402
403 dump_header->error = cpu_to_be32(error);
404 memcpy(dump_header->spec, spec, total_spec_size);
405
406 return 0;
407}
408
409static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump)
410{
411 struct nfp_dump_tl *dump_header = dump->p;
412 u32 fwname_len, total_size;
413 const char *fwname;
414 int err;
415
416 fwname = nfp_mip_name(pf->mip);
417 fwname_len = strlen(fwname);
418 total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1);
419
420 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump);
421 if (err)
422 return err;
423
424 memcpy(dump_header->data, fwname, fwname_len);
425
426 return 0;
427}
428
429static int
430nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec,
431 struct nfp_dump_state *dump)
432{
433 struct nfp_dump_tl *dump_header = dump->p;
434 u32 hwinfo_size, total_size;
435 char *hwinfo;
436 int err;
437
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);
441
442 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump);
443 if (err)
444 return err;
445
446 memcpy(dump_header->data, hwinfo, hwinfo_size);
447
448 return 0;
449}
450
451static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec,
452 struct nfp_dump_state *dump)
453{
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;
459
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);
464
465 key = spec->data;
466 value = nfp_hwinfo_lookup(pf->hwinfo, key);
467 if (!value)
468 return nfp_dump_error_tlv(spec, -ENOENT, dump);
469
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;
475
476 memcpy(dump_header->data, key, key_len + 1);
477 memcpy(dump_header->data + key_len + 1, value, val_len + 1);
478
479 return 0;
480}
481
482static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id)
483{
484 return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB &&
485 cpp_id->action == 0 && cpp_id->token == 0;
486}
487
488static int
489nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,
490 struct nfp_dump_state *dump)
491{
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;
499
500 if (!nfp_csr_spec_valid(spec_csr))
501 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
502
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;
508
509 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
510 if (err)
511 return err;
512
513 dump_header->cpp = spec_csr->cpp;
514 dump_header->register_width = spec_csr->register_width;
515
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);
519
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;
527 }
528 if (err) {
529 dump_header->error = cpu_to_be32(err);
530 dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
531 break;
532 }
533 cpp_rd_addr += reg_sz;
534 dest += reg_sz;
535 }
536
537 return 0;
538}
539
540
541
542
543static int
544nfp_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)
547{
548 u32 csr_ctx_ptr_offs;
549 u32 cpp_id;
550 int result;
551
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;
559
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;
564
565 result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz);
566 if (result != reg_sz)
567 return result < 0 ? result : -EIO;
568
569 return 0;
570}
571
572static int
573nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp,
574 struct nfp_dumpspec_csr *spec_csr, u32 address,
575 u32 reg_sz, void *dest)
576{
577 u32 ctx;
578 int err;
579
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;
585 }
586
587 return 0;
588}
589
590static int
591nfp_dump_indirect_csr_range(struct nfp_pf *pf,
592 struct nfp_dumpspec_csr *spec_csr,
593 struct nfp_dump_state *dump)
594{
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;
601
602 if (!nfp_csr_spec_valid(spec_csr))
603 return nfp_dump_error_tlv(&spec_csr->tl, -EINVAL, dump);
604
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;
611
612 err = nfp_add_tlv(be32_to_cpu(spec_csr->tl.type), total_size, dump);
613 if (err)
614 return err;
615
616 dump_header->cpp = spec_csr->cpp;
617 dump_header->register_width = spec_csr->register_width;
618
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;
628 }
629 cpp_rd_addr += reg_sz;
630 dest += reg_sz * NFP_IND_NUM_CONTEXTS;
631 }
632
633 return 0;
634}
635
636static int
637nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
638 struct nfp_dump_state *dump)
639{
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;
650
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);
655
656 sym = nfp_rtsym_lookup(rtbl, spec->rtsym);
657 if (!sym)
658 return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
659
660 if (sym->type == NFP_RTSYM_TYPE_ABS)
661 sym_size = sizeof(sym->addr);
662 else
663 sym_size = sym->size;
664
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;
669
670 err = nfp_add_tlv(be32_to_cpu(spec->tl.type), total_size, dump);
671 if (err)
672 return err;
673
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);
678
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);
695 }
696 }
697
698 return 0;
699}
700
701static int
702nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
703{
704 struct nfp_dumpspec_rtsym *spec_rtsym;
705 struct nfp_dump_state *dump = param;
706 struct nfp_dumpspec_csr *spec_csr;
707 int err;
708
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;
749 }
750
751 return 0;
752}
753
754static int
755nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
756 void *param)
757{
758 struct nfp_dump_state *dump = param;
759
760 if (dump_level->type != dump->requested_level)
761 return 0;
762
763 return nfp_traverse_tlvs(pf, dump_level->data,
764 be32_to_cpu(dump_level->length), dump,
765 nfp_dump_for_tlv);
766}
767
768static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)
769{
770 struct nfp_dump_prolog *prolog = dump->p;
771 u32 total_size;
772 int err;
773
774 total_size = ALIGN8(sizeof(*prolog));
775
776 err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);
777 if (err)
778 return err;
779
780 prolog->dump_level = dump->requested_level;
781
782 return 0;
783}
784
785int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
786 struct ethtool_dump *dump_param, void *dest)
787{
788 struct nfp_dump_state dump;
789 int err;
790
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;
795
796 err = nfp_dump_populate_prolog(&dump);
797 if (err)
798 return err;
799
800 err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,
801 nfp_dump_specific_level);
802 if (err)
803 return err;
804
805
806
807
808 dump_param->len = dump.dumped_size;
809
810 return 0;
811}
812