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

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

unix.superglobalmegacorp.com

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