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