blob: 2fe0db0fe7171db962b1edda0e6d26764e2ace35 [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 Glass0f2af882020-05-10 11:40:05 -060012#include <common.h>
Simon Glassed38aef2020-05-10 11:40:03 -060013#include <command.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053016#include <net/pfe_eth/pfe_eth.h>
17
18static inline void pfe_command_help(void)
19{
20 printf("Usage: pfe [pe | status | expt ] <options>\n");
21}
22
Simon Glassed38aef2020-05-10 11:40:03 -060023static void pfe_command_pe(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053024{
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);
Simon Glass3ff49ec2021-07-24 09:03:29 -060044 addr = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053045 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);
Simon Glass3ff49ec2021-07-24 09:03:29 -060078 addr = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +053079 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);
Simon Glass3ff49ec2021-07-24 09:03:29 -0600102 val = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530103 val = cpu_to_be32(val);
Simon Glass3ff49ec2021-07-24 09:03:29 -0600104 addr = hextoul(argv[6], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530105 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
Simon Glass3ff49ec2021-07-24 09:03:29 -0600126 offset = hextoul(argv[4], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530127
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
Simon Glass3ff49ec2021-07-24 09:03:29 -0600144 val = hextoul(argv[4], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530145 val = cpu_to_be32(val);
Simon Glass3ff49ec2021-07-24 09:03:29 -0600146 offset = hextoul(argv[5], NULL);
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530147 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 */
175u32 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
191static 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
212static 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
223static 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
246static 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
261static 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
Simon Glassed38aef2020-05-10 11:40:03 -0600278static void pfe_pe_status(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530279{
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
Simon Glassed38aef2020-05-10 11:40:03 -0600343static void pfe_command_status(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530344{
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
369static 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
Simon Glassed38aef2020-05-10 11:40:03 -0600377static void pfe_command_expt(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530378{
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 */
399static 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
Mian Yousaf Kaukab2529deae2021-04-14 12:33:58 +0200421void pfe_command_stop(int argc, char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530422{
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
Simon Glassed38aef2020-05-10 11:40:03 -0600469static int pfe_command(struct cmd_tbl *cmdtp, int flag, int argc,
470 char *const argv[])
Calvin Johnson8abd6cc2018-03-08 15:30:26 +0530471{
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
495U_BOOT_CMD(
496 pfe, 7, 1, pfe_command,
497 "Performs PFE lib utility functions",
498 "Usage:\n"
499 "pfe <options>"
500);