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