nfp_net_debugdump.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
  3. #include <linux/ethtool.h>
  4. #include <linux/vmalloc.h>
  5. #include "nfp_asm.h"
  6. #include "nfp_main.h"
  7. #include "nfpcore/nfp.h"
  8. #include "nfpcore/nfp_nffw.h"
  9. #include "nfpcore/nfp6000/nfp6000.h"
  10. #define NFP_DUMP_SPEC_RTSYM "_abi_dump_spec"
  11. #define ALIGN8(x) ALIGN(x, 8)
  12. enum nfp_dumpspec_type {
  13. NFP_DUMPSPEC_TYPE_CPP_CSR = 0,
  14. NFP_DUMPSPEC_TYPE_XPB_CSR = 1,
  15. NFP_DUMPSPEC_TYPE_ME_CSR = 2,
  16. NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR = 3,
  17. NFP_DUMPSPEC_TYPE_RTSYM = 4,
  18. NFP_DUMPSPEC_TYPE_HWINFO = 5,
  19. NFP_DUMPSPEC_TYPE_FWNAME = 6,
  20. NFP_DUMPSPEC_TYPE_HWINFO_FIELD = 7,
  21. NFP_DUMPSPEC_TYPE_PROLOG = 10000,
  22. NFP_DUMPSPEC_TYPE_ERROR = 10001,
  23. };
  24. /* The following structs must be carefully aligned so that they can be used to
  25. * interpret the binary dumpspec and populate the dump data in a deterministic
  26. * way.
  27. */
  28. /* generic type plus length */
  29. struct nfp_dump_tl {
  30. /* New members must be added within the struct_group() macro below. */
  31. struct_group_tagged(nfp_dump_tl_hdr, hdr,
  32. __be32 type;
  33. __be32 length; /* chunk length to follow, aligned to 8 bytes */
  34. );
  35. char data[];
  36. };
  37. static_assert(offsetof(struct nfp_dump_tl, data) == sizeof(struct nfp_dump_tl_hdr),
  38. "struct member likely outside of struct_group_tagged()");
  39. /* NFP CPP parameters */
  40. struct nfp_dumpspec_cpp_isl_id {
  41. u8 target;
  42. u8 action;
  43. u8 token;
  44. u8 island;
  45. };
  46. struct nfp_dump_common_cpp {
  47. struct nfp_dumpspec_cpp_isl_id cpp_id;
  48. __be32 offset; /* address to start dump */
  49. __be32 dump_length; /* total bytes to dump, aligned to reg size */
  50. };
  51. /* CSR dumpables */
  52. struct nfp_dumpspec_csr {
  53. struct nfp_dump_tl_hdr tl;
  54. struct nfp_dump_common_cpp cpp;
  55. __be32 register_width; /* in bits */
  56. };
  57. struct nfp_dumpspec_rtsym {
  58. struct nfp_dump_tl_hdr tl;
  59. char rtsym[];
  60. };
  61. /* header for register dumpable */
  62. struct nfp_dump_csr {
  63. struct nfp_dump_tl_hdr tl;
  64. struct nfp_dump_common_cpp cpp;
  65. __be32 register_width; /* in bits */
  66. __be32 error; /* error code encountered while reading */
  67. __be32 error_offset; /* offset being read when error occurred */
  68. };
  69. struct nfp_dump_rtsym {
  70. struct nfp_dump_tl_hdr tl;
  71. struct nfp_dump_common_cpp cpp;
  72. __be32 error; /* error code encountered while reading */
  73. u8 padded_name_length; /* pad so data starts at 8 byte boundary */
  74. char rtsym[];
  75. /* after padded_name_length, there is dump_length data */
  76. };
  77. struct nfp_dump_prolog {
  78. struct nfp_dump_tl_hdr tl;
  79. __be32 dump_level;
  80. };
  81. struct nfp_dump_error {
  82. struct nfp_dump_tl_hdr tl;
  83. __be32 error;
  84. char padding[4];
  85. char spec[];
  86. };
  87. /* to track state through debug size calculation TLV traversal */
  88. struct nfp_level_size {
  89. __be32 requested_level; /* input */
  90. u32 total_size; /* output */
  91. };
  92. /* to track state during debug dump creation TLV traversal */
  93. struct nfp_dump_state {
  94. __be32 requested_level; /* input param */
  95. u32 dumped_size; /* adds up to size of dumped data */
  96. u32 buf_size; /* size of buffer pointer to by p */
  97. void *p; /* current point in dump buffer */
  98. };
  99. typedef int (*nfp_tlv_visit)(struct nfp_pf *pf, struct nfp_dump_tl *tl,
  100. void *param);
  101. static int
  102. nfp_traverse_tlvs(struct nfp_pf *pf, void *data, u32 data_length, void *param,
  103. nfp_tlv_visit tlv_visit)
  104. {
  105. long long remaining = data_length;
  106. struct nfp_dump_tl *tl;
  107. u32 total_tlv_size;
  108. void *p = data;
  109. int err;
  110. while (remaining >= sizeof(*tl)) {
  111. tl = p;
  112. if (!tl->type && !tl->length)
  113. break;
  114. if (be32_to_cpu(tl->length) > remaining - sizeof(*tl))
  115. return -EINVAL;
  116. total_tlv_size = sizeof(*tl) + be32_to_cpu(tl->length);
  117. /* Spec TLVs should be aligned to 4 bytes. */
  118. if (total_tlv_size % 4 != 0)
  119. return -EINVAL;
  120. p += total_tlv_size;
  121. remaining -= total_tlv_size;
  122. err = tlv_visit(pf, tl, param);
  123. if (err)
  124. return err;
  125. }
  126. return 0;
  127. }
  128. static u32 nfp_get_numeric_cpp_id(struct nfp_dumpspec_cpp_isl_id *cpp_id)
  129. {
  130. return NFP_CPP_ISLAND_ID(cpp_id->target, cpp_id->action, cpp_id->token,
  131. cpp_id->island);
  132. }
  133. struct nfp_dumpspec *
  134. nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
  135. {
  136. const struct nfp_rtsym *specsym;
  137. struct nfp_dumpspec *dumpspec;
  138. int bytes_read;
  139. u64 sym_size;
  140. specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
  141. if (!specsym)
  142. return NULL;
  143. sym_size = nfp_rtsym_size(specsym);
  144. /* expected size of this buffer is in the order of tens of kilobytes */
  145. dumpspec = vmalloc(sizeof(*dumpspec) + sym_size);
  146. if (!dumpspec)
  147. return NULL;
  148. dumpspec->size = sym_size;
  149. bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size);
  150. if (bytes_read != sym_size) {
  151. vfree(dumpspec);
  152. nfp_warn(cpp, "Debug dump specification read failed.\n");
  153. return NULL;
  154. }
  155. return dumpspec;
  156. }
  157. static int nfp_dump_error_tlv_size(struct nfp_dump_tl *spec)
  158. {
  159. return ALIGN8(sizeof(struct nfp_dump_error) + sizeof(*spec) +
  160. be32_to_cpu(spec->length));
  161. }
  162. static int nfp_calc_fwname_tlv_size(struct nfp_pf *pf)
  163. {
  164. u32 fwname_len = strlen(nfp_mip_name(pf->mip));
  165. return sizeof(struct nfp_dump_tl) + ALIGN8(fwname_len + 1);
  166. }
  167. static int nfp_calc_hwinfo_field_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
  168. {
  169. u32 tl_len, key_len;
  170. const char *value;
  171. tl_len = be32_to_cpu(spec->length);
  172. key_len = strnlen(spec->data, tl_len);
  173. if (key_len == tl_len)
  174. return nfp_dump_error_tlv_size(spec);
  175. value = nfp_hwinfo_lookup(pf->hwinfo, spec->data);
  176. if (!value)
  177. return nfp_dump_error_tlv_size(spec);
  178. return sizeof(struct nfp_dump_tl) + ALIGN8(key_len + strlen(value) + 2);
  179. }
  180. static bool nfp_csr_spec_valid(struct nfp_dumpspec_csr *spec_csr)
  181. {
  182. u32 required_read_sz = sizeof(*spec_csr) - sizeof(spec_csr->tl);
  183. u32 available_sz = be32_to_cpu(spec_csr->tl.length);
  184. u32 reg_width;
  185. if (available_sz < required_read_sz)
  186. return false;
  187. reg_width = be32_to_cpu(spec_csr->register_width);
  188. return reg_width == 32 || reg_width == 64;
  189. }
  190. static int
  191. nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
  192. {
  193. struct nfp_rtsym_table *rtbl = pf->rtbl;
  194. struct nfp_dumpspec_rtsym *spec_rtsym;
  195. const struct nfp_rtsym *sym;
  196. u32 tl_len, key_len;
  197. spec_rtsym = (struct nfp_dumpspec_rtsym *)spec;
  198. tl_len = be32_to_cpu(spec->length);
  199. key_len = strnlen(spec_rtsym->rtsym, tl_len);
  200. if (key_len == tl_len)
  201. return nfp_dump_error_tlv_size(spec);
  202. sym = nfp_rtsym_lookup(rtbl, spec_rtsym->rtsym);
  203. if (!sym)
  204. return nfp_dump_error_tlv_size(spec);
  205. return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
  206. ALIGN8(nfp_rtsym_size(sym));
  207. }
  208. static int
  209. nfp_add_tlv_size(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
  210. {
  211. struct nfp_dumpspec_csr *spec_csr;
  212. u32 *size = param;
  213. u32 hwinfo_size;
  214. switch (be32_to_cpu(tl->type)) {
  215. case NFP_DUMPSPEC_TYPE_FWNAME:
  216. *size += nfp_calc_fwname_tlv_size(pf);
  217. break;
  218. case NFP_DUMPSPEC_TYPE_CPP_CSR:
  219. case NFP_DUMPSPEC_TYPE_XPB_CSR:
  220. case NFP_DUMPSPEC_TYPE_ME_CSR:
  221. spec_csr = (struct nfp_dumpspec_csr *)tl;
  222. if (!nfp_csr_spec_valid(spec_csr))
  223. *size += nfp_dump_error_tlv_size(tl);
  224. else
  225. *size += ALIGN8(sizeof(struct nfp_dump_csr)) +
  226. ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
  227. break;
  228. case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:
  229. spec_csr = (struct nfp_dumpspec_csr *)tl;
  230. if (!nfp_csr_spec_valid(spec_csr))
  231. *size += nfp_dump_error_tlv_size(tl);
  232. else
  233. *size += ALIGN8(sizeof(struct nfp_dump_csr)) +
  234. ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length) *
  235. NFP_IND_NUM_CONTEXTS);
  236. break;
  237. case NFP_DUMPSPEC_TYPE_RTSYM:
  238. *size += nfp_calc_rtsym_dump_sz(pf, tl);
  239. break;
  240. case NFP_DUMPSPEC_TYPE_HWINFO:
  241. hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);
  242. *size += sizeof(struct nfp_dump_tl) + ALIGN8(hwinfo_size);
  243. break;
  244. case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
  245. *size += nfp_calc_hwinfo_field_sz(pf, tl);
  246. break;
  247. default:
  248. *size += nfp_dump_error_tlv_size(tl);
  249. break;
  250. }
  251. return 0;
  252. }
  253. static int
  254. nfp_calc_specific_level_size(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
  255. void *param)
  256. {
  257. struct nfp_level_size *lev_sz = param;
  258. if (dump_level->type != lev_sz->requested_level)
  259. return 0;
  260. return nfp_traverse_tlvs(pf, dump_level->data,
  261. be32_to_cpu(dump_level->length),
  262. &lev_sz->total_size, nfp_add_tlv_size);
  263. }
  264. s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
  265. u32 flag)
  266. {
  267. struct nfp_level_size lev_sz;
  268. int err;
  269. lev_sz.requested_level = cpu_to_be32(flag);
  270. lev_sz.total_size = ALIGN8(sizeof(struct nfp_dump_prolog));
  271. err = nfp_traverse_tlvs(pf, spec->data, spec->size, &lev_sz,
  272. nfp_calc_specific_level_size);
  273. if (err)
  274. return err;
  275. return lev_sz.total_size;
  276. }
  277. static int nfp_add_tlv(u32 type, u32 total_tlv_sz, struct nfp_dump_state *dump)
  278. {
  279. struct nfp_dump_tl *tl = dump->p;
  280. if (total_tlv_sz > dump->buf_size)
  281. return -ENOSPC;
  282. if (dump->buf_size - total_tlv_sz < dump->dumped_size)
  283. return -ENOSPC;
  284. tl->type = cpu_to_be32(type);
  285. tl->length = cpu_to_be32(total_tlv_sz - sizeof(*tl));
  286. dump->dumped_size += total_tlv_sz;
  287. dump->p += total_tlv_sz;
  288. return 0;
  289. }
  290. static int
  291. nfp_dump_error_tlv(struct nfp_dump_tl *spec, int error,
  292. struct nfp_dump_state *dump)
  293. {
  294. struct nfp_dump_error *dump_header = dump->p;
  295. u32 total_spec_size, total_size;
  296. int err;
  297. total_spec_size = sizeof(*spec) + be32_to_cpu(spec->length);
  298. total_size = ALIGN8(sizeof(*dump_header) + total_spec_size);
  299. err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_ERROR, total_size, dump);
  300. if (err)
  301. return err;
  302. dump_header->error = cpu_to_be32(error);
  303. memcpy(dump_header->spec, spec, total_spec_size);
  304. return 0;
  305. }
  306. static int nfp_dump_fwname(struct nfp_pf *pf, struct nfp_dump_state *dump)
  307. {
  308. struct nfp_dump_tl *dump_header = dump->p;
  309. u32 fwname_len, total_size;
  310. const char *fwname;
  311. int err;
  312. fwname = nfp_mip_name(pf->mip);
  313. fwname_len = strlen(fwname);
  314. total_size = sizeof(*dump_header) + ALIGN8(fwname_len + 1);
  315. err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_FWNAME, total_size, dump);
  316. if (err)
  317. return err;
  318. memcpy(dump_header->data, fwname, fwname_len);
  319. return 0;
  320. }
  321. static int
  322. nfp_dump_hwinfo(struct nfp_pf *pf, struct nfp_dump_tl *spec,
  323. struct nfp_dump_state *dump)
  324. {
  325. struct nfp_dump_tl *dump_header = dump->p;
  326. u32 hwinfo_size, total_size;
  327. char *hwinfo;
  328. int err;
  329. hwinfo = nfp_hwinfo_get_packed_strings(pf->hwinfo);
  330. hwinfo_size = nfp_hwinfo_get_packed_str_size(pf->hwinfo);
  331. total_size = sizeof(*dump_header) + ALIGN8(hwinfo_size);
  332. err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO, total_size, dump);
  333. if (err)
  334. return err;
  335. memcpy(dump_header->data, hwinfo, hwinfo_size);
  336. return 0;
  337. }
  338. static int nfp_dump_hwinfo_field(struct nfp_pf *pf, struct nfp_dump_tl *spec,
  339. struct nfp_dump_state *dump)
  340. {
  341. struct nfp_dump_tl *dump_header = dump->p;
  342. u32 tl_len, key_len, val_len;
  343. const char *key, *value;
  344. u32 total_size;
  345. int err;
  346. tl_len = be32_to_cpu(spec->length);
  347. key_len = strnlen(spec->data, tl_len);
  348. if (key_len == tl_len)
  349. return nfp_dump_error_tlv(spec, -EINVAL, dump);
  350. key = spec->data;
  351. value = nfp_hwinfo_lookup(pf->hwinfo, key);
  352. if (!value)
  353. return nfp_dump_error_tlv(spec, -ENOENT, dump);
  354. val_len = strlen(value);
  355. total_size = sizeof(*dump_header) + ALIGN8(key_len + val_len + 2);
  356. err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_HWINFO_FIELD, total_size, dump);
  357. if (err)
  358. return err;
  359. memcpy(dump_header->data, key, key_len + 1);
  360. memcpy(dump_header->data + key_len + 1, value, val_len + 1);
  361. return 0;
  362. }
  363. static bool is_xpb_read(struct nfp_dumpspec_cpp_isl_id *cpp_id)
  364. {
  365. return cpp_id->target == NFP_CPP_TARGET_ISLAND_XPB &&
  366. cpp_id->action == 0 && cpp_id->token == 0;
  367. }
  368. static int
  369. nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,
  370. struct nfp_dump_state *dump)
  371. {
  372. struct nfp_dump_tl *spec_csr_tl =
  373. container_of(&spec_csr->tl, struct nfp_dump_tl, hdr);
  374. struct nfp_dump_csr *dump_header = dump->p;
  375. u32 reg_sz, header_size, total_size;
  376. u32 cpp_rd_addr, max_rd_addr;
  377. int bytes_read;
  378. void *dest;
  379. u32 cpp_id;
  380. int err;
  381. if (!nfp_csr_spec_valid(spec_csr))
  382. return nfp_dump_error_tlv(spec_csr_tl, -EINVAL, dump);
  383. reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;
  384. header_size = ALIGN8(sizeof(*dump_header));
  385. total_size = header_size +
  386. ALIGN8(be32_to_cpu(spec_csr->cpp.dump_length));
  387. dest = dump->p + header_size;
  388. err = nfp_add_tlv(be32_to_cpu(spec_csr_tl->type), total_size, dump);
  389. if (err)
  390. return err;
  391. dump_header->cpp = spec_csr->cpp;
  392. dump_header->register_width = spec_csr->register_width;
  393. cpp_id = nfp_get_numeric_cpp_id(&spec_csr->cpp.cpp_id);
  394. cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);
  395. max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
  396. while (cpp_rd_addr < max_rd_addr) {
  397. if (is_xpb_read(&spec_csr->cpp.cpp_id)) {
  398. err = nfp_xpb_readl(pf->cpp, cpp_rd_addr, (u32 *)dest);
  399. } else {
  400. bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr,
  401. dest, reg_sz);
  402. err = bytes_read == reg_sz ? 0 : -EIO;
  403. }
  404. if (err) {
  405. dump_header->error = cpu_to_be32(err);
  406. dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
  407. break;
  408. }
  409. cpp_rd_addr += reg_sz;
  410. dest += reg_sz;
  411. }
  412. return 0;
  413. }
  414. /* Write context to CSRCtxPtr, then read from it. Then the value can be read
  415. * from IndCtxStatus.
  416. */
  417. static int
  418. nfp_read_indirect_csr(struct nfp_cpp *cpp,
  419. struct nfp_dumpspec_cpp_isl_id cpp_params, u32 offset,
  420. u32 reg_sz, u32 context, void *dest)
  421. {
  422. u32 csr_ctx_ptr_offs;
  423. u32 cpp_id;
  424. int result;
  425. csr_ctx_ptr_offs = nfp_get_ind_csr_ctx_ptr_offs(offset);
  426. cpp_id = NFP_CPP_ISLAND_ID(cpp_params.target,
  427. NFP_IND_ME_REFL_WR_SIG_INIT,
  428. cpp_params.token, cpp_params.island);
  429. result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context);
  430. if (result)
  431. return result;
  432. cpp_id = nfp_get_numeric_cpp_id(&cpp_params);
  433. result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz);
  434. if (result != reg_sz)
  435. return result < 0 ? result : -EIO;
  436. result = nfp_cpp_read(cpp, cpp_id, offset, dest, reg_sz);
  437. if (result != reg_sz)
  438. return result < 0 ? result : -EIO;
  439. return 0;
  440. }
  441. static int
  442. nfp_read_all_indirect_csr_ctx(struct nfp_cpp *cpp,
  443. struct nfp_dumpspec_csr *spec_csr, u32 address,
  444. u32 reg_sz, void *dest)
  445. {
  446. u32 ctx;
  447. int err;
  448. for (ctx = 0; ctx < NFP_IND_NUM_CONTEXTS; ctx++) {
  449. err = nfp_read_indirect_csr(cpp, spec_csr->cpp.cpp_id, address,
  450. reg_sz, ctx, dest + ctx * reg_sz);
  451. if (err)
  452. return err;
  453. }
  454. return 0;
  455. }
  456. static int
  457. nfp_dump_indirect_csr_range(struct nfp_pf *pf,
  458. struct nfp_dumpspec_csr *spec_csr,
  459. struct nfp_dump_state *dump)
  460. {
  461. struct nfp_dump_tl *spec_csr_tl =
  462. container_of(&spec_csr->tl, struct nfp_dump_tl, hdr);
  463. struct nfp_dump_csr *dump_header = dump->p;
  464. u32 reg_sz, header_size, total_size;
  465. u32 cpp_rd_addr, max_rd_addr;
  466. u32 reg_data_length;
  467. void *dest;
  468. int err;
  469. if (!nfp_csr_spec_valid(spec_csr))
  470. return nfp_dump_error_tlv(spec_csr_tl, -EINVAL, dump);
  471. reg_sz = be32_to_cpu(spec_csr->register_width) / BITS_PER_BYTE;
  472. header_size = ALIGN8(sizeof(*dump_header));
  473. reg_data_length = be32_to_cpu(spec_csr->cpp.dump_length) *
  474. NFP_IND_NUM_CONTEXTS;
  475. total_size = header_size + ALIGN8(reg_data_length);
  476. dest = dump->p + header_size;
  477. err = nfp_add_tlv(be32_to_cpu(spec_csr_tl->type), total_size, dump);
  478. if (err)
  479. return err;
  480. dump_header->cpp = spec_csr->cpp;
  481. dump_header->register_width = spec_csr->register_width;
  482. cpp_rd_addr = be32_to_cpu(spec_csr->cpp.offset);
  483. max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
  484. while (cpp_rd_addr < max_rd_addr) {
  485. err = nfp_read_all_indirect_csr_ctx(pf->cpp, spec_csr,
  486. cpp_rd_addr, reg_sz, dest);
  487. if (err) {
  488. dump_header->error = cpu_to_be32(err);
  489. dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
  490. break;
  491. }
  492. cpp_rd_addr += reg_sz;
  493. dest += reg_sz * NFP_IND_NUM_CONTEXTS;
  494. }
  495. return 0;
  496. }
  497. static int
  498. nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
  499. struct nfp_dump_state *dump)
  500. {
  501. struct nfp_dump_tl *spec_tl =
  502. container_of(&spec->tl, struct nfp_dump_tl, hdr);
  503. struct nfp_dump_rtsym *dump_header = dump->p;
  504. struct nfp_dumpspec_cpp_isl_id cpp_params;
  505. struct nfp_rtsym_table *rtbl = pf->rtbl;
  506. u32 header_size, total_size, sym_size;
  507. const struct nfp_rtsym *sym;
  508. u32 tl_len, key_len;
  509. int bytes_read;
  510. void *dest;
  511. int err;
  512. tl_len = be32_to_cpu(spec_tl->length);
  513. key_len = strnlen(spec->rtsym, tl_len);
  514. if (key_len == tl_len)
  515. return nfp_dump_error_tlv(spec_tl, -EINVAL, dump);
  516. sym = nfp_rtsym_lookup(rtbl, spec->rtsym);
  517. if (!sym)
  518. return nfp_dump_error_tlv(spec_tl, -ENOENT, dump);
  519. sym_size = nfp_rtsym_size(sym);
  520. header_size =
  521. ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1);
  522. total_size = header_size + ALIGN8(sym_size);
  523. dest = dump->p + header_size;
  524. err = nfp_add_tlv(be32_to_cpu(spec_tl->type), total_size, dump);
  525. if (err)
  526. return err;
  527. dump_header->padded_name_length =
  528. header_size - offsetof(struct nfp_dump_rtsym, rtsym);
  529. memcpy(dump_header->rtsym, spec->rtsym, key_len + 1);
  530. dump_header->cpp.dump_length = cpu_to_be32(sym_size);
  531. if (sym->type != NFP_RTSYM_TYPE_ABS) {
  532. cpp_params.target = sym->target;
  533. cpp_params.action = NFP_CPP_ACTION_RW;
  534. cpp_params.token = 0;
  535. cpp_params.island = sym->domain;
  536. dump_header->cpp.cpp_id = cpp_params;
  537. dump_header->cpp.offset = cpu_to_be32(sym->addr);
  538. }
  539. bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size);
  540. if (bytes_read != sym_size) {
  541. if (bytes_read >= 0)
  542. bytes_read = -EIO;
  543. dump_header->error = cpu_to_be32(bytes_read);
  544. }
  545. return 0;
  546. }
  547. static int
  548. nfp_dump_for_tlv(struct nfp_pf *pf, struct nfp_dump_tl *tl, void *param)
  549. {
  550. struct nfp_dumpspec_rtsym *spec_rtsym;
  551. struct nfp_dump_state *dump = param;
  552. struct nfp_dumpspec_csr *spec_csr;
  553. int err;
  554. switch (be32_to_cpu(tl->type)) {
  555. case NFP_DUMPSPEC_TYPE_FWNAME:
  556. err = nfp_dump_fwname(pf, dump);
  557. if (err)
  558. return err;
  559. break;
  560. case NFP_DUMPSPEC_TYPE_CPP_CSR:
  561. case NFP_DUMPSPEC_TYPE_XPB_CSR:
  562. case NFP_DUMPSPEC_TYPE_ME_CSR:
  563. spec_csr = (struct nfp_dumpspec_csr *)tl;
  564. err = nfp_dump_csr_range(pf, spec_csr, dump);
  565. if (err)
  566. return err;
  567. break;
  568. case NFP_DUMPSPEC_TYPE_INDIRECT_ME_CSR:
  569. spec_csr = (struct nfp_dumpspec_csr *)tl;
  570. err = nfp_dump_indirect_csr_range(pf, spec_csr, dump);
  571. if (err)
  572. return err;
  573. break;
  574. case NFP_DUMPSPEC_TYPE_RTSYM:
  575. spec_rtsym = (struct nfp_dumpspec_rtsym *)tl;
  576. err = nfp_dump_single_rtsym(pf, spec_rtsym, dump);
  577. if (err)
  578. return err;
  579. break;
  580. case NFP_DUMPSPEC_TYPE_HWINFO:
  581. err = nfp_dump_hwinfo(pf, tl, dump);
  582. if (err)
  583. return err;
  584. break;
  585. case NFP_DUMPSPEC_TYPE_HWINFO_FIELD:
  586. err = nfp_dump_hwinfo_field(pf, tl, dump);
  587. if (err)
  588. return err;
  589. break;
  590. default:
  591. err = nfp_dump_error_tlv(tl, -EOPNOTSUPP, dump);
  592. if (err)
  593. return err;
  594. }
  595. return 0;
  596. }
  597. static int
  598. nfp_dump_specific_level(struct nfp_pf *pf, struct nfp_dump_tl *dump_level,
  599. void *param)
  600. {
  601. struct nfp_dump_state *dump = param;
  602. if (dump_level->type != dump->requested_level)
  603. return 0;
  604. return nfp_traverse_tlvs(pf, dump_level->data,
  605. be32_to_cpu(dump_level->length), dump,
  606. nfp_dump_for_tlv);
  607. }
  608. static int nfp_dump_populate_prolog(struct nfp_dump_state *dump)
  609. {
  610. struct nfp_dump_prolog *prolog = dump->p;
  611. u32 total_size;
  612. int err;
  613. total_size = ALIGN8(sizeof(*prolog));
  614. err = nfp_add_tlv(NFP_DUMPSPEC_TYPE_PROLOG, total_size, dump);
  615. if (err)
  616. return err;
  617. prolog->dump_level = dump->requested_level;
  618. return 0;
  619. }
  620. int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
  621. struct ethtool_dump *dump_param, void *dest)
  622. {
  623. struct nfp_dump_state dump;
  624. int err;
  625. dump.requested_level = cpu_to_be32(dump_param->flag);
  626. dump.dumped_size = 0;
  627. dump.p = dest;
  628. dump.buf_size = dump_param->len;
  629. err = nfp_dump_populate_prolog(&dump);
  630. if (err)
  631. return err;
  632. err = nfp_traverse_tlvs(pf, spec->data, spec->size, &dump,
  633. nfp_dump_specific_level);
  634. if (err)
  635. return err;
  636. /* Set size of actual dump, to trigger warning if different from
  637. * calculated size.
  638. */
  639. dump_param->len = dump.dumped_size;
  640. return 0;
  641. }