xref: /openbmc/u-boot/board/gdsys/common/cmd_ioloop.c (revision ae485b54)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2014
4  * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
5  */
6 
7 #include <common.h>
8 #include <command.h>
9 #include <console.h>
10 
11 #include <gdsys_fpga.h>
12 
13 enum {
14 	STATE_TX_PACKET_BUILDING = 1<<0,
15 	STATE_TX_TRANSMITTING = 1<<1,
16 	STATE_TX_BUFFER_FULL = 1<<2,
17 	STATE_TX_ERR = 1<<3,
18 	STATE_RECEIVE_TIMEOUT = 1<<4,
19 	STATE_PROC_RX_STORE_TIMEOUT = 1<<5,
20 	STATE_PROC_RX_RECEIVE_TIMEOUT = 1<<6,
21 	STATE_RX_DIST_ERR = 1<<7,
22 	STATE_RX_LENGTH_ERR = 1<<8,
23 	STATE_RX_FRAME_CTR_ERR = 1<<9,
24 	STATE_RX_FCS_ERR = 1<<10,
25 	STATE_RX_PACKET_DROPPED = 1<<11,
26 	STATE_RX_DATA_LAST = 1<<12,
27 	STATE_RX_DATA_FIRST = 1<<13,
28 	STATE_RX_DATA_AVAILABLE = 1<<15,
29 };
30 
31 enum {
32 	CTRL_PROC_RECEIVE_ENABLE = 1<<12,
33 	CTRL_FLUSH_TRANSMIT_BUFFER = 1<<15,
34 };
35 
36 enum {
37 	IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = 1<<5,
38 	IRQ_CPU_PACKET_TRANSMITTED_EVENT = 1<<6,
39 	IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = 1<<7,
40 	IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = 1<<8,
41 };
42 
43 struct io_generic_packet {
44 	u16 target_address;
45 	u16 source_address;
46 	u8 packet_type;
47 	u8 bc;
48 	u16 packet_length;
49 } __attribute__((__packed__));
50 
51 unsigned long long rx_ctr;
52 unsigned long long tx_ctr;
53 unsigned long long err_ctr;
54 
55 static void io_check_status(unsigned int fpga, u16 status, bool silent)
56 {
57 	u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR |
58 		   STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR |
59 		   STATE_RX_PACKET_DROPPED | STATE_TX_ERR;
60 
61 	if (!(status & mask)) {
62 		FPGA_SET_REG(fpga, ep.rx_tx_status, status);
63 		return;
64 	}
65 
66 	err_ctr++;
67 	FPGA_SET_REG(fpga, ep.rx_tx_status, status);
68 
69 	if (silent)
70 		return;
71 
72 	if (status & STATE_RX_PACKET_DROPPED)
73 		printf("RX_PACKET_DROPPED, status %04x\n", status);
74 
75 	if (status & STATE_RX_DIST_ERR)
76 		printf("RX_DIST_ERR\n");
77 	if (status & STATE_RX_LENGTH_ERR)
78 		printf("RX_LENGTH_ERR\n");
79 	if (status & STATE_RX_FRAME_CTR_ERR)
80 		printf("RX_FRAME_CTR_ERR\n");
81 	if (status & STATE_RX_FCS_ERR)
82 		printf("RX_FCS_ERR\n");
83 
84 	if (status & STATE_TX_ERR)
85 		printf("TX_ERR\n");
86 }
87 
88 static void io_send(unsigned int fpga, unsigned int size)
89 {
90 	unsigned int k;
91 	struct io_generic_packet packet = {
92 		.source_address = 1,
93 		.packet_type = 1,
94 		.packet_length = size,
95 	};
96 	u16 *p = (u16 *)&packet;
97 
98 	for (k = 0; k < sizeof(packet) / 2; ++k)
99 		FPGA_SET_REG(fpga, ep.transmit_data, *p++);
100 
101 	for (k = 0; k < (size + 1) / 2; ++k)
102 		FPGA_SET_REG(fpga, ep.transmit_data, k);
103 
104 	FPGA_SET_REG(fpga, ep.rx_tx_control,
105 		     CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
106 
107 	tx_ctr++;
108 }
109 
110 static void io_receive(unsigned int fpga)
111 {
112 	unsigned int k = 0;
113 	u16 rx_tx_status;
114 
115 	FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
116 
117 	while (rx_tx_status & STATE_RX_DATA_AVAILABLE) {
118 		u16 rx;
119 
120 		if (rx_tx_status & STATE_RX_DATA_LAST)
121 			rx_ctr++;
122 
123 		FPGA_GET_REG(fpga, ep.receive_data, &rx);
124 
125 		FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
126 
127 		++k;
128 	}
129 }
130 
131 static void io_reflect(unsigned int fpga)
132 {
133 	u16 buffer[128];
134 
135 	unsigned int k = 0;
136 	unsigned int n;
137 	u16 rx_tx_status;
138 
139 	FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
140 
141 	while (rx_tx_status & STATE_RX_DATA_AVAILABLE) {
142 		FPGA_GET_REG(fpga, ep.receive_data, &buffer[k++]);
143 		if (rx_tx_status & STATE_RX_DATA_LAST)
144 			break;
145 
146 		FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
147 	}
148 
149 	if (!k)
150 		return;
151 
152 	for (n = 0; n < k; ++n)
153 		FPGA_SET_REG(fpga, ep.transmit_data, buffer[n]);
154 
155 	FPGA_SET_REG(fpga, ep.rx_tx_control,
156 		     CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
157 
158 	tx_ctr++;
159 }
160 
161 /*
162  * FPGA io-endpoint reflector
163  *
164  * Syntax:
165  *	ioreflect {fpga} {reportrate}
166  */
167 int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
168 {
169 	unsigned int fpga;
170 	unsigned int rate = 0;
171 	unsigned long long last_seen = 0;
172 
173 	if (argc < 2)
174 		return CMD_RET_USAGE;
175 
176 	fpga = simple_strtoul(argv[1], NULL, 10);
177 
178 	/*
179 	 * If another parameter, it is the report rate in packets.
180 	 */
181 	if (argc > 2)
182 		rate = simple_strtoul(argv[2], NULL, 10);
183 
184 	/* enable receive path */
185 	FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
186 
187 	/* set device address to dummy 1*/
188 	FPGA_SET_REG(fpga, ep.device_address, 1);
189 
190 	rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
191 
192 	while (1) {
193 		u16 top_int;
194 		u16 rx_tx_status;
195 
196 		FPGA_GET_REG(fpga, top_interrupt, &top_int);
197 		FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
198 
199 		io_check_status(fpga, rx_tx_status, true);
200 		if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) &&
201 		    (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS))
202 			io_reflect(fpga);
203 
204 		if (rate) {
205 			if (!(tx_ctr % rate) && (tx_ctr != last_seen))
206 				printf("refl %llu, err %llu\n", tx_ctr,
207 				       err_ctr);
208 			last_seen = tx_ctr;
209 		}
210 
211 		if (ctrlc())
212 			break;
213 	}
214 
215 	return 0;
216 }
217 
218 /*
219  * FPGA io-endpoint looptest
220  *
221  * Syntax:
222  *	ioloop {fpga} {size} {rate}
223  */
224 #define DISP_LINE_LEN	16
225 int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
226 {
227 	unsigned int fpga;
228 	unsigned int size;
229 	unsigned int rate = 0;
230 
231 	if (argc < 3)
232 		return CMD_RET_USAGE;
233 
234 	/*
235 	 * FPGA is specified since argc > 2
236 	 */
237 	fpga = simple_strtoul(argv[1], NULL, 10);
238 
239 	/*
240 	 * packet size is specified since argc > 2
241 	 */
242 	size = simple_strtoul(argv[2], NULL, 10);
243 
244 	/*
245 	 * If another parameter, it is the test rate in packets per second.
246 	 */
247 	if (argc > 3)
248 		rate = simple_strtoul(argv[3], NULL, 10);
249 
250 	/* enable receive path */
251 	FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
252 
253 	/* set device address to dummy 1*/
254 	FPGA_SET_REG(fpga, ep.device_address, 1);
255 
256 	rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
257 
258 	while (1) {
259 		u16 top_int;
260 		u16 rx_tx_status;
261 
262 		FPGA_GET_REG(fpga, top_interrupt, &top_int);
263 		FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
264 
265 		io_check_status(fpga, rx_tx_status, false);
266 		if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)
267 			io_send(fpga, size);
268 		if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS)
269 			io_receive(fpga);
270 
271 		if (rate) {
272 			if (ctrlc())
273 				break;
274 			udelay(1000000 / rate);
275 			if (!(tx_ctr % rate))
276 				printf("d %lld, tx %llu, rx %llu, err %llu\n",
277 				       tx_ctr - rx_ctr, tx_ctr, rx_ctr,
278 				       err_ctr);
279 		}
280 	}
281 
282 	return 0;
283 }
284 
285 U_BOOT_CMD(
286 	ioloop,	4,	0,	do_ioloop,
287 	"fpga io-endpoint looptest",
288 	"fpga packetsize [packets/sec]"
289 );
290 
291 U_BOOT_CMD(
292 	ioreflect, 3,	0,	do_ioreflect,
293 	"fpga io-endpoint reflector",
294 	"fpga reportrate"
295 );
296