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