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 
pfe_command_help(void)18 static inline void pfe_command_help(void)
19 {
20 	printf("Usage: pfe [pe | status | expt ] <options>\n");
21 }
22 
pfe_command_pe(int argc,char * const argv[])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  */
qm_read_drop_stat(u32 tmu,u32 queue,u32 * total_drops,int do_reset)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 
tmu_queue_stats(char * buf,int tmu,int queue)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 
tmu_queues(char * buf,int tmu)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 
hif_status(void)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 
gpi(int id,void * base)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 
bmu(int id,void * base)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 
pfe_pe_status(int argc,char * const argv[])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 
pfe_command_status(int argc,char * const argv[])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 
pfe_command_expt(int argc,char * const argv[])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 */
send_dummy_pkt_to_hif(void)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 
pfe_command_stop(int argc,char * const argv[])421 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 
pfe_command(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 );
501