Lennert Buytenhek | 15d014d | 2005-11-11 18:23:13 +0100 | [diff] [blame] | 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 | |