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

1.1     ! root        1: /* $Id: am7990.c,v 1.3 2007/03/25 21:18:50 fredette Exp $ */
        !             2: 
        !             3: /* ic/am7990.c - implementation of Am7990 emulation: */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2006 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: am7990.c,v 1.3 2007/03/25 21:18:50 fredette Exp $");
        !            38: 
        !            39: /* includes: */
        !            40: #include <tme/generic/bus-device.h>
        !            41: #include <tme/generic/ethernet.h>
        !            42: 
        !            43: /* macros: */
        !            44: 
        !            45: /* CSR0: */
        !            46: #define TME_AM7990_CSR0_ERR                    TME_BIT(15)
        !            47: #define TME_AM7990_CSR0_BABL                   TME_BIT(14)
        !            48: #define TME_AM7990_CSR0_CERR                   TME_BIT(13)
        !            49: #define TME_AM7990_CSR0_MISS                   TME_BIT(12)
        !            50: #define TME_AM7990_CSR0_MERR                   TME_BIT(11)
        !            51: #define TME_AM7990_CSR0_RINT                   TME_BIT(10)
        !            52: #define TME_AM7990_CSR0_TINT                   TME_BIT(9)
        !            53: #define TME_AM7990_CSR0_IDON                   TME_BIT(8)
        !            54: #define TME_AM7990_CSR0_INTR                   TME_BIT(7)
        !            55: #define TME_AM7990_CSR0_INEA                   TME_BIT(6)
        !            56: #define TME_AM7990_CSR0_RXON                   TME_BIT(5)
        !            57: #define TME_AM7990_CSR0_TXON                   TME_BIT(4)
        !            58: #define TME_AM7990_CSR0_TDMD                   TME_BIT(3)
        !            59: #define TME_AM7990_CSR0_STOP                   TME_BIT(2)
        !            60: #define TME_AM7990_CSR0_STRT                   TME_BIT(1)
        !            61: #define TME_AM7990_CSR0_INIT                   TME_BIT(0)
        !            62: #define TME_AM7990_CSR0_READ_ONLY      \
        !            63:   (TME_AM7990_CSR0_ERR                 \
        !            64:    | TME_AM7990_CSR0_INTR              \
        !            65:    | TME_AM7990_CSR0_RXON              \
        !            66:    | TME_AM7990_CSR0_TXON)
        !            67: #define TME_AM7990_CSR0_WRITE_ONE_TO_CLEAR     \
        !            68:   (TME_AM7990_CSR0_BABL                        \
        !            69:    | TME_AM7990_CSR0_CERR              \
        !            70:    | TME_AM7990_CSR0_MISS              \
        !            71:    | TME_AM7990_CSR0_MERR              \
        !            72:    | TME_AM7990_CSR0_RINT              \
        !            73:    | TME_AM7990_CSR0_TINT              \
        !            74:    | TME_AM7990_CSR0_IDON)
        !            75: #define TME_AM7990_CSR0_WRITE_ONE_ONLY \
        !            76:   (TME_AM7990_CSR0_TDMD                        \
        !            77:    | TME_AM7990_CSR0_STOP              \
        !            78:    | TME_AM7990_CSR0_STRT              \
        !            79:    | TME_AM7990_CSR0_INIT)
        !            80: 
        !            81: /* CSR3: */
        !            82: #define TME_AM7990_CSR3_BSWAP                  TME_BIT(2)
        !            83: #define TME_AM7990_CSR3_ACON                   TME_BIT(1)
        !            84: #define TME_AM7990_CSR3_BCON                   TME_BIT(0)
        !            85: 
        !            86: /* Mode: */
        !            87: #define TME_AM7990_MODE_PROM                   TME_BIT(15)
        !            88: #define TME_AM7990_MODE_EMBA                   TME_BIT(7)
        !            89: #define TME_AM7990_MODE_INTL                   TME_BIT(6)
        !            90: #define TME_AM7990_MODE_DRTY                   TME_BIT(5)
        !            91: #define TME_AM7990_MODE_COLL                   TME_BIT(4)
        !            92: #define TME_AM7990_MODE_DTCR                   TME_BIT(3)
        !            93: #define TME_AM7990_MODE_LOOP                   TME_BIT(2)
        !            94: #define TME_AM7990_MODE_DTX                    TME_BIT(1)
        !            95: #define TME_AM7990_MODE_DRX                    TME_BIT(0)
        !            96: 
        !            97: /* a Descriptor Ring Pointer: */
        !            98: #define TME_AM7990_DRP_XDRA                    (0x00fffff8)
        !            99: #define TME_AM7990_DRP_XLEN_LOG2               (0xe0000000)
        !           100: 
        !           101: /* a descriptor table entry: */
        !           102: #define TME_AM7990_DTE_OFFSET_XMD0             (0 * sizeof(tme_uint16_t))
        !           103: #define TME_AM7990_DTE_OFFSET_XMD1             (1 * sizeof(tme_uint16_t))
        !           104: #define TME_AM7990_DTE_OFFSET_XMD2             (2 * sizeof(tme_uint16_t))
        !           105: #define TME_AM7990_DTE_OFFSET_XMD3             (3 * sizeof(tme_uint16_t))
        !           106: #define TME_AM7990_DTE_SIZE                    (4 * sizeof(tme_uint16_t))
        !           107: 
        !           108: /* common parts of TMD1 and RMD1: */
        !           109: #define TME_AM7990_XMD1_OWN                    TME_BIT(15)
        !           110: #define TME_AM7990_XMD1_ERR                    TME_BIT(14)
        !           111: #define TME_AM7990_XMD1_STP                    TME_BIT(9)
        !           112: #define TME_AM7990_XMD1_ENP                    TME_BIT(8)
        !           113: #define TME_AM7990_XMD1_HADR                   (0x00ff)
        !           114: 
        !           115: /* common parts of TMD2 and RMD2: */
        !           116: #define TME_AM7990_XMD2_BCNT                   (0x0fff)
        !           117: 
        !           118: /* TMD1: */
        !           119: #define TME_AM7990_TMD1_ADD_FCS                        TME_BIT(13)
        !           120: 
        !           121: /* TMD3: */
        !           122: #define TME_AM7990_TMD3_BUFF                   TME_BIT(15)
        !           123: 
        !           124: /* RMD1: */
        !           125: #define TME_AM7990_RMD1_BUFF                   TME_BIT(10)
        !           126: 
        !           127: /* the callout flags: */
        !           128: #define TME_AM7990_CALLOUTS_RUNNING            TME_BIT(0)
        !           129: #define TME_AM7990_CALLOUTS_MASK               (-2)
        !           130: #define  TME_AM7990_CALLOUT_RECEIVE            TME_BIT(1)
        !           131: #define  TME_AM7990_CALLOUT_TRANSMIT_SCAN      TME_BIT(2)
        !           132: #define  TME_AM7990_CALLOUT_CONFIG             TME_BIT(3)
        !           133: #define  TME_AM7990_CALLOUT_DMA_READ           TME_BIT(4)
        !           134: #define  TME_AM7990_CALLOUT_DMA_WRITE          TME_BIT(5)
        !           135: 
        !           136: /* the default locks: */
        !           137: #define TME_AM7990_LOCKS_DEFAULT               (0)
        !           138: 
        !           139: /* the size of the TLB entry hash: */
        !           140: #define TME_AM7990_TLB_HASH_SIZE               (512)
        !           141: 
        !           142: /* structures: */
        !           143: 
        !           144: /* the chip: */
        !           145: struct tme_am7990 {
        !           146: 
        !           147:   /* our simple bus device header: */
        !           148:   struct tme_bus_device tme_am7990_device;
        !           149: #define tme_am7990_element tme_am7990_device.tme_bus_device_element
        !           150: 
        !           151:   /* the Ethernet connection: */
        !           152:   struct tme_ethernet_connection *tme_am7990_eth_connection;
        !           153: 
        !           154:   /* the mutex protecting the chip: */
        !           155:   tme_mutex_t tme_am7990_mutex;
        !           156: 
        !           157:   /* the callout flags: */
        !           158:   int tme_am7990_callout_flags;
        !           159: 
        !           160:   /* our DMA TLB hash: */
        !           161:   struct tme_bus_tlb * tme_shared tme_am7990_tlb_hash;
        !           162:   tme_rwlock_t tme_am7990_tlb_hash_rwlock;
        !           163: 
        !           164:   /* our bus addresses: */
        !           165:   tme_bus_addr_t tme_am7990_offset_rap;
        !           166:   tme_bus_addr_t tme_am7990_offset_rdp;
        !           167: 
        !           168:   /* registers: */
        !           169:   tme_uint16_t tme_am7990_rap;
        !           170:   tme_uint16_t tme_am7990_csrs[4];
        !           171: #define tme_am7990_csr0 tme_am7990_csrs[0]
        !           172: 
        !           173:   /* the initialization block: */
        !           174:   tme_uint16_t tme_am7990_init[12];
        !           175: #define tme_am7990_mode                tme_am7990_init[0]
        !           176: #define tme_am7990_padr                tme_am7990_init[1]
        !           177: #define tme_am7990_ladrf       tme_am7990_init[4]
        !           178: #define tme_am7990_rdra                tme_am7990_init[8]
        !           179: #define tme_am7990_rlen_rdra   tme_am7990_init[9]
        !           180: #define tme_am7990_tdra                tme_am7990_init[10]
        !           181: #define tme_am7990_tlen_tdra   tme_am7990_init[11]
        !           182: 
        !           183:   /* the transmit ring: */
        !           184:   unsigned int tme_am7990_transmit_dte_index_mask;
        !           185:   tme_uint32_t tme_am7990_transmit_dte_address;
        !           186: 
        !           187:   /* the current transmit DTE index, and any previously read TMD1
        !           188:      value: */
        !           189:   unsigned int tme_am7990_transmit_dte_index;
        !           190:   tme_uint16_t tme_am7990_transmit_dte_tmd1;
        !           191: 
        !           192:   /* the receive buffer: */
        !           193:   tme_uint8_t tme_am7990_receive_buffer[TME_ETHERNET_FRAME_MAX];
        !           194:   unsigned int tme_am7990_receive_buffer_length;
        !           195: 
        !           196:   /* the receive ring: */
        !           197:   unsigned int tme_am7990_receive_dte_index_mask;
        !           198:   tme_uint32_t tme_am7990_receive_dte_address;
        !           199: 
        !           200:   /* the current receive DTE index: */
        !           201:   unsigned int tme_am7990_receive_dte_index;
        !           202: 
        !           203:   /* this is nonzero if the interrupt is asserted: */
        !           204:   int tme_am7990_int_asserted;
        !           205: 
        !           206:   /* the input and output Ethernet controls: */
        !           207:   unsigned int tme_am7990_ether_ctrl_out;
        !           208:   unsigned int tme_am7990_ether_ctrl_in;
        !           209: };
        !           210: 
        !           211: /* prototypes: */
        !           212: static int _tme_am7990_transmit _TME_P((struct tme_ethernet_connection *,
        !           213:                                        tme_ethernet_fid_t *,
        !           214:                                        struct tme_ethernet_frame_chunk *,
        !           215:                                        unsigned int));
        !           216: 
        !           217: /* this resets the am7990: */
        !           218: static void
        !           219: _tme_am7990_reset(struct tme_am7990 *am7990)
        !           220: {
        !           221: 
        !           222:   tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !           223:          100, TME_OK,
        !           224:          (&am7990->tme_am7990_element->tme_element_log_handle,
        !           225:           "reset"));
        !           226: 
        !           227:   /* clear all pending callouts: */
        !           228:   am7990->tme_am7990_callout_flags &= TME_AM7990_CALLOUTS_MASK;
        !           229: 
        !           230:   /* reset CSR0: */
        !           231:   am7990->tme_am7990_csr0 = TME_AM7990_CSR0_STOP;
        !           232: 
        !           233:   /* reset CSR3: */
        !           234:   am7990->tme_am7990_csrs[3] = 0;
        !           235: 
        !           236:   /* "EMBA is cleared by activation of the RESET pin or setting the
        !           237:      STOP bit." */
        !           238:   am7990->tme_am7990_mode &= ~TME_AM7990_MODE_EMBA;
        !           239: }
        !           240: 
        !           241: /* this hashes an address into a TLB entry: */
        !           242: static struct tme_bus_tlb *
        !           243: _tme_am7990_tlb_hash(void *_am7990,
        !           244:                     tme_bus_addr_t linear_address,
        !           245:                     unsigned int cycles)
        !           246: {
        !           247:   struct tme_am7990 *am7990;
        !           248: 
        !           249:   /* recover our data structure: */
        !           250:   am7990 = (struct tme_am7990 *) _am7990;
        !           251: 
        !           252:   /* return the TLB entry: */
        !           253:   return (tme_memory_atomic_pointer_read(struct tme_bus_tlb *,
        !           254:                                         am7990->tme_am7990_tlb_hash,
        !           255:                                         &am7990->tme_am7990_tlb_hash_rwlock)
        !           256:          + ((linear_address >> 10) & (TME_AM7990_TLB_HASH_SIZE - 1)));
        !           257: }
        !           258: 
        !           259: /* this locks the mutex: */
        !           260: static void
        !           261: _tme_am7990_lock(void *_am7990,
        !           262:                 unsigned int locks)
        !           263: {
        !           264:   struct tme_am7990 *am7990;
        !           265: 
        !           266:   /* recover our data structure: */
        !           267:   am7990 = (struct tme_am7990 *) _am7990;
        !           268: 
        !           269:   /* lock the mutex: */
        !           270:   tme_mutex_lock(&am7990->tme_am7990_mutex);
        !           271: }
        !           272: 
        !           273: /* this unlocks the mutex: */
        !           274: static void
        !           275: _tme_am7990_unlock(void *_am7990,
        !           276:                   unsigned int locks)
        !           277: {
        !           278:   struct tme_am7990 *am7990;
        !           279: 
        !           280:   /* recover our data structure: */
        !           281:   am7990 = (struct tme_am7990 *) _am7990;
        !           282: 
        !           283:   /* unlock the mutex: */
        !           284:   tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !           285: }
        !           286: 
        !           287: /* this does a DMA: */
        !           288: static int
        !           289: _tme_am7990_dma(struct tme_am7990 *am7990,
        !           290:                tme_uint32_t callout_flags,
        !           291:                tme_uint32_t address,
        !           292:                unsigned int count,
        !           293:                tme_uint8_t *buffer)
        !           294: {
        !           295:   int rc;
        !           296: 
        !           297:   /* make the callout: */
        !           298:   rc = ((callout_flags & TME_AM7990_CALLOUT_DMA_READ)
        !           299:        ? tme_bus_device_dma_read_16(&am7990->tme_am7990_device,
        !           300:                                     address,
        !           301:                                     count,
        !           302:                                     buffer,
        !           303:                                     TME_AM7990_LOCKS_DEFAULT)
        !           304:        : tme_bus_device_dma_write_16(&am7990->tme_am7990_device,
        !           305:                                      address,
        !           306:                                      count,
        !           307:                                      buffer,
        !           308:                                      TME_AM7990_LOCKS_DEFAULT));
        !           309: 
        !           310:   /* if we got a bus error: */
        !           311:   if (rc != TME_OK) {
        !           312: 
        !           313:     /* set MERR: */
        !           314:     am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_MERR;
        !           315:     
        !           316:     /* we were cancelled: */
        !           317:     return (TRUE);
        !           318:   }
        !           319: 
        !           320:   /* we weren't cancelled: */
        !           321:   return (FALSE);
        !           322: }
        !           323: 
        !           324: /* this returns the address for a 16-bit DTE read or write: */
        !           325: static inline tme_uint32_t
        !           326: _tme_am7990_dte_address(struct tme_am7990 *am7990,
        !           327:                        tme_uint32_t callout_flags,
        !           328:                        tme_uint32_t dte_offset)
        !           329: {
        !           330:   tme_uint32_t dte_address;
        !           331:   tme_uint32_t dte_index;
        !           332:   tme_uint32_t dte_index_mask;
        !           333: 
        !           334:   /* get the DTE address, index, and index mask: */
        !           335:   if (callout_flags & TME_AM7990_CALLOUT_RECEIVE) {
        !           336:     dte_address = am7990->tme_am7990_receive_dte_address;
        !           337:     dte_index = am7990->tme_am7990_receive_dte_index;
        !           338:     dte_index_mask = am7990->tme_am7990_receive_dte_index_mask;
        !           339:   }
        !           340:   else {
        !           341:     dte_address = am7990->tme_am7990_transmit_dte_address;
        !           342:     dte_index = am7990->tme_am7990_transmit_dte_index;
        !           343:     dte_index_mask = am7990->tme_am7990_transmit_dte_index_mask;
        !           344:   }
        !           345: 
        !           346:   /* get the DTE address to read or write: */
        !           347:   dte_address
        !           348:     += (((dte_index * TME_AM7990_DTE_SIZE)
        !           349:         + dte_offset)
        !           350:        & ((dte_index_mask * TME_AM7990_DTE_SIZE)
        !           351:           | (TME_AM7990_DTE_SIZE - 1)));
        !           352:   assert ((dte_address % sizeof(tme_uint16_t)) == 0);
        !           353: 
        !           354:   return (dte_address);
        !           355: }
        !           356: 
        !           357: /* this does a 16-bit DTE read: */
        !           358: static tme_uint16_t
        !           359: _tme_am7990_read(struct tme_am7990 *am7990,
        !           360:                 tme_uint32_t callout_flags,
        !           361:                 tme_uint32_t dte_offset,
        !           362:                 int *_cancelled)
        !           363: {
        !           364:   tme_uint16_t value;
        !           365: 
        !           366:   /* do the DMA read: */
        !           367:   *_cancelled = 
        !           368:     _tme_am7990_dma(am7990,
        !           369:                    callout_flags,
        !           370:                    _tme_am7990_dte_address(am7990,
        !           371:                                            callout_flags,
        !           372:                                            dte_offset),
        !           373:                    sizeof(value),
        !           374:                    (tme_uint8_t *) &value);
        !           375: 
        !           376:   /* possibly byteswap the value read: */
        !           377:   assert (am7990->tme_am7990_device.tme_bus_device_router != NULL);
        !           378:   if (am7990->tme_am7990_device.tme_bus_device_router
        !           379:       != (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE
        !           380:          ? tme_bus_device_router_16el
        !           381:          : tme_bus_device_router_16eb)) {
        !           382:     value = tme_bswap_u16(value);
        !           383:   }
        !           384: 
        !           385:   return (value);
        !           386: }
        !           387: #define _tme_am7990_tx_read(am7990, dte_offset, _cancelled)            \
        !           388:   _tme_am7990_read((am7990), TME_AM7990_CALLOUT_DMA_READ, (dte_offset), (_cancelled))
        !           389: #define _tme_am7990_rx_read(am7990, dte_offset, _cancelled)            \
        !           390:   _tme_am7990_read((am7990), TME_AM7990_CALLOUT_DMA_READ | TME_AM7990_CALLOUT_RECEIVE, (dte_offset), (_cancelled))
        !           391: 
        !           392: /* this does a 16-bit DTE write: */
        !           393: static int
        !           394: _tme_am7990_write(struct tme_am7990 *am7990,
        !           395:                  tme_uint32_t callout_flags,
        !           396:                  tme_uint32_t dte_offset,
        !           397:                  tme_uint16_t value)
        !           398: {
        !           399: 
        !           400:   /* possibly byteswap the value to write: */
        !           401:   assert (am7990->tme_am7990_device.tme_bus_device_router != NULL);
        !           402:   if (am7990->tme_am7990_device.tme_bus_device_router
        !           403:       != (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE
        !           404:          ? tme_bus_device_router_16el
        !           405:          : tme_bus_device_router_16eb)) {
        !           406:     value = tme_bswap_u16(value);
        !           407:   }
        !           408: 
        !           409:   /* do the DMA write: */
        !           410:   return (_tme_am7990_dma(am7990,
        !           411:                          callout_flags,
        !           412:                          _tme_am7990_dte_address(am7990,
        !           413:                                                  callout_flags,
        !           414:                                                  dte_offset),
        !           415:                          sizeof(value),
        !           416:                          (tme_uint8_t *) &value));
        !           417: }
        !           418: #define _tme_am7990_tx_write(am7990, dte_offset, value)                \
        !           419:   _tme_am7990_write((am7990), TME_AM7990_CALLOUT_DMA_WRITE, (dte_offset), (value))
        !           420: #define _tme_am7990_rx_write(am7990, dte_offset, value)                \
        !           421:   _tme_am7990_write((am7990), TME_AM7990_CALLOUT_DMA_WRITE | TME_AM7990_CALLOUT_RECEIVE, (dte_offset), (value))
        !           422: 
        !           423: /* this initializes the am7990: */
        !           424: static void
        !           425: _tme_am7990_init(struct tme_am7990 *am7990)
        !           426: {
        !           427:   tme_uint32_t iadr;
        !           428:   int cancelled;
        !           429:   unsigned int init_i;
        !           430:   tme_uint16_t csr0;
        !           431:   tme_uint32_t drp;
        !           432:   
        !           433:   /* DMA in the initialization block: */
        !           434:   iadr = am7990->tme_am7990_csrs[2];
        !           435:   iadr = (iadr << 16) + am7990->tme_am7990_csrs[1];
        !           436:   cancelled
        !           437:     = _tme_am7990_dma(am7990,
        !           438:                      TME_AM7990_CALLOUT_DMA_READ,
        !           439:                      iadr,
        !           440:                      sizeof(am7990->tme_am7990_init),
        !           441:                      (tme_uint8_t *) am7990->tme_am7990_init);
        !           442:   if (cancelled) {
        !           443:     return;
        !           444:   }
        !           445: 
        !           446:   /* possibly byteswap the 16-bit words of the initialization block: */
        !           447:   assert (am7990->tme_am7990_device.tme_bus_device_router != NULL);
        !           448:   if (am7990->tme_am7990_device.tme_bus_device_router
        !           449:       != (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE
        !           450:          ? tme_bus_device_router_16el
        !           451:          : tme_bus_device_router_16eb)) {
        !           452:     for (init_i = 0; init_i < TME_ARRAY_ELS(am7990->tme_am7990_init); init_i++) {
        !           453:       am7990->tme_am7990_init[init_i] = tme_bswap_u16(am7990->tme_am7990_init[init_i]);
        !           454:     }
        !           455:   }
        !           456: 
        !           457:   /* the least significant byte of PADR is actually the "first" byte
        !           458:      of the Ethernet address as is is normally seen, but otherwise the
        !           459:      16-bit words of PADR are in the correct order.  so we only need
        !           460:      to swap those words into little-endian order: */
        !           461:   (&am7990->tme_am7990_padr)[0] = tme_htole_u16((&am7990->tme_am7990_padr)[0]);
        !           462:   (&am7990->tme_am7990_padr)[1] = tme_htole_u16((&am7990->tme_am7990_padr)[1]);
        !           463:   (&am7990->tme_am7990_padr)[2] = tme_htole_u16((&am7990->tme_am7990_padr)[2]);
        !           464: 
        !           465:   tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !           466:          100, TME_OK,
        !           467:          (&am7990->tme_am7990_element->tme_element_log_handle,
        !           468:           "init CSR0 0x%04x IADR 0x%08x MODE 0x%04x",
        !           469:           (unsigned int) am7990->tme_am7990_csr0,
        !           470:           iadr,
        !           471:           (unsigned int) am7990->tme_am7990_mode));
        !           472: 
        !           473:   /* get CSR0: */
        !           474:   csr0 = am7990->tme_am7990_csr0;
        !           475: 
        !           476:   /* set IDON: */
        !           477:   csr0 |= TME_AM7990_CSR0_IDON;
        !           478: 
        !           479:   /* "RXON is cleared when IDON is set from setting the INIT bit and
        !           480:      DRX = 1 in the MODE register" */
        !           481:   if (am7990->tme_am7990_mode & TME_AM7990_MODE_DRX) {
        !           482:     csr0 &= ~TME_AM7990_CSR0_RXON;
        !           483:   }
        !           484: 
        !           485:   /* "TXON is cleared when IDON is set and DTX = 1 in the MODE
        !           486:      register" */
        !           487:   if (am7990->tme_am7990_mode & TME_AM7990_MODE_DTX) {
        !           488:     csr0 &= ~TME_AM7990_CSR0_TXON;
        !           489:   }
        !           490: 
        !           491:   /* clear STOP: */
        !           492:   csr0 &= ~TME_AM7990_CSR0_STOP;
        !           493: 
        !           494:   /* update CSR0: */
        !           495:   am7990->tme_am7990_csr0 = csr0;
        !           496: 
        !           497:   /* call out an Ethernet configuration update: */
        !           498:   am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_CONFIG;
        !           499: 
        !           500:   /* if we're not in internal loopback mode, and the Ethernet
        !           501:      connection is readable, call out an Ethernet receive: */
        !           502:   if (!(am7990->tme_am7990_mode & TME_AM7990_MODE_INTL)
        !           503:       && (am7990->tme_am7990_ether_ctrl_in & TME_ETHERNET_CTRL_OK_READ)) {
        !           504:     am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE;
        !           505:   }
        !           506: 
        !           507:   /* initialize for the receive ring: */
        !           508:   drp = am7990->tme_am7990_rlen_rdra;
        !           509:   drp = (drp << 16) | am7990->tme_am7990_rdra;
        !           510:   am7990->tme_am7990_receive_dte_address = drp & TME_AM7990_DRP_XDRA;
        !           511:   am7990->tme_am7990_receive_dte_index_mask = (1 << TME_FIELD_MASK_EXTRACTU(drp, TME_AM7990_DRP_XLEN_LOG2)) - 1;
        !           512:   am7990->tme_am7990_receive_dte_index = 0;
        !           513: 
        !           514:   /* initialize for the transmit ring: */
        !           515:   drp = am7990->tme_am7990_tlen_tdra;
        !           516:   drp = (drp << 16) | am7990->tme_am7990_tdra;
        !           517:   am7990->tme_am7990_transmit_dte_address = drp & TME_AM7990_DRP_XDRA;
        !           518:   am7990->tme_am7990_transmit_dte_index_mask = (1 << TME_FIELD_MASK_EXTRACTU(drp, TME_AM7990_DRP_XLEN_LOG2)) - 1;
        !           519:   am7990->tme_am7990_transmit_dte_index = 0;
        !           520:   am7990->tme_am7990_transmit_dte_tmd1 = 0;
        !           521: }
        !           522: 
        !           523: /* this starts the am7990: */
        !           524: static void
        !           525: _tme_am7990_start(struct tme_am7990 *am7990)
        !           526: {
        !           527:   tme_uint16_t csr0;
        !           528: 
        !           529:   tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !           530:          100, TME_OK,
        !           531:          (&am7990->tme_am7990_element->tme_element_log_handle,
        !           532:           "start CSR0 0x%04x MODE 0x%04x",
        !           533:           (unsigned int) am7990->tme_am7990_csr0,
        !           534:           (unsigned int) am7990->tme_am7990_mode));
        !           535: 
        !           536:   /* get CSR0: */
        !           537:   csr0 = am7990->tme_am7990_csr0;
        !           538: 
        !           539:   /* "RXON is set when STRT is set if DRX = 0 in the MODE register" */
        !           540:   if (!(am7990->tme_am7990_mode & TME_AM7990_MODE_DRX)) {
        !           541:     csr0 |= TME_AM7990_CSR0_RXON;
        !           542:   }
        !           543: 
        !           544:   /* "TXON is set when STRT is set if DTX = 0 in the MODE register" */
        !           545:   if (!(am7990->tme_am7990_mode & TME_AM7990_MODE_DTX)) {
        !           546:     csr0 |= TME_AM7990_CSR0_TXON;
        !           547:   }
        !           548: 
        !           549:   /* clear STOP: */
        !           550:   csr0 &= ~TME_AM7990_CSR0_STOP;
        !           551: 
        !           552:   /* update CSR0: */
        !           553:   am7990->tme_am7990_csr0 = csr0;
        !           554: }  
        !           555: 
        !           556: /* this scans for a start-of-packet transmit buffer owned by us: */
        !           557: static void
        !           558: _tme_am7990_transmit_scan(struct tme_am7990 *am7990)
        !           559: {
        !           560:   tme_uint16_t transmit_dte_tmd1;
        !           561:   int cancelled;
        !           562: 
        !           563:   /* if the transmitter is not on, return now: */
        !           564:   if (!(am7990->tme_am7990_csr0 & TME_AM7990_CSR0_TXON)) {
        !           565:     return;
        !           566:   }
        !           567: 
        !           568:   /* clear TDMD: */
        !           569:   am7990->tme_am7990_csr0 &= ~TME_AM7990_CSR0_TDMD;
        !           570: 
        !           571:   /* loop forever: */
        !           572:   for (;;) {
        !           573: 
        !           574:     /* if we own the current transmit buffer: */
        !           575:     transmit_dte_tmd1 = am7990->tme_am7990_transmit_dte_tmd1;
        !           576:     if (transmit_dte_tmd1 & TME_AM7990_XMD1_OWN) {
        !           577: 
        !           578:       /* if the current transmit buffer is also for the start of a
        !           579:         packet, return now: */
        !           580:       if (transmit_dte_tmd1 & TME_AM7990_XMD1_STP) {
        !           581:        return;
        !           582:       }
        !           583: 
        !           584:       /* write TMD1 to clear OWN: */
        !           585:       cancelled
        !           586:        = _tme_am7990_tx_write(am7990,
        !           587:                               TME_AM7990_DTE_OFFSET_XMD1,
        !           588:                               (transmit_dte_tmd1
        !           589:                                & ~TME_AM7990_XMD1_OWN));
        !           590:       if (cancelled) {
        !           591:        return;
        !           592:       }
        !           593: 
        !           594:       /* advance to the next transmit buffer and request a transmit
        !           595:         interrupt: */
        !           596:       am7990->tme_am7990_transmit_dte_index
        !           597:        = ((am7990->tme_am7990_transmit_dte_index
        !           598:            + 1)
        !           599:           & am7990->tme_am7990_transmit_dte_index_mask);
        !           600:       am7990->tme_am7990_transmit_dte_tmd1 = 0;
        !           601:       am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_TINT;
        !           602:     }
        !           603: 
        !           604:     /* otherwise, we must not own the current transmit buffer: */
        !           605:     else {
        !           606: 
        !           607:       /* read TMD1: */
        !           608:       transmit_dte_tmd1
        !           609:        = _tme_am7990_tx_read(am7990,
        !           610:                              TME_AM7990_DTE_OFFSET_XMD1,
        !           611:                              &cancelled);
        !           612:       if (cancelled) {
        !           613:        return;
        !           614:       }
        !           615:       am7990->tme_am7990_transmit_dte_tmd1 = transmit_dte_tmd1;
        !           616: 
        !           617:       /* if we still don't own the current transmit buffer, return now: */
        !           618:       if (!(transmit_dte_tmd1 & TME_AM7990_XMD1_OWN)) {
        !           619:        return;
        !           620:       }
        !           621:     }
        !           622:   }
        !           623:   /* NOTREACHED */
        !           624: }
        !           625: 
        !           626: /* this receives a frame: */
        !           627: static void
        !           628: _tme_am7990_receive(struct tme_am7990 *am7990)
        !           629: {
        !           630:   struct tme_ethernet_frame_chunk frame_chunk_buffer;
        !           631:   struct tme_ethernet_connection *conn_eth;
        !           632:   tme_ethernet_fid_t frame_id;
        !           633:   int resid;
        !           634:   tme_uint8_t *frame_chunk_bytes;
        !           635:   unsigned int frame_chunk_bytes_count;
        !           636:   struct tme_ethernet_header *ether_header;
        !           637:   tme_uint32_t crc32;
        !           638:   tme_uint16_t receive_dte_rmd0;
        !           639:   tme_uint16_t receive_dte_rmd1;
        !           640:   tme_uint16_t receive_dte_rmd2;
        !           641:   tme_uint16_t receive_dte_rmd1_next;
        !           642:   tme_uint32_t receive_buffer_address;
        !           643:   tme_uint16_t receive_buffer_count;
        !           644:   int cancelled;
        !           645:   int stop;
        !           646: 
        !           647:   /* assume that there is no loopback packet: */
        !           648:   resid = 0;
        !           649: 
        !           650:   /* if we're in loopback mode: */
        !           651:   if (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP) {
        !           652: 
        !           653:     /* get and clear any loopback packet length: */
        !           654:     resid = am7990->tme_am7990_receive_buffer_length;
        !           655:     am7990->tme_am7990_receive_buffer_length = 0;
        !           656: 
        !           657:     /* "The C-LANCE will not receive any packets externally when it is
        !           658:        in internal loopback mode." */
        !           659:     if (resid == 0
        !           660:        && (am7990->tme_am7990_mode & TME_AM7990_MODE_INTL)) {
        !           661:       return;
        !           662:     }
        !           663:   }
        !           664: 
        !           665:   /* if there isn't any loopback packet, and the Ethernet connection
        !           666:      is not readable, return now: */
        !           667:   if (resid == 0
        !           668:       && !(am7990->tme_am7990_ether_ctrl_in & TME_ETHERNET_CTRL_OK_READ)) {
        !           669:     return;
        !           670:   }
        !           671: 
        !           672:   /* receive the packet into the internal buffer: */
        !           673:   frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL;
        !           674:   frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count = sizeof(am7990->tme_am7990_receive_buffer);
        !           675:   frame_chunk_buffer.tme_ethernet_frame_chunk_bytes = &am7990->tme_am7990_receive_buffer[0];
        !           676: 
        !           677:   /* if there isn't any loopback packet: */
        !           678:   if (resid == 0) {
        !           679: 
        !           680:     /* assume that the Ethernet read will fail: */
        !           681:     am7990->tme_am7990_ether_ctrl_in &= ~TME_ETHERNET_CTRL_OK_READ;
        !           682: 
        !           683:     /* get the Ethernet connection: */
        !           684:     conn_eth = am7990->tme_am7990_eth_connection;
        !           685: 
        !           686:     /* unlock the mutex: */
        !           687:     tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !           688:   
        !           689:     /* do the callout: */
        !           690:     resid = (conn_eth == NULL
        !           691:             ? 0
        !           692:             : ((*conn_eth->tme_ethernet_connection_read)
        !           693:                (conn_eth,
        !           694:                 &frame_id,
        !           695:                 &frame_chunk_buffer,
        !           696:                 TME_ETHERNET_READ_NEXT)));
        !           697:     
        !           698:     /* lock the mutex: */
        !           699:     tme_mutex_lock(&am7990->tme_am7990_mutex);
        !           700: 
        !           701:     /* if the read failed, return now: */
        !           702:     if (resid <= 0) {
        !           703:       return;
        !           704:     }
        !           705: 
        !           706:     /* assume that the Ethernet connection is still readable: */
        !           707:     am7990->tme_am7990_ether_ctrl_in |= TME_ETHERNET_CTRL_OK_READ;
        !           708: 
        !           709:     /* append four dummy CRC bytes: */
        !           710:     resid = TME_MIN((unsigned int) resid + TME_ETHERNET_CRC_SIZE,
        !           711:                    sizeof(am7990->tme_am7990_receive_buffer));
        !           712:   }
        !           713: 
        !           714:   /* assume that we should callout another receive after this one: */
        !           715:   am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE;
        !           716: 
        !           717:   /* if the receiver is not on, return now: */
        !           718:   if (!(am7990->tme_am7990_csr0 & TME_AM7990_CSR0_RXON)) {
        !           719:     return;
        !           720:   }
        !           721: 
        !           722:   /* if this packet is not addressed to our physical address: */
        !           723:   ether_header = (struct tme_ethernet_header *) &am7990->tme_am7990_receive_buffer[0];
        !           724:   if (memcmp(&ether_header->tme_ethernet_header_dst[0],
        !           725:             &am7990->tme_am7990_padr,
        !           726:             TME_ETHERNET_ADDR_SIZE) != 0) {
        !           727: 
        !           728:     /* if this is not a multicast packet, return now: */
        !           729:     if (!(ether_header->tme_ethernet_header_dst[0] & 0x1)) {
        !           730:       return;
        !           731:     }
        !           732: 
        !           733:     /* if this is not a broadcast packet: */
        !           734:     if (memcmp(&ether_header->tme_ethernet_header_dst[0],
        !           735:               &tme_ethernet_addr_broadcast[0],
        !           736:               TME_ETHERNET_ADDR_SIZE) != 0) {
        !           737: 
        !           738:       /* calculate the CRC of the destination address: */
        !           739:       crc32 = tme_ethernet_crc32_el(&ether_header->tme_ethernet_header_dst[0],
        !           740:                                    TME_ETHERNET_ADDR_SIZE);
        !           741:     
        !           742:       /* the am7990 only uses the most significant six bits of the CRC: */
        !           743:       crc32 >>= (32 - 6);
        !           744: 
        !           745:       /* if the bit in the logical address filter is clear, return now: */
        !           746:       if (((&am7990->tme_am7990_ladrf)[crc32 / (8 * sizeof(am7990->tme_am7990_ladrf))]
        !           747:           & TME_BIT(crc32 % (8 * sizeof(am7990->tme_am7990_ladrf)))) == 0) {
        !           748:        return;
        !           749:       }
        !           750:     }
        !           751:   }
        !           752: 
        !           753:   /* read RMD1: */
        !           754:   receive_dte_rmd1
        !           755:     = _tme_am7990_rx_read(am7990,
        !           756:                          TME_AM7990_DTE_OFFSET_XMD1,
        !           757:                          &cancelled);
        !           758:   if (cancelled) {
        !           759:     return;
        !           760:   }
        !           761: 
        !           762:   /* if we don't own this receive buffer: */
        !           763:   if (!(receive_dte_rmd1 & TME_AM7990_XMD1_OWN)) {
        !           764: 
        !           765:     if ((am7990->tme_am7990_csr0 & TME_AM7990_CSR0_MISS) == 0) {
        !           766:       tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !           767:              500, TME_OK,
        !           768:              (&am7990->tme_am7990_element->tme_element_log_handle,
        !           769:               "receive MISS"));
        !           770:     }
        !           771: 
        !           772:     /* set MISS in CSR0 and return now: */
        !           773:     am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_MISS;
        !           774:     return;
        !           775:   }
        !           776: 
        !           777:   /* set STP in RMD1: */
        !           778:   receive_dte_rmd1 |= TME_AM7990_XMD1_STP;
        !           779: 
        !           780:   /* while we have bytes to write: */
        !           781:   frame_chunk_bytes = &am7990->tme_am7990_receive_buffer[0];
        !           782:   frame_chunk_bytes_count = resid;
        !           783:   do {
        !           784: 
        !           785:     /* read RMD0 and RMD2: */
        !           786:     receive_dte_rmd0
        !           787:       = _tme_am7990_rx_read(am7990,
        !           788:                            TME_AM7990_DTE_OFFSET_XMD0,
        !           789:                            &cancelled);
        !           790:     if (cancelled) {
        !           791:       break;
        !           792:     }
        !           793:     receive_dte_rmd2
        !           794:       = _tme_am7990_rx_read(am7990,
        !           795:                            TME_AM7990_DTE_OFFSET_XMD2,
        !           796:                            &cancelled);
        !           797:     if (cancelled) {
        !           798:       break;
        !           799:     }
        !           800: 
        !           801:     /* get the receive buffer address and count: */
        !           802:     receive_buffer_address = (receive_dte_rmd1 & TME_AM7990_XMD1_HADR);
        !           803:     receive_buffer_address = (receive_buffer_address << 16) + receive_dte_rmd0;
        !           804:     receive_buffer_count = (0 - receive_dte_rmd2) & TME_AM7990_XMD2_BCNT;
        !           805: 
        !           806:     /* get the count of bytes to write in this iteration: */
        !           807:     receive_buffer_count = TME_MIN(frame_chunk_bytes_count, receive_buffer_count);
        !           808: 
        !           809:     /* do the write: */
        !           810:     cancelled 
        !           811:       = _tme_am7990_dma(am7990,
        !           812:                        (TME_AM7990_CALLOUT_DMA_WRITE
        !           813:                         | TME_AM7990_CALLOUT_RECEIVE),
        !           814:                        receive_buffer_address,
        !           815:                        receive_buffer_count,
        !           816:                        frame_chunk_bytes);
        !           817:     if (cancelled) {
        !           818:       break;
        !           819:     }
        !           820: 
        !           821:     /* advance: */
        !           822:     frame_chunk_bytes += receive_buffer_count;
        !           823:     frame_chunk_bytes_count -= receive_buffer_count;
        !           824: 
        !           825:     /* if this is the last buffer for this packet: */
        !           826:     if (frame_chunk_bytes_count == 0) {
        !           827: 
        !           828:       /* write RMD3 to set MCNT: */
        !           829:       cancelled
        !           830:        = _tme_am7990_rx_write(am7990,
        !           831:                               TME_AM7990_DTE_OFFSET_XMD3,
        !           832:                               (unsigned int) resid);
        !           833:       if (cancelled) {
        !           834:        break;
        !           835:       }
        !           836: 
        !           837:       /* set ENP in RMD1: */
        !           838:       receive_dte_rmd1 |= TME_AM7990_XMD1_ENP;
        !           839: 
        !           840:       /* we don't read RMD1 for the next receive buffer: */
        !           841:       receive_dte_rmd1_next = 0;
        !           842: 
        !           843:       /* stop now: */
        !           844:       stop = TRUE;
        !           845:     }
        !           846: 
        !           847:     /* otherwise, this is not the last buffer for this packet: */
        !           848:     else {
        !           849: 
        !           850:       /* read RMD1 for the next transmit buffer: */
        !           851:       receive_dte_rmd1_next
        !           852:        = _tme_am7990_rx_read(am7990,
        !           853:                              (TME_AM7990_DTE_SIZE
        !           854:                               + TME_AM7990_DTE_OFFSET_XMD1),
        !           855:                              &cancelled);
        !           856:       if (cancelled) {
        !           857:        break;
        !           858:       }
        !           859: 
        !           860:       /* if we don't own the next buffer: */
        !           861:       stop = !(receive_dte_rmd1_next & TME_AM7990_XMD1_OWN);
        !           862:       if (stop) {
        !           863: 
        !           864:        tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !           865:                500, TME_OK,
        !           866:                (&am7990->tme_am7990_element->tme_element_log_handle,
        !           867:                 "receive BUFF"));
        !           868: 
        !           869:        /* set BUFF and ERR in RMD1: */
        !           870:        receive_dte_rmd1 |= TME_AM7990_RMD1_BUFF | TME_AM7990_XMD1_ERR;
        !           871:       }
        !           872:     }
        !           873: 
        !           874:     /* write RMD1 to clear OWN: */
        !           875:     cancelled
        !           876:       = _tme_am7990_rx_write(am7990,
        !           877:                             TME_AM7990_DTE_OFFSET_XMD1,
        !           878:                             (receive_dte_rmd1
        !           879:                              & ~TME_AM7990_XMD1_OWN));
        !           880:     if (cancelled) {
        !           881:       break;
        !           882:     }
        !           883: 
        !           884:     /* advance to the next receive buffer: */
        !           885:     am7990->tme_am7990_receive_dte_index
        !           886:       = ((am7990->tme_am7990_receive_dte_index
        !           887:          + 1)
        !           888:         & am7990->tme_am7990_receive_dte_index_mask);
        !           889:     receive_dte_rmd1 = receive_dte_rmd1_next;
        !           890:   } while (!stop);
        !           891: 
        !           892:   /* if nothing was cancelled: */
        !           893:   if (!cancelled) {
        !           894:       
        !           895:     /* generate a receive interrupt: */
        !           896:     am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_RINT;
        !           897:   }
        !           898: }
        !           899: 
        !           900: /* the am7990 callout function.  it must be called with the mutex locked: */
        !           901: static void
        !           902: _tme_am7990_callout(struct tme_am7990 *am7990)
        !           903: {
        !           904:   struct tme_ethernet_connection *conn_eth;
        !           905:   struct tme_ethernet_connection conn_eth_buffer;
        !           906:   struct tme_bus_connection *conn_bus;
        !           907:   unsigned int ctrl;
        !           908:   struct tme_ethernet_config config;
        !           909:   const tme_uint8_t *config_addrs[2];
        !           910:   int again;
        !           911:   int rc;
        !           912:   int int_asserted;
        !           913: 
        !           914:   /* if this function is already running in another thread, simply
        !           915:      return now.  the other thread will do our work: */
        !           916:   if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUTS_RUNNING) {
        !           917:     return;
        !           918:   }
        !           919: 
        !           920:   /* callouts are now running: */
        !           921:   am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUTS_RUNNING;
        !           922: 
        !           923:   /* loop while we have work to do: */
        !           924:   do {
        !           925:     again = FALSE;
        !           926: 
        !           927:     /* if we need to do a transmit scan: */
        !           928:     if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUT_TRANSMIT_SCAN) {
        !           929:       again = TRUE;
        !           930: 
        !           931:       /* clear the callout flag: */
        !           932:       am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUT_TRANSMIT_SCAN;
        !           933: 
        !           934:       /* do the transmit scan: */
        !           935:       _tme_am7990_transmit_scan(am7990);
        !           936:     }
        !           937: 
        !           938:     /* form our ctrl: */
        !           939:     ctrl = 0;
        !           940: 
        !           941:     /* if the transmitter is on and the next transmit buffer is for
        !           942:        the start of a packet and is owned by us, we are readable: */
        !           943:     if ((am7990->tme_am7990_csr0
        !           944:         & TME_AM7990_CSR0_TXON)
        !           945:        && ((am7990->tme_am7990_transmit_dte_tmd1
        !           946:             & (TME_AM7990_XMD1_OWN
        !           947:                | TME_AM7990_XMD1_STP))
        !           948:            == (TME_AM7990_XMD1_OWN
        !           949:                | TME_AM7990_XMD1_STP))) {
        !           950:       ctrl |= TME_ETHERNET_CTRL_OK_READ;
        !           951:     }
        !           952: 
        !           953:     /* if we are readable and in loopback mode: */
        !           954:     if ((ctrl & TME_ETHERNET_CTRL_OK_READ)
        !           955:        && (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP)) {
        !           956:       again = TRUE;
        !           957: 
        !           958:       /* unlock the mutex: */
        !           959:       tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !           960: 
        !           961:       /* call out a loopback transmit: */
        !           962:       conn_eth_buffer.tme_ethernet_connection.tme_connection_element = am7990->tme_am7990_element;
        !           963:       _tme_am7990_transmit(&conn_eth_buffer,
        !           964:                           NULL,
        !           965:                           NULL,
        !           966:                           0);
        !           967: 
        !           968:       /* lock the mutex: */
        !           969:       tme_mutex_lock(&am7990->tme_am7990_mutex);
        !           970: 
        !           971:       /* don't call out any new control information for now: */
        !           972:       ctrl = am7990->tme_am7990_ether_ctrl_out;
        !           973:     }
        !           974: 
        !           975:     /* if we need to call out new control information: */
        !           976:     if (am7990->tme_am7990_ether_ctrl_out != ctrl) {
        !           977:       again = TRUE;
        !           978: 
        !           979:       /* note the new state of the called-out control information: */
        !           980:       am7990->tme_am7990_ether_ctrl_out = ctrl;
        !           981: 
        !           982:       /* get this card's connection: */
        !           983:       conn_eth = am7990->tme_am7990_eth_connection;
        !           984: 
        !           985:       /* unlock the mutex: */
        !           986:       tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !           987:       
        !           988:       /* do the callout: */
        !           989:       rc = (conn_eth != NULL
        !           990:            ? ((*conn_eth->tme_ethernet_connection_ctrl)
        !           991:               (conn_eth,
        !           992:                ctrl))
        !           993:            : TME_OK);
        !           994:       assert (rc == TME_OK);
        !           995: 
        !           996:       /* lock the mutex: */
        !           997:       tme_mutex_lock(&am7990->tme_am7990_mutex);
        !           998:     }
        !           999: 
        !          1000:     /* if we need to call out new config information: */
        !          1001:     if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUT_CONFIG) {
        !          1002:       again = TRUE;
        !          1003: 
        !          1004:       /* clear the callout flag: */
        !          1005:       am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUT_CONFIG;
        !          1006:       
        !          1007:       /* form the new config: */
        !          1008:       memset(&config, 0, sizeof(config));
        !          1009: 
        !          1010:       /* if we're in promiscuous mode or any bits the logical address
        !          1011:         filter are nonzero: */
        !          1012:       if ((am7990->tme_am7990_mode & TME_AM7990_MODE_PROM)
        !          1013:          || (&am7990->tme_am7990_ladrf)[0]
        !          1014:          || (&am7990->tme_am7990_ladrf)[1]
        !          1015:          || (&am7990->tme_am7990_ladrf)[2]
        !          1016:          || (&am7990->tme_am7990_ladrf)[3]) {
        !          1017: 
        !          1018:        /* we have to be in promiscuous mode: */
        !          1019:        config.tme_ethernet_config_flags |= TME_ETHERNET_CONFIG_PROMISC;
        !          1020:       }
        !          1021: 
        !          1022:       /* otherwise, we only need to see packets addressed to our
        !          1023:         physical address, and broadcast packets: */
        !          1024:       else {
        !          1025:       
        !          1026:        /* our Ethernet addresses: */
        !          1027:        config.tme_ethernet_config_addr_count = 2;
        !          1028:        config_addrs[0] = (tme_uint8_t *) &am7990->tme_am7990_padr;
        !          1029:        config_addrs[1] = &tme_ethernet_addr_broadcast[0];
        !          1030:        config.tme_ethernet_config_addrs = config_addrs;
        !          1031:       }
        !          1032: 
        !          1033:       /* get this card's connection: */
        !          1034:       conn_eth = am7990->tme_am7990_eth_connection;
        !          1035: 
        !          1036:       /* unlock the mutex: */
        !          1037:       tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1038:       
        !          1039:       /* do the callout: */
        !          1040:       rc = (conn_eth == NULL
        !          1041:            ? TME_OK
        !          1042:            : ((*conn_eth->tme_ethernet_connection_config)
        !          1043:               (conn_eth,
        !          1044:                &config)));
        !          1045:       assert (rc == TME_OK);
        !          1046:       
        !          1047:       /* lock the mutex: */
        !          1048:       tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1049:     }
        !          1050: 
        !          1051:     /* if we need to receive a frame: */
        !          1052:     if (am7990->tme_am7990_callout_flags & TME_AM7990_CALLOUT_RECEIVE) {
        !          1053:       again = TRUE;
        !          1054: 
        !          1055:       /* clear the callout flag: */
        !          1056:       am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUT_RECEIVE;
        !          1057: 
        !          1058:       /* do the receive: */
        !          1059:       _tme_am7990_receive(am7990);
        !          1060:     }
        !          1061: 
        !          1062:     /* if we need to call out an interrupt: */
        !          1063:     if (am7990->tme_am7990_csr0
        !          1064:        & (TME_AM7990_CSR0_TINT
        !          1065:           | TME_AM7990_CSR0_BABL
        !          1066:           | TME_AM7990_CSR0_MISS
        !          1067:           | TME_AM7990_CSR0_MERR
        !          1068:           | TME_AM7990_CSR0_RINT
        !          1069:           | TME_AM7990_CSR0_TINT
        !          1070:           | TME_AM7990_CSR0_IDON)) {
        !          1071:       am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_INTR;
        !          1072:     }
        !          1073:     else {
        !          1074:       am7990->tme_am7990_csr0 &= ~TME_AM7990_CSR0_INTR;
        !          1075:     }
        !          1076:     int_asserted
        !          1077:       = ((am7990->tme_am7990_csr0
        !          1078:          & (TME_AM7990_CSR0_INTR
        !          1079:             | TME_AM7990_CSR0_INEA))
        !          1080:         == (TME_AM7990_CSR0_INTR
        !          1081:             | TME_AM7990_CSR0_INEA));
        !          1082:     if (!!am7990->tme_am7990_int_asserted != int_asserted) {
        !          1083:       again = TRUE;
        !          1084: 
        !          1085:       /* note the new state of the interrupt signal: */
        !          1086:       am7990->tme_am7990_int_asserted = int_asserted;
        !          1087: 
        !          1088:       /* get our bus connection: */
        !          1089:       conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *,
        !          1090:                                                am7990->tme_am7990_device.tme_bus_device_connection,
        !          1091:                                                &am7990->tme_am7990_device.tme_bus_device_connection_rwlock);
        !          1092: 
        !          1093:       /* unlock our mutex: */
        !          1094:       tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1095:       
        !          1096:       /* call out the bus interrupt signal edge: */
        !          1097:       rc = (*conn_bus->tme_bus_signal)
        !          1098:        (conn_bus,
        !          1099:         TME_BUS_SIGNAL_INT_UNSPEC
        !          1100:         | (int_asserted
        !          1101:            ? TME_BUS_SIGNAL_LEVEL_ASSERTED
        !          1102:            : TME_BUS_SIGNAL_LEVEL_NEGATED));
        !          1103:       assert (rc == TME_OK);
        !          1104:       
        !          1105:       /* lock our mutex: */
        !          1106:       tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1107:     }
        !          1108:   } while (again);
        !          1109: 
        !          1110:   /* clear that callouts are running: */
        !          1111:   am7990->tme_am7990_callout_flags &= ~TME_AM7990_CALLOUTS_RUNNING;
        !          1112: }
        !          1113: 
        !          1114: /* the am7990 bus signal handler: */
        !          1115: static int
        !          1116: _tme_am7990_signal(void *_am7990, 
        !          1117:                   unsigned int signal)
        !          1118: {
        !          1119:   struct tme_am7990 *am7990;
        !          1120:   unsigned int level;
        !          1121: 
        !          1122:   /* recover our data structure: */
        !          1123:   am7990 = (struct tme_am7990 *) _am7990;
        !          1124: 
        !          1125:   /* lock the mutex: */
        !          1126:   tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1127: 
        !          1128:   /* take out the signal level: */
        !          1129:   level = signal & TME_BUS_SIGNAL_LEVEL_MASK;
        !          1130:   signal = TME_BUS_SIGNAL_WHICH(signal);
        !          1131: 
        !          1132:   /* dispatch on the generic bus signals: */
        !          1133:   switch (signal) {
        !          1134:   case TME_BUS_SIGNAL_RESET:
        !          1135:     if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
        !          1136:       _tme_am7990_reset(am7990);
        !          1137:     }
        !          1138:     break;
        !          1139:   default:
        !          1140:     signal = TME_BUS_SIGNAL_IGNORE;
        !          1141:     break;
        !          1142:   }
        !          1143: 
        !          1144:   /* if we didn't ignore this bus signal: */
        !          1145:   if (signal != TME_BUS_SIGNAL_IGNORE) {
        !          1146: 
        !          1147:     /* make any new callouts: */
        !          1148:     _tme_am7990_callout(am7990);
        !          1149:   }
        !          1150: 
        !          1151:   /* unlock the mutex: */
        !          1152:   tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1153: 
        !          1154:   /* no faults: */
        !          1155:   return (TME_OK);
        !          1156: }
        !          1157: 
        !          1158: /* this is called when a device changes its configuration: */
        !          1159: static int
        !          1160: _tme_am7990_config(struct tme_ethernet_connection *conn_eth, 
        !          1161:                  struct tme_ethernet_config *config)
        !          1162: {
        !          1163:   /* we don't care when other devices on the Ethernet
        !          1164:      reconfigure themselves: */
        !          1165:   return (TME_OK);
        !          1166: }
        !          1167: 
        !          1168: /* this is called when control lines change: */
        !          1169: static int
        !          1170: _tme_am7990_ctrl(struct tme_ethernet_connection *conn_eth, 
        !          1171:                 unsigned int ctrl)
        !          1172: {
        !          1173:   struct tme_am7990 *am7990;
        !          1174: 
        !          1175:   /* recover our data structures: */
        !          1176:   am7990 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
        !          1177: 
        !          1178:   /* lock the mutex: */
        !          1179:   tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1180: 
        !          1181:   /* note the new state of the controls: */
        !          1182:   am7990->tme_am7990_ether_ctrl_in = ctrl;
        !          1183: 
        !          1184:   /* if this connection is readable, call out a read: */
        !          1185:   if (ctrl & TME_ETHERNET_CTRL_OK_READ) {
        !          1186:     am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE;
        !          1187:   }
        !          1188: 
        !          1189:   /* make any new callouts: */
        !          1190:   _tme_am7990_callout(am7990);
        !          1191: 
        !          1192:   /* unlock the mutex: */
        !          1193:   tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1194: 
        !          1195:   return (TME_OK);
        !          1196: }
        !          1197: 
        !          1198: /* this transmits a frame: */
        !          1199: static int
        !          1200: _tme_am7990_transmit(struct tme_ethernet_connection *conn_eth, 
        !          1201:                     tme_ethernet_fid_t *_frame_id,
        !          1202:                     struct tme_ethernet_frame_chunk *frame_chunk,
        !          1203:                     unsigned int flags)
        !          1204: {
        !          1205:   struct tme_am7990 *am7990;
        !          1206:   struct tme_ethernet_frame_chunk frame_chunk_buffer;
        !          1207:   tme_uint8_t frame_chunk_bytes_buffer[32];
        !          1208:   tme_uint8_t *frame_chunk_bytes;
        !          1209:   unsigned int frame_chunk_bytes_count;
        !          1210:   tme_uint16_t transmit_dte_tmd0;
        !          1211:   tme_uint16_t transmit_dte_tmd1;
        !          1212:   tme_uint16_t transmit_dte_tmd2;
        !          1213:   tme_uint16_t transmit_dte_tmd1_next;
        !          1214:   tme_uint32_t transmit_buffer_address;
        !          1215:   tme_uint16_t transmit_buffer_count;
        !          1216:   unsigned int count;
        !          1217:   int rc;
        !          1218:   int add_fcs;
        !          1219:   int stop;
        !          1220:   int cancelled;
        !          1221: 
        !          1222:   /* recover our data structures: */
        !          1223:   am7990 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
        !          1224: 
        !          1225:   /* lock our mutex: */
        !          1226:   tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1227: 
        !          1228:   /* assume that we will have no packet to transmit: */
        !          1229:   rc = 0;
        !          1230: 
        !          1231:   /* if the transmitter is on, and the current transmit buffer is for
        !          1232:      the start of a packet and is owned by us: */
        !          1233:   if ((am7990->tme_am7990_csr0
        !          1234:        & TME_AM7990_CSR0_TXON)
        !          1235:       && ((am7990->tme_am7990_transmit_dte_tmd1
        !          1236:           & (TME_AM7990_XMD1_OWN
        !          1237:              | TME_AM7990_XMD1_STP))
        !          1238:          == (TME_AM7990_XMD1_OWN
        !          1239:              | TME_AM7990_XMD1_STP))) {
        !          1240:        
        !          1241:     /* see if we will add the FCS to this transmitted packet.
        !          1242:        "ADD_FCS is only valid when STP=1." */
        !          1243:     add_fcs =
        !          1244:       (!(am7990->tme_am7990_mode
        !          1245:         & TME_AM7990_MODE_DTCR)
        !          1246:        || (am7990->tme_am7990_transmit_dte_tmd1
        !          1247:           & TME_AM7990_TMD1_ADD_FCS));
        !          1248: 
        !          1249:     /* if we're in loopback mode, transmit this packet directly into
        !          1250:        the receive buffer: */
        !          1251:     if (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP) {
        !          1252:       frame_chunk_buffer.tme_ethernet_frame_chunk_bytes = &am7990->tme_am7990_receive_buffer[0];
        !          1253:       frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count = sizeof(am7990->tme_am7990_receive_buffer);
        !          1254:       frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL;
        !          1255:       frame_chunk = &frame_chunk_buffer;
        !          1256:     }
        !          1257: 
        !          1258:     do {
        !          1259: 
        !          1260:       /* recover the previously read TMD1: */
        !          1261:       transmit_dte_tmd1 = am7990->tme_am7990_transmit_dte_tmd1;
        !          1262: 
        !          1263:       /* read TMD0 and TMD2: */
        !          1264:       transmit_dte_tmd0
        !          1265:        = _tme_am7990_tx_read(am7990,
        !          1266:                              TME_AM7990_DTE_OFFSET_XMD0,
        !          1267:                              &cancelled);
        !          1268:       if (cancelled) {
        !          1269:        break;
        !          1270:       }
        !          1271:       transmit_dte_tmd2
        !          1272:        = _tme_am7990_tx_read(am7990,
        !          1273:                              TME_AM7990_DTE_OFFSET_XMD2,
        !          1274:                              &cancelled);
        !          1275:       if (cancelled) {
        !          1276:        break;
        !          1277:       }
        !          1278: 
        !          1279:       /* get the transmit buffer address and count: */
        !          1280:       transmit_buffer_address = (transmit_dte_tmd1 & TME_AM7990_XMD1_HADR);
        !          1281:       transmit_buffer_address = (transmit_buffer_address << 16) + transmit_dte_tmd0;
        !          1282:       transmit_buffer_count = (0 - transmit_dte_tmd2) & TME_AM7990_XMD2_BCNT;
        !          1283: 
        !          1284:       /* read this transmit buffer into the frame chunks: */
        !          1285:       frame_chunk_bytes = NULL;
        !          1286:       frame_chunk_bytes_count = 0;
        !          1287:       for (; transmit_buffer_count > 0; ) {
        !          1288: 
        !          1289:        /* if we have exhausted the previous chunk: */
        !          1290:        if (frame_chunk_bytes_count == 0) {
        !          1291:          
        !          1292:          /* advance to the next chunk: */
        !          1293:          if (frame_chunk == NULL) {
        !          1294:            frame_chunk_bytes = &frame_chunk_bytes_buffer[0];
        !          1295:            frame_chunk_bytes_count = sizeof(frame_chunk_bytes_buffer);
        !          1296:          }
        !          1297:          else {
        !          1298:            frame_chunk_bytes = frame_chunk->tme_ethernet_frame_chunk_bytes;
        !          1299:            frame_chunk_bytes_count = frame_chunk->tme_ethernet_frame_chunk_bytes_count;
        !          1300:            frame_chunk = frame_chunk->tme_ethernet_frame_chunk_next;
        !          1301:            continue;
        !          1302:          }
        !          1303:        }
        !          1304:            
        !          1305:        /* get the count of bytes to read in this iteration: */
        !          1306:        count = TME_MIN(frame_chunk_bytes_count, transmit_buffer_count);
        !          1307: 
        !          1308:        /* do the read: */
        !          1309:        cancelled 
        !          1310:          = _tme_am7990_dma(am7990,
        !          1311:                            TME_AM7990_CALLOUT_DMA_READ,
        !          1312:                            transmit_buffer_address,
        !          1313:                            count,
        !          1314:                            frame_chunk_bytes);
        !          1315:        if (cancelled) {
        !          1316:          break;
        !          1317:        }
        !          1318: 
        !          1319:        /* advance: */
        !          1320:        frame_chunk_bytes += count;
        !          1321:        frame_chunk_bytes_count -= count;
        !          1322:        transmit_buffer_address += count;
        !          1323:        transmit_buffer_count -= count;
        !          1324:        rc += count;
        !          1325:       }
        !          1326:       if (cancelled) {
        !          1327:        break;
        !          1328:       }
        !          1329: 
        !          1330:       /* if this is the last transmit buffer in the packet: */
        !          1331:       if (transmit_dte_tmd1 & TME_AM7990_XMD1_ENP) {
        !          1332: 
        !          1333:        /* we can't suppress CRC generation: */
        !          1334:        if (!add_fcs) {
        !          1335:          abort();
        !          1336:        }
        !          1337: 
        !          1338:        /* clear TMD1 for the next transmit buffer: */
        !          1339:        transmit_dte_tmd1_next = 0;
        !          1340: 
        !          1341:        /* this is the last transmit buffer: */
        !          1342:        stop = TRUE;
        !          1343:       }
        !          1344: 
        !          1345:       /* otherwise, this is not the last transmit buffer in the packet: */
        !          1346:       else {
        !          1347:        
        !          1348:        /* read TMD1 for the next transmit buffer: */
        !          1349:        transmit_dte_tmd1_next
        !          1350:          = _tme_am7990_tx_read(am7990,
        !          1351:                                (TME_AM7990_DTE_SIZE
        !          1352:                                 + TME_AM7990_DTE_OFFSET_XMD1),
        !          1353:                                &cancelled);
        !          1354:        if (cancelled) {
        !          1355:          break;
        !          1356:        }
        !          1357: 
        !          1358:        /* if we don't own the next transmit buffer: */
        !          1359:        stop = !(transmit_dte_tmd1_next & TME_AM7990_XMD1_OWN);
        !          1360:        if (stop) {
        !          1361: 
        !          1362:          tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !          1363:                  500, TME_OK,
        !          1364:                  (&am7990->tme_am7990_element->tme_element_log_handle,
        !          1365:                   "transmit BUFF"));
        !          1366: 
        !          1367:          /* write a TMD3 with BUFF set: */
        !          1368:          cancelled
        !          1369:            = _tme_am7990_tx_write(am7990,
        !          1370:                                   TME_AM7990_DTE_OFFSET_XMD3, 
        !          1371:                                   TME_AM7990_TMD3_BUFF);
        !          1372:          if (cancelled) {
        !          1373:            break;
        !          1374:          }
        !          1375: 
        !          1376:          /* turn off the transmitter: */
        !          1377:          am7990->tme_am7990_csr0 &= ~TME_AM7990_CSR0_TXON;
        !          1378:        }
        !          1379:       }
        !          1380: 
        !          1381:       /* write TMD1 to clear OWN: */
        !          1382:       cancelled
        !          1383:        = _tme_am7990_tx_write(am7990,
        !          1384:                               TME_AM7990_DTE_OFFSET_XMD1,
        !          1385:                               (transmit_dte_tmd1
        !          1386:                                & ~TME_AM7990_XMD1_OWN));
        !          1387:       if (cancelled) {
        !          1388:        break;
        !          1389:       }
        !          1390: 
        !          1391:       /* advance to the next transmit buffer: */
        !          1392:       am7990->tme_am7990_transmit_dte_index
        !          1393:        = ((am7990->tme_am7990_transmit_dte_index
        !          1394:            + 1)
        !          1395:           & am7990->tme_am7990_transmit_dte_index_mask);
        !          1396:       am7990->tme_am7990_transmit_dte_tmd1 = transmit_dte_tmd1_next;
        !          1397:     } while (!stop);
        !          1398: 
        !          1399:     /* if nothing was cancelled: */
        !          1400:     if (!cancelled) {
        !          1401:       
        !          1402:       /* generate a transmit interrupt: */
        !          1403:       am7990->tme_am7990_csr0 |= TME_AM7990_CSR0_TINT;
        !          1404:     }
        !          1405:   }
        !          1406: 
        !          1407:   /* if we're in loopback mode: */
        !          1408:   if (am7990->tme_am7990_mode & TME_AM7990_MODE_LOOP) {
        !          1409: 
        !          1410:     /* if we have a loopback packet: */
        !          1411:     if (rc > 0) {
        !          1412: 
        !          1413:       /* append the CRC bytes: */
        !          1414:       if ((rc + sizeof(tme_uint32_t)) > sizeof(am7990->tme_am7990_receive_buffer)) {
        !          1415:        abort();
        !          1416:       }
        !          1417:       rc += sizeof(tme_uint32_t);
        !          1418:       
        !          1419:       /* set the receive buffer length: */
        !          1420:       am7990->tme_am7990_receive_buffer_length = rc;
        !          1421:     }
        !          1422: 
        !          1423:     /* if we have a loopback packet, call out a receive: */
        !          1424:     if (am7990->tme_am7990_receive_buffer_length > 0) {
        !          1425:       am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_RECEIVE;
        !          1426:     }
        !          1427:   }
        !          1428: 
        !          1429:   /* otherwise, if we're not returning a packet: */
        !          1430:   else if (rc <= 0) {
        !          1431: 
        !          1432:     /* we aren't considered readable any more: */
        !          1433:     am7990->tme_am7990_ether_ctrl_out &= ~TME_ETHERNET_CTRL_OK_READ;
        !          1434:   }
        !          1435: 
        !          1436:   /* start a scan for the first buffer in the next packet to transmit: */
        !          1437:   am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_TRANSMIT_SCAN;
        !          1438: 
        !          1439:   /* make any new callouts: */
        !          1440:   _tme_am7990_callout(am7990);
        !          1441: 
        !          1442:   /* unlock our mutex: */
        !          1443:   tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1444: 
        !          1445:   /* done: */
        !          1446:   return (rc);
        !          1447: 
        !          1448:   /* unused: */
        !          1449:   _frame_id = 0;
        !          1450:   flags = 0;
        !          1451: }
        !          1452: 
        !          1453: /* the am7990 descriptor polling thread: */
        !          1454: static void
        !          1455: _tme_am7990_poll_th(struct tme_am7990 *am7990)
        !          1456: {
        !          1457: 
        !          1458:   /* lock our mutex: */
        !          1459:   tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1460: 
        !          1461:   /* loop forever: */
        !          1462:   for (;;) {
        !          1463: 
        !          1464:     /* call out a transmit scan: */
        !          1465:     am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_TRANSMIT_SCAN;
        !          1466: 
        !          1467:     /* make any callouts: */
        !          1468:     _tme_am7990_callout(am7990);
        !          1469: 
        !          1470:     /* unlock our mutex: */
        !          1471:     tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1472: 
        !          1473:     /* "[T]he C-LANCE will automatically poll the transmit ring in the
        !          1474:        memory once it has started ..  every 1.6ms" */
        !          1475:     tme_thread_sleep_yield(0, 16000);
        !          1476: 
        !          1477:     /* lock our mutex: */
        !          1478:     tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1479:   }
        !          1480:   /* NOTREACHED */
        !          1481: }
        !          1482: 
        !          1483: /* the am7990 bus cycle handler: */
        !          1484: static int
        !          1485: _tme_am7990_bus_cycle(void *_am7990, struct tme_bus_cycle *cycle_init)
        !          1486: {
        !          1487:   struct tme_am7990 *am7990;
        !          1488:   tme_bus_addr_t address, am7990_address_last;
        !          1489:   tme_uint16_t value;
        !          1490:   tme_uint32_t reg;
        !          1491:   tme_uint16_t csr0_old;
        !          1492:   tme_uint16_t csr0_new;
        !          1493:   tme_uint8_t port_init;
        !          1494:   unsigned int routing_index;
        !          1495: 
        !          1496:   /* recover our data structure: */
        !          1497:   am7990 = (struct tme_am7990 *) _am7990;
        !          1498: 
        !          1499:   /* the address must be within range: */
        !          1500:   am7990_address_last = am7990->tme_am7990_device.tme_bus_device_address_last;
        !          1501:   assert(cycle_init->tme_bus_cycle_address <= am7990_address_last);
        !          1502:   assert(cycle_init->tme_bus_cycle_size <= (am7990_address_last - cycle_init->tme_bus_cycle_address) + 1);
        !          1503: 
        !          1504:   /* get the register being accessed: */
        !          1505:   address = cycle_init->tme_bus_cycle_address;
        !          1506:   reg = (address & ((am7990_address_last + 1) / 2));
        !          1507: 
        !          1508:   /* save the initiator's port description: */
        !          1509:   port_init = cycle_init->tme_bus_cycle_port;
        !          1510:   
        !          1511:   /* lock the mutex: */
        !          1512:   tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1513: 
        !          1514:   /* if this is a write: */
        !          1515:   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
        !          1516: 
        !          1517:     /* run the bus cycle: */
        !          1518:     tme_bus_cycle_xfer_reg(cycle_init, 
        !          1519:                           &value,
        !          1520:                           TME_BUS16_LOG2);
        !          1521: 
        !          1522:     /* if this was a write to the RAP: */
        !          1523:     if (reg == am7990->tme_am7990_offset_rap) {
        !          1524: 
        !          1525:       /* set the new RAP: */
        !          1526:       am7990->tme_am7990_rap = value % TME_ARRAY_ELS(am7990->tme_am7990_csrs);
        !          1527:     }
        !          1528: 
        !          1529:     /* otherwise, this was a write to the RDP: */
        !          1530:     else {
        !          1531:       assert (reg == am7990->tme_am7990_offset_rdp);
        !          1532: 
        !          1533:       /* if this is a write to CSR0: */
        !          1534:       if (am7990->tme_am7990_rap == 0) {
        !          1535: 
        !          1536:        /* get the previous value of CSR0: */
        !          1537:        csr0_old = am7990->tme_am7990_csr0;
        !          1538: 
        !          1539:        /* handle the read-only, write-1-to-clear, and write-1-only
        !          1540:            bits: */
        !          1541:        csr0_new = ((value & ~TME_AM7990_CSR0_READ_ONLY)
        !          1542:                    | (csr0_old
        !          1543:                       & (TME_AM7990_CSR0_READ_ONLY
        !          1544:                          | TME_AM7990_CSR0_WRITE_ONE_ONLY)));
        !          1545:        csr0_new = ((csr0_new ^ TME_AM7990_CSR0_WRITE_ONE_TO_CLEAR)
        !          1546:                    & (csr0_old | ~TME_AM7990_CSR0_WRITE_ONE_TO_CLEAR));
        !          1547: 
        !          1548:        /* update ERR: */
        !          1549:        csr0_new &= ~TME_AM7990_CSR0_ERR;
        !          1550:        if (csr0_new
        !          1551:            & (TME_AM7990_CSR0_BABL
        !          1552:               | TME_AM7990_CSR0_CERR
        !          1553:               | TME_AM7990_CSR0_MISS
        !          1554:               | TME_AM7990_CSR0_MERR)) {
        !          1555:          csr0_new |= TME_AM7990_CSR0_ERR;
        !          1556:        }
        !          1557: 
        !          1558:        /* set the initial new CSR0 value: */
        !          1559:        am7990->tme_am7990_csr0 = csr0_new;
        !          1560: 
        !          1561:        /* "If STRT, INIT and STOP are all set together, STOP will
        !          1562:            override the other bits and only STOP will be set." */
        !          1563:        if (value & TME_AM7990_CSR0_STOP) {
        !          1564: 
        !          1565:          /* reset the am7990: */
        !          1566:          _tme_am7990_reset(am7990);
        !          1567:        }
        !          1568: 
        !          1569:        /* otherwise, STOP is not set in the new CSR0 value: */
        !          1570:        else {
        !          1571: 
        !          1572:          /* if INIT is set in the CSR0 value written, and STOP is set
        !          1573:              in the old CSR0 value: */
        !          1574:          if ((value & TME_AM7990_CSR0_INIT)
        !          1575:              && (csr0_old & TME_AM7990_CSR0_STOP)) {
        !          1576: 
        !          1577:            /* run the initialization procedure: */
        !          1578:            _tme_am7990_init(am7990);
        !          1579:          }
        !          1580: 
        !          1581:          /* if STRT is set in the CSR0 value written, and STRT is not
        !          1582:             set in the old CSR0 value: */
        !          1583:          if ((value & TME_AM7990_CSR0_STRT)
        !          1584:              && !(csr0_old & TME_AM7990_CSR0_STRT)) {
        !          1585: 
        !          1586:            /* start the am7990: */
        !          1587:            _tme_am7990_start(am7990);
        !          1588:          }
        !          1589: 
        !          1590:          /* if TDMD is set in the CSR0 value written, call out a
        !          1591:              transmit scan: */
        !          1592:          if (value & TME_AM7990_CSR0_TDMD) {
        !          1593:            am7990->tme_am7990_callout_flags |= TME_AM7990_CALLOUT_TRANSMIT_SCAN;
        !          1594:          }
        !          1595:        }
        !          1596:       }
        !          1597: 
        !          1598:       /* otherwise, this is writing another CSR: */
        !          1599:       else {
        !          1600: 
        !          1601:        tme_log(&am7990->tme_am7990_element->tme_element_log_handle,
        !          1602:                100, TME_OK,
        !          1603:                (&am7990->tme_am7990_element->tme_element_log_handle,
        !          1604:                 "CSR%u <- 0x%04x",
        !          1605:                 am7990->tme_am7990_rap,
        !          1606:                 value));
        !          1607: 
        !          1608:        am7990->tme_am7990_csrs[am7990->tme_am7990_rap] = value;
        !          1609:       }
        !          1610:     }
        !          1611:   }
        !          1612:            
        !          1613:   /* otherwise, this is a read: */
        !          1614:   else {
        !          1615:     assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
        !          1616: 
        !          1617:     /* get the value to read: */
        !          1618:     if (reg == am7990->tme_am7990_offset_rap) {
        !          1619:       value = am7990->tme_am7990_rap;
        !          1620:     }
        !          1621:     else {
        !          1622:       assert (reg == am7990->tme_am7990_offset_rdp);
        !          1623:       value = am7990->tme_am7990_csrs[am7990->tme_am7990_rap];
        !          1624:     }
        !          1625: 
        !          1626:     /* run the bus cycle: */
        !          1627:     tme_bus_cycle_xfer_reg(cycle_init, 
        !          1628:                           &value,
        !          1629:                           TME_BUS16_LOG2);
        !          1630:   }
        !          1631: 
        !          1632:   /* NB: the generic memory implementation doesn't know its own port
        !          1633:      size or endianness, and instead just follows the endianness of
        !          1634:      whatever reads and writes it (see tme_bus_cycle_xfer_memory()).
        !          1635:      this is sort of a fragile system, but does allow the same generic
        !          1636:      memory implementation to work with all kinds of CPU emulations.
        !          1637: 
        !          1638:      the fragility shows with a chip like the am7990.  for all of its
        !          1639:      non-Ethernet data bus mastering, the real chip doesn't need to
        !          1640:      know memory's endianness; it just reads a 16-bit quantity from a
        !          1641:      16-bit aligned address and expects that the most-significant
        !          1642:      eight bits will be on D8..D15.  but since the memory doesn't know
        !          1643:      its own endianness, we have to use a bus routing that matches the
        !          1644:      endianness of the bus routing used by the CPU that wrote the
        !          1645:      memory.
        !          1646: 
        !          1647:      fortunately, we can learn the endianness of the CPU when it reads
        !          1648:      or writes us.  we do this here: */
        !          1649:   if (am7990->tme_am7990_device.tme_bus_device_router == NULL) {
        !          1650: 
        !          1651:     /* get the index into the bus routing used by the initiator for
        !          1652:        this cycle.  if the initiator's least lane is zero, then this
        !          1653:        is also a lane number: */
        !          1654:     routing_index
        !          1655:       = (TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_init->tme_bus_cycle_port)
        !          1656:         - TME_BUS_CYCLE_PORT_LANE_LEAST(port_init));
        !          1657: 
        !          1658:     /* if the initiator routed a byte from a lower address to the byte
        !          1659:        lane of lesser significance, then we assume that memory is
        !          1660:        little-endian: */
        !          1661:     am7990->tme_am7990_device.tme_bus_device_router
        !          1662:       = ((cycle_init->tme_bus_cycle_lane_routing[routing_index + 0]
        !          1663:          < cycle_init->tme_bus_cycle_lane_routing[routing_index + 1])
        !          1664:         ? tme_bus_device_router_16el
        !          1665:         : tme_bus_device_router_16eb);
        !          1666:   }
        !          1667: 
        !          1668:   /* make any new callouts: */
        !          1669:   _tme_am7990_callout(am7990);
        !          1670: 
        !          1671:   /* unlock the mutex: */
        !          1672:   tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1673: 
        !          1674:   /* no faults: */
        !          1675:   return (TME_OK);
        !          1676: }
        !          1677: 
        !          1678: /* the am7990 TLB filler: */
        !          1679: static int
        !          1680: _tme_am7990_tlb_fill(void *_am7990,
        !          1681:                     struct tme_bus_tlb *tlb, 
        !          1682:                     tme_bus_addr_t address,
        !          1683:                     unsigned int cycles)
        !          1684: {
        !          1685:   struct tme_am7990 *am7990;
        !          1686:   tme_bus_addr_t am7990_address_last;
        !          1687: 
        !          1688:   /* recover our data structure: */
        !          1689:   am7990 = (struct tme_am7990 *) _am7990;
        !          1690: 
        !          1691:   /* the address must be within range: */
        !          1692:   am7990_address_last = am7990->tme_am7990_device.tme_bus_device_address_last;
        !          1693:   assert(address <= am7990_address_last);
        !          1694: 
        !          1695:   /* initialize the TLB entry: */
        !          1696:   tme_bus_tlb_initialize(tlb);
        !          1697: 
        !          1698:   /* this TLB entry can cover the whole device: */
        !          1699:   tlb->tme_bus_tlb_addr_first = 0;
        !          1700:   tlb->tme_bus_tlb_addr_last = am7990_address_last;
        !          1701: 
        !          1702:   /* allow reading and writing: */
        !          1703:   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
        !          1704: 
        !          1705:   /* our bus cycle handler: */
        !          1706:   tlb->tme_bus_tlb_cycle_private = am7990;
        !          1707:   tlb->tme_bus_tlb_cycle = _tme_am7990_bus_cycle;
        !          1708: 
        !          1709:   return (TME_OK);
        !          1710: }
        !          1711: 
        !          1712: /* this makes a new Ethernet connection: */
        !          1713: static int
        !          1714: _tme_am7990_connection_make_eth(struct tme_connection *conn, unsigned int state)
        !          1715: {
        !          1716:   struct tme_am7990 *am7990;
        !          1717:   struct tme_ethernet_connection *conn_eth;
        !          1718:   struct tme_ethernet_connection *conn_eth_other;
        !          1719: 
        !          1720:   /* recover our data structures: */
        !          1721:   am7990 = conn->tme_connection_element->tme_element_private;
        !          1722:   conn_eth = (struct tme_ethernet_connection *) conn;
        !          1723:   conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other;
        !          1724: 
        !          1725:   /* both sides must be Ethernet connections: */
        !          1726:   assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET);
        !          1727:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET);
        !          1728: 
        !          1729:   /* we're always set up to answer calls across the connection, so we
        !          1730:      only have to do work when the connection has gone full, namely
        !          1731:      taking the other side of the connection: */
        !          1732:   if (state == TME_CONNECTION_FULL) {
        !          1733: 
        !          1734:     /* lock our mutex: */
        !          1735:     tme_mutex_lock(&am7990->tme_am7990_mutex);
        !          1736: 
        !          1737:     /* save our connection: */
        !          1738:     am7990->tme_am7990_eth_connection = conn_eth_other;
        !          1739: 
        !          1740:     /* unlock our mutex: */
        !          1741:     tme_mutex_unlock(&am7990->tme_am7990_mutex);
        !          1742:   }
        !          1743: 
        !          1744:   return (TME_OK);
        !          1745: }
        !          1746: 
        !          1747: /* this makes a new bus connection: */
        !          1748: static int
        !          1749: _tme_am7990_connection_make_bus(struct tme_connection *conn,
        !          1750:                                unsigned int state)
        !          1751: {
        !          1752:   struct tme_am7990 *am7990;
        !          1753:   struct tme_bus_connection *conn_bus;
        !          1754:   int rc;
        !          1755: 
        !          1756:   /* recover our data structure: */
        !          1757:   am7990 = conn->tme_connection_element->tme_element_private;
        !          1758: 
        !          1759:   /* call the bus device connection maker: */
        !          1760:   rc = tme_bus_device_connection_make(conn, state);
        !          1761: 
        !          1762:   /* if the full connection was successful, and we don't have a TLB
        !          1763:      hash yet, allocate it: */
        !          1764:   if (rc == TME_OK
        !          1765:       && state == TME_CONNECTION_FULL
        !          1766:       && tme_memory_atomic_pointer_read(struct tme_bus_tlb *,
        !          1767:                                        am7990->tme_am7990_tlb_hash,
        !          1768:                                        &am7990->tme_am7990_tlb_hash_rwlock) == NULL) {
        !          1769: 
        !          1770:     /* get our bus connection: */
        !          1771:     conn_bus
        !          1772:       = tme_memory_atomic_pointer_read(struct tme_bus_connection *,
        !          1773:                                       am7990->tme_am7990_device.tme_bus_device_connection,
        !          1774:                                       &am7990->tme_am7990_device.tme_bus_device_connection_rwlock);
        !          1775: 
        !          1776:     /* allocate the TLB set: */
        !          1777:     rc = ((*conn_bus->tme_bus_tlb_set_allocate)
        !          1778:          (conn_bus,
        !          1779:           TME_AM7990_TLB_HASH_SIZE, 
        !          1780:           sizeof(struct tme_bus_tlb),
        !          1781:           &am7990->tme_am7990_tlb_hash,
        !          1782:           &am7990->tme_am7990_device.tme_bus_device_connection_rwlock));
        !          1783:     assert (rc == TME_OK);
        !          1784:   }
        !          1785: 
        !          1786:   return (rc);
        !          1787: }
        !          1788: 
        !          1789: /* this breaks a connection: */
        !          1790: static int
        !          1791: _tme_am7990_connection_break(struct tme_connection *conn, unsigned int state)
        !          1792: {
        !          1793:   abort();
        !          1794: }
        !          1795: 
        !          1796: /* this makes a new connection side for a am7990: */
        !          1797: static int
        !          1798: _tme_am7990_connections_new(struct tme_element *element,
        !          1799:                           const char * const *args,
        !          1800:                           struct tme_connection **_conns,
        !          1801:                           char **_output)
        !          1802: {
        !          1803:   struct tme_am7990 *am7990;
        !          1804:   struct tme_ethernet_connection *conn_eth;
        !          1805:   struct tme_connection *conn;
        !          1806:   int rc;
        !          1807: 
        !          1808:   /* recover our data structure: */
        !          1809:   am7990 = (struct tme_am7990 *) element->tme_element_private;
        !          1810: 
        !          1811:   /* make the generic bus device connection side: */
        !          1812:   rc = tme_bus_device_connections_new(element, args, _conns, _output);
        !          1813:   if (rc != TME_OK) {
        !          1814:     return (rc);
        !          1815:   }
        !          1816: 
        !          1817:   /* since we need to allocate our TLB hash when we make our bus
        !          1818:      connection, make sure any generic bus device connection sides use
        !          1819:      our connection maker: */
        !          1820:   for (conn = *_conns;
        !          1821:        conn != NULL;
        !          1822:        conn = conn->tme_connection_next) {
        !          1823:     if ((conn->tme_connection_type
        !          1824:         == TME_CONNECTION_BUS_GENERIC)
        !          1825:        && (conn->tme_connection_make
        !          1826:            == tme_bus_device_connection_make)) {
        !          1827:       conn->tme_connection_make
        !          1828:        = _tme_am7990_connection_make_bus;
        !          1829:     }
        !          1830:   }
        !          1831: 
        !          1832:   /* if we don't have an Ethernet connection, make one: */
        !          1833:   if (am7990->tme_am7990_eth_connection == NULL) {
        !          1834: 
        !          1835:     /* allocate the new Ethernet connection: */
        !          1836:     conn_eth = tme_new0(struct tme_ethernet_connection, 1);
        !          1837:     conn = &conn_eth->tme_ethernet_connection;
        !          1838:     
        !          1839:     /* fill in the generic connection: */
        !          1840:     conn->tme_connection_next = *_conns;
        !          1841:     conn->tme_connection_type = TME_CONNECTION_ETHERNET;
        !          1842:     conn->tme_connection_score = tme_ethernet_connection_score;
        !          1843:     conn->tme_connection_make = _tme_am7990_connection_make_eth;
        !          1844:     conn->tme_connection_break = _tme_am7990_connection_break;
        !          1845: 
        !          1846:     /* fill in the Ethernet connection: */
        !          1847:     conn_eth->tme_ethernet_connection_config = _tme_am7990_config;
        !          1848:     conn_eth->tme_ethernet_connection_ctrl = _tme_am7990_ctrl;
        !          1849:     conn_eth->tme_ethernet_connection_read = _tme_am7990_transmit;
        !          1850: 
        !          1851:     /* return the connection side possibility: */
        !          1852:     *_conns = conn;
        !          1853:   }
        !          1854: 
        !          1855:   /* done: */
        !          1856:   return (TME_OK);
        !          1857: }
        !          1858: 
        !          1859: /* the new am7990 function: */
        !          1860: TME_ELEMENT_X_NEW_DECL(tme_ic_,am7990,am7990) {
        !          1861:   struct tme_am7990 *am7990;
        !          1862:   int arg_i;
        !          1863:   int usage;
        !          1864:   tme_uint32_t reg_size;
        !          1865: 
        !          1866:   /* check our arguments: */
        !          1867:   usage = 0;
        !          1868:   arg_i = 1;
        !          1869:   for (;;) {
        !          1870: 
        !          1871:     if (0) {
        !          1872:     }
        !          1873: 
        !          1874:     /* if we ran out of arguments: */
        !          1875:     else if (args[arg_i] == NULL) {
        !          1876: 
        !          1877:       break;
        !          1878:     }
        !          1879: 
        !          1880:     /* otherwise this is a bad argument: */
        !          1881:     else {
        !          1882:       tme_output_append_error(_output,
        !          1883:                              "%s %s, ",
        !          1884:                              args[arg_i],
        !          1885:                              _("unexpected"));
        !          1886:       usage = TRUE;
        !          1887:       break;
        !          1888:     }
        !          1889:   }
        !          1890: 
        !          1891:   if (usage) {
        !          1892:     tme_output_append_error(_output, 
        !          1893:                            "%s %s",
        !          1894:                            _("usage:"),
        !          1895:                            args[0]);
        !          1896:     return (EINVAL);
        !          1897:   }
        !          1898: 
        !          1899:   /* start the am7990 structure: */
        !          1900:   am7990 = tme_new0(struct tme_am7990, 1);
        !          1901:   am7990->tme_am7990_element = element;
        !          1902:   tme_mutex_init(&am7990->tme_am7990_mutex);
        !          1903: 
        !          1904:   /* set the register offsets: */
        !          1905:   /* XXX FIXME - these should come from a socket structure: */
        !          1906:   am7990->tme_am7990_offset_rdp = 0;
        !          1907:   am7990->tme_am7990_offset_rap = sizeof(tme_uint16_t);
        !          1908: 
        !          1909:   /* get the total register size: */
        !          1910:   assert ((am7990->tme_am7990_offset_rdp & (am7990->tme_am7990_offset_rdp - 1)) == 0);
        !          1911:   assert ((am7990->tme_am7990_offset_rap & (am7990->tme_am7990_offset_rap - 1)) == 0);
        !          1912:   reg_size = TME_MAX(am7990->tme_am7990_offset_rdp, am7990->tme_am7990_offset_rap) * 2;
        !          1913: 
        !          1914:   /* initialize our simple bus device descriptor: */
        !          1915:   am7990->tme_am7990_device.tme_bus_device_element = element;
        !          1916:   am7990->tme_am7990_device.tme_bus_device_tlb_fill = _tme_am7990_tlb_fill;
        !          1917:   am7990->tme_am7990_device.tme_bus_device_address_last = reg_size - 1;
        !          1918:   am7990->tme_am7990_device.tme_bus_device_signal = _tme_am7990_signal;
        !          1919:   am7990->tme_am7990_device.tme_bus_device_lock = _tme_am7990_lock;
        !          1920:   am7990->tme_am7990_device.tme_bus_device_unlock = _tme_am7990_unlock;
        !          1921:   am7990->tme_am7990_device.tme_bus_device_tlb_hash = _tme_am7990_tlb_hash;
        !          1922: 
        !          1923:   /* fill the element: */
        !          1924:   element->tme_element_private = am7990;
        !          1925:   element->tme_element_connections_new = _tme_am7990_connections_new;
        !          1926: 
        !          1927:   /* start the descriptor polling thread: */
        !          1928:   tme_thread_create((tme_thread_t) _tme_am7990_poll_th, am7990);
        !          1929: 
        !          1930:   /* reset the am7990: */
        !          1931:   _tme_am7990_reset(am7990);
        !          1932: 
        !          1933:   return (TME_OK);
        !          1934: }

unix.superglobalmegacorp.com

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