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