nfp_net_debugdump.c 21 KB

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