diff options
Diffstat (limited to 'drivers/net/ixp2000/ixp2400_rx.uc')
-rw-r--r-- | drivers/net/ixp2000/ixp2400_rx.uc | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/drivers/net/ixp2000/ixp2400_rx.uc b/drivers/net/ixp2000/ixp2400_rx.uc new file mode 100644 index 000000000000..42a73e357afa --- /dev/null +++ b/drivers/net/ixp2000/ixp2400_rx.uc | |||
@@ -0,0 +1,408 @@ | |||
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 | |||
127 | mpacket_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 | |||
393 | abort_rswerr#: | ||
394 | halt | ||
395 | |||
396 | abort_proterr#: | ||
397 | halt | ||
398 | |||
399 | state_corrupted#: | ||
400 | halt | ||
401 | |||
402 | buffer_overflow#: | ||
403 | halt | ||
404 | |||
405 | rx_done_ring_overflow#: | ||
406 | halt | ||
407 | |||
408 | |||