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

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

unix.superglobalmegacorp.com

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