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 98mpacket_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 269zero_byte_packet#: 270 halt 271 272 273