Annotation of tme/ic/i825x6.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.