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 127mpacket_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 393abort_rswerr#: 394 halt 395 396abort_proterr#: 397 halt 398 399state_corrupted#: 400 halt 401 402buffer_overflow#: 403 halt 404 405rx_done_ring_overflow#: 406 halt 407 408 409