pfe_cmd.c 13 KB

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