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