1/*
2 * RX ucode for the Intel IXP2400 in POS-PHY mode.
3 * Copyright (C) 2004, 2005 Lennert Buytenhek
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Assumptions made in this code:
12 * - The IXP2400 MSF is configured for POS-PHY mode, in a mode where
13 *   only one full element list is used.  This includes, for example,
14 *   1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4.  (This
15 *   is not an exhaustive list.)
16 * - The RBUF uses 64-byte mpackets.
17 * - RX descriptors reside in SRAM, and have the following format:
18 *	struct rx_desc
19 *	{
20 *	// to uengine
21 *		u32	buf_phys_addr;
22 *		u32	buf_length;
23 *
24 *	// from uengine
25 *		u32	channel;
26 *		u32	pkt_length;
27 *	};
28 * - Packet data resides in DRAM.
29 * - Packet buffer addresses are 8-byte aligned.
30 * - Scratch ring 0 is rx_pending.
31 * - Scratch ring 1 is rx_done, and has status condition 'full'.
32 * - The host triggers rx_done flush and rx_pending refill on seeing INTA.
33 * - This code is run on all eight threads of the microengine it runs on.
34 *
35 * Local memory is used for per-channel RX state.
36 */
37
38#define RX_THREAD_FREELIST_0		0x0030
39#define RBUF_ELEMENT_DONE		0x0044
40
41#define CHANNEL_FLAGS			*l$index0[0]
42#define CHANNEL_FLAG_RECEIVING		1
43#define PACKET_LENGTH			*l$index0[1]
44#define PACKET_CHECKSUM			*l$index0[2]
45#define BUFFER_HANDLE			*l$index0[3]
46#define BUFFER_START			*l$index0[4]
47#define BUFFER_LENGTH			*l$index0[5]
48
49#define CHANNEL_STATE_SIZE		24	// in bytes
50#define CHANNEL_STATE_SHIFT		5	// ceil(log2(state size))
51
52
53	.sig volatile sig1
54	.sig volatile sig2
55	.sig volatile sig3
56
57	.sig mpacket_arrived
58	.reg add_to_rx_freelist
59	.reg read $rsw0, $rsw1
60	.xfer_order $rsw0 $rsw1
61
62	.reg zero
63
64	/*
65	 * Initialise add_to_rx_freelist.
66	 */
67	.begin
68		.reg temp
69		.reg temp2
70
71		immed[add_to_rx_freelist, RX_THREAD_FREELIST_0]
72		immed_w1[add_to_rx_freelist, (&$rsw0 | (&mpacket_arrived << 12))]
73
74		local_csr_rd[ACTIVE_CTX_STS]
75		immed[temp, 0]
76		alu[temp2, temp, and, 0x1f]
77		alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<20]
78		alu[temp2, temp, and, 0x80]
79		alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<18]
80	.end
81
82	immed[zero, 0]
83
84	/*
85	 * Skip context 0 initialisation?
86	 */
87	.begin
88		br!=ctx[0, mpacket_receive_loop#]
89	.end
90
91	/*
92	 * Initialise local memory.
93	 */
94	.begin
95		.reg addr
96		.reg temp
97
98		immed[temp, 0]
99	init_local_mem_loop#:
100		alu_shf[addr, --, b, temp, <<CHANNEL_STATE_SHIFT]
101		local_csr_wr[ACTIVE_LM_ADDR_0, addr]
102		nop
103		nop
104		nop
105
106		immed[CHANNEL_FLAGS, 0]
107
108		alu[temp, temp, +, 1]
109		alu[--, temp, and, 0x20]
110		beq[init_local_mem_loop#]
111	.end
112
113	/*
114	 * Initialise signal pipeline.
115	 */
116	.begin
117		local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)]
118		.set_sig sig1
119
120		local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)]
121		.set_sig sig2
122
123		local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)]
124		.set_sig sig3
125	.end
126
127mpacket_receive_loop#:
128	/*
129	 * Synchronise and wait for mpacket.
130	 */
131	.begin
132		ctx_arb[sig1]
133		local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))]
134
135		msf[fast_wr, --, add_to_rx_freelist, 0]
136		.set_sig mpacket_arrived
137		ctx_arb[mpacket_arrived]
138		.set $rsw0 $rsw1
139	.end
140
141	/*
142	 * We halt if we see {inbparerr,parerr,null,soperror}.
143	 */
144	.begin
145		alu_shf[--, 0x1b, and, $rsw0, >>8]
146		bne[abort_rswerr#]
147	.end
148
149	/*
150	 * Point local memory pointer to this channel's state area.
151	 */
152	.begin
153		.reg chanaddr
154
155		alu[chanaddr, $rsw0, and, 0x1f]
156		alu_shf[chanaddr, --, b, chanaddr, <<CHANNEL_STATE_SHIFT]
157		local_csr_wr[ACTIVE_LM_ADDR_0, chanaddr]
158		nop
159		nop
160		nop
161	.end
162
163	/*
164	 * Check whether we received a SOP mpacket while we were already
165	 * working on a packet, or a non-SOP mpacket while there was no
166	 * packet pending.  (SOP == RECEIVING -> abort)  If everything's
167	 * okay, update the RECEIVING flag to reflect our new state.
168	 */
169	.begin
170		.reg temp
171		.reg eop
172
173		#if CHANNEL_FLAG_RECEIVING != 1
174		#error CHANNEL_FLAG_RECEIVING is not 1
175		#endif
176
177		alu_shf[temp, 1, and, $rsw0, >>15]
178		alu[temp, temp, xor, CHANNEL_FLAGS]
179		alu[--, temp, and, CHANNEL_FLAG_RECEIVING]
180		beq[abort_proterr#]
181
182		alu_shf[eop, 1, and, $rsw0, >>14]
183		alu[CHANNEL_FLAGS, temp, xor, eop]
184	.end
185
186	/*
187	 * Copy the mpacket into the right spot, and in case of EOP,
188	 * write back the descriptor and pass the packet on.
189	 */
190	.begin
191		.reg buffer_offset
192		.reg _packet_length
193		.reg _packet_checksum
194		.reg _buffer_handle
195		.reg _buffer_start
196		.reg _buffer_length
197
198		/*
199		 * Determine buffer_offset, _packet_length and
200		 * _packet_checksum.
201		 */
202		.begin
203			.reg temp
204
205			alu[--, 1, and, $rsw0, >>15]
206			beq[not_sop#]
207
208			immed[PACKET_LENGTH, 0]
209			immed[PACKET_CHECKSUM, 0]
210
211		not_sop#:
212			alu[buffer_offset, --, b, PACKET_LENGTH]
213			alu_shf[temp, 0xff, and, $rsw0, >>16]
214			alu[_packet_length, buffer_offset, +, temp]
215			alu[PACKET_LENGTH, --, b, _packet_length]
216
217			immed[temp, 0xffff]
218			alu[temp, $rsw1, and, temp]
219			alu[_packet_checksum, PACKET_CHECKSUM, +, temp]
220			alu[PACKET_CHECKSUM, --, b, _packet_checksum]
221		.end
222
223		/*
224		 * Allocate buffer in case of SOP.
225		 */
226		.begin
227			.reg temp
228
229			alu[temp, 1, and, $rsw0, >>15]
230			beq[skip_buffer_alloc#]
231
232			.begin
233				.sig zzz
234				.reg read $stemp $stemp2
235				.xfer_order $stemp $stemp2
236
237			rx_nobufs#:
238				scratch[get, $stemp, zero, 0, 1], ctx_swap[zzz]
239				alu[_buffer_handle, --, b, $stemp]
240				beq[rx_nobufs#]
241
242				sram[read, $stemp, _buffer_handle, 0, 2],
243								ctx_swap[zzz]
244				alu[_buffer_start, --, b, $stemp]
245				alu[_buffer_length, --, b, $stemp2]
246			.end
247
248		skip_buffer_alloc#:
249		.end
250
251		/*
252		 * Resynchronise.
253		 */
254		.begin
255			ctx_arb[sig2]
256			local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))]
257		.end
258
259		/*
260		 * Synchronise buffer state.
261		 */
262		.begin
263			.reg temp
264
265			alu[temp, 1, and, $rsw0, >>15]
266			beq[copy_from_local_mem#]
267
268			alu[BUFFER_HANDLE, --, b, _buffer_handle]
269			alu[BUFFER_START, --, b, _buffer_start]
270			alu[BUFFER_LENGTH, --, b, _buffer_length]
271			br[sync_state_done#]
272
273		copy_from_local_mem#:
274			alu[_buffer_handle, --, b, BUFFER_HANDLE]
275			alu[_buffer_start, --, b, BUFFER_START]
276			alu[_buffer_length, --, b, BUFFER_LENGTH]
277
278		sync_state_done#:
279		.end
280
281#if 0
282		/*
283		 * Debug buffer state management.
284		 */
285		.begin
286			.reg temp
287
288			alu[temp, 1, and, $rsw0, >>14]
289			beq[no_poison#]
290			immed[BUFFER_HANDLE, 0xdead]
291			immed[BUFFER_START, 0xdead]
292			immed[BUFFER_LENGTH, 0xdead]
293		no_poison#:
294
295			immed[temp, 0xdead]
296			alu[--, _buffer_handle, -, temp]
297			beq[state_corrupted#]
298			alu[--, _buffer_start, -, temp]
299			beq[state_corrupted#]
300			alu[--, _buffer_length, -, temp]
301			beq[state_corrupted#]
302		.end
303#endif
304
305		/*
306		 * Check buffer length.
307		 */
308		.begin
309			alu[--, _buffer_length, -, _packet_length]
310			blo[buffer_overflow#]
311		.end
312
313		/*
314		 * Copy the mpacket and give back the RBUF element.
315		 */
316		.begin
317			.reg element
318			.reg xfer_size
319			.reg temp
320			.sig copy_sig
321
322			alu_shf[element, 0x7f, and, $rsw0, >>24]
323			alu_shf[xfer_size, 0xff, and, $rsw0, >>16]
324
325			alu[xfer_size, xfer_size, -, 1]
326			alu_shf[xfer_size, 0x10, or, xfer_size, >>3]
327			alu_shf[temp, 0x10, or, xfer_size, <<21]
328			alu_shf[temp, temp, or, element, <<11]
329			alu_shf[--, temp, or, 1, <<18]
330
331			dram[rbuf_rd, --, _buffer_start, buffer_offset, max_8],
332						indirect_ref, sig_done[copy_sig]
333			ctx_arb[copy_sig]
334
335			alu[temp, RBUF_ELEMENT_DONE, or, element, <<16]
336			msf[fast_wr, --, temp, 0]
337		.end
338
339		/*
340		 * If EOP, write back the packet descriptor.
341		 */
342		.begin
343			.reg write $stemp $stemp2
344			.xfer_order $stemp $stemp2
345			.sig zzz
346
347			alu_shf[--, 1, and, $rsw0, >>14]
348			beq[no_writeback#]
349
350			alu[$stemp, $rsw0, and, 0x1f]
351			alu[$stemp2, --, b, _packet_length]
352			sram[write, $stemp, _buffer_handle, 8, 2], ctx_swap[zzz]
353
354		no_writeback#:
355		.end
356
357		/*
358		 * Resynchronise.
359		 */
360		.begin
361			ctx_arb[sig3]
362			local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))]
363		.end
364
365		/*
366		 * If EOP, put the buffer back onto the scratch ring.
367		 */
368		.begin
369			.reg write $stemp
370			.sig zzz
371
372			br_inp_state[SCR_Ring1_Status, rx_done_ring_overflow#]
373
374			alu_shf[--, 1, and, $rsw0, >>14]
375			beq[mpacket_receive_loop#]
376
377			alu[--, 1, and, $rsw0, >>10]
378			bne[rxerr#]
379
380			alu[$stemp, --, b, _buffer_handle]
381			scratch[put, $stemp, zero, 4, 1], ctx_swap[zzz]
382			cap[fast_wr, 0, XSCALE_INT_A]
383			br[mpacket_receive_loop#]
384
385		rxerr#:
386			alu[$stemp, --, b, _buffer_handle]
387			scratch[put, $stemp, zero, 0, 1], ctx_swap[zzz]
388			br[mpacket_receive_loop#]
389		.end
390	.end
391
392
393abort_rswerr#:
394	halt
395
396abort_proterr#:
397	halt
398
399state_corrupted#:
400	halt
401
402buffer_overflow#:
403	halt
404
405rx_done_ring_overflow#:
406	halt
407
408
409