Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[linux-2.6] / drivers / net / ixp2000 / ixp2400_rx.uc
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