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