pfe_cmd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2015-2016 Freescale Semiconductor, Inc.
  4. * Copyright 2017 NXP
  5. */
  6. /*
  7. * @file
  8. * @brief PFE utility commands
  9. */
  10. #include <net/pfe_eth/pfe_eth.h>
  11. static inline void pfe_command_help(void)
  12. {
  13. printf("Usage: pfe [pe | status | expt ] <options>\n");
  14. }
  15. static void pfe_command_pe(int argc, char * const argv[])
  16. {
  17. if (argc >= 3 && strcmp(argv[2], "pmem") == 0) {
  18. if (argc >= 4 && strcmp(argv[3], "read") == 0) {
  19. int i;
  20. int num;
  21. int id;
  22. u32 addr;
  23. u32 size;
  24. u32 val;
  25. if (argc == 7) {
  26. num = simple_strtoul(argv[6], NULL, 0);
  27. } else if (argc == 6) {
  28. num = 1;
  29. } else {
  30. printf("Usage: pfe pe pmem read <id> <addr> [<num>]\n");
  31. return;
  32. }
  33. id = simple_strtoul(argv[4], NULL, 0);
  34. addr = simple_strtoul(argv[5], NULL, 16);
  35. size = 4;
  36. for (i = 0; i < num; i++, addr += 4) {
  37. val = pe_pmem_read(id, addr, size);
  38. val = be32_to_cpu(val);
  39. if (!(i & 3))
  40. printf("%08x: ", addr);
  41. printf("%08x%s", val, i == num - 1 || (i & 3)
  42. == 3 ? "\n" : " ");
  43. }
  44. } else {
  45. printf("Usage: pfe pe pmem read <parameters>\n");
  46. }
  47. } else if (argc >= 3 && strcmp(argv[2], "dmem") == 0) {
  48. if (argc >= 4 && strcmp(argv[3], "read") == 0) {
  49. int i;
  50. int num;
  51. int id;
  52. u32 addr;
  53. u32 size;
  54. u32 val;
  55. if (argc == 7) {
  56. num = simple_strtoul(argv[6], NULL, 0);
  57. } else if (argc == 6) {
  58. num = 1;
  59. } else {
  60. printf("Usage: pfe pe dmem read <id> <addr> [<num>]\n");
  61. return;
  62. }
  63. id = simple_strtoul(argv[4], NULL, 0);
  64. addr = simple_strtoul(argv[5], NULL, 16);
  65. size = 4;
  66. for (i = 0; i < num; i++, addr += 4) {
  67. val = pe_dmem_read(id, addr, size);
  68. val = be32_to_cpu(val);
  69. if (!(i & 3))
  70. printf("%08x: ", addr);
  71. printf("%08x%s", val, i == num - 1 || (i & 3)
  72. == 3 ? "\n" : " ");
  73. }
  74. } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
  75. int id;
  76. u32 val;
  77. u32 addr;
  78. u32 size;
  79. if (argc != 7) {
  80. printf("Usage: pfe pe dmem write <id> <val> <addr>\n");
  81. return;
  82. }
  83. id = simple_strtoul(argv[4], NULL, 0);
  84. val = simple_strtoul(argv[5], NULL, 16);
  85. val = cpu_to_be32(val);
  86. addr = simple_strtoul(argv[6], NULL, 16);
  87. size = 4;
  88. pe_dmem_write(id, val, addr, size);
  89. } else {
  90. printf("Usage: pfe pe dmem [read | write] <parameters>\n");
  91. }
  92. } else if (argc >= 3 && strcmp(argv[2], "lmem") == 0) {
  93. if (argc >= 4 && strcmp(argv[3], "read") == 0) {
  94. int i;
  95. int num;
  96. u32 val;
  97. u32 offset;
  98. if (argc == 6) {
  99. num = simple_strtoul(argv[5], NULL, 0);
  100. } else if (argc == 5) {
  101. num = 1;
  102. } else {
  103. printf("Usage: pfe pe lmem read <offset> [<num>]\n");
  104. return;
  105. }
  106. offset = simple_strtoul(argv[4], NULL, 16);
  107. for (i = 0; i < num; i++, offset += 4) {
  108. pe_lmem_read(&val, 4, offset);
  109. val = be32_to_cpu(val);
  110. printf("%08x%s", val, i == num - 1 || (i & 7)
  111. == 7 ? "\n" : " ");
  112. }
  113. } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
  114. u32 val;
  115. u32 offset;
  116. if (argc != 6) {
  117. printf("Usage: pfe pe lmem write <val> <offset>\n");
  118. return;
  119. }
  120. val = simple_strtoul(argv[4], NULL, 16);
  121. val = cpu_to_be32(val);
  122. offset = simple_strtoul(argv[5], NULL, 16);
  123. pe_lmem_write(&val, 4, offset);
  124. } else {
  125. printf("Usage: pfe pe lmem [read | write] <parameters>\n");
  126. }
  127. } else {
  128. if (strcmp(argv[2], "help") != 0)
  129. printf("Unknown option: %s\n", argv[2]);
  130. printf("Usage: pfe pe <parameters>\n");
  131. }
  132. }
  133. #define NUM_QUEUES 16
  134. /*
  135. * qm_read_drop_stat
  136. * This function is used to read the drop statistics from the TMU
  137. * hw drop counter. Since the hw counter is always cleared afer
  138. * reading, this function maintains the previous drop count, and
  139. * adds the new value to it. That value can be retrieved by
  140. * passing a pointer to it with the total_drops arg.
  141. *
  142. * @param tmu TMU number (0 - 3)
  143. * @param queue queue number (0 - 15)
  144. * @param total_drops pointer to location to store total drops (or NULL)
  145. * @param do_reset if TRUE, clear total drops after updating
  146. *
  147. */
  148. u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset)
  149. {
  150. static u32 qtotal[TMU_MAX_ID + 1][NUM_QUEUES];
  151. u32 val;
  152. writel((tmu << 8) | queue, TMU_TEQ_CTRL);
  153. writel((tmu << 8) | queue, TMU_LLM_CTRL);
  154. val = readl(TMU_TEQ_DROP_STAT);
  155. qtotal[tmu][queue] += val;
  156. if (total_drops)
  157. *total_drops = qtotal[tmu][queue];
  158. if (do_reset)
  159. qtotal[tmu][queue] = 0;
  160. return val;
  161. }
  162. static ssize_t tmu_queue_stats(char *buf, int tmu, int queue)
  163. {
  164. ssize_t len = 0;
  165. u32 drops;
  166. printf("%d-%02d, ", tmu, queue);
  167. drops = qm_read_drop_stat(tmu, queue, NULL, 0);
  168. /* Select queue */
  169. writel((tmu << 8) | queue, TMU_TEQ_CTRL);
  170. writel((tmu << 8) | queue, TMU_LLM_CTRL);
  171. printf("(teq) drop: %10u, tx: %10u (llm) head: %08x, tail: %08x, drop: %10u\n",
  172. drops, readl(TMU_TEQ_TRANS_STAT),
  173. readl(TMU_LLM_QUE_HEADPTR), readl(TMU_LLM_QUE_TAILPTR),
  174. readl(TMU_LLM_QUE_DROPCNT));
  175. return len;
  176. }
  177. static ssize_t tmu_queues(char *buf, int tmu)
  178. {
  179. ssize_t len = 0;
  180. int queue;
  181. for (queue = 0; queue < 16; queue++)
  182. len += tmu_queue_stats(buf + len, tmu, queue);
  183. return len;
  184. }
  185. static inline void hif_status(void)
  186. {
  187. printf("hif:\n");
  188. printf(" tx curr bd: %x\n", readl(HIF_TX_CURR_BD_ADDR));
  189. printf(" tx status: %x\n", readl(HIF_TX_STATUS));
  190. printf(" tx dma status: %x\n", readl(HIF_TX_DMA_STATUS));
  191. printf(" rx curr bd: %x\n", readl(HIF_RX_CURR_BD_ADDR));
  192. printf(" rx status: %x\n", readl(HIF_RX_STATUS));
  193. printf(" rx dma status: %x\n", readl(HIF_RX_DMA_STATUS));
  194. printf("hif nocopy:\n");
  195. printf(" tx curr bd: %x\n", readl(HIF_NOCPY_TX_CURR_BD_ADDR));
  196. printf(" tx status: %x\n", readl(HIF_NOCPY_TX_STATUS));
  197. printf(" tx dma status: %x\n", readl(HIF_NOCPY_TX_DMA_STATUS));
  198. printf(" rx curr bd: %x\n", readl(HIF_NOCPY_RX_CURR_BD_ADDR));
  199. printf(" rx status: %x\n", readl(HIF_NOCPY_RX_STATUS));
  200. printf(" rx dma status: %x\n", readl(HIF_NOCPY_RX_DMA_STATUS));
  201. }
  202. static void gpi(int id, void *base)
  203. {
  204. u32 val;
  205. printf("%s%d:\n", __func__, id);
  206. printf(" tx under stick: %x\n", readl(base + GPI_FIFO_STATUS));
  207. val = readl(base + GPI_FIFO_DEBUG);
  208. printf(" tx pkts: %x\n", (val >> 23) & 0x3f);
  209. printf(" rx pkts: %x\n", (val >> 18) & 0x3f);
  210. printf(" tx bytes: %x\n", (val >> 9) & 0x1ff);
  211. printf(" rx bytes: %x\n", (val >> 0) & 0x1ff);
  212. printf(" overrun: %x\n", readl(base + GPI_OVERRUN_DROPCNT));
  213. }
  214. static void bmu(int id, void *base)
  215. {
  216. printf("%s%d:\n", __func__, id);
  217. printf(" buf size: %x\n", (1 << readl(base + BMU_BUF_SIZE)));
  218. printf(" buf count: %x\n", readl(base + BMU_BUF_CNT));
  219. printf(" buf rem: %x\n", readl(base + BMU_REM_BUF_CNT));
  220. printf(" buf curr: %x\n", readl(base + BMU_CURR_BUF_CNT));
  221. printf(" free err: %x\n", readl(base + BMU_FREE_ERR_ADDR));
  222. }
  223. #define PESTATUS_ADDR_CLASS 0x800
  224. #define PEMBOX_ADDR_CLASS 0x890
  225. #define PESTATUS_ADDR_TMU 0x80
  226. #define PEMBOX_ADDR_TMU 0x290
  227. #define PESTATUS_ADDR_UTIL 0x0
  228. static void pfe_pe_status(int argc, char * const argv[])
  229. {
  230. int do_clear = 0;
  231. u32 id;
  232. u32 dmem_addr;
  233. u32 cpu_state;
  234. u32 activity_counter;
  235. u32 rx;
  236. u32 tx;
  237. u32 drop;
  238. char statebuf[5];
  239. u32 class_debug_reg = 0;
  240. if (argc == 4 && strcmp(argv[3], "clear") == 0)
  241. do_clear = 1;
  242. for (id = CLASS0_ID; id < MAX_PE; id++) {
  243. if (id >= TMU0_ID) {
  244. if (id == TMU2_ID)
  245. continue;
  246. if (id == TMU0_ID)
  247. printf("tmu:\n");
  248. dmem_addr = PESTATUS_ADDR_TMU;
  249. } else {
  250. if (id == CLASS0_ID)
  251. printf("class:\n");
  252. dmem_addr = PESTATUS_ADDR_CLASS;
  253. class_debug_reg = readl(CLASS_PE0_DEBUG + id * 4);
  254. }
  255. cpu_state = pe_dmem_read(id, dmem_addr, 4);
  256. dmem_addr += 4;
  257. memcpy(statebuf, (char *)&cpu_state, 4);
  258. statebuf[4] = '\0';
  259. activity_counter = pe_dmem_read(id, dmem_addr, 4);
  260. dmem_addr += 4;
  261. rx = pe_dmem_read(id, dmem_addr, 4);
  262. if (do_clear)
  263. pe_dmem_write(id, 0, dmem_addr, 4);
  264. dmem_addr += 4;
  265. tx = pe_dmem_read(id, dmem_addr, 4);
  266. if (do_clear)
  267. pe_dmem_write(id, 0, dmem_addr, 4);
  268. dmem_addr += 4;
  269. drop = pe_dmem_read(id, dmem_addr, 4);
  270. if (do_clear)
  271. pe_dmem_write(id, 0, dmem_addr, 4);
  272. dmem_addr += 4;
  273. if (id >= TMU0_ID) {
  274. printf("%d: state=%4s ctr=%08x rx=%x qstatus=%x\n",
  275. id - TMU0_ID, statebuf,
  276. cpu_to_be32(activity_counter),
  277. cpu_to_be32(rx), cpu_to_be32(tx));
  278. } else {
  279. printf("%d: pc=1%04x ldst=%04x state=%4s ctr=%08x rx=%x tx=%x drop=%x\n",
  280. id - CLASS0_ID, class_debug_reg & 0xFFFF,
  281. class_debug_reg >> 16,
  282. statebuf, cpu_to_be32(activity_counter),
  283. cpu_to_be32(rx), cpu_to_be32(tx),
  284. cpu_to_be32(drop));
  285. }
  286. }
  287. }
  288. static void pfe_command_status(int argc, char * const argv[])
  289. {
  290. if (argc >= 3 && strcmp(argv[2], "pe") == 0) {
  291. pfe_pe_status(argc, argv);
  292. } else if (argc == 3 && strcmp(argv[2], "bmu") == 0) {
  293. bmu(1, BMU1_BASE_ADDR);
  294. bmu(2, BMU2_BASE_ADDR);
  295. } else if (argc == 3 && strcmp(argv[2], "hif") == 0) {
  296. hif_status();
  297. } else if (argc == 3 && strcmp(argv[2], "gpi") == 0) {
  298. gpi(0, EGPI1_BASE_ADDR);
  299. gpi(1, EGPI2_BASE_ADDR);
  300. gpi(3, HGPI_BASE_ADDR);
  301. } else if (argc == 3 && strcmp(argv[2], "tmu0_queues") == 0) {
  302. tmu_queues(NULL, 0);
  303. } else if (argc == 3 && strcmp(argv[2], "tmu1_queues") == 0) {
  304. tmu_queues(NULL, 1);
  305. } else if (argc == 3 && strcmp(argv[2], "tmu3_queues") == 0) {
  306. tmu_queues(NULL, 3);
  307. } else {
  308. printf("Usage: pfe status [pe <clear> | bmu | gpi | hif | tmuX_queues ]\n");
  309. }
  310. }
  311. #define EXPT_DUMP_ADDR 0x1fa8
  312. #define EXPT_REG_COUNT 20
  313. static const char *register_names[EXPT_REG_COUNT] = {
  314. " pc", "ECAS", " EID", " ED",
  315. " sp", " r1", " r2", " r3",
  316. " r4", " r5", " r6", " r7",
  317. " r8", " r9", " r10", " r11",
  318. " r12", " r13", " r14", " r15"
  319. };
  320. static void pfe_command_expt(int argc, char * const argv[])
  321. {
  322. unsigned int id, i, val, addr;
  323. if (argc == 3) {
  324. id = simple_strtoul(argv[2], NULL, 0);
  325. addr = EXPT_DUMP_ADDR;
  326. printf("Exception information for PE %d:\n", id);
  327. for (i = 0; i < EXPT_REG_COUNT; i++) {
  328. val = pe_dmem_read(id, addr, 4);
  329. val = be32_to_cpu(val);
  330. printf("%s:%08x%s", register_names[i], val,
  331. (i & 3) == 3 ? "\n" : " ");
  332. addr += 4;
  333. }
  334. } else {
  335. printf("Usage: pfe expt <id>\n");
  336. }
  337. }
  338. #ifdef PFE_RESET_WA
  339. /*This function sends a dummy packet to HIF through TMU3 */
  340. static void send_dummy_pkt_to_hif(void)
  341. {
  342. u32 buf;
  343. static u32 dummy_pkt[] = {
  344. 0x4200800a, 0x01000003, 0x00018100, 0x00000000,
  345. 0x33221100, 0x2b785544, 0xd73093cb, 0x01000608,
  346. 0x04060008, 0x2b780200, 0xd73093cb, 0x0a01a8c0,
  347. 0x33221100, 0xa8c05544, 0x00000301, 0x00000000,
  348. 0x00000000, 0x00000000, 0x00000000, 0xbe86c51f };
  349. /*Allocate BMU2 buffer */
  350. buf = readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL);
  351. debug("Sending a dummy pkt to HIF %x\n", buf);
  352. buf += 0x80;
  353. memcpy((void *)DDR_PFE_TO_VIRT(buf), dummy_pkt, sizeof(dummy_pkt));
  354. /*Write length and pkt to TMU*/
  355. writel(0x03000042, TMU_PHY_INQ_PKTPTR);
  356. writel(buf, TMU_PHY_INQ_PKTINFO);
  357. }
  358. static void pfe_command_stop(int argc, char * const argv[])
  359. {
  360. int pfe_pe_id, hif_stop_loop = 10;
  361. u32 rx_status;
  362. printf("Stopping PFE...\n");
  363. /*Mark all descriptors as LAST_BD */
  364. hif_rx_desc_disable();
  365. /*If HIF Rx BDP is busy send a dummy packet */
  366. do {
  367. rx_status = readl(HIF_RX_STATUS);
  368. if (rx_status & BDP_CSR_RX_DMA_ACTV)
  369. send_dummy_pkt_to_hif();
  370. udelay(10);
  371. } while (hif_stop_loop--);
  372. if (readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)
  373. printf("Unable to stop HIF\n");
  374. /*Disable Class PEs */
  375. for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
  376. /*Inform PE to stop */
  377. pe_dmem_write(pfe_pe_id, cpu_to_be32(1), PEMBOX_ADDR_CLASS, 4);
  378. udelay(10);
  379. /*Read status */
  380. if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_CLASS + 4, 4))
  381. printf("Failed to stop PE%d\n", pfe_pe_id);
  382. }
  383. /*Disable TMU PEs */
  384. for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
  385. if (pfe_pe_id == TMU2_ID)
  386. continue;
  387. /*Inform PE to stop */
  388. pe_dmem_write(pfe_pe_id, 1, PEMBOX_ADDR_TMU, 4);
  389. udelay(10);
  390. /*Read status */
  391. if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_TMU + 4, 4))
  392. printf("Failed to stop PE%d\n", pfe_pe_id);
  393. }
  394. }
  395. #endif
  396. static int pfe_command(cmd_tbl_t *cmdtp, int flag, int argc,
  397. char * const argv[])
  398. {
  399. if (argc == 1 || strcmp(argv[1], "help") == 0) {
  400. pfe_command_help();
  401. return CMD_RET_SUCCESS;
  402. }
  403. if (strcmp(argv[1], "pe") == 0) {
  404. pfe_command_pe(argc, argv);
  405. } else if (strcmp(argv[1], "status") == 0) {
  406. pfe_command_status(argc, argv);
  407. } else if (strcmp(argv[1], "expt") == 0) {
  408. pfe_command_expt(argc, argv);
  409. #ifdef PFE_RESET_WA
  410. } else if (strcmp(argv[1], "stop") == 0) {
  411. pfe_command_stop(argc, argv);
  412. #endif
  413. } else {
  414. printf("Unknown option: %s\n", argv[1]);
  415. pfe_command_help();
  416. return CMD_RET_FAILURE;
  417. }
  418. return CMD_RET_SUCCESS;
  419. }
  420. U_BOOT_CMD(
  421. pfe, 7, 1, pfe_command,
  422. "Performs PFE lib utility functions",
  423. "Usage:\n"
  424. "pfe <options>"
  425. );