Commit | Line | Data |
---|---|---|
15d014d1 LB |
1 | /* |
2 | * TX 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 TBUF partition 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 TBUF uses 64-byte mpackets. | |
17 | * - TX descriptors reside in SRAM, and have the following format: | |
18 | * struct tx_desc | |
19 | * { | |
20 | * // to uengine | |
21 | * u32 buf_phys_addr; | |
22 | * u32 pkt_length; | |
23 | * u32 channel; | |
24 | * }; | |
25 | * - Packet data resides in DRAM. | |
26 | * - Packet buffer addresses are 8-byte aligned. | |
27 | * - Scratch ring 2 is tx_pending. | |
28 | * - Scratch ring 3 is tx_done, and has status condition 'full'. | |
29 | * - This code is run on all eight threads of the microengine it runs on. | |
30 | */ | |
31 | ||
32 | #define TX_SEQUENCE_0 0x0060 | |
33 | #define TBUF_CTRL 0x1800 | |
34 | ||
35 | #define PARTITION_SIZE 128 | |
36 | #define PARTITION_THRESH 96 | |
37 | ||
38 | ||
39 | .sig volatile sig1 | |
40 | .sig volatile sig2 | |
41 | .sig volatile sig3 | |
42 | ||
43 | .reg @old_tx_seq_0 | |
44 | .reg @mpkts_in_flight | |
45 | .reg @next_tbuf_mpacket | |
46 | ||
47 | .reg @buffer_handle | |
48 | .reg @buffer_start | |
49 | .reg @packet_length | |
50 | .reg @channel | |
51 | .reg @packet_offset | |
52 | ||
53 | .reg zero | |
54 | ||
55 | immed[zero, 0] | |
56 | ||
57 | /* | |
58 | * Skip context 0 initialisation? | |
59 | */ | |
60 | .begin | |
61 | br!=ctx[0, mpacket_tx_loop#] | |
62 | .end | |
63 | ||
64 | /* | |
65 | * Wait until all pending TBUF elements have been transmitted. | |
66 | */ | |
67 | .begin | |
68 | .reg read $tx | |
69 | .sig zzz | |
70 | ||
71 | loop_empty#: | |
72 | msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz] | |
73 | alu_shf[--, --, b, $tx, >>31] | |
74 | beq[loop_empty#] | |
75 | ||
76 | alu[@old_tx_seq_0, --, b, $tx] | |
77 | .end | |
78 | ||
79 | immed[@mpkts_in_flight, 0] | |
80 | alu[@next_tbuf_mpacket, @old_tx_seq_0, and, (PARTITION_SIZE - 1)] | |
81 | ||
82 | immed[@buffer_handle, 0] | |
83 | ||
84 | /* | |
85 | * Initialise signal pipeline. | |
86 | */ | |
87 | .begin | |
88 | local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)] | |
89 | .set_sig sig1 | |
90 | ||
91 | local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)] | |
92 | .set_sig sig2 | |
93 | ||
94 | local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)] | |
95 | .set_sig sig3 | |
96 | .end | |
97 | ||
98 | mpacket_tx_loop#: | |
99 | .begin | |
100 | .reg tbuf_element_index | |
101 | .reg buffer_handle | |
102 | .reg sop_eop | |
103 | .reg packet_data | |
104 | .reg channel | |
105 | .reg mpacket_size | |
106 | ||
107 | /* | |
108 | * If there is no packet currently being transmitted, | |
109 | * dequeue the next TX descriptor, and fetch the buffer | |
110 | * address, packet length and destination channel number. | |
111 | */ | |
112 | .begin | |
113 | .reg read $stemp $stemp2 $stemp3 | |
114 | .xfer_order $stemp $stemp2 $stemp3 | |
115 | .sig zzz | |
116 | ||
117 | ctx_arb[sig1] | |
118 | ||
119 | alu[--, --, b, @buffer_handle] | |
120 | bne[already_got_packet#] | |
121 | ||
122 | tx_nobufs#: | |
123 | scratch[get, $stemp, zero, 8, 1], ctx_swap[zzz] | |
124 | alu[@buffer_handle, --, b, $stemp] | |
125 | beq[tx_nobufs#] | |
126 | ||
127 | sram[read, $stemp, $stemp, 0, 3], ctx_swap[zzz] | |
128 | alu[@buffer_start, --, b, $stemp] | |
129 | alu[@packet_length, --, b, $stemp2] | |
130 | beq[zero_byte_packet#] | |
131 | alu[@channel, --, b, $stemp3] | |
132 | immed[@packet_offset, 0] | |
133 | ||
134 | already_got_packet#: | |
135 | local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))] | |
136 | .end | |
137 | ||
138 | /* | |
139 | * Determine tbuf element index, SOP/EOP flags, mpacket | |
140 | * offset and mpacket size and cache buffer_handle and | |
141 | * channel number. | |
142 | */ | |
143 | .begin | |
144 | alu[tbuf_element_index, --, b, @next_tbuf_mpacket] | |
145 | alu[@next_tbuf_mpacket, @next_tbuf_mpacket, +, 1] | |
146 | alu[@next_tbuf_mpacket, @next_tbuf_mpacket, and, | |
147 | (PARTITION_SIZE - 1)] | |
148 | ||
149 | alu[buffer_handle, --, b, @buffer_handle] | |
150 | immed[@buffer_handle, 0] | |
151 | ||
152 | immed[sop_eop, 1] | |
153 | ||
154 | alu[packet_data, --, b, @packet_offset] | |
155 | bne[no_sop#] | |
156 | alu[sop_eop, sop_eop, or, 2] | |
157 | no_sop#: | |
158 | alu[packet_data, packet_data, +, @buffer_start] | |
159 | ||
160 | alu[channel, --, b, @channel] | |
161 | ||
162 | alu[mpacket_size, @packet_length, -, @packet_offset] | |
163 | alu[--, 64, -, mpacket_size] | |
164 | bhs[eop#] | |
165 | alu[@buffer_handle, --, b, buffer_handle] | |
166 | immed[mpacket_size, 64] | |
167 | alu[sop_eop, sop_eop, and, 2] | |
168 | eop#: | |
169 | ||
170 | alu[@packet_offset, @packet_offset, +, mpacket_size] | |
171 | .end | |
172 | ||
173 | /* | |
174 | * Wait until there's enough space in the TBUF. | |
175 | */ | |
176 | .begin | |
177 | .reg read $tx | |
178 | .reg temp | |
179 | .sig zzz | |
180 | ||
181 | ctx_arb[sig2] | |
182 | ||
183 | br[test_space#] | |
184 | ||
185 | loop_space#: | |
186 | msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz] | |
187 | ||
188 | alu[temp, $tx, -, @old_tx_seq_0] | |
189 | alu[temp, temp, and, 0xff] | |
190 | alu[@mpkts_in_flight, @mpkts_in_flight, -, temp] | |
191 | ||
192 | alu[@old_tx_seq_0, --, b, $tx] | |
193 | ||
194 | test_space#: | |
195 | alu[--, PARTITION_THRESH, -, @mpkts_in_flight] | |
196 | blo[loop_space#] | |
197 | ||
198 | alu[@mpkts_in_flight, @mpkts_in_flight, +, 1] | |
199 | ||
200 | local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))] | |
201 | .end | |
202 | ||
203 | /* | |
204 | * Copy the packet data to the TBUF. | |
205 | */ | |
206 | .begin | |
207 | .reg temp | |
208 | .sig copy_sig | |
209 | ||
210 | alu[temp, mpacket_size, -, 1] | |
211 | alu_shf[temp, 0x10, or, temp, >>3] | |
212 | alu_shf[temp, 0x10, or, temp, <<21] | |
213 | alu_shf[temp, temp, or, tbuf_element_index, <<11] | |
214 | alu_shf[--, temp, or, 1, <<18] | |
215 | ||
216 | dram[tbuf_wr, --, packet_data, 0, max_8], | |
217 | indirect_ref, sig_done[copy_sig] | |
218 | ctx_arb[copy_sig] | |
219 | .end | |
220 | ||
221 | /* | |
222 | * Mark TBUF element as ready-to-be-transmitted. | |
223 | */ | |
224 | .begin | |
225 | .reg write $tsw $tsw2 | |
226 | .xfer_order $tsw $tsw2 | |
227 | .reg temp | |
228 | .sig zzz | |
229 | ||
230 | alu_shf[temp, channel, or, mpacket_size, <<24] | |
231 | alu_shf[$tsw, temp, or, sop_eop, <<8] | |
232 | immed[$tsw2, 0] | |
233 | ||
234 | immed[temp, TBUF_CTRL] | |
235 | alu_shf[temp, temp, or, tbuf_element_index, <<3] | |
236 | msf[write, $tsw, temp, 0, 2], ctx_swap[zzz] | |
237 | .end | |
238 | ||
239 | /* | |
240 | * Resynchronise. | |
241 | */ | |
242 | .begin | |
243 | ctx_arb[sig3] | |
244 | local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))] | |
245 | .end | |
246 | ||
247 | /* | |
248 | * If this was an EOP mpacket, recycle the TX buffer | |
249 | * and signal the host. | |
250 | */ | |
251 | .begin | |
252 | .reg write $stemp | |
253 | .sig zzz | |
254 | ||
255 | alu[--, sop_eop, and, 1] | |
256 | beq[mpacket_tx_loop#] | |
257 | ||
258 | tx_done_ring_full#: | |
259 | br_inp_state[SCR_Ring3_Status, tx_done_ring_full#] | |
260 | ||
261 | alu[$stemp, --, b, buffer_handle] | |
262 | scratch[put, $stemp, zero, 12, 1], ctx_swap[zzz] | |
263 | cap[fast_wr, 0, XSCALE_INT_A] | |
264 | br[mpacket_tx_loop#] | |
265 | .end | |
266 | .end | |
267 | ||
268 | ||
269 | zero_byte_packet#: | |
270 | halt | |
271 | ||
272 |