|
|
1.1.1.3 ! root 1: /* $Id: i825x6.c,v 1.8 2010/06/05 14:43:27 fredette Exp $ */ 1.1 root 2: 3: /* ic/i825x6.c - implementation of the Intel 825x6 emulation: */ 4: 5: /* 6: * Copyright (c) 2004 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.3 ! root 37: _TME_RCSID("$Id: i825x6.c,v 1.8 2010/06/05 14:43:27 fredette Exp $"); 1.1.1.2 root 38: 39: /* XXX FIXME - TLB usage here is not thread-safe: */ 1.1 root 40: 41: /* includes: */ 42: #include <tme/generic/bus-device.h> 43: #include <tme/generic/ethernet.h> 44: #undef TME_I825X6_VERSION 45: #define TME_I825X6_VERSION TME_X_VERSION(0, 0) 46: #include <tme/ic/i825x6.h> 47: #include "i825x6reg.h" 48: 49: /* macros: */ 50: 51: /* these get and put values of different sizes. the values *must* be aligned: */ 52: #define TME_I825X6_GET16(bytes) tme_letoh_u16(*((const tme_uint16_t *) (bytes))) 53: #define TME_I825X6_PUT16(bytes, val) (*((tme_uint16_t *) (bytes)) = tme_htole_u16(val)) 54: #define TME_I82586_GET24(bytes) (tme_letoh_u32(*((const tme_uint32_t *) (bytes))) & 0xffffff) 55: 56: /* these read and write regions using DMA: */ 57: #define TME_I825X6_READ(address, v) \ 58: do { \ 59: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, \ 60: (address), \ 61: sizeof(v), \ 62: (tme_uint8_t *) &(v), \ 63: TME_I825X6_LOCKS_DEFAULT); \ 64: assert (rc == TME_OK); \ 65: } while (/* CONSTCOND */ 0) 66: #define TME_I825X6_WRITE(address, v) \ 67: do { \ 68: rc = tme_bus_device_dma_write_16(&i825x6->tme_i825x6_device, \ 69: (address), \ 70: sizeof(v), \ 71: (const tme_uint8_t *) &(v), \ 72: TME_I825X6_LOCKS_DEFAULT); \ 73: assert (rc == TME_OK); \ 74: } while (/* CONSTCOND */ 0) 75: 76: /* these read and write values of different sizes using DMA: */ 77: #define TME_I825X6_READ16(address, v) \ 78: do { \ 79: TME_I825X6_READ(address, value16); \ 80: v = TME_I825X6_GET16(&value16); \ 81: } while (/* CONSTCOND */ 0) 82: #define TME_I82586_READ24(address, v) \ 83: do { \ 84: TME_I825X6_READ(address, value32); \ 85: v = TME_I82586_GET24(&value32); \ 86: } while (/* CONSTCOND */ 0) 87: #define TME_I825X6_WRITE16(address, v) \ 88: do { \ 89: TME_I825X6_PUT16(&value16, v); \ 90: TME_I825X6_WRITE(address, value16); \ 91: } while (/* CONSTCOND */ 0) 92: 93: /* the "reset" stat_cus_rus_t value: */ 94: #define TME_I825X6_CA_RESET (0xffff) 95: 96: /* the address of the idle "Command Block": */ 97: #define TME_I825X6_CB_ADDRESS_IDLE (0xffffffff) 98: 99: /* an undefined Receive Unit address: */ 100: #define TME_I825X6_RU_ADDRESS_UNDEF (0xffffffff) 101: 102: /* an undefined Receive Unit offset: */ 103: #define TME_I825X6_RU_OFFSET_UNDEF (0xffff) 104: 105: /* the default locks: */ 106: #define TME_I825X6_LOCKS_DEFAULT (0) 107: 108: /* the size of the TLB entry hash: */ 109: #define TME_I825X6_TLB_HASH_SIZE (512) 110: 111: /* the callout flags: */ 112: #define TME_I825X6_CALLOUTS_CHECK (0) 113: #define TME_I825X6_CALLOUTS_RUNNING TME_BIT(0) 114: #define TME_I825X6_CALLOUTS_MASK (-2) 115: #define TME_I825X6_CALLOUT_CTRL TME_BIT(1) 116: #define TME_I825X6_CALLOUT_CONFIG TME_BIT(2) 117: #define TME_I825X6_CALLOUT_READ TME_BIT(3) 118: #define TME_I825X6_CALLOUT_INT TME_BIT(4) 119: #define TME_I825X6_CALLOUT_CA TME_BIT(5) 120: #define TME_I825X6_CALLOUT_CU TME_BIT(6) 121: 122: /* structures: */ 123: 124: /* an rx buffer: */ 125: struct tme_i825x6_rx_buffer { 126: 127: /* the generic ethernet frame chunk. this must be first, since we 128: abuse its tme_ethernet_frame_chunk_next for our own next pointer: */ 1.1.1.2 root 129: union { 130: struct tme_i825x6_rx_buffer *_tme_i825x6_rx_buffer_u_next; 131: struct tme_ethernet_frame_chunk _tme_i825x6_rx_buffer_u_frame_chunk; 132: } _tme_i825x6_rx_buffer_u; 1.1 root 133: #define TME_I825X6_RX_BUFFER_NEXT(rx_buffer) \ 1.1.1.2 root 134: ((rx_buffer)->_tme_i825x6_rx_buffer_u._tme_i825x6_rx_buffer_u_next) 135: #define tme_i825x6_rx_buffer_frame_chunk _tme_i825x6_rx_buffer_u._tme_i825x6_rx_buffer_u_frame_chunk 1.1 root 136: 137: /* when this is TME_I825X6_RU_ADDRESS_UNDEF, this rx buffer was made 138: from a fast-write TLB entry, and the generic ethernet frame chunk 139: points directly into the fast-write memory. otherwise, the 140: generic ethernet frame chunk points to a private intermediate 141: buffer, and this is the bus address to DMA the buffer back to: */ 142: tme_uint32_t tme_i825x6_rx_buffer_rb_address; 143: 144: /* when this is not TME_I825X6_RU_ADDRESS_UNDEF, this rx buffer 145: finishes filling the buffer attached to the Receive Buffer 146: Descriptor at this address, and signals the receiver to update 147: that descriptor's Size field: */ 148: tme_uint32_t tme_i825x6_rx_buffer_rbd_address; 149: }; 150: 151: /* the chip: */ 152: struct tme_i825x6 { 153: 154: /* our simple bus device header: */ 155: struct tme_bus_device tme_i825x6_device; 156: #define tme_i825x6_element tme_i825x6_device.tme_bus_device_element 157: 158: /* the Ethernet connection: */ 159: struct tme_ethernet_connection *tme_i825x6_eth_connection; 160: 161: /* the mutex protecting the chip: */ 162: tme_mutex_t tme_i825x6_mutex; 163: 164: /* the callout flags: */ 165: int tme_i825x6_callout_flags; 166: 167: /* our DMA TLB hash: */ 1.1.1.3 ! root 168: struct tme_bus_tlb tme_i825x6_tlb_hash[TME_I825X6_TLB_HASH_SIZE]; ! 169: int tme_i825x6_tlb_hash_added; 1.1 root 170: 171: /* the i825x6 bus signals: */ 172: struct tme_bus_signals tme_i825x6_bus_signals; 173: 174: /* the rx buffer free list: */ 175: struct tme_i825x6_rx_buffer *tme_i825x6_rx_buffer_free_list; 176: 177: /* this is nonzero if the next CA follows RESET: */ 178: int tme_i825x6_ca_follows_reset; 179: 180: /* the Ethernet addresses. there are always at least two addresses 181: in this array - the broadcast address and the Individual Address, 182: in that order: */ 183: unsigned int tme_i825x6_address_count; 184: tme_uint8_t *tme_i825x6_addresses; 185: 186: /* the i82586 AL-LOC value: */ 187: int tme_i825x6_al_loc; 188: 189: /* the i82586 PRM value: */ 190: int tme_i825x6_prm; 191: 192: /* the i82586 and 32-bit segmented i82596 SCB base: */ 193: tme_uint32_t tme_i825x6_scb_base; 194: 195: /* the SCB address: */ 196: tme_uint32_t tme_i825x6_scb_address; 197: 198: /* the SCB status word: */ 199: tme_uint16_t tme_i825x6_stat_cus_rus_t; 200: 201: /* the SCB Command Unit Command: */ 202: tme_uint16_t tme_i825x6_cuc; 203: 204: /* the CB address: */ 205: tme_uint32_t tme_i825x6_cb_address; 206: 207: /* the CB status word: */ 208: tme_uint16_t tme_i825x6_c_b_ok_a; 209: 210: /* the CB command word: */ 211: tme_uint16_t tme_i825x6_el_s_i_cmd; 212: 213: /* the next CB address: */ 214: tme_uint32_t tme_i825x6_cb_address_next; 215: 216: /* the RFD address: */ 217: tme_uint32_t tme_i825x6_rfd_address; 218: 219: /* the Free Buffer List: */ 220: struct tme_i825x6_rx_buffer *tme_i825x6_fbl; 221: 222: /* the size of all buffers on the Free Buffer List: */ 223: tme_uint32_t tme_i825x6_fbl_size; 224: 225: /* the address of the offset of the next free RBD: */ 226: tme_uint32_t tme_i825x6_rbd_offset_address; 227: }; 228: 229: /* prototypes: */ 230: static void _tme_i825x6_abort_ru _TME_P((struct tme_i825x6 *)); 231: 232: /* globals: */ 233: static const struct tme_bus_signals _tme_i825x6_bus_signals = TME_BUS_SIGNALS_I825X6; 234: 235: /* this resets the i825x6: */ 236: static void 237: _tme_i825x6_reset(struct tme_i825x6 *i825x6) 238: { 239: 240: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 241: 100, TME_OK, 242: (&i825x6->tme_i825x6_element->tme_element_log_handle, 243: "reset")); 244: 245: /* clear all pending callouts: */ 246: i825x6->tme_i825x6_callout_flags &= TME_I825X6_CALLOUTS_MASK; 247: 248: /* abort the Receive Unit: */ 249: _tme_i825x6_abort_ru(i825x6); 250: 251: /* the Receive Unit is now Idle: */ 252: i825x6->tme_i825x6_stat_cus_rus_t 253: = ((i825x6->tme_i825x6_stat_cus_rus_t 254: & ~TME_I82586_SCB_RUS_MASK) 255: | TME_I825X6_SCB_RUS_IDLE); 256: 257: /* we have no packet to transmit: */ 258: i825x6->tme_i825x6_el_s_i_cmd = TME_I825X6_CB_CMD_NOP; 259: 260: /* if the interrupt line is currently asserted, negate it: */ 261: if (i825x6->tme_i825x6_stat_cus_rus_t 262: & TME_I825X6_SCB_STAT_MASK) { 263: i825x6->tme_i825x6_stat_cus_rus_t &= ~TME_I825X6_SCB_STAT_MASK; 264: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_INT; 265: } 266: 267: /* initialize the address list to match two addresses - the 268: broadcast address, and the Individual Address (which is 269: initially the same as the broadcast address): */ 270: i825x6->tme_i825x6_address_count = 2; 271: memcpy (i825x6->tme_i825x6_addresses, 272: &tme_ethernet_addr_broadcast[0], 273: TME_ETHERNET_ADDR_SIZE); 274: memcpy (i825x6->tme_i825x6_addresses + TME_ETHERNET_ADDR_SIZE, 275: &tme_ethernet_addr_broadcast[0], 276: TME_ETHERNET_ADDR_SIZE); 277: 278: /* the next CA follows RESET: */ 279: i825x6->tme_i825x6_ca_follows_reset = TRUE; 280: } 281: 282: /* this hashes an address into a TLB entry: */ 283: static struct tme_bus_tlb * 284: _tme_i825x6_tlb_hash(void *_i825x6, 285: tme_bus_addr_t linear_address, 286: unsigned int cycles) 287: { 288: struct tme_i825x6 *i825x6; 289: 290: /* recover our data structure: */ 291: i825x6 = (struct tme_i825x6 *) _i825x6; 292: 293: /* return the TLB entry: */ 1.1.1.3 ! root 294: return (i825x6->tme_i825x6_tlb_hash ! 295: + ((((tme_bus_addr32_t) linear_address) >> 10) & (TME_I825X6_TLB_HASH_SIZE - 1))); 1.1 root 296: } 297: 298: /* this locks the mutex: */ 299: static void 300: _tme_i825x6_lock(void *_i825x6, 301: unsigned int locks) 302: { 303: struct tme_i825x6 *i825x6; 304: 305: /* recover our data structure: */ 306: i825x6 = (struct tme_i825x6 *) _i825x6; 307: 308: /* lock the mutex: */ 309: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 310: } 311: 312: /* this unlocks the mutex: */ 313: static void 314: _tme_i825x6_unlock(void *_i825x6, 315: unsigned int locks) 316: { 317: struct tme_i825x6 *i825x6; 318: 319: /* recover our data structure: */ 320: i825x6 = (struct tme_i825x6 *) _i825x6; 321: 322: /* unlock the mutex: */ 323: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 324: } 325: 326: /* this frees an rx buffer: */ 327: static struct tme_i825x6_rx_buffer * 328: _tme_i825x6_rx_buffer_free(struct tme_i825x6 *i825x6, 329: struct tme_i825x6_rx_buffer *rx_buffer) 330: { 331: struct tme_i825x6_rx_buffer *rx_buffer_next; 332: 333: /* get the next rx buffer: */ 334: rx_buffer_next = TME_I825X6_RX_BUFFER_NEXT(rx_buffer); 335: 336: /* put this rx buffer on the free list: */ 337: TME_I825X6_RX_BUFFER_NEXT(rx_buffer) = i825x6->tme_i825x6_rx_buffer_free_list; 338: i825x6->tme_i825x6_rx_buffer_free_list = rx_buffer; 339: 340: /* return the next rx buffer: */ 341: return (rx_buffer_next); 342: } 343: 344: /* this allocates a rx buffer: */ 345: static struct tme_i825x6_rx_buffer * 346: _tme_i825x6_rx_buffer_new(struct tme_i825x6 *i825x6, 347: struct tme_i825x6_rx_buffer ***__prev) 348: { 349: struct tme_i825x6_rx_buffer *rx_buffer, **_prev; 350: 351: /* if the free list is not empty: */ 352: rx_buffer = i825x6->tme_i825x6_rx_buffer_free_list; 353: if (rx_buffer != NULL) { 354: 355: /* remove this rx buffer from the free list: */ 356: i825x6->tme_i825x6_rx_buffer_free_list = TME_I825X6_RX_BUFFER_NEXT(rx_buffer); 357: } 358: 359: /* otherwise, the free list is empty: */ 360: else { 361: 362: /* allocate a new rx buffer: */ 363: rx_buffer = tme_new(struct tme_i825x6_rx_buffer, 1); 364: 365: /* treat this as an old fast-write TLB entry: */ 366: rx_buffer->tme_i825x6_rx_buffer_rb_address = TME_I825X6_RU_ADDRESS_UNDEF; 367: } 368: 369: /* add this new rx buffer to the list: */ 370: _prev = *__prev; 371: *_prev = rx_buffer; 372: _prev = &TME_I825X6_RX_BUFFER_NEXT(rx_buffer); 373: *__prev = _prev; 374: 375: /* return the new buffer: */ 376: return (rx_buffer); 377: } 378: 379: /* given a bus address and a size, this adds rx buffers to a list: */ 380: static struct tme_i825x6_rx_buffer * 381: _tme_i825x6_rx_buffers_add(struct tme_i825x6 *i825x6, 382: tme_uint32_t address_init, 383: tme_uint32_t size, 384: struct tme_i825x6_rx_buffer ***__prev) 385: { 386: struct tme_i825x6_rx_buffer *rx_buffer, **_prev; 387: struct tme_bus_tlb *tlb, tlb_local; 388: struct tme_bus_connection *conn_bus; 1.1.1.3 ! root 389: tme_bus_addr32_t count_minus_one, count; ! 390: tme_bus_addr32_t tlb_addr_last; 1.1 root 391: int err; 392: 393: /* recover the rx buffers list: */ 394: _prev = *__prev; 395: 396: /* there isn't a last rx buffer yet: */ 397: rx_buffer = NULL; 398: 399: /* loop while we have more addresses to cover: */ 400: for (; size > 0; ) { 401: 402: /* hash this address into a TLB entry: */ 403: tlb = _tme_i825x6_tlb_hash(i825x6, 404: address_init, 405: TME_BUS_CYCLE_WRITE); 1.1.1.2 root 406: 407: /* busy this TLB entry: */ 408: tme_bus_tlb_busy(tlb); 1.1 root 409: 1.1.1.2 root 410: /* if this TLB entry is invalid, or doesn't cover this address, or 411: if it doesn't allow writing, reload it: */ 412: tlb_addr_last = tlb->tme_bus_tlb_addr_last; 413: if (tme_bus_tlb_is_invalid(tlb) 1.1.1.3 ! root 414: || address_init < (tme_bus_addr32_t) tlb->tme_bus_tlb_addr_first 1.1 root 415: || address_init > tlb_addr_last 416: || (tlb->tme_bus_tlb_emulator_off_write == TME_EMULATOR_OFF_UNDEF 417: && !(tlb->tme_bus_tlb_cycles_ok & TME_BUS_CYCLE_WRITE))) { 1.1.1.2 root 418: 419: /* unbusy this TLB entry for filling: */ 420: tme_bus_tlb_unbusy_fill(tlb); 1.1 root 421: 1.1.1.3 ! root 422: /* pass this TLB's token: */ ! 423: tlb_local.tme_bus_tlb_token = tlb->tme_bus_tlb_token; 1.1 root 424: 425: /* get our bus connection: */ 1.1.1.2 root 426: conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *, 427: i825x6->tme_i825x6_device.tme_bus_device_connection, 428: &i825x6->tme_i825x6_device.tme_bus_device_connection_rwlock); 1.1 root 429: 430: /* unlock the mutex: */ 431: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 432: 433: /* reload the TLB entry: */ 434: err = (*conn_bus->tme_bus_tlb_fill) 435: (conn_bus, 1.1.1.3 ! root 436: &tlb_local, 1.1 root 437: address_init, 438: TME_BUS_CYCLE_WRITE); 439: 440: /* lock the mutex: */ 441: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 442: 443: /* XXX we could create a poison frame chunk instead of 444: aborting: */ 445: if (err != TME_OK) { 446: abort(); 447: } 448: 449: /* store the TLB entry: */ 1.1.1.3 ! root 450: *tlb = tlb_local; 1.1.1.2 root 451: 452: /* loop to check the newly filled TLB entry: */ 453: continue; 1.1 root 454: } 455: 456: /* see how many addresses we can cover with this TLB entry, 457: starting at this address: */ 458: count_minus_one = (tlb_addr_last - address_init); 459: count_minus_one = TME_MIN(count_minus_one, 460: (size - 1)); 461: count = count_minus_one + 1; 462: assert (count != 0); 463: 464: /* allocate another rx buffer: */ 465: rx_buffer = _tme_i825x6_rx_buffer_new(i825x6, &_prev); 466: 467: /* if this TLB entry allows fast writing: */ 468: if (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) { 469: 470: /* if this rx buffer was previously a slow rx buffer, free its 471: chunk buffer: */ 472: if (rx_buffer->tme_i825x6_rx_buffer_rb_address != TME_I825X6_RU_ADDRESS_UNDEF) { 473: tme_free(rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes); 474: } 475: 476: /* this is a fast rx buffer: */ 477: rx_buffer->tme_i825x6_rx_buffer_rb_address = TME_I825X6_RU_ADDRESS_UNDEF; 478: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes 1.1.1.2 root 479: /* XXX FIXME - this breaks volatile: */ 480: = (tme_uint8_t *) tlb->tme_bus_tlb_emulator_off_write + address_init; 481: 482: /* unbusy the TLB: */ 483: /* XXX FIXME - this is not thread-safe: */ 484: tme_bus_tlb_unbusy(tlb); 1.1 root 485: } 486: 487: /* otherwise, this TLB entry does not allow fast writing: */ 488: else { 489: 490: /* if this rx buffer was previously a fast rx buffer, 491: allocate a new chunk buffer: */ 492: if (rx_buffer->tme_i825x6_rx_buffer_rb_address == TME_I825X6_RU_ADDRESS_UNDEF) { 493: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes 494: = tme_new(tme_uint8_t, 495: count); 496: } 497: 498: /* otherwise, if this rx buffer was previously a slow receive 499: buffer, with a chunk buffer smaller than what we need, 500: reallocate the chunk buffer: */ 501: else if (rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count 502: < count) { 503: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes 504: = tme_renew(tme_uint8_t, 505: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes, 506: count); 507: } 508: 509: /* this is a slow frame chunk: */ 510: rx_buffer->tme_i825x6_rx_buffer_rb_address = address_init; 511: } 512: 513: /* finish this rx buffer: */ 514: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count = count; 515: rx_buffer->tme_i825x6_rx_buffer_rbd_address = TME_I825X6_RU_ADDRESS_UNDEF; 516: 517: /* update the address and size: */ 518: address_init += count; 519: size -= count; 520: } 521: 522: /* update the rx buffers list end: */ 523: *__prev = _prev; 524: 525: /* return the last rx buffer: */ 526: return (rx_buffer); 527: } 528: 529: /* this refills the Free Buffer List: */ 530: static tme_uint16_t 531: _tme_i825x6_fbl_refill(struct tme_i825x6 *i825x6, int from_rfd) 532: { 533: struct tme_i825x6_rx_buffer *rx_buffer, **_prev; 534: tme_uint32_t fbl_size; 535: tme_uint32_t rbd_offset_address, rbd_address, rb_address; 536: tme_uint16_t rbd_offset, rbd_offset_first; 537: tme_uint16_t el_p_size; 538: tme_uint16_t size; 539: tme_uint32_t value32; 540: tme_uint16_t value16; 541: int rc; 542: 543: /* assume that there are no free Receive Buffer Descriptors: */ 544: rbd_offset_first = TME_I825X6_RU_OFFSET_UNDEF; 545: 546: /* find the end of the Free Buffer List: */ 547: for (_prev = &i825x6->tme_i825x6_fbl; 548: (rx_buffer = *_prev) != NULL; 549: _prev = &TME_I825X6_RX_BUFFER_NEXT(rx_buffer)) { 550: 551: /* if we don't have the first free Receive Buffer Descriptor yet, 552: and this is the last rx buffer for a Receive Buffer, its 553: Receive Buffer Descriptor is the first free one: */ 554: rbd_address = rx_buffer->tme_i825x6_rx_buffer_rbd_address; 555: if (rbd_offset_first == TME_I825X6_RU_OFFSET_UNDEF 556: && rbd_address != TME_I825X6_RU_ADDRESS_UNDEF) { 557: rbd_offset_first = rbd_address - i825x6->tme_i825x6_scb_base; 558: } 559: } 560: 561: /* get the address of the next RBD offset: */ 562: rbd_offset_address = i825x6->tme_i825x6_rbd_offset_address; 563: 564: /* stop now if the address of the next RBD offset is undefined: */ 565: if (rbd_offset_address == TME_I825X6_RU_ADDRESS_UNDEF) { 566: return (rbd_offset_first); 567: } 568: 569: /* get the current size of the Free Buffer List: */ 570: fbl_size = i825x6->tme_i825x6_fbl_size; 571: 572: /* turn Receive Buffers into rx buffers on the Free Buffer List, 573: until the Free Buffer List has a maximum-sized Ethernet frame's 574: worth of buffers: */ 575: for (; fbl_size < TME_ETHERNET_FRAME_MAX; ) { 576: 577: /* read in the Receive Buffer Descriptor offset: */ 578: TME_I825X6_READ16(rbd_offset_address, 579: rbd_offset); 580: 581: /* if this Receive Buffer Descriptor offset is in an RFD, stop if 582: the offset is all-bits-one, indicating no RBDs: */ 583: if (from_rfd 584: && rbd_offset == TME_I825X6_RU_OFFSET_UNDEF) { 585: break; 586: } 587: from_rfd = FALSE; 588: 589: /* if we don't have the first free Receive Buffer Descriptor yet, 590: this is it: */ 591: if (rbd_offset_first == TME_I825X6_RU_OFFSET_UNDEF) { 592: rbd_offset_first = rbd_offset; 593: } 594: 595: /* make the Receive Buffer Descriptor address: */ 596: rbd_address = i825x6->tme_i825x6_scb_base + rbd_offset; 597: 598: /* read in the Receive Buffer address: */ 599: TME_I82586_READ24((rbd_address 600: + TME_I82586_RBD_RB_ADDRESS), 601: rb_address); 602: 603: /* read in the EL_P_SIZE field: */ 604: TME_I825X6_READ16((rbd_address 605: + TME_I82586_RBD_EL_P_SIZE), 606: el_p_size); 607: 608: /* get the size of this Receive Buffer: */ 609: size = el_p_size & TME_I825X6_RBD_SIZE_MASK; 610: 611: /* if this Receive Buffer has zero size, stop now. this can 612: happen with NetBSD 1.6.x, which zeroes and reinitializes the 613: memory for the i825x6 without stopping the Receive Unit: */ 614: if (size == 0) { 615: 616: /* log a complaint: */ 617: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 618: 0, EBADF, 619: (&i825x6->tme_i825x6_element->tme_element_log_handle, 620: _("caught an empty Receive Buffer"))); 621: 622: break; 623: } 624: 625: /* add this Receive Buffer to the rx buffers: */ 626: rx_buffer = _tme_i825x6_rx_buffers_add(i825x6, 627: rb_address, 628: size, 629: &_prev); 630: 631: /* on the last rx buffer for a Receive Buffer, set the address of 632: the Receive Buffer Descriptor, so we can update its size field: */ 633: rx_buffer->tme_i825x6_rx_buffer_rbd_address = rbd_address; 634: 635: /* update the amount of space on the Free Buffer list: */ 636: fbl_size += size; 637: 638: /* if this is the last Receive Buffer Descriptor: */ 639: if (el_p_size & TME_I825X6_RBD_EL) { 640: 641: /* the address of the next RBD offset is undefined: */ 642: rbd_offset_address = TME_I825X6_RU_ADDRESS_UNDEF; 643: 644: /* stop now: */ 645: break; 646: } 647: 648: /* get the address of the next RBD offset: */ 649: rbd_offset_address 650: = (rbd_address 651: + TME_I82586_RBD_RBD_OFFSET); 652: } 653: 654: /* terminate the Free Buffer List: */ 655: *_prev = NULL; 656: 657: /* save the current size of the Free Buffer List: */ 658: i825x6->tme_i825x6_fbl_size = fbl_size; 659: 660: /* save the address of the next RBD offset: */ 661: i825x6->tme_i825x6_rbd_offset_address = rbd_offset_address; 662: 663: /* return the address of the first free Receive Buffer Descriptor: */ 664: return (rbd_offset_first); 665: } 666: 667: /* this aborts the Receive Unit: */ 668: static void 669: _tme_i825x6_abort_ru(struct tme_i825x6 *i825x6) 670: { 671: struct tme_i825x6_rx_buffer *rx_buffer; 672: 673: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 674: 100, TME_OK, 675: (&i825x6->tme_i825x6_element->tme_element_log_handle, 676: "RU abort")); 677: 678: /* free the Free Buffer List: */ 679: for (rx_buffer = i825x6->tme_i825x6_fbl; 680: rx_buffer != NULL; 681: rx_buffer = _tme_i825x6_rx_buffer_free(i825x6, rx_buffer)); 682: 683: /* the Receive Unit now has no resources: */ 684: i825x6->tme_i825x6_rfd_address = TME_I825X6_RU_ADDRESS_UNDEF; 685: i825x6->tme_i825x6_rbd_offset_address = TME_I825X6_RU_ADDRESS_UNDEF; 686: i825x6->tme_i825x6_fbl = NULL; 687: i825x6->tme_i825x6_fbl_size = 0; 688: } 689: 690: /* this does a DMA directly into transmit frame chunks: */ 691: static int 692: _tme_i825x6_chunks_dma_tx(struct tme_i825x6 *i825x6, 693: struct tme_ethernet_frame_chunk *frame_chunks, 694: tme_uint32_t address, 695: tme_uint32_t size) 696: { 697: tme_uint32_t count; 698: int rc; 699: 700: /* while we have bytes left to DMA: */ 701: for (; size > 0; ) { 702: 703: /* get the count of bytes to copy in this iteration: */ 704: count = frame_chunks->tme_ethernet_frame_chunk_bytes_count; 705: if (count == 0) { 706: break; 707: } 708: count = TME_MIN(count, size); 709: 710: /* do the copy: */ 711: /* XXX FIXME this assumes an i82586: */ 712: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, 713: address, 714: count, 715: frame_chunks->tme_ethernet_frame_chunk_bytes, 716: TME_I825X6_LOCKS_DEFAULT); 717: if (rc != TME_OK) { 718: return (rc); 719: } 720: 721: /* update: */ 722: size -= count; 723: frame_chunks->tme_ethernet_frame_chunk_bytes += count; 724: if ((frame_chunks->tme_ethernet_frame_chunk_bytes_count -= count) == 0 725: && frame_chunks->tme_ethernet_frame_chunk_next != NULL) { 726: *frame_chunks = *frame_chunks->tme_ethernet_frame_chunk_next; 727: } 728: } 729: 730: /* success: */ 731: return (TME_OK); 732: } 733: 734: /* this does a memcpy directly into transmit frame chunks: */ 735: static void 736: _tme_i825x6_chunks_mem_tx(struct tme_ethernet_frame_chunk *frame_chunks, 737: const tme_uint8_t *data, 738: unsigned int size) 739: { 740: unsigned int count; 741: 742: /* while we have bytes left to copy: */ 743: for (; size > 0; ) { 744: 745: /* get the count of bytes to copy in this iteration: */ 746: count = frame_chunks->tme_ethernet_frame_chunk_bytes_count; 747: if (count == 0) { 748: break; 749: } 750: count = TME_MIN(count, size); 751: 752: /* do the copy: */ 753: memcpy(frame_chunks->tme_ethernet_frame_chunk_bytes, 754: data, 755: count); 756: 757: /* update: */ 758: size -= count; 759: frame_chunks->tme_ethernet_frame_chunk_bytes += count; 760: if ((frame_chunks->tme_ethernet_frame_chunk_bytes_count -= count) == 0 761: && frame_chunks->tme_ethernet_frame_chunk_next != NULL) { 762: *frame_chunks = *frame_chunks->tme_ethernet_frame_chunk_next; 763: } 764: } 765: } 766: 767: /* this is called to handle a Channel Attention (CA) callout: */ 768: static tme_uint16_t 769: _tme_i825x6_callout_ca(struct tme_i825x6 *i825x6, tme_uint16_t stat_cus_rus_t) 770: { 771: tme_uint8_t scp[TME_I825X6_SCP_SIZE]; 772: tme_uint32_t iscp_address, rfd_offset; 773: tme_uint8_t iscp[TME_I825X6_ISCP_SIZE]; 774: tme_uint16_t ack_cuc_r_ruc; 775: tme_uint16_t cuc; 776: tme_uint16_t value16; 777: tme_uint16_t rbd_offset_first; 778: int rc; 779: 780: /* if this CA follows RESET: */ 781: if (i825x6->tme_i825x6_ca_follows_reset) { 782: 783: /* the next CA will not follow RESET: */ 784: i825x6->tme_i825x6_ca_follows_reset = FALSE; 785: 786: /* read in the SCP: */ 787: TME_I825X6_READ(TME_I825X6_SCP_ADDRESS, scp); 788: 789: /* check the SYSBUS byte: */ 790: assert ((scp[TME_I825X6_SCP_SYSBUS] 791: & TME_I825X6_SCP_SYSBUS_MODE_MASK) 792: == TME_I825X6_SCP_SYSBUS_MODE_82586); 793: 794: /* get the ISCP address: */ 795: iscp_address = TME_I82586_GET24(&scp[TME_I825X6_SCP_ISCP_ADDRESS]); 796: 797: /* read in the ISCP: */ 798: TME_I825X6_READ(iscp_address, iscp); 799: 800: /* get the SCB base and SCB address: */ 801: i825x6->tme_i825x6_scb_base = TME_I82586_GET24(&iscp[TME_I82586_ISCP_SCB_BASE]); 802: i825x6->tme_i825x6_scb_address 803: = (i825x6->tme_i825x6_scb_base 804: + TME_I825X6_GET16(&iscp[TME_I82586_ISCP_SCB_OFFSET])); 805: 806: /* "The 82596 clears BUSY": */ 807: iscp[TME_I825X6_ISCP_BUSY] = 0; 808: TME_I825X6_WRITE((iscp_address 809: + TME_I825X6_ISCP_BUSY), 810: iscp[TME_I825X6_ISCP_BUSY]); 811: 812: /* "The 82596 ... sets CX and CNR to equal 1 in the SCB": */ 813: stat_cus_rus_t 814: = (TME_I825X6_SCB_STAT_CX 815: | TME_I825X6_SCB_STAT_CNA 816: | TME_I825X6_SCB_CUS_IDLE 817: | TME_I825X6_SCB_RUS_IDLE); 818: 819: /* "The 82596 ... sends an interrupt to the CPU": */ 820: i825x6->tme_i825x6_callout_flags = TME_I825X6_CALLOUTS_RUNNING | TME_I825X6_CALLOUT_INT; 821: } 822: 823: /* otherwise, this CA does not follow RESET: */ 824: else { 825: 826: /* read in the SCB command word: */ 827: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address 828: + TME_I825X6_SCB_ACK_CUC_R_RUC), 829: ack_cuc_r_ruc); 830: 831: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 832: 100, TME_OK, 833: (&i825x6->tme_i825x6_element->tme_element_log_handle, 834: "SCB command 0x%04x", 835: ack_cuc_r_ruc)); 836: 837: /* handle a Reset: */ 838: if (ack_cuc_r_ruc & TME_I825X6_SCB_RESET) { 839: _tme_i825x6_reset(i825x6); 840: return (TME_I825X6_CA_RESET); 841: } 842: 843: /* clear any acknowledged Status bits: */ 844: stat_cus_rus_t 845: &= ~(ack_cuc_r_ruc 846: & TME_I825X6_SCB_STAT_MASK); 847: 848: /* if the Command Unit Command isn't a NOP: */ 849: cuc = (ack_cuc_r_ruc 850: & TME_I825X6_SCB_CUC_MASK); 851: if (cuc != TME_I825X6_SCB_CUC_NOP) { 852: 853: /* set this Command Unit Command: */ 854: i825x6->tme_i825x6_cuc = cuc; 855: 856: /* if the Command Unit Command is an Abort, or if the Command 857: Unit isn't already Active, run the Command Unit: */ 858: if ((cuc == TME_I825X6_SCB_CUC_ABORT) 859: || ((stat_cus_rus_t 860: & TME_I825X6_SCB_CUS_MASK) 861: != TME_I825X6_SCB_CUS_ACTIVE)) { 862: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_CU; 863: } 864: } 865: 866: /* dispatch on the Receive Unit command: */ 867: switch (ack_cuc_r_ruc & TME_I825X6_SCB_RUC_MASK) { 868: 869: case TME_I825X6_SCB_RUC_NOP: 870: break; 871: 872: case TME_I825X6_SCB_RUC_START: 873: 1.1.1.2 root 874: /* if the Receive Unit is not Idle: */ 1.1 root 875: switch (stat_cus_rus_t & TME_I82586_SCB_RUS_MASK) { 876: case TME_I825X6_SCB_RUS_READY: 877: case TME_I825X6_SCB_RUS_SUSPENDED: 1.1.1.2 root 878: case TME_I825X6_SCB_RUS_ERESOURCE: 1.1 root 879: 880: /* abort the Receive Unit: */ 881: _tme_i825x6_abort_ru(i825x6); 882: break; 883: 884: case TME_I825X6_SCB_RUS_IDLE: 885: break; 886: 887: default: 888: abort(); 889: } 890: 891: /* the Receive Unit must have no resources: */ 892: assert (i825x6->tme_i825x6_rfd_address == TME_I825X6_RU_ADDRESS_UNDEF); 893: assert (i825x6->tme_i825x6_rbd_offset_address == TME_I825X6_RU_ADDRESS_UNDEF); 894: assert (i825x6->tme_i825x6_fbl == NULL && i825x6->tme_i825x6_fbl_size == 0); 895: 896: /* get the RFD offset from the SCB: */ 897: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address 898: + TME_I82586_SCB_RFA_OFFSET), 899: rfd_offset); 900: 901: /* if the RFD offset is defined: */ 902: if (rfd_offset != TME_I825X6_RU_OFFSET_UNDEF) { 903: 904: /* set the RFD address: */ 905: i825x6->tme_i825x6_rfd_address 906: = (i825x6->tme_i825x6_scb_base 907: + rfd_offset); 908: 909: /* set the RBD offset address: */ 910: i825x6->tme_i825x6_rbd_offset_address 911: = (i825x6->tme_i825x6_rfd_address 912: + TME_I82586_RFD_RBD_OFFSET); 913: 914: /* refill the Free Buffer List: */ 915: rbd_offset_first = _tme_i825x6_fbl_refill(i825x6, TRUE); 916: 917: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 918: 100, TME_OK, 919: (&i825x6->tme_i825x6_element->tme_element_log_handle, 920: "RU start RFD 0x%06x RBD 0x%04x", 921: i825x6->tme_i825x6_rfd_address, 922: rbd_offset_first)); 923: } 924: 925: /* FALLTHROUGH: */ 926: case TME_I825X6_SCB_RUC_RESUME: 927: 928: /* the Receive Unit is now Ready: */ 929: stat_cus_rus_t 930: = ((stat_cus_rus_t 931: & ~TME_I82586_SCB_RUS_MASK) 932: | TME_I825X6_SCB_RUS_READY); 933: break; 934: 935: case TME_I825X6_SCB_RUC_SUSPEND: 936: 937: /* the Receive Unit is now Suspended: */ 938: stat_cus_rus_t 939: = ((stat_cus_rus_t 940: & ~TME_I82586_SCB_RUS_MASK) 941: | TME_I825X6_SCB_RUS_SUSPENDED); 942: break; 943: 944: case TME_I825X6_SCB_RUC_ABORT: 945: 946: /* abort the Receive Unit: */ 947: _tme_i825x6_abort_ru(i825x6); 948: 949: /* the Receive Unit is now Idle: */ 950: stat_cus_rus_t 951: = ((stat_cus_rus_t 952: & ~TME_I82586_SCB_RUS_MASK) 953: | TME_I825X6_SCB_RUS_IDLE); 954: break; 955: 956: default: 957: abort(); 958: } 959: } 960: 961: /* always clear the SCB command word after a CA: */ 962: TME_I825X6_WRITE16((i825x6->tme_i825x6_scb_address 963: + TME_I825X6_SCB_ACK_CUC_R_RUC), 964: 0); 965: 966: /* return the current status word: */ 967: return (stat_cus_rus_t); 968: } 969: 970: /* this is called to handle a Command Unit (CU) callout: */ 971: static tme_uint16_t 972: _tme_i825x6_callout_cu(struct tme_i825x6 *i825x6, tme_uint16_t stat_cus_rus_t) 973: { 974: tme_uint16_t cuc; 975: tme_uint16_t el_s_i_cmd; 976: tme_uint16_t mc_count; 977: tme_uint8_t config_bytes[12]; 978: unsigned int config_byte_count; 979: unsigned int callouts; 980: tme_uint16_t value16; 981: int rc; 982: 983: /* get the SCB Command Unit Command: */ 984: cuc = i825x6->tme_i825x6_cuc; 985: 986: /* if the Command Unit was active, complete the command that it 987: was working on: */ 988: if ((stat_cus_rus_t 989: & TME_I825X6_SCB_CUS_MASK) 990: == TME_I825X6_SCB_CUS_ACTIVE) { 991: 992: /* finish the CB status word. clear B, and set C. if the 993: command was aborted, clear OK and set A, else set OK and 994: clear A: */ 995: i825x6->tme_i825x6_c_b_ok_a 996: = ((i825x6->tme_i825x6_c_b_ok_a 997: & ~TME_I825X6_FLAG_B) 998: | TME_I825X6_FLAG_C 999: | TME_I825X6_FLAG_OK 1000: | TME_I825X6_CB_A); 1001: i825x6->tme_i825x6_c_b_ok_a 1002: ^= ((cuc 1003: == TME_I825X6_SCB_CUC_ABORT) 1004: ? TME_I825X6_FLAG_OK 1005: : TME_I825X6_CB_A); 1006: 1007: /* write the CB status word: */ 1008: TME_I825X6_WRITE16((i825x6->tme_i825x6_cb_address 1009: + TME_I825X6_CB_C_B_OK_A), 1010: i825x6->tme_i825x6_c_b_ok_a); 1011: 1012: /* if this command had the I bit set, set CX: */ 1013: if (i825x6->tme_i825x6_el_s_i_cmd & TME_I825X6_CB_I) { 1014: stat_cus_rus_t |= TME_I825X6_SCB_STAT_CX; 1015: } 1016: 1017: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 1018: 100, TME_OK, 1019: (&i825x6->tme_i825x6_element->tme_element_log_handle, 1020: "CU finish 0x%06x status 0x%04x", 1021: i825x6->tme_i825x6_cb_address, 1022: i825x6->tme_i825x6_c_b_ok_a)); 1023: } 1024: 1025: /* dispatch on the Command Unit command: */ 1026: switch (cuc) { 1027: 1028: case TME_I825X6_SCB_CUC_NOP: 1029: break; 1030: 1031: case TME_I825X6_SCB_CUC_START: 1032: 1033: /* get the CBL address: */ 1034: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address 1035: + TME_I82586_SCB_CBL_OFFSET), 1036: i825x6->tme_i825x6_cb_address_next); 1037: i825x6->tme_i825x6_cb_address_next += i825x6->tme_i825x6_scb_base; 1038: 1039: /* FALLTHROUGH */ 1040: case TME_I825X6_SCB_CUC_RESUME: 1041: 1042: /* the Command Unit is now active: */ 1043: stat_cus_rus_t 1044: = ((stat_cus_rus_t 1045: & ~TME_I825X6_SCB_CUS_MASK) 1046: | TME_I825X6_SCB_CUS_ACTIVE); 1047: break; 1048: 1049: case TME_I825X6_SCB_CUC_ABORT: 1050: 1051: /* the Command Unit is now Idle: */ 1052: stat_cus_rus_t 1053: = ((stat_cus_rus_t 1054: & ~TME_I825X6_SCB_CUS_MASK) 1055: | TME_I825X6_SCB_CUS_IDLE); 1056: break; 1057: 1058: case TME_I825X6_SCB_CUC_SUSPEND: 1059: 1060: /* the Command Unit is now Suspended: */ 1061: stat_cus_rus_t 1062: = ((stat_cus_rus_t 1063: & ~TME_I825X6_SCB_CUS_MASK) 1064: | TME_I825X6_SCB_CUS_SUSPENDED); 1065: break; 1066: 1067: default: 1068: abort(); 1069: } 1070: 1071: /* if the Command Unit is not active, return now: */ 1072: if ((stat_cus_rus_t 1073: & TME_I825X6_SCB_CUS_MASK) 1074: != TME_I825X6_SCB_CUS_ACTIVE) { 1075: return (stat_cus_rus_t); 1076: } 1077: 1078: /* advance to the next command: */ 1079: i825x6->tme_i825x6_cb_address = i825x6->tme_i825x6_cb_address_next; 1080: 1081: /* if there is no next command, the Command Unit is now Idle: */ 1082: if (i825x6->tme_i825x6_cb_address == TME_I825X6_CB_ADDRESS_IDLE) { 1083: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 1084: 100, TME_OK, 1085: (&i825x6->tme_i825x6_element->tme_element_log_handle, 1086: "CU idle")); 1087: stat_cus_rus_t 1088: = ((stat_cus_rus_t 1089: & ~TME_I825X6_SCB_CUS_MASK) 1090: | TME_I825X6_SCB_CUS_IDLE); 1091: return (stat_cus_rus_t); 1092: } 1093: 1094: /* start the CB status word: */ 1095: i825x6->tme_i825x6_c_b_ok_a = TME_I825X6_FLAG_B; 1096: TME_I825X6_WRITE16((i825x6->tme_i825x6_cb_address 1097: + TME_I825X6_CB_C_B_OK_A), 1098: i825x6->tme_i825x6_c_b_ok_a); 1099: 1100: /* get the CB command word: */ 1101: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address 1102: + TME_I825X6_CB_EL_S_I_CMD), 1103: i825x6->tme_i825x6_el_s_i_cmd); 1104: el_s_i_cmd = i825x6->tme_i825x6_el_s_i_cmd; 1105: 1106: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 1107: 100, TME_OK, 1108: (&i825x6->tme_i825x6_element->tme_element_log_handle, 1109: "CU start 0x%06x el_s_i_cmd 0x%04x", 1110: i825x6->tme_i825x6_cb_address, 1111: el_s_i_cmd)); 1112: 1113: /* if EL is set, there is no next Command Block, and when 1114: the Command Unit tries to execute the next command it 1115: will go Idle: */ 1116: if (el_s_i_cmd & TME_I825X6_FLAG_EL) { 1117: i825x6->tme_i825x6_cb_address_next = TME_I825X6_CB_ADDRESS_IDLE; 1118: } 1119: 1120: /* otherwise, get the address of the next Command Block: */ 1121: else { 1122: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address 1123: + TME_I82586_CB_LINK_OFFSET), 1124: i825x6->tme_i825x6_cb_address_next); 1125: i825x6->tme_i825x6_cb_address_next += i825x6->tme_i825x6_scb_base; 1126: } 1127: 1128: /* if S is set, after the Command Unit executes this command 1129: it will Suspend, else it will stay Active: */ 1130: i825x6->tme_i825x6_cuc 1131: = ((el_s_i_cmd & TME_I825X6_FLAG_S) 1132: ? TME_I825X6_SCB_CUC_SUSPEND 1133: : TME_I825X6_SCB_CUC_NOP); 1134: 1135: /* assume that this command will complete now: */ 1136: callouts = TME_I825X6_CALLOUT_CU; 1137: 1138: /* dispatch on this command: */ 1139: switch (el_s_i_cmd & TME_I825X6_CB_CMD_MASK) { 1140: 1141: case TME_I825X6_CB_CMD_NOP: 1142: break; 1143: 1144: case TME_I825X6_CB_CMD_SETUP_IA: 1145: 1146: /* read in the new Individual Address, into the second element of 1147: the addresses array: */ 1148: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, 1149: (i825x6->tme_i825x6_cb_address 1150: + TME_I82586_CB_X), 1151: TME_ETHERNET_ADDR_SIZE, 1152: (i825x6->tme_i825x6_addresses 1153: + TME_ETHERNET_ADDR_SIZE), 1154: TME_I825X6_LOCKS_DEFAULT); 1155: assert (rc == TME_OK); 1156: 1157: /* call out an Ethernet configuration change: */ 1158: callouts |= TME_I825X6_CALLOUT_CONFIG; 1159: break; 1160: 1161: case TME_I825X6_CB_CMD_CONFIGURE: 1162: 1163: /* read in bytes 0 and 1 of the configuration: */ 1164: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, 1165: (i825x6->tme_i825x6_cb_address 1166: + TME_I82586_CB_X), 1167: sizeof(tme_uint16_t), 1168: config_bytes, 1169: TME_I825X6_LOCKS_DEFAULT); 1170: assert (rc == TME_OK); 1171: 1172: /* "In the 82586 mode the maximum number of configuration bytes 1173: is 12. Any number larger than 12 will be reduced to 12 and 1174: any number less than 4 will be increased to 4." */ 1175: config_byte_count = (config_bytes[0] & 0x0f); 1176: if (config_byte_count < 4) { 1177: config_byte_count = 4; 1178: } 1179: else if (config_byte_count > 12) { 1180: config_byte_count = 12; 1181: } 1182: 1183: /* read in the remaining bytes of the configuration: */ 1184: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, 1185: (i825x6->tme_i825x6_cb_address 1186: + TME_I82586_CB_X 1187: + sizeof(tme_uint16_t)), 1188: (config_byte_count 1189: - sizeof(tme_uint16_t)), 1190: (config_bytes 1191: + sizeof(tme_uint16_t)), 1192: TME_I825X6_LOCKS_DEFAULT); 1193: assert (rc == TME_OK); 1194: 1195: /* byte 3: */ 1196: if (config_byte_count > 3) { 1197: 1198: /* AL-LOC: */ 1199: i825x6->tme_i825x6_al_loc = config_bytes[3] & 0x08; 1200: 1201: /* Address Length: */ 1202: if ((config_bytes[3] & 0x07) != TME_ETHERNET_ADDR_SIZE) { 1203: abort(); 1204: } 1205: } 1206: 1207: /* byte 8: */ 1208: if (config_byte_count > 8) { 1209: 1210: /* Promiscuous Mode: */ 1211: i825x6->tme_i825x6_prm = config_bytes[8] & 0x01; 1212: 1213: /* call out an Ethernet configuration change: */ 1214: callouts |= TME_I825X6_CALLOUT_CONFIG; 1215: } 1216: break; 1217: 1218: case TME_I825X6_CB_CMD_SETUP_MC: 1219: 1220: /* read in the MC COUNT byte count: */ 1221: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address 1222: + TME_I82586_CB_X), 1223: mc_count); 1224: mc_count -= (mc_count % TME_ETHERNET_ADDR_SIZE); 1225: 1226: /* reallocate the addresses list, which is always at least two 1227: elements long - the broadcast address and the individual 1228: address: */ 1229: i825x6->tme_i825x6_address_count = (2 + (mc_count / TME_ETHERNET_ADDR_SIZE)); 1230: i825x6->tme_i825x6_addresses 1231: = tme_renew(tme_uint8_t, 1232: i825x6->tme_i825x6_addresses, 1233: (i825x6->tme_i825x6_address_count 1234: * TME_ETHERNET_ADDR_SIZE)); 1235: 1236: /* read in the new Multicast addresses: */ 1237: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, 1238: (i825x6->tme_i825x6_cb_address 1239: + TME_I82586_CB_X 1240: + sizeof(mc_count)), 1241: mc_count, 1242: (i825x6->tme_i825x6_addresses 1243: + (2 1244: * TME_ETHERNET_ADDR_SIZE)), 1245: TME_I825X6_LOCKS_DEFAULT); 1246: assert (rc == TME_OK); 1247: 1248: /* call out an Ethernet configuration change: */ 1249: callouts |= TME_I825X6_CALLOUT_CONFIG; 1250: break; 1251: 1252: case TME_I825X6_CB_CMD_TRANSMIT: 1253: 1254: /* call out only a control change; this command is not 1255: completing now: */ 1256: callouts = TME_I825X6_CALLOUT_CTRL; 1257: break; 1258: 1259: case TME_I825X6_CB_CMD_TDR: 1260: 1261: /* write a successful TDR status: */ 1262: TME_I825X6_WRITE16((i825x6->tme_i825x6_cb_address 1263: + TME_I82586_CB_X), 1264: TME_I82586_TDR_STATUS_OK); 1265: break; 1266: 1267: case TME_I825X6_CB_CMD_DUMP: 1268: abort(); 1.1.1.2 root 1269: 1270: case TME_I825X6_CB_CMD_DIAGNOSE: 1271: break; 1.1 root 1272: } 1273: 1274: /* add to the callouts and return the current status: */ 1275: i825x6->tme_i825x6_callout_flags |= callouts; 1276: return (stat_cus_rus_t); 1277: } 1278: 1279: /* this is called to handle a Receive Unit (RU) callout: */ 1280: static tme_uint16_t 1281: _tme_i825x6_callout_ru(struct tme_i825x6 *i825x6, tme_uint16_t stat_cus_rus_t) 1282: { 1283: struct tme_ethernet_connection *conn_eth; 1284: tme_ethernet_fid_t frame_id; 1285: tme_uint16_t el_s_sf; 1286: tme_uint16_t eof_f_act_count; 1287: tme_uint16_t c_b_ok_status; 1288: struct tme_i825x6_rx_buffer *rx_buffers, *rx_buffer, **_prev; 1289: unsigned int rbd_size, rx_buffer_size; 1290: tme_uint32_t rfd_address; 1291: tme_uint16_t rbd_offset_next; 1292: tme_uint16_t discards; 1293: int resid; 1294: int rc; 1295: tme_uint16_t value16; 1296: 1297: /* start a list of rx buffers: */ 1298: rx_buffers = NULL; 1299: _prev = &rx_buffers; 1300: 1301: /* start counting the number of bytes in the first Receive Buffer: */ 1302: rbd_size = 0; 1303: 1304: /* assume that we have no Receive Frame Descriptor: */ 1305: rfd_address = TME_I825X6_RU_ADDRESS_UNDEF; 1306: el_s_sf = 0; 1307: 1308: /* if the Receive Unit is Active and we have a Receive Frame Descriptor: */ 1309: if (((stat_cus_rus_t & TME_I82586_SCB_RUS_MASK) 1310: == TME_I825X6_SCB_RUS_READY) 1311: && ((rfd_address = i825x6->tme_i825x6_rfd_address) 1312: != TME_I825X6_RU_ADDRESS_UNDEF)) { 1313: 1314: /* get the flags word: */ 1315: TME_I825X6_READ16((rfd_address 1316: + TME_I825X6_RFD_EL_S_SF), 1317: el_s_sf); 1318: 1319: /* if AL-LOC is set to zero, the Ethernet/802.3 MAC header will be 1320: received into the Receive Frame Descriptor: */ 1321: if (i825x6->tme_i825x6_al_loc == 0) { 1322: 1323: /* make a set of rx buffers out of the Ethernet header part of 1324: the Receive Frame Descriptor: */ 1325: _tme_i825x6_rx_buffers_add(i825x6, 1326: (rfd_address 1327: + TME_I82586_RFD_RBD_ETH_HEADER), 1328: TME_ETHERNET_HEADER_SIZE, 1329: &_prev); 1330: 1331: /* account for the Receive Frame Descriptor header bytes in the 1332: Free Buffer List space and Receive Buffer size calculations: */ 1333: i825x6->tme_i825x6_fbl_size += TME_ETHERNET_HEADER_SIZE; 1334: rbd_size = 0 - TME_ETHERNET_HEADER_SIZE; 1335: } 1336: 1337: /* take the Free Buffer List: */ 1338: *_prev = i825x6->tme_i825x6_fbl; 1339: } 1340: 1341: /* get the Ethernet connection: */ 1342: conn_eth = i825x6->tme_i825x6_eth_connection; 1343: 1344: /* unlock the mutex: */ 1345: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 1346: 1347: /* do the callout: */ 1348: resid = (conn_eth == NULL 1349: ? 0 1350: : ((*conn_eth->tme_ethernet_connection_read) 1351: (conn_eth, 1352: &frame_id, 1353: &rx_buffers->tme_i825x6_rx_buffer_frame_chunk, 1354: TME_ETHERNET_READ_NEXT))); 1355: 1356: /* lock the mutex: */ 1357: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1358: 1359: /* if the read failed: */ 1360: if (resid <= 0) { 1361: 1362: /* convention dictates that we forget that the connection was 1363: readable, which we already have done by clearing the 1364: CALLOUT_READ flag: */ 1365: return (stat_cus_rus_t); 1366: } 1367: 1368: /* mark that we need to loop to callout to read more frames: */ 1369: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_READ; 1370: 1371: /* return now if the Receive Unit is Idle: */ 1372: if ((stat_cus_rus_t & TME_I82586_SCB_RUS_MASK) 1373: == TME_I825X6_SCB_RUS_IDLE) { 1374: return (stat_cus_rus_t); 1375: } 1376: 1377: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 1378: 100, TME_OK, 1379: (&i825x6->tme_i825x6_element->tme_element_log_handle, 1380: "RU RFD 0x%06x el_s_sf 0x%04x", 1381: rfd_address, 1382: el_s_sf)); 1383: 1384: /* we must have received more than just headers: */ 1385: assert (resid > TME_ETHERNET_HEADER_SIZE); 1386: 1387: /* if we have a Receive Frame Descriptor: */ 1388: if (rfd_address != TME_I825X6_RU_ADDRESS_UNDEF) { 1389: 1390: /* walk the rx buffers, stopping early only if we have exhausted 1391: the Ethernet frame *and* we have updated the last Receive 1392: Buffer used to receive it: */ 1393: for (rx_buffer = rx_buffers; 1394: (rx_buffer != NULL 1395: && (resid > 0 1396: || rbd_size > 0)); ) { 1397: 1398: /* calculate the number of bytes used in this rx buffer. since 1399: a single Receive Buffer can be split into many rx buffers, 1400: the Ethernet frame may not fill all of them, so this can be 1401: zero: */ 1402: rx_buffer_size 1403: = TME_MIN((unsigned int) resid, 1404: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count); 1405: 1406: /* this many more bytes have been received into this Receive Buffer: */ 1407: rbd_size += rx_buffer_size; 1408: 1409: /* this many more bytes have been accounted for in the Ethernet frame: */ 1410: resid -= rx_buffer_size; 1411: 1412: /* if this was a slow frame chunk: */ 1413: if (rx_buffer->tme_i825x6_rx_buffer_rb_address 1414: != TME_I825X6_RU_ADDRESS_UNDEF) { 1415: 1416: /* DMA the contents out: */ 1417: rc = tme_bus_device_dma_write_16(&i825x6->tme_i825x6_device, 1418: rx_buffer->tme_i825x6_rx_buffer_rb_address, 1419: rx_buffer_size, 1420: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes, 1421: TME_I825X6_LOCKS_DEFAULT); 1422: assert (rc == TME_OK); 1423: } 1424: 1425: /* if this was the last rx buffer for a Receive Buffer: */ 1426: if (rx_buffer->tme_i825x6_rx_buffer_rbd_address 1427: != TME_I825X6_RU_ADDRESS_UNDEF) { 1428: 1429: /* make the EOF_F_ACT_COUNT field: */ 1430: assert (rbd_size > 0 && rbd_size <= TME_I825X6_RBD_ACT_COUNT_MASK); 1431: eof_f_act_count = ((resid == 0 1432: ? TME_I825X6_RBD_EOF 1433: : 0) 1434: | TME_I825X6_RBD_F 1435: | rbd_size); 1436: 1437: /* write the EOF_F_ACT_COUNT field out to the Receive Buffer 1438: Descriptor: */ 1439: TME_I825X6_WRITE16((rx_buffer->tme_i825x6_rx_buffer_rbd_address 1440: + TME_I825X6_RBD_EOF_F_ACT_COUNT), 1441: eof_f_act_count); 1442: 1443: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 1444: 100, TME_OK, 1445: (&i825x6->tme_i825x6_element->tme_element_log_handle, 1446: "RU RBD 0x%06x last-size 0x%04x eof_f_act_count 0x%04x", 1447: rx_buffer->tme_i825x6_rx_buffer_rbd_address, 1448: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count, 1449: eof_f_act_count)); 1450: 1451: /* we're starting on the next Receive Buffer: */ 1452: rbd_size = 0; 1453: } 1454: 1455: /* free this rx buffer and move to the next rx buffer: */ 1456: i825x6->tme_i825x6_fbl_size -= rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count; 1457: rx_buffer = _tme_i825x6_rx_buffer_free(i825x6, rx_buffer); 1458: } 1459: 1460: /* update the Free Buffer List: */ 1461: assert ((rx_buffer != NULL) == (i825x6->tme_i825x6_fbl_size != 0)); 1462: i825x6->tme_i825x6_fbl = rx_buffer; 1463: 1464: /* make the C_B_OK_STATUS field: */ 1465: c_b_ok_status = (TME_I825X6_FLAG_C 1466: | (resid == 0 1467: ? TME_I825X6_FLAG_OK 1468: : TME_I825X6_RFD_STATUS_RNR)); 1469: 1470: /* write the C_B_OK_STATUS field in the RFD: */ 1471: TME_I825X6_WRITE16((rfd_address 1472: + TME_I825X6_RFD_C_B_OK_STATUS), 1473: c_b_ok_status); 1474: 1475: /* signal an interrupt: */ 1476: stat_cus_rus_t |= TME_I825X6_SCB_STAT_FR; 1477: 1478: /* if EL is set, there is no next Receive Frame Descriptor, 1479: and when the Receive Unit tries to receive another frame 1480: it will go No Resources: */ 1481: if (el_s_sf & TME_I825X6_FLAG_EL) { 1482: rfd_address = TME_I825X6_RU_ADDRESS_UNDEF; 1483: } 1484: 1485: /* otherwise, get the address of the next Receive Frame Descriptor: */ 1486: else { 1487: TME_I825X6_READ16((rfd_address 1488: + TME_I82586_RFD_LINK_OFFSET), 1489: rfd_address); 1490: rfd_address += i825x6->tme_i825x6_scb_base; 1491: } 1492: 1493: /* set the next RFD address: */ 1494: i825x6->tme_i825x6_rfd_address = rfd_address; 1495: 1496: /* if there is a next RFD address: */ 1497: if (rfd_address != TME_I825X6_RU_ADDRESS_UNDEF) { 1498: 1499: /* refill the Free Buffer List: */ 1500: rbd_offset_next = _tme_i825x6_fbl_refill(i825x6, FALSE); 1501: 1502: /* write the offset of the first free Receive Buffer Descriptor 1503: in the RBD Offset field in the RFD: */ 1504: TME_I825X6_WRITE16((rfd_address 1505: + TME_I82586_RFD_RBD_OFFSET), 1506: rbd_offset_next); 1507: } 1508: 1509: /* if S is set, the Receive Unit becomes Suspended: */ 1510: if (el_s_sf & TME_I825X6_FLAG_S) { 1511: 1512: /* the Receive Unit is now Suspended: */ 1513: stat_cus_rus_t 1514: = ((stat_cus_rus_t 1515: & ~TME_I82586_SCB_RUS_MASK) 1516: | TME_I825X6_SCB_RUS_SUSPENDED); 1517: } 1518: } 1519: 1520: /* otherwise, we had no Receive Frame Descriptor, so we had 1521: to discard this packet entirely: */ 1522: else { 1523: 1524: /* account for the discarded packet: */ 1525: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address 1526: + TME_I82586_SCB_ERRORS_RESOURCE), 1527: discards); 1528: discards++; 1529: TME_I825X6_WRITE16((i825x6->tme_i825x6_scb_address 1530: + TME_I82586_SCB_ERRORS_RESOURCE), 1531: discards); 1532: } 1533: 1534: /* if we ran out of resources: */ 1535: if (resid > 0) { 1536: 1537: /* the receiver is now out of resources: */ 1538: stat_cus_rus_t = ((stat_cus_rus_t 1539: & ~TME_I82586_SCB_RUS_MASK) 1540: | TME_I825X6_SCB_RUS_ERESOURCE); 1541: } 1542: 1543: /* done: */ 1544: return (stat_cus_rus_t); 1545: } 1546: 1547: /* the i825x6 callout function. it must be called with the mutex locked: */ 1548: static void 1549: _tme_i825x6_callout(struct tme_i825x6 *i825x6, int new_callouts) 1550: { 1551: struct tme_ethernet_connection *conn_eth; 1552: struct tme_bus_connection *conn_bus; 1553: int callouts, later_callouts; 1554: unsigned int ctrl; 1555: struct tme_ethernet_config config; 1556: int rc; 1557: tme_uint16_t stat_cus_rus_t; 1558: tme_uint16_t value16; 1559: int int_asserted; 1560: unsigned int address_i; 1561: 1562: /* add in any new callouts: */ 1563: i825x6->tme_i825x6_callout_flags |= new_callouts; 1564: 1565: /* if this function is already running in another thread, simply 1566: return now. the other thread will do our work: */ 1567: if (i825x6->tme_i825x6_callout_flags & TME_I825X6_CALLOUTS_RUNNING) { 1568: return; 1569: } 1570: 1571: /* callouts are now running: */ 1572: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUTS_RUNNING; 1573: 1574: /* assume that we won't need any later callouts: */ 1575: later_callouts = 0; 1576: 1577: /* loop while callouts are needed: */ 1578: for (; (callouts = i825x6->tme_i825x6_callout_flags) & TME_I825X6_CALLOUTS_MASK; ) { 1579: 1580: /* clear the needed callouts: */ 1581: i825x6->tme_i825x6_callout_flags = callouts & ~TME_I825X6_CALLOUTS_MASK; 1582: callouts &= TME_I825X6_CALLOUTS_MASK; 1583: 1584: /* get this card's connection: */ 1585: conn_eth = i825x6->tme_i825x6_eth_connection; 1586: 1587: /* get the current SCB status word. this word is referenced and 1588: updated throughout the body of this for loop; any changes made 1589: are written out at the bottom of the loop: */ 1590: stat_cus_rus_t = i825x6->tme_i825x6_stat_cus_rus_t; 1591: 1592: /* if we need to handle a Channel Attention: */ 1593: if (callouts & TME_I825X6_CALLOUT_CA) { 1594: stat_cus_rus_t = _tme_i825x6_callout_ca(i825x6, stat_cus_rus_t); 1595: if (stat_cus_rus_t == TME_I825X6_CA_RESET) { 1596: continue; 1597: } 1598: } 1599: 1600: /* if we need to run the Command Unit: */ 1601: if (callouts & TME_I825X6_CALLOUT_CU) { 1602: stat_cus_rus_t = _tme_i825x6_callout_cu(i825x6, stat_cus_rus_t); 1603: } 1604: 1605: /* if we need to call out new control information: */ 1606: if (callouts & TME_I825X6_CALLOUT_CTRL) { 1607: 1608: /* form the new ctrl: */ 1609: ctrl = 0; 1610: if (((stat_cus_rus_t 1611: & TME_I825X6_SCB_CUS_MASK) 1612: == TME_I825X6_SCB_CUS_ACTIVE) 1613: && ((i825x6->tme_i825x6_el_s_i_cmd 1614: & TME_I825X6_CB_CMD_MASK) 1615: == TME_I825X6_CB_CMD_TRANSMIT)) { 1616: ctrl |= TME_ETHERNET_CTRL_OK_READ; 1617: } 1618: 1619: /* unlock the mutex: */ 1620: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 1621: 1622: /* do the callout: */ 1623: rc = (conn_eth != NULL 1624: ? ((*conn_eth->tme_ethernet_connection_ctrl) 1625: (conn_eth, 1626: ctrl)) 1627: : TME_OK); 1628: 1629: /* lock the mutex: */ 1630: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1631: 1632: /* if the callout was unsuccessful, remember that at some later 1633: time this callout should be attempted again: */ 1634: if (rc != TME_OK) { 1635: later_callouts |= TME_I825X6_CALLOUT_CTRL; 1636: } 1637: } 1638: 1639: /* if we need to call out new config information: */ 1640: if (callouts & TME_I825X6_CALLOUT_CONFIG) { 1641: 1642: /* form the new config: */ 1643: memset(&config, 0, sizeof(config)); 1644: 1645: /* our Ethernet addresses: */ 1646: config.tme_ethernet_config_addr_count = i825x6->tme_i825x6_address_count; 1647: config.tme_ethernet_config_addrs 1648: = tme_new(const tme_uint8_t *, 1649: i825x6->tme_i825x6_address_count); 1650: for (address_i = 0; 1651: address_i < i825x6->tme_i825x6_address_count; 1652: address_i++) { 1653: config.tme_ethernet_config_addrs[address_i] 1654: = &i825x6->tme_i825x6_addresses[(address_i 1655: * TME_ETHERNET_ADDR_SIZE)]; 1656: } 1657: 1658: /* our config flags: */ 1659: config.tme_ethernet_config_flags 1660: = (TME_ETHERNET_CONFIG_NORMAL 1661: | (i825x6->tme_i825x6_prm 1662: ? TME_ETHERNET_CONFIG_PROMISC 1663: : 0)); 1664: 1665: /* unlock the mutex: */ 1666: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 1667: 1668: /* do the callout: */ 1669: rc = (conn_eth == NULL 1670: ? TME_OK 1671: : ((*conn_eth->tme_ethernet_connection_config) 1672: (conn_eth, 1673: &config))); 1674: 1675: /* lock the mutex: */ 1676: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1677: 1678: /* free the Ethernet address pointer array: */ 1679: tme_free(config.tme_ethernet_config_addrs); 1680: 1681: /* if the callout was unsuccessful, remember that at some later 1682: time this callout should be attempted again: */ 1683: if (rc != TME_OK) { 1684: later_callouts |= TME_I825X6_CALLOUT_CONFIG; 1685: } 1686: } 1687: 1688: /* if the Ethernet is readable: */ 1689: if (callouts & TME_I825X6_CALLOUT_READ) { 1690: 1691: /* if the Receive Unit is Suspended, make this callout later: */ 1692: if ((stat_cus_rus_t 1693: & TME_I82586_SCB_RUS_MASK) 1694: == TME_I825X6_SCB_RUS_SUSPENDED) { 1695: later_callouts |= TME_I825X6_CALLOUT_READ; 1696: } 1697: 1698: /* otherwise, the Receive Unit is not Suspended, so read this 1699: frame. the frame will not be stored if the Receive Unit is 1700: in the Idle or No Resources state: */ 1701: else { 1702: stat_cus_rus_t = _tme_i825x6_callout_ru(i825x6, stat_cus_rus_t); 1703: } 1704: } 1705: 1706: /* note if the Command Unit left the Active state: */ 1707: if (((i825x6->tme_i825x6_stat_cus_rus_t 1708: & TME_I825X6_SCB_CUS_MASK) 1709: == TME_I825X6_SCB_CUS_ACTIVE) 1710: && ((stat_cus_rus_t 1711: & TME_I825X6_SCB_CUS_MASK) 1712: != TME_I825X6_SCB_CUS_ACTIVE)) { 1713: stat_cus_rus_t |= TME_I825X6_SCB_STAT_CNA; 1714: } 1715: 1716: /* note if the Receive Unit left the Ready state: */ 1717: if (((i825x6->tme_i825x6_stat_cus_rus_t 1718: & TME_I82586_SCB_RUS_MASK) 1719: == TME_I825X6_SCB_RUS_READY) 1720: && ((stat_cus_rus_t 1721: & TME_I82586_SCB_RUS_MASK) 1722: != TME_I825X6_SCB_RUS_READY)) { 1723: stat_cus_rus_t |= TME_I825X6_SCB_STAT_RNR; 1724: } 1725: 1726: /* if our Status bits have changed such that our interrupt signal 1727: changes, we need to call out an interrupt: */ 1728: if (!(i825x6->tme_i825x6_stat_cus_rus_t 1729: & TME_I825X6_SCB_STAT_MASK) 1730: != !(stat_cus_rus_t 1731: & TME_I825X6_SCB_STAT_MASK)) { 1732: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_INT; 1733: } 1734: 1735: /* if our SCB status word has changed, write it out: */ 1736: if (stat_cus_rus_t != i825x6->tme_i825x6_stat_cus_rus_t) { 1737: 1738: /* log: */ 1739: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle, 1740: 100, TME_OK, 1741: (&i825x6->tme_i825x6_element->tme_element_log_handle, 1742: "SCB status 0x%04x -> 0x%04x", 1743: i825x6->tme_i825x6_stat_cus_rus_t, 1744: stat_cus_rus_t)); 1745: 1746: TME_I825X6_WRITE16((i825x6->tme_i825x6_scb_address 1747: + TME_I825X6_SCB_STAT_CUS_RUS_T), 1748: stat_cus_rus_t); 1749: i825x6->tme_i825x6_stat_cus_rus_t = stat_cus_rus_t; 1750: } 1751: 1752: /* if we need to call out a change to our interrupt signal: */ 1753: if (callouts & TME_I825X6_CALLOUT_INT) { 1754: 1755: /* see if the interrupt signal should be asserted or negated: */ 1756: int_asserted = (stat_cus_rus_t & TME_I825X6_SCB_STAT_MASK); 1757: 1758: /* unlock our mutex: */ 1759: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 1760: 1761: /* get our bus connection: */ 1.1.1.2 root 1762: conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *, 1763: i825x6->tme_i825x6_device.tme_bus_device_connection, 1764: &i825x6->tme_i825x6_device.tme_bus_device_connection_rwlock); 1.1 root 1765: 1766: /* call out the bus interrupt signal edge: */ 1767: rc = (*conn_bus->tme_bus_signal) 1768: (conn_bus, 1769: TME_BUS_SIGNAL_INT_UNSPEC 1770: | (int_asserted 1771: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 1772: : TME_BUS_SIGNAL_LEVEL_NEGATED)); 1773: 1774: /* lock our mutex: */ 1775: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1776: 1777: /* if this callout failed, remember that at some later time this 1778: callout should be attempted again: */ 1779: if (rc != TME_OK) { 1780: later_callouts |= TME_I825X6_CALLOUT_INT; 1781: } 1782: } 1783: } 1784: 1785: /* put in any later callouts, and clear that callouts are running: */ 1786: i825x6->tme_i825x6_callout_flags = later_callouts; 1787: } 1788: 1789: /* the i825x6 bus signal handler: */ 1790: static int 1791: _tme_i825x6_signal(void *_i825x6, 1792: unsigned int signal) 1793: { 1794: struct tme_i825x6 *i825x6; 1795: int new_callouts; 1796: unsigned int level; 1797: 1798: /* recover our data structure: */ 1799: i825x6 = (struct tme_i825x6 *) _i825x6; 1800: 1801: /* assume we won't need any new callouts: */ 1802: new_callouts = 0; 1803: 1804: /* lock the mutex: */ 1805: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1806: 1807: /* take out the signal level: */ 1808: level = signal & TME_BUS_SIGNAL_LEVEL_MASK; 1.1.1.2 root 1809: signal = TME_BUS_SIGNAL_WHICH(signal); 1.1 root 1810: 1811: /* dispatch on the generic bus signals: */ 1812: switch (signal) { 1813: case TME_BUS_SIGNAL_RESET: 1814: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) { 1815: _tme_i825x6_reset(i825x6); 1816: } 1817: break; 1818: default: 1819: break; 1820: } 1821: 1822: /* dispatch on the i825x6 bus signals: */ 1823: if (signal >= i825x6->tme_i825x6_bus_signals.tme_bus_signals_first) { 1824: switch (signal - i825x6->tme_i825x6_bus_signals.tme_bus_signals_first) { 1825: 1826: case TME_I825X6_SIGNAL_CA: 1827: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) { 1828: new_callouts |= TME_I825X6_CALLOUT_CA; 1829: } 1830: break; 1831: 1832: case TME_I825X6_SIGNAL_LOOP: 1833: #if 0 1834: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) { 1835: abort(); 1836: } 1837: #endif 1838: break; 1839: 1840: default: 1841: break; 1842: } 1843: } 1844: 1845: /* make any new callouts: */ 1846: _tme_i825x6_callout(i825x6, new_callouts); 1847: 1848: /* unlock the mutex: */ 1849: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 1850: 1851: /* no faults: */ 1852: return (TME_OK); 1853: } 1854: 1855: /* this is called when a device changes its configuration: */ 1856: static int 1857: _tme_i825x6_config(struct tme_ethernet_connection *conn_eth, 1858: struct tme_ethernet_config *config) 1859: { 1860: /* we don't care when other devices on the Ethernet 1861: reconfigure themselves: */ 1862: return (TME_OK); 1863: } 1864: 1865: /* this is called when control lines change: */ 1866: static int 1867: _tme_i825x6_ctrl(struct tme_ethernet_connection *conn_eth, 1868: unsigned int ctrl) 1869: { 1870: struct tme_i825x6 *i825x6; 1871: int new_callouts; 1872: 1873: /* recover our data structures: */ 1874: i825x6 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 1875: 1876: /* assume that we won't need any new callouts: */ 1877: new_callouts = 0; 1878: 1879: /* lock the mutex: */ 1880: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1881: 1882: /* if this connection is readable, call out a read: */ 1883: if (ctrl & TME_ETHERNET_CTRL_OK_READ) { 1884: new_callouts |= TME_I825X6_CALLOUT_READ; 1885: } 1886: 1887: /* make any new callouts: */ 1888: _tme_i825x6_callout(i825x6, new_callouts); 1889: 1890: /* unlock the mutex: */ 1891: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 1892: 1893: return (TME_OK); 1894: } 1895: 1896: /* this is called to read frames (from the i825x6 perspective, to transmit them): */ 1897: static int 1898: _tme_i825x6_read(struct tme_ethernet_connection *conn_eth, 1899: tme_ethernet_fid_t *_frame_id, 1900: struct tme_ethernet_frame_chunk *frame_chunks, 1901: unsigned int flags) 1902: { 1903: struct tme_i825x6 *i825x6; 1904: int new_callouts; 1905: struct tme_ethernet_frame_chunk frame_chunk_buffer; 1906: tme_uint32_t tbd_address, tb_address; 1907: tme_uint16_t eof_size; 1908: tme_uint16_t c_b_ok_a; 1909: tme_uint16_t value16; 1910: tme_uint32_t value32; 1911: int rc, err; 1.1.1.2 root 1912: int length; 1.1 root 1913: 1914: /* recover our data structures: */ 1915: i825x6 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 1916: 1917: /* assume that we won't need any new callouts: */ 1918: new_callouts = 0; 1919: 1920: /* start our local copy of the caller's frame chunks: */ 1921: if (frame_chunks != NULL) { 1922: frame_chunk_buffer = *frame_chunks; 1923: } 1924: else { 1925: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count = 0; 1926: } 1927: frame_chunks = &frame_chunk_buffer; 1928: 1929: /* lock our mutex: */ 1930: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 1931: 1932: /* assume that we will have no packet to transmit: */ 1.1.1.2 root 1933: length = 0; 1.1 root 1934: 1935: /* if we have a packet to transmit: */ 1936: if ((i825x6->tme_i825x6_el_s_i_cmd 1937: & TME_I825X6_CB_CMD_MASK) 1938: == TME_I825X6_CB_CMD_TRANSMIT) { 1939: 1940: /* assume that we will succeed: */ 1941: err = TME_OK; 1942: do { 1943: 1944: /* a helper macro for DMAing and copying data into chunks: */ 1945: #define CHUNKS_DMA_TX(addr, size) \ 1946: err = _tme_i825x6_chunks_dma_tx(i825x6, frame_chunks, (addr), (size)); \ 1947: if (err != TME_OK) break; \ 1.1.1.2 root 1948: length += size 1.1 root 1949: #define CHUNKS_MEM_TX(data, size) \ 1950: _tme_i825x6_chunks_mem_tx(frame_chunks, (data), (size)); \ 1.1.1.2 root 1951: length += size 1.1 root 1952: 1953: /* if AL-LOC is set to zero, add the Ethernet/802.3 MAC header: */ 1954: if (i825x6->tme_i825x6_al_loc == 0) { 1955: 1956: /* the destination address: */ 1957: CHUNKS_DMA_TX(i825x6->tme_i825x6_cb_address + TME_I82586_TCB_ADDR_DEST, 1958: TME_ETHERNET_ADDR_SIZE); 1959: 1960: /* our source address (our Individual Address): */ 1961: CHUNKS_MEM_TX(&i825x6->tme_i825x6_addresses[TME_ETHERNET_ADDR_SIZE], 1962: TME_ETHERNET_ADDR_SIZE); 1963: 1964: /* the length field: */ 1965: CHUNKS_DMA_TX(i825x6->tme_i825x6_cb_address + TME_I82586_TCB_LENGTH, 1966: TME_ETHERNET_LENGTH_SIZE); 1967: } 1968: 1969: /* the transmit buffers: */ 1970: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address 1971: + TME_I82586_TCB_TBD_OFFSET), 1972: tbd_address); 1973: for (; tbd_address != 0xffff; ) { 1974: tbd_address += i825x6->tme_i825x6_scb_base; 1975: 1976: TME_I825X6_READ16((tbd_address 1977: + TME_I82586_TBD_EOF_SIZE), 1978: eof_size); 1979: TME_I82586_READ24((tbd_address 1980: + TME_I82586_TBD_TB_ADDRESS), 1981: tb_address); 1982: 1983: /* the transmit buffer contents: */ 1984: CHUNKS_DMA_TX(tb_address, 1985: (eof_size & TME_I82586_TBD_SIZE_MASK)); 1986: 1987: /* the next transmit buffer: */ 1988: if (eof_size & TME_I82586_TBD_EOF) { 1989: break; 1990: } 1991: TME_I825X6_READ16((tbd_address 1992: + TME_I82586_TBD_TBD_OFFSET), 1993: tbd_address); 1994: } 1995: 1996: #undef CHUNKS_DMA_TX 1997: #undef CHUNKS_MEM_TX 1998: 1999: } while (/* CONSTCOND */ 0); 2000: 2001: /* get the CB status word and clear all of the transmit status bits: */ 2002: c_b_ok_a 2003: = (i825x6->tme_i825x6_c_b_ok_a 2004: & ~TME_I825X6_TCB_STATUS_MASK); 2005: 2006: /* if we got a bus error: */ 2007: if (err != TME_OK) { 2008: 2009: /* set the DMA underrun transmit status bit: */ 2010: c_b_ok_a |= TME_I825X6_TCB_STATUS_UNDERRUN; 2011: 2012: /* return an error to our caller: */ 1.1.1.2 root 2013: length = -ENOENT; 1.1 root 2014: } 2015: 2016: /* update the CB status word: */ 2017: i825x6->tme_i825x6_c_b_ok_a = c_b_ok_a; 2018: 2019: /* run the Command Unit: */ 2020: new_callouts |= TME_I825X6_CALLOUT_CU; 2021: 2022: /* we no longer have a packet to transmit: */ 2023: i825x6->tme_i825x6_el_s_i_cmd 2024: = ((i825x6->tme_i825x6_el_s_i_cmd 2025: & ~TME_I825X6_CB_CMD_MASK) 2026: | TME_I825X6_CB_CMD_NOP); 2027: } 2028: 2029: /* make any new callouts: */ 2030: _tme_i825x6_callout(i825x6, new_callouts); 2031: 2032: /* unlock our mutex: */ 2033: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 2034: 2035: /* done: */ 1.1.1.2 root 2036: return (length); 1.1 root 2037: } 2038: 2039: /* this makes a new Ethernet connection: */ 2040: static int 2041: _tme_i825x6_connection_make_eth(struct tme_connection *conn, unsigned int state) 2042: { 2043: struct tme_i825x6 *i825x6; 2044: struct tme_ethernet_connection *conn_eth; 2045: struct tme_ethernet_connection *conn_eth_other; 2046: 2047: /* recover our data structures: */ 2048: i825x6 = conn->tme_connection_element->tme_element_private; 2049: conn_eth = (struct tme_ethernet_connection *) conn; 2050: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other; 2051: 2052: /* both sides must be Ethernet connections: */ 2053: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET); 2054: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET); 2055: 2056: /* we're always set up to answer calls across the connection, so we 2057: only have to do work when the connection has gone full, namely 2058: taking the other side of the connection: */ 2059: if (state == TME_CONNECTION_FULL) { 2060: 2061: /* lock our mutex: */ 2062: tme_mutex_lock(&i825x6->tme_i825x6_mutex); 2063: 2064: /* save our connection: */ 2065: i825x6->tme_i825x6_eth_connection = conn_eth_other; 2066: 2067: /* unlock our mutex: */ 2068: tme_mutex_unlock(&i825x6->tme_i825x6_mutex); 2069: } 2070: 2071: return (TME_OK); 2072: } 2073: 2074: /* this makes a new bus connection: */ 2075: static int 2076: _tme_i825x6_connection_make_bus(struct tme_connection *conn, 2077: unsigned int state) 2078: { 2079: struct tme_i825x6 *i825x6; 2080: struct tme_bus_connection *conn_bus; 2081: int rc; 2082: 2083: /* recover our data structure: */ 2084: i825x6 = conn->tme_connection_element->tme_element_private; 2085: 2086: /* call the bus device connection maker: */ 2087: rc = tme_bus_device_connection_make(conn, state); 2088: 2089: /* if the full connection was successful, and we don't have a TLB 2090: hash yet, allocate it and add our bus signals: */ 2091: if (rc == TME_OK 2092: && state == TME_CONNECTION_FULL 1.1.1.3 ! root 2093: && !i825x6->tme_i825x6_tlb_hash_added) { 1.1 root 2094: 2095: /* get our bus connection: */ 2096: conn_bus 1.1.1.2 root 2097: = tme_memory_atomic_pointer_read(struct tme_bus_connection *, 2098: i825x6->tme_i825x6_device.tme_bus_device_connection, 2099: &i825x6->tme_i825x6_device.tme_bus_device_connection_rwlock); 1.1 root 2100: 1.1.1.3 ! root 2101: /* add the TLB set: */ ! 2102: rc = tme_bus_device_tlb_set_add(&i825x6->tme_i825x6_device, ! 2103: TME_I825X6_TLB_HASH_SIZE, ! 2104: i825x6->tme_i825x6_tlb_hash); 1.1 root 2105: assert (rc == TME_OK); 1.1.1.3 ! root 2106: i825x6->tme_i825x6_tlb_hash_added = TRUE; 1.1 root 2107: 2108: /* add our bus signals: */ 2109: i825x6->tme_i825x6_bus_signals = _tme_i825x6_bus_signals; 2110: rc = ((*conn_bus->tme_bus_signals_add) 2111: (conn_bus, 2112: &i825x6->tme_i825x6_bus_signals)); 2113: assert (rc == TME_OK); 2114: } 2115: 2116: return (rc); 2117: } 2118: 2119: /* this breaks a connection: */ 2120: static int 2121: _tme_i825x6_connection_break(struct tme_connection *conn, unsigned int state) 2122: { 2123: abort(); 2124: } 2125: 2126: /* this makes a new connection side for a i825x6: */ 2127: static int 2128: _tme_i825x6_connections_new(struct tme_element *element, 2129: const char * const *args, 2130: struct tme_connection **_conns, 2131: char **_output) 2132: { 2133: struct tme_i825x6 *i825x6; 2134: struct tme_ethernet_connection *conn_eth; 2135: struct tme_connection *conn; 2136: int rc; 2137: 2138: /* recover our data structure: */ 2139: i825x6 = (struct tme_i825x6 *) element->tme_element_private; 2140: 2141: /* make the generic bus device connection side: */ 2142: rc = tme_bus_device_connections_new(element, args, _conns, _output); 2143: if (rc != TME_OK) { 2144: return (rc); 2145: } 2146: 2147: /* since we need to allocate our TLB hash and add our signals sets 2148: when we make our bus connection, make sure any generic bus device 2149: connection sides use our connection maker: */ 2150: for (conn = *_conns; 2151: conn != NULL; 2152: conn = conn->tme_connection_next) { 2153: if ((conn->tme_connection_type 2154: == TME_CONNECTION_BUS_GENERIC) 2155: && (conn->tme_connection_make 2156: == tme_bus_device_connection_make)) { 2157: conn->tme_connection_make 2158: = _tme_i825x6_connection_make_bus; 2159: } 2160: } 2161: 2162: /* if we don't have an Ethernet connection, make one: */ 2163: if (i825x6->tme_i825x6_eth_connection == NULL) { 2164: 2165: /* allocate the new Ethernet connection: */ 2166: conn_eth = tme_new0(struct tme_ethernet_connection, 1); 2167: conn = &conn_eth->tme_ethernet_connection; 2168: 2169: /* fill in the generic connection: */ 2170: conn->tme_connection_next = *_conns; 2171: conn->tme_connection_type = TME_CONNECTION_ETHERNET; 2172: conn->tme_connection_score = tme_ethernet_connection_score; 2173: conn->tme_connection_make = _tme_i825x6_connection_make_eth; 2174: conn->tme_connection_break = _tme_i825x6_connection_break; 2175: 2176: /* fill in the Ethernet connection: */ 2177: conn_eth->tme_ethernet_connection_config = _tme_i825x6_config; 2178: conn_eth->tme_ethernet_connection_ctrl = _tme_i825x6_ctrl; 2179: conn_eth->tme_ethernet_connection_read = _tme_i825x6_read; 2180: 2181: /* return the connection side possibility: */ 2182: *_conns = conn; 2183: } 2184: 2185: /* done: */ 2186: return (TME_OK); 2187: } 2188: 2189: /* the new i82586 function: */ 2190: TME_ELEMENT_X_NEW_DECL(tme_ic_,i825x6,i82586) { 2191: struct tme_i825x6 *i825x6; 2192: int arg_i; 2193: int usage; 2194: 2195: /* check our arguments: */ 2196: usage = 0; 2197: arg_i = 1; 2198: for (;;) { 2199: 2200: if (0) { 2201: } 2202: 2203: /* if we ran out of arguments: */ 2204: else if (args[arg_i] == NULL) { 2205: 2206: break; 2207: } 2208: 2209: /* otherwise this is a bad argument: */ 2210: else { 2211: tme_output_append_error(_output, 2212: "%s %s, ", 2213: args[arg_i], 2214: _("unexpected")); 2215: usage = TRUE; 2216: break; 2217: } 2218: } 2219: 2220: if (usage) { 2221: tme_output_append_error(_output, 2222: "%s %s", 2223: _("usage:"), 2224: args[0]); 2225: return (EINVAL); 2226: } 2227: 2228: /* start the i825x6 structure: */ 2229: i825x6 = tme_new0(struct tme_i825x6, 1); 2230: i825x6->tme_i825x6_element = element; 2231: tme_mutex_init(&i825x6->tme_i825x6_mutex); 2232: i825x6->tme_i825x6_address_count = 2; 2233: i825x6->tme_i825x6_addresses 2234: = tme_new(tme_uint8_t, 2235: i825x6->tme_i825x6_address_count 2236: * TME_ETHERNET_ADDR_SIZE); 2237: 2238: /* initialize our simple bus device descriptor: */ 2239: i825x6->tme_i825x6_device.tme_bus_device_element = element; 2240: i825x6->tme_i825x6_device.tme_bus_device_signal = _tme_i825x6_signal; 2241: i825x6->tme_i825x6_device.tme_bus_device_lock = _tme_i825x6_lock; 2242: i825x6->tme_i825x6_device.tme_bus_device_unlock = _tme_i825x6_unlock; 2243: i825x6->tme_i825x6_device.tme_bus_device_tlb_hash = _tme_i825x6_tlb_hash; 2244: i825x6->tme_i825x6_device.tme_bus_device_router = tme_bus_device_router_16el; 2245: 2246: /* fill the element: */ 2247: element->tme_element_private = i825x6; 2248: element->tme_element_connections_new = _tme_i825x6_connections_new; 2249: 2250: /* reset the i825x6: */ 2251: _tme_i825x6_reset(i825x6); 2252: 2253: return (TME_OK); 2254: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.