| 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 |  |