[BACK]Return to midway.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/midway.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: midway.c,v 1.37 2006/03/25 22:41:43 djm Exp $ */
                      2: /*     (sync'd to midway.c 1.68)       */
                      3:
                      4: /*
                      5:  *
                      6:  * Copyright (c) 1996 Charles D. Cranor and Washington University.
                      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 Charles D. Cranor and
                     20:  *     Washington University.
                     21:  * 4. The name of the author may not be used to endorse or promote products
                     22:  *    derived from this software without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     27:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     28:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     29:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     30:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     31:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     32:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     33:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35:
                     36: /*
                     37:  *
                     38:  * m i d w a y . c   e n i 1 5 5   d r i v e r
                     39:  *
                     40:  * author: Chuck Cranor <chuck@ccrc.wustl.edu>
                     41:  * started: spring, 1996 (written from scratch).
                     42:  *
                     43:  * notes from the author:
                     44:  *   Extra special thanks go to Werner Almesberger, EPFL LRC.   Werner's
                     45:  *   ENI driver was especially useful in figuring out how this card works.
                     46:  *   I would also like to thank Werner for promptly answering email and being
                     47:  *   generally helpful.
                     48:  */
                     49:
                     50:
                     51: #undef EN_DEBUG
                     52: #undef EN_DEBUG_RANGE          /* check ranges on en_read/en_write's? */
                     53: #define        EN_MBUF_OPT             /* try and put more stuff in mbuf? */
                     54: #define        EN_DIAG
                     55: #define        EN_STAT
                     56: #ifndef EN_DMA
                     57: #define EN_DMA         1       /* use dma? */
                     58: #endif
                     59: #define EN_NOTXDMA     0       /* hook to disable tx dma only */
                     60: #define EN_NORXDMA     0       /* hook to disable rx dma only */
                     61: #define EN_NOWMAYBE    1       /* hook to disable word maybe DMA */
                     62:                                /* XXX: WMAYBE doesn't work, needs debugging */
                     63: #define EN_DDBHOOK     1       /* compile in ddb functions */
                     64: #if defined(MIDWAY_ADPONLY)
                     65: #define EN_ENIDMAFIX   0       /* no ENI cards to worry about */
                     66: #else
                     67: #define EN_ENIDMAFIX   1       /* avoid byte DMA on the ENI card (see below) */
                     68: #endif
                     69:
                     70: /*
                     71:  * note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card
                     72:  * appears to be broken.   it works just fine if there is no load... however
                     73:  * when the card is loaded the data get corrupted.   to see this, one only
                     74:  * has to use "telnet" over ATM.   do the following command in "telnet":
                     75:  *     cat /usr/share/misc/termcap
                     76:  * "telnet" seems to generate lots of 1023 byte mbufs (which make great
                     77:  * use of the byte aligner).   watch "netstat -s" for checksum errors.
                     78:  *
                     79:  * I further tested this by adding a function that compared the transmit
                     80:  * data on the card's SRAM with the data in the mbuf chain _after_ the
                     81:  * "transmit DMA complete" interrupt.   using the "telnet" test I got data
                     82:  * mismatches where the byte-aligned data should have been.   using ddb
                     83:  * and en_dumpmem() I verified that the DTQs fed into the card were
                     84:  * absolutely correct.   thus, we are forced to concluded that the ENI
                     85:  * hardware is buggy.   note that the Adaptec version of the card works
                     86:  * just fine with byte DMA.
                     87:  *
                     88:  * bottom line: we set EN_ENIDMAFIX to 1 to avoid byte DMAs on the ENI
                     89:  * card.
                     90:  */
                     91:
                     92: #if defined(DIAGNOSTIC) && !defined(EN_DIAG)
                     93: #define EN_DIAG                        /* link in with master DIAG option */
                     94: #endif
                     95: #ifdef EN_STAT
                     96: #define EN_COUNT(X) (X)++
                     97: #else
                     98: #define EN_COUNT(X) /* nothing */
                     99: #endif
                    100:
                    101: #ifdef EN_DEBUG
                    102: #undef EN_DDBHOOK
                    103: #define        EN_DDBHOOK      1
                    104: #define STATIC /* nothing */
                    105: #define INLINE /* nothing */
                    106: #else /* EN_DEBUG */
                    107: #define STATIC static
                    108: #define INLINE inline
                    109: #endif /* EN_DEBUG */
                    110:
                    111: #include "bpfilter.h"
                    112:
                    113: #ifdef __FreeBSD__
                    114: #include "en.h"
                    115: #endif
                    116:
                    117: #if NEN > 0 || !defined(__FreeBSD__)
                    118:
                    119: #include <sys/param.h>
                    120: #include <sys/systm.h>
                    121: #include <sys/types.h>
                    122: #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
                    123: #include <sys/device.h>
                    124: #endif
                    125: #if defined(__FreeBSD__)
                    126: #include <sys/sockio.h>
                    127: #else
                    128: #include <sys/ioctl.h>
                    129: #endif
                    130: #include <sys/mbuf.h>
                    131: #include <sys/socket.h>
                    132: #include <sys/socketvar.h>
                    133:
                    134: #include <net/if.h>
                    135: #include <net/if_atm.h>
                    136:
                    137: #include <uvm/uvm_extern.h>
                    138:
                    139: #ifdef INET
                    140: #include <netinet/if_atm.h>
                    141: #endif
                    142:
                    143: #ifdef NATM
                    144: #include <netinet/in.h>
                    145: #include <netnatm/natm.h>
                    146: #endif
                    147:
                    148:
                    149: #if !defined(__sparc__) && !defined(__FreeBSD__)
                    150: #include <machine/bus.h>
                    151: #endif
                    152:
                    153: #if defined(__NetBSD__) || defined(__OpenBSD__)
                    154: #include <dev/ic/midwayreg.h>
                    155: #include <dev/ic/midwayvar.h>
                    156: #if defined(__alpha__)
                    157: /* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
                    158: #undef vtophys
                    159: #define        vtophys(va)     alpha_XXX_dmamap((vaddr_t)(va))
                    160: #endif
                    161: #elif defined(__FreeBSD__)
                    162: #include <machine/cpufunc.h>            /* for rdtsc proto for clock.h below */
                    163: #include <machine/clock.h>              /* for DELAY */
                    164: #include <dev/en/midwayreg.h>
                    165: #include <dev/en/midwayvar.h>
                    166: #include <vm/pmap.h>                   /* for vtophys proto */
                    167:
                    168: /*
                    169:  * 2.1.x does not have if_softc.   detect this by seeing if IFF_NOTRAILERS
                    170:  * is defined, as per kjc.
                    171:  */
                    172: #ifdef IFF_NOTRAILERS
                    173: #define MISSING_IF_SOFTC
                    174: #else
                    175: #define IFF_NOTRAILERS 0
                    176: #endif
                    177:
                    178: #endif /* __FreeBSD__ */
                    179:
                    180: #if NBPFILTER > 0
                    181: #include <net/bpf.h>
                    182: #endif
                    183:
                    184: /*
                    185:  * params
                    186:  */
                    187:
                    188: #ifndef EN_TXHIWAT
                    189: #define EN_TXHIWAT     (64*1024)       /* max 64 KB waiting to be DMAd out */
                    190: #endif
                    191:
                    192: #ifndef EN_MINDMA
                    193: #define EN_MINDMA      32      /* don't DMA anything less than this (bytes) */
                    194: #endif
                    195:
                    196: #define RX_NONE                0xffff  /* recv VC not in use */
                    197:
                    198: #define EN_OBHDR       ATM_PH_DRIVER7  /* TBD in first mbuf ! */
                    199: #define EN_OBTRL       ATM_PH_DRIVER8  /* PDU trailer in last mbuf ! */
                    200:
                    201: #define ENOTHER_FREE   0x01            /* free rxslot */
                    202: #define ENOTHER_DRAIN  0x02            /* almost free (drain DRQ dma) */
                    203: #define ENOTHER_RAW    0x04            /* 'raw' access  (aka boodi mode) */
                    204: #define ENOTHER_SWSL   0x08            /* in software service list */
                    205:
                    206: int en_dma = EN_DMA;                   /* use DMA (switch off for dbg) */
                    207:
                    208: /*
                    209:  * autoconfig attachments
                    210:  */
                    211:
                    212: struct cfdriver en_cd = {
                    213:     0, "en", DV_IFNET,
                    214: };
                    215:
                    216: /*
                    217:  * local structures
                    218:  */
                    219:
                    220: /*
                    221:  * params to en_txlaunch() function
                    222:  */
                    223:
                    224: struct en_launch {
                    225:   u_int32_t tbd1;              /* TBD 1 */
                    226:   u_int32_t tbd2;              /* TBD 2 */
                    227:   u_int32_t pdu1;              /* PDU 1 (aal5) */
                    228:   int nodma;                   /* don't use DMA */
                    229:   int need;                    /* total space we need (pad out if less data) */
                    230:   int mlen;                    /* length of mbuf (for dtq) */
                    231:   struct mbuf *t;              /* data */
                    232:   u_int32_t aal;               /* aal code */
                    233:   u_int32_t atm_vci;           /* vci */
                    234:   u_int8_t atm_flags;          /* flags */
                    235: };
                    236:
                    237:
                    238: /*
                    239:  * dma table (index by # of words)
                    240:  *
                    241:  * plan A: use WMAYBE
                    242:  * plan B: avoid WMAYBE
                    243:  */
                    244:
                    245: struct en_dmatab {
                    246:   u_int8_t bcode;              /* code */
                    247:   u_int8_t divshift;           /* byte divisor */
                    248: };
                    249:
                    250: static struct en_dmatab en_dma_planA[] = {
                    251:   { 0, 0 },            /* 0 */         { MIDDMA_WORD, 2 },     /* 1 */
                    252:   { MIDDMA_2WORD, 3},  /* 2 */         { MIDDMA_4WMAYBE, 2},   /* 3 */
                    253:   { MIDDMA_4WORD, 4},  /* 4 */         { MIDDMA_8WMAYBE, 2},   /* 5 */
                    254:   { MIDDMA_8WMAYBE, 2},        /* 6 */         { MIDDMA_8WMAYBE, 2},   /* 7 */
                    255:   { MIDDMA_8WORD, 5},   /* 8 */                { MIDDMA_16WMAYBE, 2},  /* 9 */
                    256:   { MIDDMA_16WMAYBE,2},        /* 10 */        { MIDDMA_16WMAYBE, 2},  /* 11 */
                    257:   { MIDDMA_16WMAYBE,2},        /* 12 */        { MIDDMA_16WMAYBE, 2},  /* 13 */
                    258:   { MIDDMA_16WMAYBE,2},        /* 14 */        { MIDDMA_16WMAYBE, 2},  /* 15 */
                    259:   { MIDDMA_16WORD, 6},  /* 16 */
                    260: };
                    261:
                    262: static struct en_dmatab en_dma_planB[] = {
                    263:   { 0, 0 },            /* 0 */         { MIDDMA_WORD, 2},      /* 1 */
                    264:   { MIDDMA_2WORD, 3},  /* 2 */         { MIDDMA_WORD, 2},      /* 3 */
                    265:   { MIDDMA_4WORD, 4},  /* 4 */         { MIDDMA_WORD, 2},      /* 5 */
                    266:   { MIDDMA_2WORD, 3},  /* 6 */         { MIDDMA_WORD, 2},      /* 7 */
                    267:   { MIDDMA_8WORD, 5},   /* 8 */                { MIDDMA_WORD, 2},      /* 9 */
                    268:   { MIDDMA_2WORD, 3},  /* 10 */        { MIDDMA_WORD, 2},      /* 11 */
                    269:   { MIDDMA_4WORD, 4},  /* 12 */        { MIDDMA_WORD, 2},      /* 13 */
                    270:   { MIDDMA_2WORD, 3},  /* 14 */        { MIDDMA_WORD, 2},      /* 15 */
                    271:   { MIDDMA_16WORD, 6},  /* 16 */
                    272: };
                    273:
                    274: static struct en_dmatab *en_dmaplan = en_dma_planA;
                    275:
                    276: /*
                    277:  * prototypes
                    278:  */
                    279:
                    280: STATIC INLINE  int en_b2sz(int) __attribute__ ((unused));
                    281: #ifdef EN_DDBHOOK
                    282:                int en_dump(int,int);
                    283:                int en_dumpmem(int,int,int);
                    284: #endif
                    285: STATIC         void en_dmaprobe(struct en_softc *);
                    286: STATIC         int en_dmaprobe_doit(struct en_softc *, u_int8_t *,
                    287:                    u_int8_t *, int);
                    288: STATIC INLINE  int en_dqneed(struct en_softc *, caddr_t, u_int,
                    289:                    u_int) __attribute__ ((unused));
                    290: STATIC         void en_init(struct en_softc *);
                    291: STATIC         int en_ioctl(struct ifnet *, EN_IOCTL_CMDT, caddr_t);
                    292: STATIC INLINE  int en_k2sz(int) __attribute__ ((unused));
                    293: STATIC         void en_loadvc(struct en_softc *, int);
                    294: STATIC         int en_mfix(struct en_softc *, struct mbuf **,
                    295:                    struct mbuf *);
                    296: STATIC INLINE  struct mbuf *en_mget(struct en_softc *, u_int,
                    297:                    u_int *) __attribute__ ((unused));
                    298: STATIC INLINE  u_int32_t en_read(struct en_softc *,
                    299:                    u_int32_t) __attribute__ ((unused));
                    300: STATIC         int en_rxctl(struct en_softc *, struct atm_pseudoioctl *,
                    301:                    int);
                    302: STATIC         void en_txdma(struct en_softc *, int);
                    303: STATIC         void en_txlaunch(struct en_softc *, int,
                    304:                    struct en_launch *);
                    305: STATIC         void en_service(struct en_softc *);
                    306: STATIC         void en_start(struct ifnet *);
                    307: STATIC INLINE  int en_sz2b(int) __attribute__ ((unused));
                    308: STATIC INLINE  void en_write(struct en_softc *, u_int32_t,
                    309:                    u_int32_t) __attribute__ ((unused));
                    310:
                    311: /*
                    312:  * macros/inline
                    313:  */
                    314:
                    315: /*
                    316:  * raw read/write macros
                    317:  */
                    318:
                    319: #define EN_READDAT(SC,R) en_read(SC,R)
                    320: #define EN_WRITEDAT(SC,R,V) en_write(SC,R,V)
                    321:
                    322: /*
                    323:  * cooked read/write macros
                    324:  */
                    325:
                    326: #define EN_READ(SC,R) ntohl(en_read(SC,R))
                    327: #define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V))
                    328:
                    329: #define EN_WRAPADD(START,STOP,CUR,VAL) { \
                    330:        (CUR) = (CUR) + (VAL); \
                    331:        if ((CUR) >= (STOP)) \
                    332:                (CUR) = (START) + ((CUR) - (STOP)); \
                    333:        }
                    334:
                    335: #define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t))
                    336:
                    337: /* we store sc->dtq and sc->drq data in the following format... */
                    338: #define EN_DQ_MK(SLOT,LEN) (((SLOT) << 20)|(LEN)|(0x80000))
                    339:                                        /* the 0x80000 ensures we != 0 */
                    340: #define EN_DQ_SLOT(X) ((X) >> 20)
                    341: #define EN_DQ_LEN(X) ((X) & 0x3ffff)
                    342:
                    343: /* format of DTQ/DRQ word 1 differs between ENI and ADP */
                    344: #if defined(MIDWAY_ENIONLY)
                    345:
                    346: #define MID_MK_TXQ(SC,CNT,CHAN,END,BCODE) \
                    347:        EN_WRITE((SC), (SC)->dtq_us, \
                    348:                MID_MK_TXQ_ENI((CNT), (CHAN), (END), (BCODE)));
                    349:
                    350: #define MID_MK_RXQ(SC,CNT,VCI,END,BCODE) \
                    351:        EN_WRITE((SC), (SC)->drq_us, \
                    352:                MID_MK_RXQ_ENI((CNT), (VCI), (END), (BCODE)));
                    353:
                    354: #elif defined(MIDWAY_ADPONLY)
                    355:
                    356: #define MID_MK_TXQ(SC,CNT,CHAN,END,JK) \
                    357:        EN_WRITE((SC), (SC)->dtq_us, \
                    358:                MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK)));
                    359:
                    360: #define MID_MK_RXQ(SC,CNT,VCI,END,JK) \
                    361:        EN_WRITE((SC), (SC)->drq_us, \
                    362:                MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK)));
                    363:
                    364: #else
                    365:
                    366: #define MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE) { \
                    367:        if ((SC)->is_adaptec) \
                    368:          EN_WRITE((SC), (SC)->dtq_us, \
                    369:                  MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK_OR_BCODE))); \
                    370:        else \
                    371:          EN_WRITE((SC), (SC)->dtq_us, \
                    372:                  MID_MK_TXQ_ENI((CNT), (CHAN), (END), (JK_OR_BCODE))); \
                    373:        }
                    374:
                    375: #define MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE) { \
                    376:        if ((SC)->is_adaptec) \
                    377:          EN_WRITE((SC), (SC)->drq_us, \
                    378:                  MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK_OR_BCODE))); \
                    379:        else \
                    380:          EN_WRITE((SC), (SC)->drq_us, \
                    381:                   MID_MK_RXQ_ENI((CNT), (VCI), (END), (JK_OR_BCODE))); \
                    382:        }
                    383:
                    384: #endif
                    385:
                    386: /* add an item to the DTQ */
                    387: #define EN_DTQADD(SC,CNT,CHAN,JK_OR_BCODE,ADDR,LEN,END) { \
                    388:        if (END) \
                    389:          (SC)->dtq[MID_DTQ_A2REG((SC)->dtq_us)] = EN_DQ_MK(CHAN,LEN); \
                    390:        MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE); \
                    391:        (SC)->dtq_us += 4; \
                    392:        EN_WRITE((SC), (SC)->dtq_us, (ADDR)); \
                    393:        EN_WRAPADD(MID_DTQOFF, MID_DTQEND, (SC)->dtq_us, 4); \
                    394:        (SC)->dtq_free--; \
                    395:        if (END) \
                    396:          EN_WRITE((SC), MID_DMA_WRTX, MID_DTQ_A2REG((SC)->dtq_us)); \
                    397: }
                    398:
                    399: /* DRQ add macro */
                    400: #define EN_DRQADD(SC,CNT,VCI,JK_OR_BCODE,ADDR,LEN,SLOT,END) { \
                    401:        if (END) \
                    402:          (SC)->drq[MID_DRQ_A2REG((SC)->drq_us)] = EN_DQ_MK(SLOT,LEN); \
                    403:        MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE); \
                    404:        (SC)->drq_us += 4; \
                    405:        EN_WRITE((SC), (SC)->drq_us, (ADDR)); \
                    406:        EN_WRAPADD(MID_DRQOFF, MID_DRQEND, (SC)->drq_us, 4); \
                    407:        (SC)->drq_free--; \
                    408:        if (END) \
                    409:          EN_WRITE((SC), MID_DMA_WRRX, MID_DRQ_A2REG((SC)->drq_us)); \
                    410: }
                    411:
                    412: /*
                    413:  * the driver code
                    414:  *
                    415:  * the code is arranged in a specific way:
                    416:  * [1] short/inline functions
                    417:  * [2] autoconfig stuff
                    418:  * [3] ioctl stuff
                    419:  * [4] reset -> init -> transmit -> intr -> receive functions
                    420:  *
                    421:  */
                    422:
                    423: /***********************************************************************/
                    424:
                    425: /*
                    426:  * en_read: read a word from the card.   this is the only function
                    427:  * that reads from the card.
                    428:  */
                    429:
                    430: STATIC INLINE u_int32_t en_read(sc, r)
                    431:
                    432: struct en_softc *sc;
                    433: u_int32_t r;
                    434:
                    435: {
                    436:
                    437: #ifdef EN_DEBUG_RANGE
                    438:   if (r > MID_MAXOFF || (r % 4)) {
                    439:     panic("en_read: out of range, r=0x%x", r);
                    440:   }
                    441: #endif
                    442:
                    443:   return(bus_space_read_4(sc->en_memt, sc->en_base, r));
                    444: }
                    445:
                    446: /*
                    447:  * en_write: write a word to the card.   this is the only function that
                    448:  * writes to the card.
                    449:  */
                    450:
                    451: STATIC INLINE void en_write(sc, r, v)
                    452:
                    453: struct en_softc *sc;
                    454: u_int32_t r, v;
                    455:
                    456: {
                    457: #ifdef EN_DEBUG_RANGE
                    458:   if (r > MID_MAXOFF || (r % 4)) {
                    459:     panic("en_write: out of range, r=0x%x", r);
                    460:   }
                    461: #endif
                    462:
                    463:   bus_space_write_4(sc->en_memt, sc->en_base, r, v);
                    464: }
                    465:
                    466: /*
                    467:  * en_k2sz: convert KBytes to a size parameter (a log2)
                    468:  */
                    469:
                    470: STATIC INLINE int en_k2sz(k)
                    471:
                    472: int k;
                    473:
                    474: {
                    475:   switch(k) {
                    476:     case 1:   return(0);
                    477:     case 2:   return(1);
                    478:     case 4:   return(2);
                    479:     case 8:   return(3);
                    480:     case 16:  return(4);
                    481:     case 32:  return(5);
                    482:     case 64:  return(6);
                    483:     case 128: return(7);
                    484:     default: panic("en_k2sz");
                    485:   }
                    486:   return(0);
                    487: }
                    488: #define en_log2(X) en_k2sz(X)
                    489:
                    490:
                    491: /*
                    492:  * en_b2sz: convert a DMA burst code to its byte size
                    493:  */
                    494:
                    495: STATIC INLINE int en_b2sz(b)
                    496:
                    497: int b;
                    498:
                    499: {
                    500:   switch (b) {
                    501:     case MIDDMA_WORD:   return(1*4);
                    502:     case MIDDMA_2WMAYBE:
                    503:     case MIDDMA_2WORD:  return(2*4);
                    504:     case MIDDMA_4WMAYBE:
                    505:     case MIDDMA_4WORD:  return(4*4);
                    506:     case MIDDMA_8WMAYBE:
                    507:     case MIDDMA_8WORD:  return(8*4);
                    508:     case MIDDMA_16WMAYBE:
                    509:     case MIDDMA_16WORD: return(16*4);
                    510:     default: panic("en_b2sz");
                    511:   }
                    512:   return(0);
                    513: }
                    514:
                    515:
                    516: /*
                    517:  * en_sz2b: convert a burst size (bytes) to DMA burst code
                    518:  */
                    519:
                    520: STATIC INLINE int en_sz2b(sz)
                    521:
                    522: int sz;
                    523:
                    524: {
                    525:   switch (sz) {
                    526:     case 1*4:  return(MIDDMA_WORD);
                    527:     case 2*4:  return(MIDDMA_2WORD);
                    528:     case 4*4:  return(MIDDMA_4WORD);
                    529:     case 8*4:  return(MIDDMA_8WORD);
                    530:     case 16*4: return(MIDDMA_16WORD);
                    531:     default: panic("en_sz2b");
                    532:   }
                    533:   return(0);
                    534: }
                    535:
                    536:
                    537: /*
                    538:  * en_dqneed: calculate number of DTQ/DRQ's needed for a buffer
                    539:  */
                    540:
                    541: STATIC INLINE int en_dqneed(sc, data, len, tx)
                    542:
                    543: struct en_softc *sc;
                    544: caddr_t data;
                    545: u_int len, tx;
                    546:
                    547: {
                    548:   int result, needalign, sz;
                    549:
                    550: #if !defined(MIDWAY_ENIONLY)
                    551: #if !defined(MIDWAY_ADPONLY)
                    552:     if (sc->is_adaptec)
                    553: #endif /* !MIDWAY_ADPONLY */
                    554:       return(1);       /* adaptec can DMA anything in one go */
                    555: #endif
                    556:
                    557: #if !defined(MIDWAY_ADPONLY)
                    558:     result = 0;
                    559:     if (len < EN_MINDMA) {
                    560:       if (!tx)                 /* XXX: conservative */
                    561:         return(1);             /* will copy/DMA_JK */
                    562:     }
                    563:
                    564:     if (tx) {                  /* byte burst? */
                    565:       needalign = (((unsigned long) data) % sizeof(u_int32_t));
                    566:       if (needalign) {
                    567:         result++;
                    568:         sz = min(len, sizeof(u_int32_t) - needalign);
                    569:         len -= sz;
                    570:         data += sz;
                    571:       }
                    572:     }
                    573:
                    574:     if (sc->alburst && len) {
                    575:       needalign = (((unsigned long) data) & sc->bestburstmask);
                    576:       if (needalign) {
                    577:        result++;               /* alburst */
                    578:         sz = min(len, sc->bestburstlen - needalign);
                    579:         len -= sz;
                    580:       }
                    581:     }
                    582:
                    583:     if (len >= sc->bestburstlen) {
                    584:       sz = len / sc->bestburstlen;
                    585:       sz = sz * sc->bestburstlen;
                    586:       len -= sz;
                    587:       result++;                        /* best shot */
                    588:     }
                    589:
                    590:     if (len) {
                    591:       result++;                        /* clean up */
                    592:       if (tx && (len % sizeof(u_int32_t)) != 0)
                    593:         result++;              /* byte cleanup */
                    594:     }
                    595:
                    596:     return(result);
                    597: #endif /* !MIDWAY_ADPONLY */
                    598: }
                    599:
                    600:
                    601: /*
                    602:  * en_mget: get an mbuf chain that can hold totlen bytes and return it
                    603:  * (for recv)   [based on am7990_get from if_le and ieget from if_ie]
                    604:  * after this call the sum of all the m_len's in the chain will be totlen.
                    605:  */
                    606:
                    607: STATIC INLINE struct mbuf *en_mget(sc, totlen, drqneed)
                    608:
                    609: struct en_softc *sc;
                    610: u_int totlen, *drqneed;
                    611:
                    612: {
                    613:   struct mbuf *m;
                    614:   struct mbuf *top, **mp;
                    615:   *drqneed = 0;
                    616:
                    617:   MGETHDR(m, M_DONTWAIT, MT_DATA);
                    618:   if (m == NULL)
                    619:     return(NULL);
                    620:   m->m_pkthdr.rcvif = &sc->enif;
                    621:   m->m_pkthdr.len = totlen;
                    622:   m->m_len = MHLEN;
                    623:   top = NULL;
                    624:   mp = &top;
                    625:
                    626:   /* if (top != NULL) then we've already got 1 mbuf on the chain */
                    627:   while (totlen > 0) {
                    628:     if (top) {
                    629:       MGET(m, M_DONTWAIT, MT_DATA);
                    630:       if (!m) {
                    631:        m_freem(top);
                    632:        return(NULL);   /* out of mbufs */
                    633:       }
                    634:       m->m_len = MLEN;
                    635:     }
                    636:     if (totlen >= MINCLSIZE) {
                    637:       MCLGET(m, M_DONTWAIT);
                    638:       if ((m->m_flags & M_EXT) == 0) {
                    639:        m_free(m);
                    640:        m_freem(top);
                    641:        return(NULL);   /* out of mbuf clusters */
                    642:       }
                    643:       m->m_len = MCLBYTES;
                    644:     }
                    645:     m->m_len = min(totlen, m->m_len);
                    646:     totlen -= m->m_len;
                    647:     *mp = m;
                    648:     mp = &m->m_next;
                    649:
                    650:     *drqneed += en_dqneed(sc, m->m_data, m->m_len, 0);
                    651:
                    652:   }
                    653:   return(top);
                    654: }
                    655:
                    656: /***********************************************************************/
                    657:
                    658: /*
                    659:  * autoconfig stuff
                    660:  */
                    661:
                    662: void en_attach(sc)
                    663:
                    664: struct en_softc *sc;
                    665:
                    666: {
                    667:   struct ifnet *ifp = &sc->enif;
                    668:   int sz;
                    669:   u_int32_t reg, lcv, check, ptr, sav, midvloc;
                    670:
                    671:   /*
                    672:    * probe card to determine memory size.   the stupid ENI card always
                    673:    * reports to PCI that it needs 4MB of space (2MB regs and 2MB RAM).
                    674:    * if it has less than 2MB RAM the addresses wrap in the RAM address space.
                    675:    * (i.e. on a 512KB card addresses 0x3ffffc, 0x37fffc, and 0x2ffffc
                    676:    * are aliases for 0x27fffc  [note that RAM starts at offset 0x200000]).
                    677:    */
                    678:
                    679:   if (sc->en_busreset)
                    680:     sc->en_busreset(sc);
                    681:   EN_WRITE(sc, MID_RESID, 0x0);        /* reset card before touching RAM */
                    682:   for (lcv = MID_PROBEOFF; lcv <= MID_MAXOFF ; lcv += MID_PROBSIZE) {
                    683:     EN_WRITE(sc, lcv, lcv);    /* data[address] = address */
                    684:     for (check = MID_PROBEOFF ; check < lcv ; check += MID_PROBSIZE) {
                    685:       reg = EN_READ(sc, check);
                    686:       if (reg != check) {              /* found an alias! */
                    687:        goto done_probe;                /* and quit */
                    688:       }
                    689:     }
                    690:   }
                    691: done_probe:
                    692:   lcv -= MID_PROBSIZE;                 /* take one step back */
                    693:   sc->en_obmemsz = (lcv + 4) - MID_RAMOFF;
                    694:
                    695:   /*
                    696:    * determine the largest DMA burst supported
                    697:    */
                    698:
                    699:   en_dmaprobe(sc);
                    700:
                    701:   /*
                    702:    * "hello world"
                    703:    */
                    704:
                    705:   if (sc->en_busreset)
                    706:     sc->en_busreset(sc);
                    707:   EN_WRITE(sc, MID_RESID, 0x0);                /* reset */
                    708:   for (lcv = MID_RAMOFF ; lcv < MID_RAMOFF + sc->en_obmemsz ; lcv += 4)
                    709:     EN_WRITE(sc, lcv, 0);      /* zero memory */
                    710:
                    711:   reg = EN_READ(sc, MID_RESID);
                    712:
                    713:   printf("%s: ATM midway v%d, board IDs %d.%d, %s%s%s, %ldKB on-board RAM\n",
                    714:        sc->sc_dev.dv_xname, MID_VER(reg), MID_MID(reg), MID_DID(reg),
                    715:        (MID_IS_SABRE(reg)) ? "sabre controller, " : "",
                    716:        (MID_IS_SUNI(reg)) ? "SUNI" : "Utopia",
                    717:        (!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "",
                    718:        sc->en_obmemsz / 1024);
                    719:
                    720:   if (sc->is_adaptec) {
                    721:     if (sc->bestburstlen == 64 && sc->alburst == 0)
                    722:       printf("%s: passed 64 byte DMA test\n", sc->sc_dev.dv_xname);
                    723:     else
                    724:       printf("%s: FAILED DMA TEST: burst=%d, alburst=%d\n",
                    725:            sc->sc_dev.dv_xname, sc->bestburstlen, sc->alburst);
                    726:   } else {
                    727:     printf("%s: maximum DMA burst length = %d bytes%s\n", sc->sc_dev.dv_xname,
                    728:          sc->bestburstlen, (sc->alburst) ? " (must align)" : "");
                    729:   }
                    730:
                    731: #if 0          /* WMAYBE doesn't work, don't complain about it */
                    732:   /* check if en_dmaprobe disabled wmaybe */
                    733:   if (en_dmaplan == en_dma_planB)
                    734:     printf("%s: note: WMAYBE DMA has been disabled\n", sc->sc_dev.dv_xname);
                    735: #endif
                    736:
                    737:   /*
                    738:    * link into network subsystem and prepare card
                    739:    */
                    740:
                    741: #if defined(__NetBSD__) || defined(__OpenBSD__)
                    742:   bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ);
                    743: #endif
                    744: #if !defined(MISSING_IF_SOFTC)
                    745:   sc->enif.if_softc = sc;
                    746: #endif
                    747:   ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS;
                    748:   ifp->if_ioctl = en_ioctl;
                    749:   ifp->if_start = en_start;
                    750:   IFQ_SET_READY(&ifp->if_snd);
                    751:
                    752:   /*
                    753:    * init softc
                    754:    */
                    755:
                    756:   for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
                    757:     sc->rxvc2slot[lcv] = RX_NONE;
                    758:     sc->txspeed[lcv] = 0;      /* full */
                    759:     sc->txvc2slot[lcv] = 0;    /* full speed == slot 0 */
                    760:   }
                    761:
                    762:   sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF);
                    763:   ptr = sav = MID_BUFOFF;
                    764:   ptr = roundup(ptr, EN_TXSZ * 1024);  /* align */
                    765:   sz = sz - (ptr - sav);
                    766:   if (EN_TXSZ*1024 * EN_NTX > sz) {
                    767:     printf("%s: EN_NTX/EN_TXSZ too big\n", sc->sc_dev.dv_xname);
                    768:     return;
                    769:   }
                    770:   for (lcv = 0 ; lcv < EN_NTX ; lcv++) {
                    771:     sc->txslot[lcv].mbsize = 0;
                    772:     sc->txslot[lcv].start = ptr;
                    773:     ptr += (EN_TXSZ * 1024);
                    774:     sz -= (EN_TXSZ * 1024);
                    775:     sc->txslot[lcv].stop = ptr;
                    776:     sc->txslot[lcv].nref = 0;
                    777:     bzero(&sc->txslot[lcv].indma, sizeof(sc->txslot[lcv].indma));
                    778:     bzero(&sc->txslot[lcv].q, sizeof(sc->txslot[lcv].q));
                    779: #ifdef EN_DEBUG
                    780:     printf("%s: tx%d: start 0x%x, stop 0x%x\n", sc->sc_dev.dv_xname, lcv,
                    781:                sc->txslot[lcv].start, sc->txslot[lcv].stop);
                    782: #endif
                    783:   }
                    784:
                    785:   sav = ptr;
                    786:   ptr = roundup(ptr, EN_RXSZ * 1024);  /* align */
                    787:   sz = sz - (ptr - sav);
                    788:   sc->en_nrx = sz / (EN_RXSZ * 1024);
                    789:   if (sc->en_nrx <= 0) {
                    790:     printf("%s: EN_NTX/EN_TXSZ/EN_RXSZ too big\n", sc->sc_dev.dv_xname);
                    791:     return;
                    792:   }
                    793:
                    794:   /*
                    795:    * ensure that there is always one VC slot on the service list free
                    796:    * so that we can tell the difference between a full and empty list.
                    797:    */
                    798:   if (sc->en_nrx >= MID_N_VC)
                    799:     sc->en_nrx = MID_N_VC - 1;
                    800:
                    801:   for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) {
                    802:     sc->rxslot[lcv].rxhand = NULL;
                    803:     sc->rxslot[lcv].oth_flags = ENOTHER_FREE;
                    804:     bzero(&sc->rxslot[lcv].indma, sizeof(sc->rxslot[lcv].indma));
                    805:     bzero(&sc->rxslot[lcv].q, sizeof(sc->rxslot[lcv].q));
                    806:     midvloc = sc->rxslot[lcv].start = ptr;
                    807:     ptr += (EN_RXSZ * 1024);
                    808:     sz -= (EN_RXSZ * 1024);
                    809:     sc->rxslot[lcv].stop = ptr;
                    810:     midvloc = midvloc - MID_RAMOFF;
                    811:     midvloc = (midvloc & ~((EN_RXSZ*1024) - 1)) >> 2; /* mask, cvt to words */
                    812:     midvloc = midvloc >> MIDV_LOCTOPSHFT;  /* we only want the top 11 bits */
                    813:     midvloc = (midvloc & MIDV_LOCMASK) << MIDV_LOCSHIFT;
                    814:     sc->rxslot[lcv].mode = midvloc |
                    815:        (en_k2sz(EN_RXSZ) << MIDV_SZSHIFT) | MIDV_TRASH;
                    816:
                    817: #ifdef EN_DEBUG
                    818:     printf("%s: rx%d: start 0x%x, stop 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname,
                    819:        lcv, sc->rxslot[lcv].start, sc->rxslot[lcv].stop, sc->rxslot[lcv].mode);
                    820: #endif
                    821:   }
                    822:
                    823: #ifdef EN_STAT
                    824:   sc->vtrash = sc->otrash = sc->mfix = sc->txmbovr = sc->dmaovr = 0;
                    825:   sc->txoutspace = sc->txdtqout = sc->launch = sc->lheader = sc->ltail = 0;
                    826:   sc->hwpull = sc->swadd = sc->rxqnotus = sc->rxqus = sc->rxoutboth = 0;
                    827:   sc->rxdrqout = sc->ttrash = sc->rxmbufout = sc->mfixfail = 0;
                    828:   sc->headbyte = sc->tailbyte = sc->tailflush = 0;
                    829: #endif
                    830:   sc->need_drqs = sc->need_dtqs = 0;
                    831:
                    832:   printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n",
                    833:        sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
                    834:
                    835:   /*
                    836:    * final commit
                    837:    */
                    838:
                    839:   if_attach(ifp);
                    840:   atm_ifattach(ifp);
                    841:
                    842:
                    843: #if NBPFILTER > 0
                    844:   bpfattach(&ifp->if_bpf, ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
                    845: #endif
                    846:
                    847: }
                    848:
                    849:
                    850: /*
                    851:  * en_dmaprobe: helper function for en_attach.
                    852:  *
                    853:  * see how the card handles DMA by running a few DMA tests.   we need
                    854:  * to figure out the largest number of bytes we can DMA in one burst
                    855:  * ("bestburstlen"), and if the starting address for a burst needs to
                    856:  * be aligned on any sort of boundary or not ("alburst").
                    857:  *
                    858:  * typical findings:
                    859:  * sparc1: bestburstlen=4, alburst=0 (ick, broken DMA!)
                    860:  * sparc2: bestburstlen=64, alburst=1
                    861:  * p166:   bestburstlen=64, alburst=0
                    862:  */
                    863:
                    864: STATIC void en_dmaprobe(sc)
                    865:
                    866: struct en_softc *sc;
                    867:
                    868: {
                    869:   u_int32_t srcbuf[64], dstbuf[64];
                    870:   u_int8_t *sp, *dp;
                    871:   int bestalgn, bestnotalgn, lcv, try, fail;
                    872:
                    873:   sc->alburst = 0;
                    874:
                    875:   sp = (u_int8_t *) srcbuf;
                    876:   while ((((unsigned long) sp) % MIDDMA_MAXBURST) != 0)
                    877:     sp += 4;
                    878:   dp = (u_int8_t *) dstbuf;
                    879:   while ((((unsigned long) dp) % MIDDMA_MAXBURST) != 0)
                    880:     dp += 4;
                    881:
                    882:   bestalgn = bestnotalgn = en_dmaprobe_doit(sc, sp, dp, 0);
                    883:
                    884:   for (lcv = 4 ; lcv < MIDDMA_MAXBURST ; lcv += 4) {
                    885:     try = en_dmaprobe_doit(sc, sp+lcv, dp+lcv, 0);
                    886:     if (try < bestnotalgn)
                    887:       bestnotalgn = try;
                    888:   }
                    889:
                    890:   if (bestalgn != bestnotalgn)                 /* need bursts aligned */
                    891:     sc->alburst = 1;
                    892:
                    893:   sc->bestburstlen = bestalgn;
                    894:   sc->bestburstshift = en_log2(bestalgn);
                    895:   sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */
                    896:   sc->bestburstcode = en_sz2b(bestalgn);
                    897:
                    898:   if (sc->bestburstlen <= 2*sizeof(u_int32_t))
                    899:     return;                            /* won't be using WMAYBE */
                    900:
                    901:   /*
                    902:    * adaptec does not have (or need) wmaybe.   do not bother testing
                    903:    * for it.
                    904:    */
                    905:   if (sc->is_adaptec) {
                    906:     /* XXX, actually don't need a DMA plan: adaptec is smarter than that */
                    907:     en_dmaplan = en_dma_planB;
                    908:     return;
                    909:   }
                    910:
                    911:   /*
                    912:    * test that WMAYBE dma works like we think it should
                    913:    * (i.e. no alignment restrictions on host address other than alburst)
                    914:    */
                    915:
                    916:   try = sc->bestburstlen - 4;
                    917:   fail = 0;
                    918:   fail += en_dmaprobe_doit(sc, sp, dp, try);
                    919:   for (lcv = 4 ; lcv < sc->bestburstlen ; lcv += 4) {
                    920:     fail += en_dmaprobe_doit(sc, sp+lcv, dp+lcv, try);
                    921:     if (sc->alburst)
                    922:       try -= 4;
                    923:   }
                    924:   if (EN_NOWMAYBE || fail) {
                    925:     if (fail)
                    926:       printf("%s: WARNING: WMAYBE DMA test failed %d time(s)\n",
                    927:        sc->sc_dev.dv_xname, fail);
                    928:     en_dmaplan = en_dma_planB;         /* fall back to plan B */
                    929:   }
                    930:
                    931: }
                    932:
                    933:
                    934: /*
                    935:  * en_dmaprobe_doit: do actual testing
                    936:  */
                    937:
                    938: int
                    939: en_dmaprobe_doit(sc, sp, dp, wmtry)
                    940:
                    941: struct en_softc *sc;
                    942: u_int8_t *sp, *dp;
                    943: int wmtry;
                    944:
                    945: {
                    946:   int lcv, retval = 4, cnt, count;
                    947:   u_int32_t reg, bcode, midvloc;
                    948:
                    949:   /*
                    950:    * set up a 1k buffer at MID_BUFOFF
                    951:    */
                    952:
                    953:   if (sc->en_busreset)
                    954:     sc->en_busreset(sc);
                    955:   EN_WRITE(sc, MID_RESID, 0x0);        /* reset card before touching RAM */
                    956:
                    957:   midvloc = ((MID_BUFOFF - MID_RAMOFF) / sizeof(u_int32_t)) >> MIDV_LOCTOPSHFT;
                    958:   EN_WRITE(sc, MIDX_PLACE(0), MIDX_MKPLACE(en_k2sz(1), midvloc));
                    959:   EN_WRITE(sc, MID_VC(0), (midvloc << MIDV_LOCSHIFT)
                    960:                | (en_k2sz(1) << MIDV_SZSHIFT) | MIDV_TRASH);
                    961:   EN_WRITE(sc, MID_DST_RP(0), 0);
                    962:   EN_WRITE(sc, MID_WP_ST_CNT(0), 0);
                    963:
                    964:   for (lcv = 0 ; lcv < 68 ; lcv++)             /* set up sample data */
                    965:     sp[lcv] = lcv+1;
                    966:   EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA);  /* enable DMA (only) */
                    967:
                    968:   sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX));
                    969:   sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX));
                    970:
                    971:   /*
                    972:    * try it now . . .  DMA it out, then DMA it back in and compare
                    973:    *
                    974:    * note: in order to get the dma stuff to reverse directions it wants
                    975:    * the "end" flag set!   since we are not dma'ing valid data we may
                    976:    * get an ident mismatch interrupt (which we will ignore).
                    977:    *
                    978:    * note: we've got two different tests rolled up in the same loop
                    979:    * if (wmtry)
                    980:    *   then we are doing a wmaybe test and wmtry is a byte count
                    981:    *   else we are doing a burst test
                    982:    */
                    983:
                    984:   for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) {
                    985:
                    986:     /* zero SRAM and dest buffer */
                    987:     for (cnt = 0 ; cnt < 1024; cnt += 4)
                    988:       EN_WRITE(sc, MID_BUFOFF+cnt, 0); /* zero memory */
                    989:     for (cnt = 0 ; cnt < 68  ; cnt++)
                    990:       dp[cnt] = 0;
                    991:
                    992:     if (wmtry) {
                    993:       count = (sc->bestburstlen - sizeof(u_int32_t)) / sizeof(u_int32_t);
                    994:       bcode = en_dmaplan[count].bcode;
                    995:       count = wmtry >> en_dmaplan[count].divshift;
                    996:     } else {
                    997:       bcode = en_sz2b(lcv);
                    998:       count = 1;
                    999:     }
                   1000:     if (sc->is_adaptec)
                   1001:       EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0));
                   1002:     else
                   1003:       EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ENI(count, 0, MID_DMA_END, bcode));
                   1004:     EN_WRITE(sc, sc->dtq_chip+4, vtophys(sp));
                   1005:     EN_WRITE(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip+8));
                   1006:     cnt = 1000;
                   1007:     while (EN_READ(sc, MID_DMA_RDTX) == MID_DTQ_A2REG(sc->dtq_chip)) {
                   1008:       DELAY(1);
                   1009:       cnt--;
                   1010:       if (cnt == 0) {
                   1011:        printf("%s: unexpected timeout in tx DMA test\n", sc->sc_dev.dv_xname);
                   1012:        return(retval);         /* timeout, give up */
                   1013:       }
                   1014:     }
                   1015:     EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
                   1016:     reg = EN_READ(sc, MID_INTACK);
                   1017:     if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) {
                   1018:       printf("%s: unexpected status in tx DMA test: 0x%x\n",
                   1019:                sc->sc_dev.dv_xname, reg);
                   1020:       return(retval);
                   1021:     }
                   1022:     EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA);   /* re-enable DMA (only) */
                   1023:
                   1024:     /* "return to sender..."  address is known ... */
                   1025:
                   1026:     if (sc->is_adaptec)
                   1027:       EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0));
                   1028:     else
                   1029:       EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ENI(count, 0, MID_DMA_END, bcode));
                   1030:     EN_WRITE(sc, sc->drq_chip+4, vtophys(dp));
                   1031:     EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip+8));
                   1032:     cnt = 1000;
                   1033:     while (EN_READ(sc, MID_DMA_RDRX) == MID_DRQ_A2REG(sc->drq_chip)) {
                   1034:       DELAY(1);
                   1035:       cnt--;
                   1036:       if (cnt == 0) {
                   1037:        printf("%s: unexpected timeout in rx DMA test\n", sc->sc_dev.dv_xname);
                   1038:        return(retval);         /* timeout, give up */
                   1039:       }
                   1040:     }
                   1041:     EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
                   1042:     reg = EN_READ(sc, MID_INTACK);
                   1043:     if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) {
                   1044:       printf("%s: unexpected status in rx DMA test: 0x%x\n",
                   1045:                sc->sc_dev.dv_xname, reg);
                   1046:       return(retval);
                   1047:     }
                   1048:     EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA);   /* re-enable DMA (only) */
                   1049:
                   1050:     if (wmtry) {
                   1051:       return(bcmp(sp, dp, wmtry));  /* wmtry always exits here, no looping */
                   1052:     }
                   1053:
                   1054:     if (bcmp(sp, dp, lcv))
                   1055:       return(retval);          /* failed, use last value */
                   1056:
                   1057:     retval = lcv;
                   1058:
                   1059:   }
                   1060:   return(retval);              /* studly 64 byte DMA present!  oh baby!! */
                   1061: }
                   1062:
                   1063: /***********************************************************************/
                   1064:
                   1065: /*
                   1066:  * en_ioctl: handle ioctl requests
                   1067:  *
                   1068:  * NOTE: if you add an ioctl to set txspeed, you should choose a new
                   1069:  * TX channel/slot.   Choose the one with the lowest sc->txslot[slot].nref
                   1070:  * value, subtract one from sc->txslot[0].nref, add one to the
                   1071:  * sc->txslot[slot].nref, set sc->txvc2slot[vci] = slot, and then set
                   1072:  * txspeed[vci].
                   1073:  */
                   1074:
                   1075: STATIC int en_ioctl(ifp, cmd, data)
                   1076:
                   1077: struct ifnet *ifp;
                   1078: EN_IOCTL_CMDT cmd;
                   1079: caddr_t data;
                   1080:
                   1081: {
                   1082: #ifdef MISSING_IF_SOFTC
                   1083:     struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
                   1084: #else
                   1085:     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
                   1086: #endif
                   1087:     struct ifaddr *ifa = (struct ifaddr *) data;
                   1088:     struct ifreq *ifr = (struct ifreq *) data;
                   1089:     struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data;
                   1090: #ifdef NATM
                   1091:     struct atm_rawioctl *ario = (struct atm_rawioctl *)data;
                   1092:     int slot;
                   1093: #endif
                   1094:     int s, error = 0;
                   1095:
                   1096:     s = splnet();
                   1097:
                   1098:     switch (cmd) {
                   1099:        case SIOCATMENA:                /* enable circuit for recv */
                   1100:                error = en_rxctl(sc, api, 1);
                   1101:                break;
                   1102:
                   1103:        case SIOCATMDIS:                /* disable circuit for recv */
                   1104:                error = en_rxctl(sc, api, 0);
                   1105:                break;
                   1106:
                   1107: #ifdef NATM
                   1108:        case SIOCXRAWATM:
                   1109:                if ((slot = sc->rxvc2slot[ario->npcb->npcb_vci]) == RX_NONE) {
                   1110:                        error = EINVAL;
                   1111:                        break;
                   1112:                }
                   1113:                if (ario->rawvalue > EN_RXSZ*1024)
                   1114:                        ario->rawvalue = EN_RXSZ*1024;
                   1115:                if (ario->rawvalue) {
                   1116:                        sc->rxslot[slot].oth_flags |= ENOTHER_RAW;
                   1117:                        sc->rxslot[slot].raw_threshold = ario->rawvalue;
                   1118:                } else {
                   1119:                        sc->rxslot[slot].oth_flags &= (~ENOTHER_RAW);
                   1120:                        sc->rxslot[slot].raw_threshold = 0;
                   1121:                }
                   1122: #ifdef EN_DEBUG
                   1123:                printf("%s: rxvci%d: turn %s raw (boodi) mode\n",
                   1124:                        sc->sc_dev.dv_xname, ario->npcb->npcb_vci,
                   1125:                        (ario->rawvalue) ? "on" : "off");
                   1126: #endif
                   1127:                break;
                   1128: #endif
                   1129:        case SIOCSIFADDR:
                   1130:                ifp->if_flags |= IFF_UP;
                   1131: #ifdef INET
                   1132:                if (ifa->ifa_addr->sa_family == AF_INET) {
                   1133:                        en_reset(sc);
                   1134:                        en_init(sc);
                   1135:                        ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
                   1136:                        break;
                   1137:                }
                   1138: #endif /* INET */
                   1139:                /* what to do if not INET? */
                   1140:                en_reset(sc);
                   1141:                en_init(sc);
                   1142:                break;
                   1143:
                   1144:        case SIOCGIFADDR:
                   1145:                error = EINVAL;
                   1146:                break;
                   1147:
                   1148:        case SIOCSIFFLAGS:
                   1149:                error = EINVAL;
                   1150:                break;
                   1151:
                   1152:        case SIOCSIFMTU:
                   1153:            /*
                   1154:             * Set the interface MTU.
                   1155:             */
                   1156: #ifdef notsure
                   1157:            if (ifr->ifr_mtu > ATMMTU) {
                   1158:                error = EINVAL;
                   1159:                break;
                   1160:            }
                   1161: #endif
                   1162:            ifp->if_mtu = ifr->ifr_mtu;
                   1163:                /* XXXCDC: do we really need to reset on MTU size change? */
                   1164:            en_reset(sc);
                   1165:            en_init(sc);
                   1166:            break;
                   1167:
                   1168:        default:
                   1169:            error = EINVAL;
                   1170:            break;
                   1171:     }
                   1172:     splx(s);
                   1173:     return error;
                   1174: }
                   1175:
                   1176:
                   1177: /*
                   1178:  * en_rxctl: turn on and off VCs for recv.
                   1179:  */
                   1180:
                   1181: STATIC int en_rxctl(sc, pi, on)
                   1182:
                   1183: struct en_softc *sc;
                   1184: struct atm_pseudoioctl *pi;
                   1185: int on;
                   1186:
                   1187: {
                   1188:   u_int s, vci, flags, slot;
                   1189:   u_int32_t oldmode, newmode;
                   1190:
                   1191:   vci = ATM_PH_VCI(&pi->aph);
                   1192:   flags = ATM_PH_FLAGS(&pi->aph);
                   1193:
                   1194: #ifdef EN_DEBUG
                   1195:   printf("%s: %s vpi=%d, vci=%d, flags=%d\n", sc->sc_dev.dv_xname,
                   1196:        (on) ? "enable" : "disable", ATM_PH_VPI(&pi->aph), vci, flags);
                   1197: #endif
                   1198:
                   1199:   if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC)
                   1200:     return(EINVAL);
                   1201:
                   1202:   /*
                   1203:    * turn on VCI!
                   1204:    */
                   1205:
                   1206:   if (on) {
                   1207:     if (sc->rxvc2slot[vci] != RX_NONE)
                   1208:       return(EINVAL);
                   1209:     for (slot = 0 ; slot < sc->en_nrx ; slot++)
                   1210:       if (sc->rxslot[slot].oth_flags & ENOTHER_FREE)
                   1211:        break;
                   1212:     if (slot == sc->en_nrx)
                   1213:       return(ENOSPC);
                   1214:     sc->rxvc2slot[vci] = slot;
                   1215:     sc->rxslot[slot].rxhand = NULL;
                   1216:     oldmode = sc->rxslot[slot].mode;
                   1217:     newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL;
                   1218:     sc->rxslot[slot].mode = MIDV_SETMODE(oldmode, newmode);
                   1219:     sc->rxslot[slot].atm_vci = vci;
                   1220:     sc->rxslot[slot].atm_flags = flags;
                   1221:     sc->rxslot[slot].oth_flags = 0;
                   1222:     sc->rxslot[slot].rxhand = pi->rxhand;
                   1223:     if (sc->rxslot[slot].indma.ifq_head || sc->rxslot[slot].q.ifq_head)
                   1224:       panic("en_rxctl: left over mbufs on enable");
                   1225:     sc->txspeed[vci] = 0;      /* full speed to start */
                   1226:     sc->txvc2slot[vci] = 0;    /* init value */
                   1227:     sc->txslot[0].nref++;      /* bump reference count */
                   1228:     en_loadvc(sc, vci);                /* does debug printf for us */
                   1229:     return(0);
                   1230:   }
                   1231:
                   1232:   /*
                   1233:    * turn off VCI
                   1234:    */
                   1235:
                   1236:   if (sc->rxvc2slot[vci] == RX_NONE)
                   1237:     return(EINVAL);
                   1238:   slot = sc->rxvc2slot[vci];
                   1239:   if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0)
                   1240:     return(EINVAL);
                   1241:   s = splnet();                /* block out enintr() */
                   1242:   oldmode = EN_READ(sc, MID_VC(vci));
                   1243:   newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE;
                   1244:   EN_WRITE(sc, MID_VC(vci), (newmode | (oldmode & MIDV_INSERVICE)));
                   1245:                /* halt in tracks, be careful to preserve inserivce bit */
                   1246:   DELAY(27);
                   1247:   sc->rxslot[slot].rxhand = NULL;
                   1248:   sc->rxslot[slot].mode = newmode;
                   1249:
                   1250:   sc->txslot[sc->txvc2slot[vci]].nref--;
                   1251:   sc->txspeed[vci] = 0;
                   1252:   sc->txvc2slot[vci] = 0;
                   1253:
                   1254:   /* if stuff is still going on we are going to have to drain it out */
                   1255:   if (sc->rxslot[slot].indma.ifq_head ||
                   1256:                sc->rxslot[slot].q.ifq_head ||
                   1257:                (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) != 0) {
                   1258:     sc->rxslot[slot].oth_flags |= ENOTHER_DRAIN;
                   1259:   } else {
                   1260:     sc->rxslot[slot].oth_flags = ENOTHER_FREE;
                   1261:     sc->rxslot[slot].atm_vci = RX_NONE;
                   1262:     sc->rxvc2slot[vci] = RX_NONE;
                   1263:   }
                   1264:   splx(s);             /* enable enintr() */
                   1265: #ifdef EN_DEBUG
                   1266:   printf("%s: rx%d: VCI %d is now %s\n", sc->sc_dev.dv_xname, slot, vci,
                   1267:        (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) ? "draining" : "free");
                   1268: #endif
                   1269:   return(0);
                   1270: }
                   1271:
                   1272: /***********************************************************************/
                   1273:
                   1274: /*
                   1275:  * en_reset: reset the board, throw away work in progress.
                   1276:  * must en_init to recover.
                   1277:  */
                   1278:
                   1279: void en_reset(sc)
                   1280:
                   1281: struct en_softc *sc;
                   1282:
                   1283: {
                   1284:   struct mbuf *m;
                   1285:   int lcv, slot;
                   1286:
                   1287: #ifdef EN_DEBUG
                   1288:   printf("%s: reset\n", sc->sc_dev.dv_xname);
                   1289: #endif
                   1290:
                   1291:   if (sc->en_busreset)
                   1292:     sc->en_busreset(sc);
                   1293:   EN_WRITE(sc, MID_RESID, 0x0);        /* reset hardware */
                   1294:
                   1295:   /*
                   1296:    * recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset
                   1297:    * will free us!
                   1298:    */
                   1299:
                   1300:   for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
                   1301:     if (sc->rxvc2slot[lcv] == RX_NONE)
                   1302:       continue;
                   1303:     slot = sc->rxvc2slot[lcv];
                   1304:     while (1) {
                   1305:       IF_DEQUEUE(&sc->rxslot[slot].indma, m);
                   1306:       if (m == NULL)
                   1307:        break;          /* >>> exit 'while(1)' here <<< */
                   1308:       m_freem(m);
                   1309:     }
                   1310:     while (1) {
                   1311:       IF_DEQUEUE(&sc->rxslot[slot].q, m);
                   1312:       if (m == NULL)
                   1313:        break;          /* >>> exit 'while(1)' here <<< */
                   1314:       m_freem(m);
                   1315:     }
                   1316:     sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL;
                   1317:     if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {
                   1318:       sc->rxslot[slot].oth_flags = ENOTHER_FREE;
                   1319:       sc->rxvc2slot[lcv] = RX_NONE;
                   1320: #ifdef EN_DEBUG
                   1321:   printf("%s: rx%d: VCI %d is now free\n", sc->sc_dev.dv_xname, slot, lcv);
                   1322: #endif
                   1323:     }
                   1324:   }
                   1325:
                   1326:   /*
                   1327:    * xmit: dump everything
                   1328:    */
                   1329:
                   1330:   for (lcv = 0 ; lcv < EN_NTX ; lcv++) {
                   1331:     while (1) {
                   1332:       IF_DEQUEUE(&sc->txslot[lcv].indma, m);
                   1333:       if (m == NULL)
                   1334:        break;          /* >>> exit 'while(1)' here <<< */
                   1335:       m_freem(m);
                   1336:     }
                   1337:     while (1) {
                   1338:       IF_DEQUEUE(&sc->txslot[lcv].q, m);
                   1339:       if (m == NULL)
                   1340:        break;          /* >>> exit 'while(1)' here <<< */
                   1341:       m_freem(m);
                   1342:     }
                   1343:     sc->txslot[lcv].mbsize = 0;
                   1344:   }
                   1345:
                   1346:   return;
                   1347: }
                   1348:
                   1349:
                   1350: /*
                   1351:  * en_init: init board and sync the card with the data in the softc.
                   1352:  */
                   1353:
                   1354: STATIC void en_init(sc)
                   1355:
                   1356: struct en_softc *sc;
                   1357:
                   1358: {
                   1359:   int vc, slot;
                   1360:   u_int32_t loc;
                   1361:
                   1362:   if ((sc->enif.if_flags & IFF_UP) == 0) {
                   1363: #ifdef EN_DEBUG
                   1364:     printf("%s: going down\n", sc->sc_dev.dv_xname);
                   1365: #endif
                   1366:     en_reset(sc);                      /* to be safe */
                   1367:     sc->enif.if_flags &= ~IFF_RUNNING; /* disable */
                   1368:     return;
                   1369:   }
                   1370:
                   1371: #ifdef EN_DEBUG
                   1372:   printf("%s: going up\n", sc->sc_dev.dv_xname);
                   1373: #endif
                   1374:   sc->enif.if_flags |= IFF_RUNNING;    /* enable */
                   1375:
                   1376:   if (sc->en_busreset)
                   1377:     sc->en_busreset(sc);
                   1378:   EN_WRITE(sc, MID_RESID, 0x0);                /* reset */
                   1379:
                   1380:   /*
                   1381:    * init obmem data structures: vc tab, dma q's, slist.
                   1382:    *
                   1383:    * note that we set drq_free/dtq_free to one less than the total number
                   1384:    * of DTQ/DRQs present.   we do this because the card uses the condition
                   1385:    * (drq_chip == drq_us) to mean "list is empty"... but if you allow the
                   1386:    * circular list to be completely full then (drq_chip == drq_us) [i.e.
                   1387:    * the drq_us pointer will wrap all the way around].   by restricting
                   1388:    * the number of active requests to (N - 1) we prevent the list from
                   1389:    * becoming completely full.    note that the card will sometimes give
                   1390:    * us an interrupt for a DTQ/DRQ we have already processes... this helps
                   1391:    * keep that interrupt from messing us up.
                   1392:    */
                   1393:
                   1394:   for (vc = 0 ; vc < MID_N_VC ; vc++)
                   1395:     en_loadvc(sc, vc);
                   1396:
                   1397:   bzero(&sc->drq, sizeof(sc->drq));
                   1398:   sc->drq_free = MID_DRQ_N - 1;                /* N - 1 */
                   1399:   sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX));
                   1400:   EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
                   1401:                                                /* ensure zero queue */
                   1402:   sc->drq_us = sc->drq_chip;
                   1403:
                   1404:   bzero(&sc->dtq, sizeof(sc->dtq));
                   1405:   sc->dtq_free = MID_DTQ_N - 1;                /* N - 1 */
                   1406:   sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX));
                   1407:   EN_WRITE(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip));
                   1408:                                                /* ensure zero queue */
                   1409:   sc->dtq_us = sc->dtq_chip;
                   1410:
                   1411:   sc->hwslistp = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE));
                   1412:   sc->swsl_size = sc->swsl_head = sc->swsl_tail = 0;
                   1413:
                   1414: #ifdef EN_DEBUG
                   1415:   printf("%s: drq free/chip: %d/0x%x, dtq free/chip: %d/0x%x, hwslist: 0x%x\n",
                   1416:     sc->sc_dev.dv_xname, sc->drq_free, sc->drq_chip,
                   1417:     sc->dtq_free, sc->dtq_chip, sc->hwslistp);
                   1418: #endif
                   1419:
                   1420:   for (slot = 0 ; slot < EN_NTX ; slot++) {
                   1421:     sc->txslot[slot].bfree = EN_TXSZ * 1024;
                   1422:     EN_WRITE(sc, MIDX_READPTR(slot), 0);
                   1423:     EN_WRITE(sc, MIDX_DESCSTART(slot), 0);
                   1424:     loc = sc->txslot[slot].cur = sc->txslot[slot].start;
                   1425:     loc = loc - MID_RAMOFF;
                   1426:     loc = (loc & ~((EN_TXSZ*1024) - 1)) >> 2; /* mask, cvt to words */
                   1427:     loc = loc >> MIDV_LOCTOPSHFT;      /* top 11 bits */
                   1428:     EN_WRITE(sc, MIDX_PLACE(slot), MIDX_MKPLACE(en_k2sz(EN_TXSZ), loc));
                   1429: #ifdef EN_DEBUG
                   1430:     printf("%s: tx%d: place 0x%x\n", sc->sc_dev.dv_xname,  slot,
                   1431:        EN_READ(sc, MIDX_PLACE(slot)));
                   1432: #endif
                   1433:   }
                   1434:
                   1435:   /*
                   1436:    * enable!
                   1437:    */
                   1438:
                   1439:   EN_WRITE(sc, MID_INTENA, MID_INT_TX|MID_INT_DMA_OVR|MID_INT_IDENT|
                   1440:        MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_DMA_RX|MID_INT_DMA_TX|
                   1441:        MID_INT_SERVICE| /* >>> MID_INT_SUNI| XXXCDC<<< */ MID_INT_STATS);
                   1442:   EN_WRITE(sc, MID_MAST_CSR, MID_SETIPL(sc->ipl)|MID_MCSR_ENDMA|
                   1443:        MID_MCSR_ENTX|MID_MCSR_ENRX);
                   1444:
                   1445: }
                   1446:
                   1447:
                   1448: /*
                   1449:  * en_loadvc: load a vc tab entry from a slot
                   1450:  */
                   1451:
                   1452: STATIC void en_loadvc(sc, vc)
                   1453:
                   1454: struct en_softc *sc;
                   1455: int vc;
                   1456:
                   1457: {
                   1458:   int slot;
                   1459:   u_int32_t reg = EN_READ(sc, MID_VC(vc));
                   1460:
                   1461:   reg = MIDV_SETMODE(reg, MIDV_TRASH);
                   1462:   EN_WRITE(sc, MID_VC(vc), reg);
                   1463:   DELAY(27);
                   1464:
                   1465:   if ((slot = sc->rxvc2slot[vc]) == RX_NONE)
                   1466:     return;
                   1467:
                   1468:   /* no need to set CRC */
                   1469:   EN_WRITE(sc, MID_DST_RP(vc), 0);     /* read pointer = 0, desc. start = 0 */
                   1470:   EN_WRITE(sc, MID_WP_ST_CNT(vc), 0);  /* write pointer = 0 */
                   1471:   EN_WRITE(sc, MID_VC(vc), sc->rxslot[slot].mode);  /* set mode, size, loc */
                   1472:   sc->rxslot[slot].cur = sc->rxslot[slot].start;
                   1473:
                   1474: #ifdef EN_DEBUG
                   1475:     printf("%s: rx%d: assigned to VCI %d\n", sc->sc_dev.dv_xname, slot, vc);
                   1476: #endif
                   1477: }
                   1478:
                   1479:
                   1480: /*
                   1481:  * en_start: start transmitting the next packet that needs to go out
                   1482:  * if there is one.    note that atm_output() has already splnet()'d us.
                   1483:  */
                   1484:
                   1485: STATIC void en_start(ifp)
                   1486:
                   1487: struct ifnet *ifp;
                   1488:
                   1489: {
                   1490: #ifdef MISSING_IF_SOFTC
                   1491:     struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
                   1492: #else
                   1493:     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
                   1494: #endif
                   1495:     struct mbuf *m, *lastm, *prev;
                   1496:     struct atm_pseudohdr *ap, *new_ap;
                   1497:     int txchan, mlen, got, need, toadd, cellcnt, first;
                   1498:     u_int32_t atm_vpi, atm_vci, atm_flags, *dat, aal;
                   1499:     u_int8_t *cp;
                   1500:
                   1501:     if ((ifp->if_flags & IFF_RUNNING) == 0)
                   1502:        return;
                   1503:
                   1504:     /*
                   1505:      * remove everything from interface queue since we handle all queueing
                   1506:      * locally ...
                   1507:      */
                   1508:
                   1509:     while (1) {
                   1510:
                   1511:       IFQ_DEQUEUE(&ifp->if_snd, m);
                   1512:       if (m == NULL)
                   1513:        return;         /* EMPTY: >>> exit here <<< */
                   1514:
                   1515:       /*
                   1516:        * calculate size of packet (in bytes)
                   1517:        * also, if we are not doing transmit DMA we eliminate all stupid
                   1518:        * (non-word) alignments here using en_mfix().   calls to en_mfix()
                   1519:        * seem to be due to tcp retransmits for the most part.
                   1520:        *
                   1521:        * after this loop mlen total length of mbuf chain (including atm_ph),
                   1522:        * and lastm is a pointer to the last mbuf on the chain.
                   1523:        */
                   1524:
                   1525:       lastm = m;
                   1526:       mlen = 0;
                   1527:       prev = NULL;
                   1528:       while (1) {
                   1529:        /* no DMA? */
                   1530:         if ((!sc->is_adaptec && EN_ENIDMAFIX) || EN_NOTXDMA || !en_dma) {
                   1531:          if ( (mtod(lastm, unsigned long) % sizeof(u_int32_t)) != 0 ||
                   1532:            ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) {
                   1533:            first = (lastm == m);
                   1534:            if (en_mfix(sc, &lastm, prev) == 0) {       /* failed? */
                   1535:              m_freem(m);
                   1536:              m = NULL;
                   1537:               break;
                   1538:             }
                   1539:            if (first)
                   1540:              m = lastm;                /* update */
                   1541:           }
                   1542:           prev = lastm;
                   1543:         }
                   1544:        mlen += lastm->m_len;
                   1545:        if (lastm->m_next == NULL)
                   1546:          break;
                   1547:        lastm = lastm->m_next;
                   1548:       }
                   1549:
                   1550:       if (m == NULL)           /* happens only if mfix fails */
                   1551:         continue;
                   1552:
                   1553:       ap = mtod(m, struct atm_pseudohdr *);
                   1554:
                   1555:       atm_vpi = ATM_PH_VPI(ap);
                   1556:       atm_vci = ATM_PH_VCI(ap);
                   1557:       atm_flags = ATM_PH_FLAGS(ap) & ~(EN_OBHDR|EN_OBTRL);
                   1558:       aal = ((atm_flags & ATM_PH_AAL5) != 0)
                   1559:                        ? MID_TBD_AAL5 : MID_TBD_NOAAL5;
                   1560:
                   1561:       /*
                   1562:        * check that vpi/vci is one we can use
                   1563:        */
                   1564:
                   1565:       if (atm_vpi || atm_vci > MID_N_VC) {
                   1566:        printf("%s: output vpi=%d, vci=%d out of card range, dropping...\n",
                   1567:                sc->sc_dev.dv_xname, atm_vpi, atm_vci);
                   1568:        m_freem(m);
                   1569:        continue;
                   1570:       }
                   1571:
                   1572:       /*
                   1573:        * computing how much padding we need on the end of the mbuf, then
                   1574:        * see if we can put the TBD at the front of the mbuf where the
                   1575:        * link header goes (well behaved protocols will reserve room for us).
                   1576:        * last, check if room for PDU tail.
                   1577:        *
                   1578:        * got = number of bytes of data we have
                   1579:        * cellcnt = number of cells in this mbuf
                   1580:        * need = number of bytes of data + padding we need (excludes TBD)
                   1581:        * toadd = number of bytes of data we need to add to end of mbuf,
                   1582:        *       [including AAL5 PDU, if AAL5]
                   1583:        */
                   1584:
                   1585:       got = mlen - sizeof(struct atm_pseudohdr);
                   1586:       toadd = (aal == MID_TBD_AAL5) ? MID_PDU_SIZE : 0;        /* PDU */
                   1587:       cellcnt = (got + toadd + (MID_ATMDATASZ - 1)) / MID_ATMDATASZ;
                   1588:       need = cellcnt * MID_ATMDATASZ;
                   1589:       toadd = need - got;              /* recompute, including zero padding */
                   1590:
                   1591: #ifdef EN_DEBUG
                   1592:       printf("%s: txvci%d: mlen=%d, got=%d, need=%d, toadd=%d, cell#=%d\n",
                   1593:        sc->sc_dev.dv_xname, atm_vci, mlen, got, need, toadd, cellcnt);
                   1594:       printf("     leading_space=%d, trailing_space=%d\n",
                   1595:        M_LEADINGSPACE(m), M_TRAILINGSPACE(lastm));
                   1596: #endif
                   1597:
                   1598: #ifdef EN_MBUF_OPT
                   1599:
                   1600:       /*
                   1601:        * note: external storage (M_EXT) can be shared between mbufs
                   1602:        * to avoid copying (see m_copym()).    this means that the same
                   1603:        * data buffer could be shared by several mbufs, and thus it isn't
                   1604:        * a good idea to try and write TBDs or PDUs to M_EXT data areas.
                   1605:        */
                   1606:
                   1607:       if (M_LEADINGSPACE(m) >= MID_TBD_SIZE && (m->m_flags & M_EXT) == 0) {
                   1608:        m->m_data -= MID_TBD_SIZE;
                   1609:        m->m_len += MID_TBD_SIZE;
                   1610:        mlen += MID_TBD_SIZE;
                   1611:        new_ap = mtod(m, struct atm_pseudohdr *);
                   1612:        *new_ap = *ap;                  /* move it back */
                   1613:        ap = new_ap;
                   1614:        dat = ((u_int32_t *) ap) + 1;
                   1615:        /* make sure the TBD is in proper byte order */
                   1616:        *dat++ = htonl(MID_TBD_MK1(aal, sc->txspeed[atm_vci], cellcnt));
                   1617:        *dat = htonl(MID_TBD_MK2(atm_vci, 0, 0));
                   1618:        atm_flags |= EN_OBHDR;
                   1619:       }
                   1620:
                   1621:       if (toadd && (lastm->m_flags & M_EXT) == 0 &&
                   1622:                                        M_TRAILINGSPACE(lastm) >= toadd) {
                   1623:        cp = mtod(lastm, u_int8_t *) + lastm->m_len;
                   1624:        lastm->m_len += toadd;
                   1625:        mlen += toadd;
                   1626:        if (aal == MID_TBD_AAL5) {
                   1627:          bzero(cp, toadd - MID_PDU_SIZE);
                   1628:          dat = (u_int32_t *)(cp + toadd - MID_PDU_SIZE);
                   1629:          /* make sure the PDU is in proper byte order */
                   1630:          *dat = htonl(MID_PDU_MK1(0, 0, got));
                   1631:        } else {
                   1632:          bzero(cp, toadd);
                   1633:        }
                   1634:        atm_flags |= EN_OBTRL;
                   1635:       }
                   1636:       ATM_PH_FLAGS(ap) = atm_flags;    /* update EN_OBHDR/EN_OBTRL bits */
                   1637: #endif /* EN_MBUF_OPT */
                   1638:
                   1639:       /*
                   1640:        * get assigned channel (will be zero unless txspeed[atm_vci] is set)
                   1641:        */
                   1642:
                   1643:       txchan = sc->txvc2slot[atm_vci];
                   1644:
                   1645:       if (sc->txslot[txchan].mbsize > EN_TXHIWAT) {
                   1646:        EN_COUNT(sc->txmbovr);
                   1647:        m_freem(m);
                   1648: #ifdef EN_DEBUG
                   1649:        printf("%s: tx%d: buffer space shortage\n", sc->sc_dev.dv_xname,
                   1650:                txchan);
                   1651: #endif
                   1652:        continue;
                   1653:       }
                   1654:
                   1655:       sc->txslot[txchan].mbsize += mlen;
                   1656:
                   1657: #ifdef EN_DEBUG
                   1658:       printf("%s: tx%d: VPI=%d, VCI=%d, FLAGS=0x%x, speed=0x%x\n",
                   1659:        sc->sc_dev.dv_xname, txchan, atm_vpi, atm_vci, atm_flags,
                   1660:        sc->txspeed[atm_vci]);
                   1661:       printf("     adjusted mlen=%d, mbsize=%d\n", mlen,
                   1662:                sc->txslot[txchan].mbsize);
                   1663: #endif
                   1664:
                   1665:       IF_ENQUEUE(&sc->txslot[txchan].q, m);
                   1666:       en_txdma(sc, txchan);
                   1667:
                   1668:   }
                   1669:   /*NOTREACHED*/
                   1670: }
                   1671:
                   1672:
                   1673: /*
                   1674:  * en_mfix: fix a stupid mbuf
                   1675:  */
                   1676:
                   1677: STATIC int en_mfix(sc, mm, prev)
                   1678:
                   1679: struct en_softc *sc;
                   1680: struct mbuf **mm, *prev;
                   1681:
                   1682: {
                   1683:   struct mbuf *m, *new;
                   1684:   u_char *d, *cp;
                   1685:   int off;
                   1686:   struct mbuf *nxt;
                   1687:
                   1688:   m = *mm;
                   1689:
                   1690:   EN_COUNT(sc->mfix);                  /* count # of calls */
                   1691: #ifdef EN_DEBUG
                   1692:   printf("%s: mfix mbuf m_data=%p, m_len=%d\n", sc->sc_dev.dv_xname,
                   1693:        m->m_data, m->m_len);
                   1694: #endif
                   1695:
                   1696:   d = mtod(m, u_char *);
                   1697:   off = ((unsigned long) d) % sizeof(u_int32_t);
                   1698:
                   1699:   if (off) {
                   1700:     if ((m->m_flags & M_EXT) == 0) {
                   1701:       bcopy(d, d - off, m->m_len);   /* ALIGN! (with costly data copy...) */
                   1702:       d -= off;
                   1703:       m->m_data = (caddr_t)d;
                   1704:     } else {
                   1705:       /* can't write to an M_EXT mbuf since it may be shared */
                   1706:       MGET(new, M_DONTWAIT, MT_DATA);
                   1707:       if (!new) {
                   1708:         EN_COUNT(sc->mfixfail);
                   1709:         return(0);
                   1710:       }
                   1711:       MCLGET(new, M_DONTWAIT);
                   1712:       if ((new->m_flags & M_EXT) == 0) {
                   1713:         m_free(new);
                   1714:         EN_COUNT(sc->mfixfail);
                   1715:         return(0);
                   1716:       }
                   1717:       bcopy(d, new->m_data, m->m_len); /* ALIGN! (with costly data copy...) */
                   1718:       new->m_len = m->m_len;
                   1719:       new->m_next = m->m_next;
                   1720:       if (prev)
                   1721:         prev->m_next = new;
                   1722:       m_free(m);
                   1723:       *mm = m = new;   /* note: 'd' now invalid */
                   1724:     }
                   1725:   }
                   1726:
                   1727:   off = m->m_len % sizeof(u_int32_t);
                   1728:   if (off == 0)
                   1729:     return(1);
                   1730:
                   1731:   d = mtod(m, u_char *) + m->m_len;
                   1732:   off = sizeof(u_int32_t) - off;
                   1733:
                   1734:   nxt = m->m_next;
                   1735:   while (off--) {
                   1736:     for ( ; nxt != NULL && nxt->m_len == 0 ; nxt = nxt->m_next)
                   1737:       /*null*/;
                   1738:     if (nxt == NULL) {         /* out of data, zero fill */
                   1739:       *d++ = 0;
                   1740:       continue;                        /* next "off" */
                   1741:     }
                   1742:     cp = mtod(nxt, u_char *);
                   1743:     *d++ = *cp++;
                   1744:     m->m_len++;
                   1745:     nxt->m_len--;
                   1746:     nxt->m_data = (caddr_t)cp;
                   1747:   }
                   1748:   return(1);
                   1749: }
                   1750:
                   1751:
                   1752: /*
                   1753:  * en_txdma: start transmit DMA, if possible
                   1754:  */
                   1755:
                   1756: STATIC void en_txdma(sc, chan)
                   1757:
                   1758: struct en_softc *sc;
                   1759: int chan;
                   1760:
                   1761: {
                   1762:   struct mbuf *tmp;
                   1763:   struct atm_pseudohdr *ap;
                   1764:   struct en_launch launch;
                   1765:   int datalen = 0, dtqneed, len, ncells;
                   1766:   u_int8_t *cp;
                   1767:
                   1768: #ifdef EN_DEBUG
                   1769:   printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan);
                   1770: #endif
                   1771:
                   1772:   /*
                   1773:    * note: now that txlaunch handles non-word aligned/sized requests
                   1774:    * the only time you can safely set launch.nodma is if you've en_mfix()'d
                   1775:    * the mbuf chain.    this happens only if EN_NOTXDMA || !en_dma.
                   1776:    */
                   1777:
                   1778:   launch.nodma = (EN_NOTXDMA || !en_dma);
                   1779:
                   1780: again:
                   1781:
                   1782:   /*
                   1783:    * get an mbuf waiting for DMA
                   1784:    */
                   1785:
                   1786:   launch.t = sc->txslot[chan].q.ifq_head; /* peek at head of queue */
                   1787:
                   1788:   if (launch.t == NULL) {
                   1789: #ifdef EN_DEBUG
                   1790:     printf("%s: tx%d: ...done!\n", sc->sc_dev.dv_xname, chan);
                   1791: #endif
                   1792:     return;    /* >>> exit here if no data waiting for DMA <<< */
                   1793:   }
                   1794:
                   1795:   /*
                   1796:    * get flags, vci
                   1797:    *
                   1798:    * note: launch.need = # bytes we need to get on the card
                   1799:    *      dtqneed = # of DTQs we need for this packet
                   1800:    *       launch.mlen = # of bytes in in mbuf chain (<= launch.need)
                   1801:    */
                   1802:
                   1803:   ap = mtod(launch.t, struct atm_pseudohdr *);
                   1804:   launch.atm_vci = ATM_PH_VCI(ap);
                   1805:   launch.atm_flags = ATM_PH_FLAGS(ap);
                   1806:   launch.aal = ((launch.atm_flags & ATM_PH_AAL5) != 0) ?
                   1807:                MID_TBD_AAL5 : MID_TBD_NOAAL5;
                   1808:
                   1809:   /*
                   1810:    * XXX: have to recompute the length again, even though we already did
                   1811:    * it in en_start().   might as well compute dtqneed here as well, so
                   1812:    * this isn't that bad.
                   1813:    */
                   1814:
                   1815:   if ((launch.atm_flags & EN_OBHDR) == 0) {
                   1816:     dtqneed = 1;               /* header still needs to be added */
                   1817:     launch.need = MID_TBD_SIZE;        /* not included with mbuf */
                   1818:   } else {
                   1819:     dtqneed = 0;               /* header on-board, dma with mbuf */
                   1820:     launch.need = 0;
                   1821:   }
                   1822:
                   1823:   launch.mlen = 0;
                   1824:   for (tmp = launch.t ; tmp != NULL ; tmp = tmp->m_next) {
                   1825:     len = tmp->m_len;
                   1826:     launch.mlen += len;
                   1827:     cp = mtod(tmp, u_int8_t *);
                   1828:     if (tmp == launch.t) {
                   1829:       len -= sizeof(struct atm_pseudohdr); /* don't count this! */
                   1830:       cp += sizeof(struct atm_pseudohdr);
                   1831:     }
                   1832:     launch.need += len;
                   1833:     if (len == 0)
                   1834:       continue;                        /* atm_pseudohdr alone in first mbuf */
                   1835:
                   1836:     dtqneed += en_dqneed(sc, (caddr_t) cp, len, 1);
                   1837:   }
                   1838:
                   1839:   if ((launch.need % sizeof(u_int32_t)) != 0)
                   1840:     dtqneed++;                 /* need DTQ to FLUSH internal buffer */
                   1841:
                   1842:   if ((launch.atm_flags & EN_OBTRL) == 0) {
                   1843:     if (launch.aal == MID_TBD_AAL5) {
                   1844:       datalen = launch.need - MID_TBD_SIZE;
                   1845:       launch.need += MID_PDU_SIZE;             /* AAL5: need PDU tail */
                   1846:     }
                   1847:     dtqneed++;                 /* need to work on the end a bit */
                   1848:   }
                   1849:
                   1850:   /*
                   1851:    * finish calculation of launch.need (need to figure out how much padding
                   1852:    * we will need).   launch.need includes MID_TBD_SIZE, but we need to
                   1853:    * remove that to so we can round off properly.     we have to add
                   1854:    * MID_TBD_SIZE back in after calculating ncells.
                   1855:    */
                   1856:
                   1857:   launch.need = roundup(launch.need - MID_TBD_SIZE, MID_ATMDATASZ);
                   1858:   ncells = launch.need / MID_ATMDATASZ;
                   1859:   launch.need += MID_TBD_SIZE;
                   1860:
                   1861:   if (launch.need > EN_TXSZ * 1024) {
                   1862:     printf("%s: tx%d: packet larger than xmit buffer (%d > %d)\n",
                   1863:       sc->sc_dev.dv_xname, chan, launch.need, EN_TXSZ * 1024);
                   1864:     goto dequeue_drop;
                   1865:   }
                   1866:
                   1867:   /*
                   1868:    * note: note that we cannot totally fill the circular buffer (i.e.
                   1869:    * we can't use up all of the remaining sc->txslot[chan].bfree free
                   1870:    * bytes) because that would cause the circular buffer read pointer
                   1871:    * to become equal to the write pointer, thus signaling 'empty buffer'
                   1872:    * to the hardware and stopping the transmitter.
                   1873:    */
                   1874:   if (launch.need >= sc->txslot[chan].bfree) {
                   1875:     EN_COUNT(sc->txoutspace);
                   1876: #ifdef EN_DEBUG
                   1877:     printf("%s: tx%d: out of transmit space\n", sc->sc_dev.dv_xname, chan);
                   1878: #endif
                   1879:     return;            /* >>> exit here if out of obmem buffer space <<< */
                   1880:   }
                   1881:
                   1882:   /*
                   1883:    * ensure we have enough dtqs to go, if not, wait for more.
                   1884:    */
                   1885:
                   1886:   if (launch.nodma) {
                   1887:     dtqneed = 1;
                   1888:   }
                   1889:   if (dtqneed > sc->dtq_free) {
                   1890:     sc->need_dtqs = 1;
                   1891:     EN_COUNT(sc->txdtqout);
                   1892: #ifdef EN_DEBUG
                   1893:     printf("%s: tx%d: out of transmit DTQs\n", sc->sc_dev.dv_xname, chan);
                   1894: #endif
                   1895:     return;            /* >>> exit here if out of dtqs <<< */
                   1896:   }
                   1897:
                   1898:   /*
                   1899:    * it is a go, commit!  dequeue mbuf start working on the xfer.
                   1900:    */
                   1901:
                   1902:   IF_DEQUEUE(&sc->txslot[chan].q, tmp);
                   1903: #ifdef EN_DIAG
                   1904:   if (launch.t != tmp)
                   1905:     panic("en dequeue");
                   1906: #endif /* EN_DIAG */
                   1907:
                   1908:   /*
                   1909:    * launch!
                   1910:    */
                   1911:
                   1912:   EN_COUNT(sc->launch);
                   1913:   sc->enif.if_opackets++;
                   1914:   if ((launch.atm_flags & EN_OBHDR) == 0) {
                   1915:     EN_COUNT(sc->lheader);
                   1916:     /* store tbd1/tbd2 in host byte order */
                   1917:     launch.tbd1 = MID_TBD_MK1(launch.aal, sc->txspeed[launch.atm_vci], ncells);
                   1918:     launch.tbd2 = MID_TBD_MK2(launch.atm_vci, 0, 0);
                   1919:   }
                   1920:   if ((launch.atm_flags & EN_OBTRL) == 0 && launch.aal == MID_TBD_AAL5) {
                   1921:     EN_COUNT(sc->ltail);
                   1922:     launch.pdu1 = MID_PDU_MK1(0, 0, datalen);  /* host byte order */
                   1923:   }
                   1924:
                   1925: #if NBPFILTER > 0
                   1926:        if (sc->enif.if_bpf != NULL) {
                   1927:                /*
                   1928:                 * adjust the top of the mbuf to skip the TBD if present
                   1929:                 * before passing the packet to bpf.
                   1930:                 * Also remove padding and the PDU trailer. Assume both of
                   1931:                 * them to be in the same mbuf. pktlen, m_len and m_data
                   1932:                 * are not needed anymore so we can change them.
                   1933:                 */
                   1934:                int size = sizeof(struct atm_pseudohdr);
                   1935:                if (launch.atm_flags & EN_OBHDR)
                   1936:                        size += MID_TBD_SIZE;
                   1937:
                   1938:                launch.t->m_data += size;
                   1939:                launch.t->m_len -= size;
                   1940:
                   1941:                bpf_mtap(sc->enif.if_bpf, launch.t, BPF_DIRECTION_OUT);
                   1942:
                   1943:                launch.t->m_data -= size;
                   1944:                launch.t->m_len += size;
                   1945:        }
                   1946: #endif
                   1947:
                   1948:   en_txlaunch(sc, chan, &launch);
                   1949:
                   1950:   /*
                   1951:    * do some housekeeping and get the next packet
                   1952:    */
                   1953:
                   1954:   sc->txslot[chan].bfree -= launch.need;
                   1955:   IF_ENQUEUE(&sc->txslot[chan].indma, launch.t);
                   1956:   goto again;
                   1957:
                   1958:   /*
                   1959:    * END of txdma loop!
                   1960:    */
                   1961:
                   1962:   /*
                   1963:    * error handles
                   1964:    */
                   1965:
                   1966: dequeue_drop:
                   1967:   IF_DEQUEUE(&sc->txslot[chan].q, tmp);
                   1968:   if (launch.t != tmp)
                   1969:     panic("en dequeue drop");
                   1970:   m_freem(launch.t);
                   1971:   sc->txslot[chan].mbsize -= launch.mlen;
                   1972:   goto again;
                   1973: }
                   1974:
                   1975:
                   1976: /*
                   1977:  * en_txlaunch: launch an mbuf into the dma pool!
                   1978:  */
                   1979:
                   1980: STATIC void en_txlaunch(sc, chan, l)
                   1981:
                   1982: struct en_softc *sc;
                   1983: int chan;
                   1984: struct en_launch *l;
                   1985:
                   1986: {
                   1987:   struct mbuf *tmp;
                   1988:   u_int32_t cur = sc->txslot[chan].cur,
                   1989:            start = sc->txslot[chan].start,
                   1990:            stop = sc->txslot[chan].stop,
                   1991:            dma, *data, *datastop, count, bcode;
                   1992:   int pad, addtail, need, len, needalign, cnt, end, mx;
                   1993:
                   1994:
                   1995:  /*
                   1996:   * vars:
                   1997:   *   need = # bytes card still needs (decr. to zero)
                   1998:   *   len = # of bytes left in current mbuf
                   1999:   *   cur = our current pointer
                   2000:   *   dma = last place we programmed into the DMA
                   2001:   *   data = pointer into data area of mbuf that needs to go next
                   2002:   *   cnt = # of bytes to transfer in this DTQ
                   2003:   *   bcode/count = DMA burst code, and chip's version of cnt
                   2004:   *
                   2005:   *   a single buffer can require up to 5 DTQs depending on its size
                   2006:   *   and alignment requirements.   the 5 possible requests are:
                   2007:   *   [1] 1, 2, or 3 byte DMA to align src data pointer to word boundary
                   2008:   *   [2] alburst DMA to align src data pointer to bestburstlen
                   2009:   *   [3] 1 or more bestburstlen DMAs
                   2010:   *   [4] clean up burst (to last word boundary)
                   2011:   *   [5] 1, 2, or 3 byte final clean up DMA
                   2012:   */
                   2013:
                   2014:  need = l->need;
                   2015:  dma = cur;
                   2016:  addtail = (l->atm_flags & EN_OBTRL) == 0;     /* add a tail? */
                   2017:
                   2018: #ifdef EN_DIAG
                   2019:   if ((need - MID_TBD_SIZE) % MID_ATMDATASZ)
                   2020:     printf("%s: tx%d: bogus transmit needs (%d)\n", sc->sc_dev.dv_xname, chan,
                   2021:                need);
                   2022: #endif
                   2023: #ifdef EN_DEBUG
                   2024:   printf("%s: tx%d: launch mbuf %p!   cur=0x%x[%d], need=%d, addtail=%d\n",
                   2025:        sc->sc_dev.dv_xname, chan, l->t, cur, (cur-start)/4, need, addtail);
                   2026:   count = EN_READ(sc, MIDX_PLACE(chan));
                   2027:   printf("     HW: base_address=0x%x, size=%d, read=%d, descstart=%d\n",
                   2028:        MIDX_BASE(count), MIDX_SZ(count), EN_READ(sc, MIDX_READPTR(chan)),
                   2029:        EN_READ(sc, MIDX_DESCSTART(chan)));
                   2030: #endif
                   2031:
                   2032:  /*
                   2033:   * do we need to insert the TBD by hand?
                   2034:   * note that tbd1/tbd2/pdu1 are in host byte order.
                   2035:   */
                   2036:
                   2037:   if ((l->atm_flags & EN_OBHDR) == 0) {
                   2038: #ifdef EN_DEBUG
                   2039:     printf("%s: tx%d: insert header 0x%x 0x%x\n", sc->sc_dev.dv_xname,
                   2040:        chan, l->tbd1, l->tbd2);
                   2041: #endif
                   2042:     EN_WRITE(sc, cur, l->tbd1);
                   2043:     EN_WRAPADD(start, stop, cur, 4);
                   2044:     EN_WRITE(sc, cur, l->tbd2);
                   2045:     EN_WRAPADD(start, stop, cur, 4);
                   2046:     need -= 8;
                   2047:   }
                   2048:
                   2049:   /*
                   2050:    * now do the mbufs...
                   2051:    */
                   2052:
                   2053:   for (tmp = l->t ; tmp != NULL ; tmp = tmp->m_next) {
                   2054:
                   2055:     /* get pointer to data and length */
                   2056:     data = mtod(tmp, u_int32_t *);
                   2057:     len = tmp->m_len;
                   2058:     if (tmp == l->t) {
                   2059:       data += sizeof(struct atm_pseudohdr)/sizeof(u_int32_t);
                   2060:       len -= sizeof(struct atm_pseudohdr);
                   2061:     }
                   2062:
                   2063:     /* now, determine if we should copy it */
                   2064:     if (l->nodma || (len < EN_MINDMA &&
                   2065:        (len % 4) == 0 && ((unsigned long) data % 4) == 0 && (cur % 4) == 0)) {
                   2066:
                   2067:       /*
                   2068:        * roundup len: the only time this will change the value of len
                   2069:        * is when l->nodma is true, tmp is the last mbuf, and there is
                   2070:        * a non-word number of bytes to transmit.   in this case it is
                   2071:        * safe to round up because we've en_mfix'd the mbuf (so the first
                   2072:        * byte is word aligned there must be enough free bytes at the end
                   2073:        * to round off to the next word boundary)...
                   2074:        */
                   2075:       len = roundup(len, sizeof(u_int32_t));
                   2076:       datastop = data + (len / sizeof(u_int32_t));
                   2077:       /* copy loop: preserve byte order!!!  use WRITEDAT */
                   2078:       while (data != datastop) {
                   2079:        EN_WRITEDAT(sc, cur, *data);
                   2080:        data++;
                   2081:        EN_WRAPADD(start, stop, cur, 4);
                   2082:       }
                   2083:       need -= len;
                   2084: #ifdef EN_DEBUG
                   2085:       printf("%s: tx%d: copied %d bytes (%d left, cur now 0x%x)\n",
                   2086:                sc->sc_dev.dv_xname, chan, len, need, cur);
                   2087: #endif
                   2088:       continue;                /* continue on to next mbuf */
                   2089:     }
                   2090:
                   2091:     /* going to do DMA, first make sure the dtq is in sync. */
                   2092:     if (dma != cur) {
                   2093:       EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0, 0, 0);
                   2094: #ifdef EN_DEBUG
                   2095:       printf("%s: tx%d: dtq_sync: advance pointer to %d\n",
                   2096:                sc->sc_dev.dv_xname, chan, cur);
                   2097: #endif
                   2098:     }
                   2099:
                   2100:     /*
                   2101:      * if this is the last buffer, and it looks like we are going to need to
                   2102:      * flush the internal buffer, can we extend the length of this mbuf to
                   2103:      * avoid the FLUSH?
                   2104:      */
                   2105:
                   2106:     if (tmp->m_next == NULL) {
                   2107:       cnt = (need - len) % sizeof(u_int32_t);
                   2108:       if (cnt && M_TRAILINGSPACE(tmp) >= cnt)
                   2109:         len += cnt;                    /* pad for FLUSH */
                   2110:     }
                   2111:
                   2112: #if !defined(MIDWAY_ENIONLY)
                   2113:
                   2114:     /*
                   2115:      * the adaptec DMA engine is smart and handles everything for us.
                   2116:      */
                   2117:
                   2118:     if (sc->is_adaptec) {
                   2119:       /* need to DMA "len" bytes out to card */
                   2120:       need -= len;
                   2121:       EN_WRAPADD(start, stop, cur, len);
                   2122: #ifdef EN_DEBUG
                   2123:       printf("%s: tx%d: adp_dma %d bytes (%d left, cur now 0x%x)\n",
                   2124:               sc->sc_dev.dv_xname, chan, len, need, cur);
                   2125: #endif
                   2126:       end = (need == 0) ? MID_DMA_END : 0;
                   2127:       EN_DTQADD(sc, len, chan, 0, vtophys(data), l->mlen, end);
                   2128:       if (end)
                   2129:         goto done;
                   2130:       dma = cur;       /* update dma pointer */
                   2131:       continue;
                   2132:     }
                   2133: #endif /* !MIDWAY_ENIONLY */
                   2134:
                   2135: #if !defined(MIDWAY_ADPONLY)
                   2136:
                   2137:     /*
                   2138:      * the ENI DMA engine is not so smart and need more help from us
                   2139:      */
                   2140:
                   2141:     /* do we need to do a DMA op to align to word boundary? */
                   2142:     needalign = (unsigned long) data % sizeof(u_int32_t);
                   2143:     if (needalign) {
                   2144:       EN_COUNT(sc->headbyte);
                   2145:       cnt = sizeof(u_int32_t) - needalign;
                   2146:       if (cnt == 2 && len >= cnt) {
                   2147:         count = 1;
                   2148:         bcode = MIDDMA_2BYTE;
                   2149:       } else {
                   2150:         cnt = min(cnt, len);           /* prevent overflow */
                   2151:         count = cnt;
                   2152:         bcode = MIDDMA_BYTE;
                   2153:       }
                   2154:       need -= cnt;
                   2155:       EN_WRAPADD(start, stop, cur, cnt);
                   2156: #ifdef EN_DEBUG
                   2157:       printf("%s: tx%d: small al_dma %d bytes (%d left, cur now 0x%x)\n",
                   2158:               sc->sc_dev.dv_xname, chan, cnt, need, cur);
                   2159: #endif
                   2160:       len -= cnt;
                   2161:       end = (need == 0) ? MID_DMA_END : 0;
                   2162:       EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
                   2163:       if (end)
                   2164:         goto done;
                   2165:       data = (u_int32_t *) ((u_char *)data + cnt);
                   2166:     }
                   2167:
                   2168:     /* do we need to do a DMA op to align? */
                   2169:     if (sc->alburst &&
                   2170:        (needalign = (((unsigned long) data) & sc->bestburstmask)) != 0
                   2171:        && len >= sizeof(u_int32_t)) {
                   2172:       cnt = sc->bestburstlen - needalign;
                   2173:       mx = len & ~(sizeof(u_int32_t)-1);       /* don't go past end */
                   2174:       if (cnt > mx) {
                   2175:         cnt = mx;
                   2176:         count = cnt / sizeof(u_int32_t);
                   2177:         bcode = MIDDMA_WORD;
                   2178:       } else {
                   2179:         count = cnt / sizeof(u_int32_t);
                   2180:         bcode = en_dmaplan[count].bcode;
                   2181:         count = cnt >> en_dmaplan[count].divshift;
                   2182:       }
                   2183:       need -= cnt;
                   2184:       EN_WRAPADD(start, stop, cur, cnt);
                   2185: #ifdef EN_DEBUG
                   2186:       printf("%s: tx%d: al_dma %d bytes (%d left, cur now 0x%x)\n",
                   2187:                sc->sc_dev.dv_xname, chan, cnt, need, cur);
                   2188: #endif
                   2189:       len -= cnt;
                   2190:       end = (need == 0) ? MID_DMA_END : 0;
                   2191:       EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
                   2192:       if (end)
                   2193:         goto done;
                   2194:       data = (u_int32_t *) ((u_char *)data + cnt);
                   2195:     }
                   2196:
                   2197:     /* do we need to do a max-sized burst? */
                   2198:     if (len >= sc->bestburstlen) {
                   2199:       count = len >> sc->bestburstshift;
                   2200:       cnt = count << sc->bestburstshift;
                   2201:       bcode = sc->bestburstcode;
                   2202:       need -= cnt;
                   2203:       EN_WRAPADD(start, stop, cur, cnt);
                   2204: #ifdef EN_DEBUG
                   2205:       printf("%s: tx%d: best_dma %d bytes (%d left, cur now 0x%x)\n",
                   2206:                sc->sc_dev.dv_xname, chan, cnt, need, cur);
                   2207: #endif
                   2208:       len -= cnt;
                   2209:       end = (need == 0) ? MID_DMA_END : 0;
                   2210:       EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
                   2211:       if (end)
                   2212:         goto done;
                   2213:       data = (u_int32_t *) ((u_char *)data + cnt);
                   2214:     }
                   2215:
                   2216:     /* do we need to do a cleanup burst? */
                   2217:     cnt = len & ~(sizeof(u_int32_t)-1);
                   2218:     if (cnt) {
                   2219:       count = cnt / sizeof(u_int32_t);
                   2220:       bcode = en_dmaplan[count].bcode;
                   2221:       count = cnt >> en_dmaplan[count].divshift;
                   2222:       need -= cnt;
                   2223:       EN_WRAPADD(start, stop, cur, cnt);
                   2224: #ifdef EN_DEBUG
                   2225:       printf("%s: tx%d: cleanup_dma %d bytes (%d left, cur now 0x%x)\n",
                   2226:                sc->sc_dev.dv_xname, chan, cnt, need, cur);
                   2227: #endif
                   2228:       len -= cnt;
                   2229:       end = (need == 0) ? MID_DMA_END : 0;
                   2230:       EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
                   2231:       if (end)
                   2232:         goto done;
                   2233:       data = (u_int32_t *) ((u_char *)data + cnt);
                   2234:     }
                   2235:
                   2236:     /* any word fragments left? */
                   2237:     if (len) {
                   2238:       EN_COUNT(sc->tailbyte);
                   2239:       if (len == 2) {
                   2240:         count = 1;
                   2241:         bcode = MIDDMA_2BYTE;                 /* use 2byte mode */
                   2242:       } else {
                   2243:         count = len;
                   2244:         bcode = MIDDMA_BYTE;                  /* use 1 byte mode */
                   2245:       }
                   2246:       need -= len;
                   2247:       EN_WRAPADD(start, stop, cur, len);
                   2248: #ifdef EN_DEBUG
                   2249:       printf("%s: tx%d: byte cleanup_dma %d bytes (%d left, cur now 0x%x)\n",
                   2250:               sc->sc_dev.dv_xname, chan, len, need, cur);
                   2251: #endif
                   2252:       end = (need == 0) ? MID_DMA_END : 0;
                   2253:       EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
                   2254:       if (end)
                   2255:         goto done;
                   2256:     }
                   2257:
                   2258:     dma = cur;         /* update dma pointer */
                   2259: #endif /* !MIDWAY_ADPONLY */
                   2260:
                   2261:   } /* next mbuf, please */
                   2262:
                   2263:   /*
                   2264:    * all mbuf data has been copied out to the obmem (or set up to be DMAd).
                   2265:    * if the trailer or padding needs to be put in, do it now.
                   2266:    *
                   2267:    * NOTE: experimental results reveal the following fact:
                   2268:    *   if you DMA "X" bytes to the card, where X is not a multiple of 4,
                   2269:    *   then the card will internally buffer the last (X % 4) bytes (in
                   2270:    *   hopes of getting (4 - (X % 4)) more bytes to make a complete word).
                   2271:    *   it is imporant to make sure we don't leave any important data in
                   2272:    *   this internal buffer because it is discarded on the last (end) DTQ.
                   2273:    *   one way to do this is to DMA in (4 - (X % 4)) more bytes to flush
                   2274:    *   the darn thing out.
                   2275:    */
                   2276:
                   2277:   if (addtail) {
                   2278:
                   2279:     pad = need % sizeof(u_int32_t);
                   2280:     if (pad) {
                   2281:       /*
                   2282:        * FLUSH internal data buffer.  pad out with random data from the front
                   2283:        * of the mbuf chain...
                   2284:        */
                   2285:       bcode = (sc->is_adaptec) ? 0 : MIDDMA_BYTE;
                   2286:       EN_COUNT(sc->tailflush);
                   2287:       EN_WRAPADD(start, stop, cur, pad);
                   2288:       EN_DTQADD(sc, pad, chan, bcode, vtophys(l->t->m_data), 0, 0);
                   2289:       need -= pad;
                   2290: #ifdef EN_DEBUG
                   2291:       printf("%s: tx%d: pad/FLUSH dma %d bytes (%d left, cur now 0x%x)\n",
                   2292:                sc->sc_dev.dv_xname, chan, pad, need, cur);
                   2293: #endif
                   2294:     }
                   2295:
                   2296:     /* copy data */
                   2297:     pad = need / sizeof(u_int32_t);    /* round *down* */
                   2298:     if (l->aal == MID_TBD_AAL5)
                   2299:       pad -= 2;
                   2300: #ifdef EN_DEBUG
                   2301:       printf("%s: tx%d: padding %d bytes (cur now 0x%x)\n",
                   2302:                sc->sc_dev.dv_xname, chan, pad * sizeof(u_int32_t), cur);
                   2303: #endif
                   2304:     while (pad--) {
                   2305:       EN_WRITEDAT(sc, cur, 0); /* no byte order issues with zero */
                   2306:       EN_WRAPADD(start, stop, cur, 4);
                   2307:     }
                   2308:     if (l->aal == MID_TBD_AAL5) {
                   2309:       EN_WRITE(sc, cur, l->pdu1); /* in host byte order */
                   2310:       EN_WRAPADD(start, stop, cur, 8);
                   2311:     }
                   2312:   }
                   2313:
                   2314:   if (addtail || dma != cur) {
                   2315:    /* write final descriptor  */
                   2316:     EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0,
                   2317:                                l->mlen, MID_DMA_END);
                   2318:     /* dma = cur; */   /* not necessary since we are done */
                   2319:   }
                   2320:
                   2321: done:
                   2322:   /* update current pointer */
                   2323:   sc->txslot[chan].cur = cur;
                   2324: #ifdef EN_DEBUG
                   2325:       printf("%s: tx%d: DONE!   cur now = 0x%x\n",
                   2326:                sc->sc_dev.dv_xname, chan, cur);
                   2327: #endif
                   2328:
                   2329:   return;
                   2330: }
                   2331:
                   2332:
                   2333: /*
                   2334:  * interrupt handler
                   2335:  */
                   2336:
                   2337: EN_INTR_TYPE en_intr(arg)
                   2338:
                   2339: void *arg;
                   2340:
                   2341: {
                   2342:   struct en_softc *sc = (struct en_softc *) arg;
                   2343:   struct mbuf *m;
                   2344:   struct atm_pseudohdr ah;
                   2345:   u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq;
                   2346:   int lcv, idx, need_softserv = 0;
                   2347:
                   2348:   reg = EN_READ(sc, MID_INTACK);
                   2349:
                   2350:   if ((reg & MID_INT_ANY) == 0)
                   2351:     EN_INTR_RET(0); /* not us */
                   2352:
                   2353: #ifdef EN_DEBUG
                   2354:   printf("%s: interrupt=0x%b\n", sc->sc_dev.dv_xname, reg, MID_INTBITS);
                   2355: #endif
                   2356:
                   2357:   /*
                   2358:    * unexpected errors that need a reset
                   2359:    */
                   2360:
                   2361:   if ((reg & (MID_INT_IDENT|MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_SUNI)) != 0) {
                   2362:     printf("%s: unexpected interrupt=0x%b, resetting card\n",
                   2363:        sc->sc_dev.dv_xname, reg, MID_INTBITS);
                   2364: #ifdef EN_DEBUG
                   2365: #ifdef DDB
                   2366:     Debugger();
                   2367: #endif /* DDB */
                   2368:     sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */
                   2369: #else
                   2370:     en_reset(sc);
                   2371:     en_init(sc);
                   2372: #endif
                   2373:     EN_INTR_RET(1); /* for us */
                   2374:   }
                   2375:
                   2376:   /*******************
                   2377:    * xmit interrupts *
                   2378:    ******************/
                   2379:
                   2380:   kick = 0;                            /* bitmask of channels to kick */
                   2381:   if (reg & MID_INT_TX) {              /* TX done! */
                   2382:
                   2383:     /*
                   2384:      * check for tx complete, if detected then this means that some space
                   2385:      * has come free on the card.   we must account for it and arrange to
                   2386:      * kick the channel to life (in case it is stalled waiting on the card).
                   2387:      */
                   2388:     for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) {
                   2389:       if (reg & MID_TXCHAN(lcv)) {
                   2390:        kick = kick | mask;     /* want to kick later */
                   2391:        val = EN_READ(sc, MIDX_READPTR(lcv));   /* current read pointer */
                   2392:        val = (val * sizeof(u_int32_t)) + sc->txslot[lcv].start;
                   2393:                                                /* convert to offset */
                   2394:        if (val > sc->txslot[lcv].cur)
                   2395:          sc->txslot[lcv].bfree = val - sc->txslot[lcv].cur;
                   2396:        else
                   2397:          sc->txslot[lcv].bfree = (val + (EN_TXSZ*1024)) - sc->txslot[lcv].cur;
                   2398: #ifdef EN_DEBUG
                   2399:        printf("%s: tx%d: transmit done.   %d bytes now free in buffer\n",
                   2400:                sc->sc_dev.dv_xname, lcv, sc->txslot[lcv].bfree);
                   2401: #endif
                   2402:       }
                   2403:     }
                   2404:   }
                   2405:
                   2406:   if (reg & MID_INT_DMA_TX) {          /* TX DMA done! */
                   2407:
                   2408:   /*
                   2409:    * check for TX DMA complete, if detected then this means that some DTQs
                   2410:    * are now free.   it also means some indma mbufs can be freed.
                   2411:    * if we needed DTQs, kick all channels.
                   2412:    */
                   2413:     val = EN_READ(sc, MID_DMA_RDTX);   /* chip's current location */
                   2414:     idx = MID_DTQ_A2REG(sc->dtq_chip);/* where we last saw chip */
                   2415:     if (sc->need_dtqs) {
                   2416:       kick = MID_NTX_CH - 1;           /* assume power of 2, kick all! */
                   2417:       sc->need_dtqs = 0;               /* recalculated in "kick" loop below */
                   2418: #ifdef EN_DEBUG
                   2419:       printf("%s: cleared need DTQ condition\n", sc->sc_dev.dv_xname);
                   2420: #endif
                   2421:     }
                   2422:     while (idx != val) {
                   2423:       sc->dtq_free++;
                   2424:       if ((dtq = sc->dtq[idx]) != 0) {
                   2425:         sc->dtq[idx] = 0;      /* don't forget to zero it out when done */
                   2426:        slot = EN_DQ_SLOT(dtq);
                   2427:        IF_DEQUEUE(&sc->txslot[slot].indma, m);
                   2428:        if (!m) panic("enintr: dtqsync");
                   2429:        sc->txslot[slot].mbsize -= EN_DQ_LEN(dtq);
                   2430: #ifdef EN_DEBUG
                   2431:        printf("%s: tx%d: free %d dma bytes, mbsize now %d\n",
                   2432:                sc->sc_dev.dv_xname, slot, EN_DQ_LEN(dtq),
                   2433:                sc->txslot[slot].mbsize);
                   2434: #endif
                   2435:        m_freem(m);
                   2436:       }
                   2437:       EN_WRAPADD(0, MID_DTQ_N, idx, 1);
                   2438:     }
                   2439:     sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */
                   2440:   }
                   2441:
                   2442:
                   2443:   /*
                   2444:    * kick xmit channels as needed
                   2445:    */
                   2446:
                   2447:   if (kick) {
                   2448: #ifdef EN_DEBUG
                   2449:   printf("%s: tx kick mask = 0x%x\n", sc->sc_dev.dv_xname, kick);
                   2450: #endif
                   2451:     for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) {
                   2452:       if ((kick & mask) && sc->txslot[lcv].q.ifq_head) {
                   2453:        en_txdma(sc, lcv);              /* kick it! */
                   2454:       }
                   2455:     }          /* for each slot */
                   2456:   }            /* if kick */
                   2457:
                   2458:
                   2459:   /*******************
                   2460:    * recv interrupts *
                   2461:    ******************/
                   2462:
                   2463:   /*
                   2464:    * check for RX DMA complete, and pass the data "upstairs"
                   2465:    */
                   2466:
                   2467:   if (reg & MID_INT_DMA_RX) {
                   2468:     val = EN_READ(sc, MID_DMA_RDRX); /* chip's current location */
                   2469:     idx = MID_DRQ_A2REG(sc->drq_chip);/* where we last saw chip */
                   2470:     while (idx != val) {
                   2471:       sc->drq_free++;
                   2472:       if ((drq = sc->drq[idx]) != 0) {
                   2473:         sc->drq[idx] = 0;      /* don't forget to zero it out when done */
                   2474:        slot = EN_DQ_SLOT(drq);
                   2475:         if (EN_DQ_LEN(drq) == 0) {  /* "JK" trash DMA? */
                   2476:           m = NULL;
                   2477:         } else {
                   2478:          IF_DEQUEUE(&sc->rxslot[slot].indma, m);
                   2479:          if (!m) {
                   2480:            panic("enintr: drqsync: %s: lost mbuf in slot %d!",
                   2481:                sc->sc_dev.dv_xname, slot);
                   2482:          }
                   2483:         }
                   2484:        /* do something with this mbuf */
                   2485:        if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {  /* drain? */
                   2486:           if (m)
                   2487:            m_freem(m);
                   2488:          vci = sc->rxslot[slot].atm_vci;
                   2489:          if (sc->rxslot[slot].indma.ifq_head == NULL &&
                   2490:                sc->rxslot[slot].q.ifq_head == NULL &&
                   2491:                (EN_READ(sc, MID_VC(vci)) & MIDV_INSERVICE) == 0 &&
                   2492:                (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) {
                   2493:            sc->rxslot[slot].oth_flags = ENOTHER_FREE; /* done drain */
                   2494:            sc->rxslot[slot].atm_vci = RX_NONE;
                   2495:            sc->rxvc2slot[vci] = RX_NONE;
                   2496: #ifdef EN_DEBUG
                   2497:            printf("%s: rx%d: VCI %d now free\n", sc->sc_dev.dv_xname,
                   2498:                        slot, vci);
                   2499: #endif
                   2500:          }
                   2501:        } else if (m != NULL) {
                   2502:          ATM_PH_FLAGS(&ah) = sc->rxslot[slot].atm_flags;
                   2503:          ATM_PH_VPI(&ah) = 0;
                   2504:          ATM_PH_SETVCI(&ah, sc->rxslot[slot].atm_vci);
                   2505: #ifdef EN_DEBUG
                   2506:          printf("%s: rx%d: rxvci%d: atm_input, mbuf %p, len %d, hand %p\n",
                   2507:                sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m,
                   2508:                EN_DQ_LEN(drq), sc->rxslot[slot].rxhand);
                   2509: #endif
                   2510:          sc->enif.if_ipackets++;
                   2511:
                   2512: #if NBPFILTER > 0
                   2513:          if (sc->enif.if_bpf)
                   2514:                bpf_mtap(sc->enif.if_bpf, m, BPF_DIRECTION_IN);
                   2515: #endif
                   2516:
                   2517:          atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand);
                   2518:        }
                   2519:
                   2520:       }
                   2521:       EN_WRAPADD(0, MID_DRQ_N, idx, 1);
                   2522:     }
                   2523:     sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */
                   2524:
                   2525:     if (sc->need_drqs) {       /* true if we had a DRQ shortage */
                   2526:       need_softserv = 1;
                   2527:       sc->need_drqs = 0;
                   2528: #ifdef EN_DEBUG
                   2529:        printf("%s: cleared need DRQ condition\n", sc->sc_dev.dv_xname);
                   2530: #endif
                   2531:     }
                   2532:   }
                   2533:
                   2534:   /*
                   2535:    * handle service interrupts
                   2536:    */
                   2537:
                   2538:   if (reg & MID_INT_SERVICE) {
                   2539:     chip = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE));
                   2540:
                   2541:     while (sc->hwslistp != chip) {
                   2542:
                   2543:       /* fetch and remove it from hardware service list */
                   2544:       vci = EN_READ(sc, sc->hwslistp);
                   2545:       EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4);/* advance hw ptr */
                   2546:       slot = sc->rxvc2slot[vci];
                   2547:       if (slot == RX_NONE) {
                   2548: #ifdef EN_DEBUG
                   2549:        printf("%s: unexpected rx interrupt on VCI %d\n",
                   2550:                sc->sc_dev.dv_xname, vci);
                   2551: #endif
                   2552:        EN_WRITE(sc, MID_VC(vci), MIDV_TRASH);  /* rx off, damn it! */
                   2553:        continue;                               /* next */
                   2554:       }
                   2555:       EN_WRITE(sc, MID_VC(vci), sc->rxslot[slot].mode); /* remove from hwsl */
                   2556:       EN_COUNT(sc->hwpull);
                   2557:
                   2558: #ifdef EN_DEBUG
                   2559:       printf("%s: pulled VCI %d off hwslist\n", sc->sc_dev.dv_xname, vci);
                   2560: #endif
                   2561:
                   2562:       /* add it to the software service list (if needed) */
                   2563:       if ((sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) {
                   2564:        EN_COUNT(sc->swadd);
                   2565:        need_softserv = 1;
                   2566:        sc->rxslot[slot].oth_flags |= ENOTHER_SWSL;
                   2567:        sc->swslist[sc->swsl_tail] = slot;
                   2568:        EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1);
                   2569:        sc->swsl_size++;
                   2570: #ifdef EN_DEBUG
                   2571:       printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci);
                   2572: #endif
                   2573:       }
                   2574:     }
                   2575:   }
                   2576:
                   2577:   /*
                   2578:    * now service (function too big to include here)
                   2579:    */
                   2580:
                   2581:   if (need_softserv)
                   2582:     en_service(sc);
                   2583:
                   2584:   /*
                   2585:    * keep our stats
                   2586:    */
                   2587:
                   2588:   if (reg & MID_INT_DMA_OVR) {
                   2589:     EN_COUNT(sc->dmaovr);
                   2590: #ifdef EN_DEBUG
                   2591:     printf("%s: MID_INT_DMA_OVR\n", sc->sc_dev.dv_xname);
                   2592: #endif
                   2593:   }
                   2594:   reg = EN_READ(sc, MID_STAT);
                   2595: #ifdef EN_STAT
                   2596:   sc->otrash += MID_OTRASH(reg);
                   2597:   sc->vtrash += MID_VTRASH(reg);
                   2598: #endif
                   2599:
                   2600:   EN_INTR_RET(1); /* for us */
                   2601: }
                   2602:
                   2603:
                   2604: /*
                   2605:  * en_service: handle a service interrupt
                   2606:  *
                   2607:  * Q: why do we need a software service list?
                   2608:  *
                   2609:  * A: if we remove a VCI from the hardware list and we find that we are
                   2610:  *    out of DRQs we must defer processing until some DRQs become free.
                   2611:  *    so we must remember to look at this RX VCI/slot later, but we can't
                   2612:  *    put it back on the hardware service list (since that isn't allowed).
                   2613:  *    so we instead save it on the software service list.   it would be nice
                   2614:  *    if we could peek at the VCI on top of the hwservice list without removing
                   2615:  *    it, however this leads to a race condition: if we peek at it and
                   2616:  *    decide we are done with it new data could come in before we have a
                   2617:  *    chance to remove it from the hwslist.   by the time we get it out of
                   2618:  *    the list the interrupt for the new data will be lost.   oops!
                   2619:  *
                   2620:  */
                   2621:
                   2622: STATIC void en_service(sc)
                   2623:
                   2624: struct en_softc *sc;
                   2625:
                   2626: {
                   2627:   struct mbuf *m, *tmp;
                   2628:   u_int32_t cur, dstart, rbd, pdu, *sav, dma, bcode, count, *data, *datastop;
                   2629:   u_int32_t start, stop, cnt, needalign;
                   2630:   int slot, raw, aal5, llc, vci, fill, mlen, tlen, drqneed, need, needfill, end;
                   2631:
                   2632:   aal5 = 0;            /* Silence gcc */
                   2633: next_vci:
                   2634:   if (sc->swsl_size == 0) {
                   2635: #ifdef EN_DEBUG
                   2636:     printf("%s: en_service done\n", sc->sc_dev.dv_xname);
                   2637: #endif
                   2638:     return;            /* >>> exit here if swsl now empty <<< */
                   2639:   }
                   2640:
                   2641:   /*
                   2642:    * get slot/vci to service
                   2643:    */
                   2644:
                   2645:   slot = sc->swslist[sc->swsl_head];
                   2646:   vci = sc->rxslot[slot].atm_vci;
                   2647: #ifdef EN_DIAG
                   2648:   if (sc->rxvc2slot[vci] != slot) panic("en_service rx slot/vci sync");
                   2649: #endif
                   2650:
                   2651:   /*
                   2652:    * determine our mode and if we've got any work to do
                   2653:    */
                   2654:
                   2655:   raw = sc->rxslot[slot].oth_flags & ENOTHER_RAW;
                   2656:   start= sc->rxslot[slot].start;
                   2657:   stop= sc->rxslot[slot].stop;
                   2658:   cur = sc->rxslot[slot].cur;
                   2659:
                   2660: #ifdef EN_DEBUG
                   2661:   printf("%s: rx%d: service vci=%d raw=%d start/stop/cur=0x%x 0x%x 0x%x\n",
                   2662:        sc->sc_dev.dv_xname, slot, vci, raw, start, stop, cur);
                   2663: #endif
                   2664:
                   2665: same_vci:
                   2666:   dstart = MIDV_DSTART(EN_READ(sc, MID_DST_RP(vci)));
                   2667:   dstart = (dstart * sizeof(u_int32_t)) + start;
                   2668:
                   2669:   /* check to see if there is any data at all */
                   2670:   if (dstart == cur) {
                   2671: defer:                                 /* defer processing */
                   2672:     EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1);
                   2673:     sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL;
                   2674:     sc->swsl_size--;
                   2675:                                        /* >>> remove from swslist <<< */
                   2676: #ifdef EN_DEBUG
                   2677:     printf("%s: rx%d: remove vci %d from swslist\n",
                   2678:                sc->sc_dev.dv_xname, slot, vci);
                   2679: #endif
                   2680:     goto next_vci;
                   2681:   }
                   2682:
                   2683:   /*
                   2684:    * figure out how many bytes we need
                   2685:    * [mlen = # bytes to go in mbufs, fill = # bytes to dump (MIDDMA_JK)]
                   2686:    */
                   2687:
                   2688:   if (raw) {
                   2689:
                   2690:     /* raw mode (aka boodi mode) */
                   2691:     fill = 0;
                   2692:     if (dstart > cur)
                   2693:       mlen = dstart - cur;
                   2694:     else
                   2695:       mlen = (dstart + (EN_RXSZ*1024)) - cur;
                   2696:
                   2697:     if (mlen < sc->rxslot[slot].raw_threshold)
                   2698:       goto defer;              /* too little data to deal with */
                   2699:
                   2700:   } else {
                   2701:
                   2702:     /* normal mode */
                   2703:     aal5 = (sc->rxslot[slot].atm_flags & ATM_PH_AAL5);
                   2704:     llc = (aal5 && (sc->rxslot[slot].atm_flags & ATM_PH_LLCSNAP)) ? 1 : 0;
                   2705:     rbd = EN_READ(sc, cur);
                   2706:     if (MID_RBD_ID(rbd) != MID_RBD_STDID)
                   2707:       panic("en_service: id mismatch");
                   2708:
                   2709:     if (rbd & MID_RBD_T) {
                   2710:       mlen = 0;                        /* we've got trash */
                   2711:       fill = MID_RBD_SIZE;
                   2712:       EN_COUNT(sc->ttrash);
                   2713:     } else if (!aal5) {
                   2714:       mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */
                   2715:       fill = 0;
                   2716:     } else {
                   2717:       tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE;
                   2718:       pdu = cur + tlen - MID_PDU_SIZE;
                   2719:       if (pdu >= stop)
                   2720:        pdu -= (EN_RXSZ*1024);
                   2721:       pdu = EN_READ(sc, pdu);  /* get PDU in correct byte order */
                   2722:       fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu);
                   2723:       if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) {
                   2724:         printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
                   2725:            (rbd & MID_RBD_CRCERR) ? "CRC error" : "invalid AAL5 PDU length");
                   2726:         printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
                   2727:          sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE,
                   2728:                MID_PDU_LEN(pdu), pdu);
                   2729:        fill = tlen;
                   2730:       }
                   2731:       mlen = tlen - fill;
                   2732:     }
                   2733:
                   2734:   }
                   2735:
                   2736:   /*
                   2737:    * now allocate mbufs for mlen bytes of data, if out of mbufs, trash all
                   2738:    *
                   2739:    * notes:
                   2740:    *  1. it is possible that we've already allocated an mbuf for this pkt
                   2741:    *    but ran out of DRQs, in which case we saved the allocated mbuf on
                   2742:    *    "q".
                   2743:    *  2. if we save an mbuf in "q" we store the "cur" (pointer) in the front
                   2744:    *     of the mbuf as an identity (that we can check later), and we also
                   2745:    *     store drqneed (so we don't have to recompute it).
                   2746:    *  3. after this block of code, if m is still NULL then we ran out of mbufs
                   2747:    */
                   2748:
                   2749:   m = sc->rxslot[slot].q.ifq_head;
                   2750:   drqneed = 1;
                   2751:   if (m) {
                   2752:     sav = mtod(m, u_int32_t *);
                   2753:     if (sav[0] != cur) {
                   2754: #ifdef EN_DEBUG
                   2755:       printf("%s: rx%d: q'ed mbuf %p not ours\n",
                   2756:                sc->sc_dev.dv_xname, slot, m);
                   2757: #endif
                   2758:       m = NULL;                        /* wasn't ours */
                   2759:       EN_COUNT(sc->rxqnotus);
                   2760:     } else {
                   2761:       EN_COUNT(sc->rxqus);
                   2762:       IF_DEQUEUE(&sc->rxslot[slot].q, m);
                   2763:       drqneed = sav[1];
                   2764: #ifdef EN_DEBUG
                   2765:       printf("%s: rx%d: recovered q'ed mbuf %p (drqneed=%d)\n",
                   2766:        sc->sc_dev.dv_xname, slot, m, drqneed);
                   2767: #endif
                   2768:     }
                   2769:   }
                   2770:
                   2771:   if (mlen != 0 && m == NULL) {
                   2772:     m = en_mget(sc, mlen, &drqneed);           /* allocate! */
                   2773:     if (m == NULL) {
                   2774:       fill += mlen;
                   2775:       mlen = 0;
                   2776:       EN_COUNT(sc->rxmbufout);
                   2777: #ifdef EN_DEBUG
                   2778:       printf("%s: rx%d: out of mbufs\n", sc->sc_dev.dv_xname, slot);
                   2779: #endif
                   2780:     }
                   2781: #ifdef EN_DEBUG
                   2782:     printf("%s: rx%d: allocate mbuf %p, mlen=%d, drqneed=%d\n",
                   2783:        sc->sc_dev.dv_xname, slot, m, mlen, drqneed);
                   2784: #endif
                   2785:   }
                   2786:
                   2787: #ifdef EN_DEBUG
                   2788:   printf("%s: rx%d: VCI %d, mbuf_chain %p, mlen %d, fill %d\n",
                   2789:        sc->sc_dev.dv_xname, slot, vci, m, mlen, fill);
                   2790: #endif
                   2791:
                   2792:   /*
                   2793:    * now check to see if we've got the DRQs needed.    if we are out of
                   2794:    * DRQs we must quit (saving our mbuf, if we've got one).
                   2795:    */
                   2796:
                   2797:   needfill = (fill) ? 1 : 0;
                   2798:   if (drqneed + needfill > sc->drq_free) {
                   2799:     sc->need_drqs = 1; /* flag condition */
                   2800:     if (m == NULL) {
                   2801:       EN_COUNT(sc->rxoutboth);
                   2802: #ifdef EN_DEBUG
                   2803:       printf("%s: rx%d: out of DRQs *and* mbufs!\n", sc->sc_dev.dv_xname, slot);
                   2804: #endif
                   2805:       return;          /* >>> exit here if out of both mbufs and DRQs <<< */
                   2806:     }
                   2807:     sav = mtod(m, u_int32_t *);
                   2808:     sav[0] = cur;
                   2809:     sav[1] = drqneed;
                   2810:     IF_ENQUEUE(&sc->rxslot[slot].q, m);
                   2811:     EN_COUNT(sc->rxdrqout);
                   2812: #ifdef EN_DEBUG
                   2813:     printf("%s: rx%d: out of DRQs\n", sc->sc_dev.dv_xname, slot);
                   2814: #endif
                   2815:     return;            /* >>> exit here if out of DRQs <<< */
                   2816:   }
                   2817:
                   2818:   /*
                   2819:    * at this point all resources have been allocated and we are commited
                   2820:    * to servicing this slot.
                   2821:    *
                   2822:    * dma = last location we told chip about
                   2823:    * cur = current location
                   2824:    * mlen = space in the mbuf we want
                   2825:    * need = bytes to xfer in (decrs to zero)
                   2826:    * fill = how much fill we need
                   2827:    * tlen = how much data to transfer to this mbuf
                   2828:    * cnt/bcode/count = <same as xmit>
                   2829:    *
                   2830:    * 'needfill' not used after this point
                   2831:    */
                   2832:
                   2833:   dma = cur;           /* dma = last location we told chip about */
                   2834:   need = roundup(mlen, sizeof(u_int32_t));
                   2835:   fill = fill - (need - mlen);  /* note: may invalidate 'needfill' */
                   2836:
                   2837:   for (tmp = m ; tmp != NULL && need > 0 ; tmp = tmp->m_next) {
                   2838:     tlen = roundup(tmp->m_len, sizeof(u_int32_t)); /* m_len set by en_mget */
                   2839:     data = mtod(tmp, u_int32_t *);
                   2840:
                   2841: #ifdef EN_DEBUG
                   2842:     printf("%s: rx%d: load mbuf %p, m_len=%d, m_data=%p, tlen=%d\n",
                   2843:        sc->sc_dev.dv_xname, slot, tmp, tmp->m_len, tmp->m_data, tlen);
                   2844: #endif
                   2845:
                   2846:     /* copy data */
                   2847:     if (EN_NORXDMA || !en_dma || tlen < EN_MINDMA) {
                   2848:       datastop = (u_int32_t *)((u_char *) data + tlen);
                   2849:       /* copy loop: preserve byte order!!!  use READDAT */
                   2850:       while (data != datastop) {
                   2851:        *data = EN_READDAT(sc, cur);
                   2852:        data++;
                   2853:        EN_WRAPADD(start, stop, cur, 4);
                   2854:       }
                   2855:       need -= tlen;
                   2856: #ifdef EN_DEBUG
                   2857:       printf("%s: rx%d: vci%d: copied %d bytes (%d left)\n",
                   2858:                sc->sc_dev.dv_xname, slot, vci, tlen, need);
                   2859: #endif
                   2860:       continue;
                   2861:     }
                   2862:
                   2863:     /* DMA data (check to see if we need to sync DRQ first) */
                   2864:     if (dma != cur) {
                   2865:       EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, 0, 0, 0);
                   2866: #ifdef EN_DEBUG
                   2867:       printf("%s: rx%d: vci%d: drq_sync: advance pointer to %d\n",
                   2868:                sc->sc_dev.dv_xname, slot, vci, cur);
                   2869: #endif
                   2870:     }
                   2871:
                   2872: #if !defined(MIDWAY_ENIONLY)
                   2873:
                   2874:     /*
                   2875:      * the adaptec DMA engine is smart and handles everything for us.
                   2876:      */
                   2877:
                   2878:     if (sc->is_adaptec) {
                   2879:       need -= tlen;
                   2880:       EN_WRAPADD(start, stop, cur, tlen);
                   2881: #ifdef EN_DEBUG
                   2882:       printf("%s: rx%d: vci%d: adp_dma %d bytes (%d left)\n",
                   2883:                sc->sc_dev.dv_xname, slot, vci, tlen, need);
                   2884: #endif
                   2885:       end = (need == 0 && !fill) ? MID_DMA_END : 0;
                   2886:       EN_DRQADD(sc, tlen, vci, 0, vtophys(data), mlen, slot, end);
                   2887:       if (end)
                   2888:         goto done;
                   2889:       dma = cur;       /* update dma pointer */
                   2890:       continue;
                   2891:     }
                   2892: #endif /* !MIDWAY_ENIONLY */
                   2893:
                   2894:
                   2895: #if !defined(MIDWAY_ADPONLY)
                   2896:
                   2897:     /*
                   2898:      * the ENI DMA engine is not so smart and need more help from us
                   2899:      */
                   2900:
                   2901:     /* do we need to do a DMA op to align? */
                   2902:     if (sc->alburst &&
                   2903:       (needalign = (((unsigned long) data) & sc->bestburstmask)) != 0) {
                   2904:       cnt = sc->bestburstlen - needalign;
                   2905:       if (cnt > tlen) {
                   2906:         cnt = tlen;
                   2907:         count = cnt / sizeof(u_int32_t);
                   2908:         bcode = MIDDMA_WORD;
                   2909:       } else {
                   2910:         count = cnt / sizeof(u_int32_t);
                   2911:         bcode = en_dmaplan[count].bcode;
                   2912:         count = cnt >> en_dmaplan[count].divshift;
                   2913:       }
                   2914:       need -= cnt;
                   2915:       EN_WRAPADD(start, stop, cur, cnt);
                   2916: #ifdef EN_DEBUG
                   2917:       printf("%s: rx%d: vci%d: al_dma %d bytes (%d left)\n",
                   2918:                sc->sc_dev.dv_xname, slot, vci, cnt, need);
                   2919: #endif
                   2920:       tlen -= cnt;
                   2921:       end = (need == 0 && !fill) ? MID_DMA_END : 0;
                   2922:       EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end);
                   2923:       if (end)
                   2924:         goto done;
                   2925:       data = (u_int32_t *)((u_char *) data + cnt);
                   2926:     }
                   2927:
                   2928:     /* do we need a max-sized burst? */
                   2929:     if (tlen >= sc->bestburstlen) {
                   2930:       count = tlen >> sc->bestburstshift;
                   2931:       cnt = count << sc->bestburstshift;
                   2932:       bcode = sc->bestburstcode;
                   2933:       need -= cnt;
                   2934:       EN_WRAPADD(start, stop, cur, cnt);
                   2935: #ifdef EN_DEBUG
                   2936:       printf("%s: rx%d: vci%d: best_dma %d bytes (%d left)\n",
                   2937:                sc->sc_dev.dv_xname, slot, vci, cnt, need);
                   2938: #endif
                   2939:       tlen -= cnt;
                   2940:       end = (need == 0 && !fill) ? MID_DMA_END : 0;
                   2941:       EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end);
                   2942:       if (end)
                   2943:         goto done;
                   2944:       data = (u_int32_t *)((u_char *) data + cnt);
                   2945:     }
                   2946:
                   2947:     /* do we need to do a cleanup burst? */
                   2948:     if (tlen) {
                   2949:       count = tlen / sizeof(u_int32_t);
                   2950:       bcode = en_dmaplan[count].bcode;
                   2951:       count = tlen >> en_dmaplan[count].divshift;
                   2952:       need -= tlen;
                   2953:       EN_WRAPADD(start, stop, cur, tlen);
                   2954: #ifdef EN_DEBUG
                   2955:       printf("%s: rx%d: vci%d: cleanup_dma %d bytes (%d left)\n",
                   2956:                sc->sc_dev.dv_xname, slot, vci, tlen, need);
                   2957: #endif
                   2958:       end = (need == 0 && !fill) ? MID_DMA_END : 0;
                   2959:       EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end);
                   2960:       if (end)
                   2961:         goto done;
                   2962:     }
                   2963:
                   2964:     dma = cur;         /* update dma pointer */
                   2965:
                   2966: #endif /* !MIDWAY_ADPONLY */
                   2967:
                   2968:   }
                   2969:
                   2970:   /* skip the end */
                   2971:   if (fill || dma != cur) {
                   2972: #ifdef EN_DEBUG
                   2973:       if (fill)
                   2974:         printf("%s: rx%d: vci%d: skipping %d bytes of fill\n",
                   2975:                sc->sc_dev.dv_xname, slot, vci, fill);
                   2976:       else
                   2977:         printf("%s: rx%d: vci%d: syncing chip from 0x%x to 0x%x [cur]\n",
                   2978:                sc->sc_dev.dv_xname, slot, vci, dma, cur);
                   2979: #endif
                   2980:     EN_WRAPADD(start, stop, cur, fill);
                   2981:     EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, mlen,
                   2982:                                        slot, MID_DMA_END);
                   2983:     /* dma = cur; */   /* not necessary since we are done */
                   2984:   }
                   2985:
                   2986:   /*
                   2987:    * done, remove stuff we don't want to pass up:
                   2988:    *   raw mode (boodi mode): pass everything up for later processing
                   2989:    *   aal5: remove RBD
                   2990:    *   aal0: remove RBD + cell header
                   2991:    */
                   2992:
                   2993: done:
                   2994:   if (m) {
                   2995:     if (!raw) {
                   2996:       cnt = MID_RBD_SIZE;
                   2997:       if (!aal5) cnt += MID_CHDR_SIZE;
                   2998:       m->m_len -= cnt;                         /* chop! */
                   2999:       m->m_pkthdr.len -= cnt;
                   3000:       m->m_data += cnt;
                   3001:     }
                   3002:     IF_ENQUEUE(&sc->rxslot[slot].indma, m);
                   3003:   }
                   3004:   sc->rxslot[slot].cur = cur;          /* update master copy of 'cur' */
                   3005:
                   3006: #ifdef EN_DEBUG
                   3007:   printf("%s: rx%d: vci%d: DONE!   cur now =0x%x\n",
                   3008:        sc->sc_dev.dv_xname, slot, vci, cur);
                   3009: #endif
                   3010:
                   3011:   goto same_vci;       /* get next packet in this slot */
                   3012: }
                   3013:
                   3014:
                   3015: #ifdef EN_DDBHOOK
                   3016: /*
                   3017:  * functions we can call from ddb
                   3018:  */
                   3019:
                   3020: /*
                   3021:  * en_dump: dump the state
                   3022:  */
                   3023:
                   3024: #define END_SWSL       0x00000040              /* swsl state */
                   3025: #define END_DRQ                0x00000020              /* drq state */
                   3026: #define END_DTQ                0x00000010              /* dtq state */
                   3027: #define END_RX         0x00000008              /* rx state */
                   3028: #define END_TX         0x00000004              /* tx state */
                   3029: #define END_MREGS      0x00000002              /* registers */
                   3030: #define END_STATS      0x00000001              /* dump stats */
                   3031:
                   3032: #define END_BITS "\20\7SWSL\6DRQ\5DTQ\4RX\3TX\2MREGS\1STATS"
                   3033:
                   3034: int en_dump(unit, level)
                   3035:
                   3036: int unit, level;
                   3037:
                   3038: {
                   3039:   struct en_softc *sc;
                   3040:   int lcv, cnt, slot;
                   3041:   u_int32_t ptr, reg;
                   3042:
                   3043:   for (lcv = 0 ; lcv < en_cd.cd_ndevs ; lcv++) {
                   3044:     sc = (struct en_softc *) en_cd.cd_devs[lcv];
                   3045:     if (sc == NULL) continue;
                   3046:     if (unit != -1 && unit != lcv)
                   3047:       continue;
                   3048:
                   3049:     printf("dumping device %s at level 0x%b\n", sc->sc_dev.dv_xname, level,
                   3050:                        END_BITS);
                   3051:
                   3052:     if (sc->dtq_us == 0) {
                   3053:       printf("<hasn't been en_init'd yet>\n");
                   3054:       continue;
                   3055:     }
                   3056:
                   3057:     if (level & END_STATS) {
                   3058:       printf("  en_stats:\n");
                   3059:       printf("    %d mfix (%d failed); %d/%d head/tail byte DMAs, %d flushes\n",
                   3060:           sc->mfix, sc->mfixfail, sc->headbyte, sc->tailbyte, sc->tailflush);
                   3061:       printf("    %d rx dma overflow interrupts\n", sc->dmaovr);
                   3062:       printf("    %d times we ran out of TX space and stalled\n",
                   3063:                                                        sc->txoutspace);
                   3064:       printf("    %d times we ran out of DTQs\n", sc->txdtqout);
                   3065:       printf("    %d times we launched a packet\n", sc->launch);
                   3066:       printf("    %d times we launched without on-board header\n", sc->lheader);
                   3067:       printf("    %d times we launched without on-board tail\n", sc->ltail);
                   3068:       printf("    %d times we pulled the hw service list\n", sc->hwpull);
                   3069:       printf("    %d times we pushed a vci on the sw service list\n",
                   3070:                                                                sc->swadd);
                   3071:       printf("    %d times RX pulled an mbuf from Q that wasn't ours\n",
                   3072:                                                         sc->rxqnotus);
                   3073:       printf("    %d times RX pulled a good mbuf from Q\n", sc->rxqus);
                   3074:       printf("    %d times we ran out of mbufs *and* DRQs\n", sc->rxoutboth);
                   3075:       printf("    %d times we ran out of DRQs\n", sc->rxdrqout);
                   3076:
                   3077:       printf("    %d transmit packets dropped due to mbsize\n", sc->txmbovr);
                   3078:       printf("    %d cells trashed due to turned off rxvc\n", sc->vtrash);
                   3079:       printf("    %d cells trashed due to totally full buffer\n", sc->otrash);
                   3080:       printf("    %d cells trashed due almost full buffer\n", sc->ttrash);
                   3081:       printf("    %d rx mbuf allocation failures\n", sc->rxmbufout);
                   3082: #ifdef NATM
                   3083:       printf("    %d drops at natmintrq\n", natmintrq.ifq_drops);
                   3084: #ifdef NATM_STAT
                   3085:       printf("    natmintr so_rcv: ok/drop cnt: %d/%d, ok/drop bytes: %d/%d\n",
                   3086:        natm_sookcnt, natm_sodropcnt, natm_sookbytes, natm_sodropbytes);
                   3087: #endif
                   3088: #endif
                   3089:     }
                   3090:
                   3091:     if (level & END_MREGS) {
                   3092:       printf("mregs:\n");
                   3093:       printf("resid = 0x%x\n", EN_READ(sc, MID_RESID));
                   3094:       printf("interrupt status = 0x%b\n",
                   3095:                                EN_READ(sc, MID_INTSTAT), MID_INTBITS);
                   3096:       printf("interrupt enable = 0x%b\n",
                   3097:                                EN_READ(sc, MID_INTENA), MID_INTBITS);
                   3098:       printf("mcsr = 0x%b\n", EN_READ(sc, MID_MAST_CSR), MID_MCSRBITS);
                   3099:       printf("serv_write = [chip=%d] [us=%d]\n", EN_READ(sc, MID_SERV_WRITE),
                   3100:                        MID_SL_A2REG(sc->hwslistp));
                   3101:       printf("dma addr = 0x%x\n", EN_READ(sc, MID_DMA_ADDR));
                   3102:       printf("DRQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n",
                   3103:        MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)),
                   3104:        MID_DRQ_REG2A(EN_READ(sc, MID_DMA_WRRX)), sc->drq_chip, sc->drq_us);
                   3105:       printf("DTQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n",
                   3106:        MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)),
                   3107:        MID_DTQ_REG2A(EN_READ(sc, MID_DMA_WRTX)), sc->dtq_chip, sc->dtq_us);
                   3108:
                   3109:       printf("  unusal txspeeds: ");
                   3110:       for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
                   3111:        if (sc->txspeed[cnt])
                   3112:          printf(" vci%d=0x%x", cnt, sc->txspeed[cnt]);
                   3113:       printf("\n");
                   3114:
                   3115:       printf("  rxvc slot mappings: ");
                   3116:       for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
                   3117:        if (sc->rxvc2slot[cnt] != RX_NONE)
                   3118:          printf("  %d->%d", cnt, sc->rxvc2slot[cnt]);
                   3119:       printf("\n");
                   3120:
                   3121:     }
                   3122:
                   3123:     if (level & END_TX) {
                   3124:       printf("tx:\n");
                   3125:       for (slot = 0 ; slot < EN_NTX; slot++) {
                   3126:        printf("tx%d: start/stop/cur=0x%x/0x%x/0x%x [%d]  ", slot,
                   3127:          sc->txslot[slot].start, sc->txslot[slot].stop, sc->txslot[slot].cur,
                   3128:                (sc->txslot[slot].cur - sc->txslot[slot].start)/4);
                   3129:        printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize,
                   3130:                sc->txslot[slot].bfree);
                   3131:         printf("txhw: base_address=0x%x, size=%d, read=%d, descstart=%d\n",
                   3132:          MIDX_BASE(EN_READ(sc, MIDX_PLACE(slot))),
                   3133:          MIDX_SZ(EN_READ(sc, MIDX_PLACE(slot))),
                   3134:          EN_READ(sc, MIDX_READPTR(slot)), EN_READ(sc, MIDX_DESCSTART(slot)));
                   3135:       }
                   3136:     }
                   3137:
                   3138:     if (level & END_RX) {
                   3139:       printf("  recv slots:\n");
                   3140:       for (slot = 0 ; slot < sc->en_nrx; slot++) {
                   3141:        printf("rx%d: vci=%d: start/stop/cur=0x%x/0x%x/0x%x ", slot,
                   3142:          sc->rxslot[slot].atm_vci, sc->rxslot[slot].start,
                   3143:          sc->rxslot[slot].stop, sc->rxslot[slot].cur);
                   3144:        printf("mode=0x%x, atm_flags=0x%x, oth_flags=0x%x\n",
                   3145:        sc->rxslot[slot].mode, sc->rxslot[slot].atm_flags,
                   3146:                sc->rxslot[slot].oth_flags);
                   3147:         printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n",
                   3148:          EN_READ(sc, MID_VC(sc->rxslot[slot].atm_vci)),
                   3149:          EN_READ(sc, MID_DST_RP(sc->rxslot[slot].atm_vci)),
                   3150:          EN_READ(sc, MID_WP_ST_CNT(sc->rxslot[slot].atm_vci)));
                   3151:       }
                   3152:     }
                   3153:
                   3154:     if (level & END_DTQ) {
                   3155:       printf("  dtq [need_dtqs=%d,dtq_free=%d]:\n",
                   3156:                                        sc->need_dtqs, sc->dtq_free);
                   3157:       ptr = sc->dtq_chip;
                   3158:       while (ptr != sc->dtq_us) {
                   3159:         reg = EN_READ(sc, ptr);
                   3160:         printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n",
                   3161:            sc->dtq[MID_DTQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_TXCHAN(reg),
                   3162:            (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4));
                   3163:         EN_WRAPADD(MID_DTQOFF, MID_DTQEND, ptr, 8);
                   3164:       }
                   3165:     }
                   3166:
                   3167:     if (level & END_DRQ) {
                   3168:       printf("  drq [need_drqs=%d,drq_free=%d]:\n",
                   3169:                                        sc->need_drqs, sc->drq_free);
                   3170:       ptr = sc->drq_chip;
                   3171:       while (ptr != sc->drq_us) {
                   3172:         reg = EN_READ(sc, ptr);
                   3173:        printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n",
                   3174:          sc->drq[MID_DRQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_RXVCI(reg),
                   3175:          (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4));
                   3176:        EN_WRAPADD(MID_DRQOFF, MID_DRQEND, ptr, 8);
                   3177:       }
                   3178:     }
                   3179:
                   3180:     if (level & END_SWSL) {
                   3181:       printf(" swslist [size=%d]: ", sc->swsl_size);
                   3182:       for (cnt = sc->swsl_head ; cnt != sc->swsl_tail ;
                   3183:                        cnt = (cnt + 1) % MID_SL_N)
                   3184:         printf("0x%x ", sc->swslist[cnt]);
                   3185:       printf("\n");
                   3186:     }
                   3187:
                   3188:   }
                   3189:   return(0);
                   3190: }
                   3191:
                   3192: /*
                   3193:  * en_dumpmem: dump the memory
                   3194:  */
                   3195:
                   3196: int en_dumpmem(unit, addr, len)
                   3197:
                   3198: int unit, addr, len;
                   3199:
                   3200: {
                   3201:   struct en_softc *sc;
                   3202:   u_int32_t reg;
                   3203:
                   3204:   if (unit < 0 || unit >= en_cd.cd_ndevs ||
                   3205:        (sc = (struct en_softc *) en_cd.cd_devs[unit]) == NULL) {
                   3206:     printf("invalid unit number: %d\n", unit);
                   3207:     return(0);
                   3208:   }
                   3209:   addr = addr & ~3;
                   3210:   if (addr < MID_RAMOFF || addr + len*4 > MID_MAXOFF || len <= 0) {
                   3211:     printf("invalid addr/len number: %d, %d\n", addr, len);
                   3212:     return(0);
                   3213:   }
                   3214:   printf("dumping %d words starting at offset 0x%x\n", len, addr);
                   3215:   while (len--) {
                   3216:     reg = EN_READ(sc, addr);
                   3217:     printf("mem[0x%x] = 0x%x\n", addr, reg);
                   3218:     addr += 4;
                   3219:   }
                   3220:   return(0);
                   3221: }
                   3222: #endif
                   3223:
                   3224:
                   3225: #endif /* NEN > 0 || !defined(__FreeBSD__) */

CVSweb