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