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