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

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

unix.superglobalmegacorp.com

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