common: Drop init.h from common header
[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 <net/pfe_eth/pfe_eth.h>
13
14 static inline void pfe_command_help(void)
15 {
16         printf("Usage: pfe [pe | status | expt ] <options>\n");
17 }
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
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  */
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
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
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
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
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
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
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
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
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 */
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
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
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 );