blob: 99c2a8d4e92b7cd82decf7135d739b0cf6a38da0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Calvin Johnson8abd6cc2018-03-08 15:30:26 +05302/*
3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
4 * Copyright 2017 NXP
Calvin Johnson8abd6cc2018-03-08 15:30:26 +05305 */
6
7/*
8 * @file
9 * @brief PFE utility commands
10 */
11
Simon Glassed38aef2020-05-10 11:40:03 -060012#include <command.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glassdbd79542020-05-10 11:40:11 -060014#include <linux/delay.h>
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053015#include <net/pfe_eth/pfe_eth.h>
16
17static inline void pfe_command_help(void)
18{
19 printf("Usage: pfe [pe | status | expt ] <options>\n");
20}
21
Simon Glassed38aef2020-05-10 11:40:03 -060022static void pfe_command_pe(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053023{
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);
Simon Glass3ff49ec2021-07-24 09:03:29 -060043 addr = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053044 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);
Simon Glass3ff49ec2021-07-24 09:03:29 -060077 addr = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053078 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);
Simon Glass3ff49ec2021-07-24 09:03:29 -0600101 val = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530102 val = cpu_to_be32(val);
Simon Glass3ff49ec2021-07-24 09:03:29 -0600103 addr = hextoul(argv[6], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530104 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
Simon Glass3ff49ec2021-07-24 09:03:29 -0600125 offset = hextoul(argv[4], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530126
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
Simon Glass3ff49ec2021-07-24 09:03:29 -0600143 val = hextoul(argv[4], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530144 val = cpu_to_be32(val);
Simon Glass3ff49ec2021-07-24 09:03:29 -0600145 offset = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530146 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 */
174u32 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
190static 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
211static 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
222static 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
245static 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
260static 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
Simon Glassed38aef2020-05-10 11:40:03 -0600277static void pfe_pe_status(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530278{
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
Simon Glassed38aef2020-05-10 11:40:03 -0600342static void pfe_command_status(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530343{
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
368static 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
Simon Glassed38aef2020-05-10 11:40:03 -0600376static void pfe_command_expt(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530377{
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 */
398static 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
Mian Yousaf Kaukab2529deae2021-04-14 12:33:58 +0200420void pfe_command_stop(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530421{
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
Simon Glassed38aef2020-05-10 11:40:03 -0600468static int pfe_command(struct cmd_tbl *cmdtp, int flag, int argc,
469 char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530470{
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
494U_BOOT_CMD(
495 pfe, 7, 1, pfe_command,
496 "Performs PFE lib utility functions",
497 "Usage:\n"
498 "pfe <options>"
499);