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

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

unix.superglobalmegacorp.com

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