Deleted Added
full compact
35c35
< * $FreeBSD: head/sys/dev/en/midway.c 112135 2003-03-12 10:28:26Z kjc $
---
> * $FreeBSD: head/sys/dev/en/midway.c 114018 2003-04-25 16:14:03Z harti $
52,54d51
< #undef EN_DEBUG
< #undef EN_DEBUG_RANGE /* check ranges on en_read/en_write's? */
< #define EN_MBUF_OPT /* try and put more stuff in mbuf? */
56,61d52
< #define EN_STAT
< #ifndef EN_DMA
< #define EN_DMA 1 /* use dma? */
< #endif
< #define EN_NOTXDMA 0 /* hook to disable tx dma only */
< #define EN_NORXDMA 0 /* hook to disable rx dma only */
63,67d53
< #if defined(MIDWAY_ADPONLY)
< #define EN_ENIDMAFIX 0 /* no ENI cards to worry about */
< #else
< #define EN_ENIDMAFIX 1 /* avoid byte DMA on the ENI card (see below) */
< #endif
70c56
< * note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card
---
> * Note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card
94c80
< #ifdef EN_STAT
---
>
96,98d81
< #else
< #define EN_COUNT(X) /* nothing */
< #endif
100a84
>
103,104c87,112
< #define STATIC /* nothing */
< #define INLINE /* nothing */
---
>
> /*
> * This macro removes almost all the EN_DEBUG conditionals in the code that make
> * to code a good deal less readable.
> */
> #define DBG(SC, FL, PRINT) do { \
> if ((SC)->debug & DBG_##FL) { \
> if_printf(&(SC)->enif, "%s: "#FL": ", __func__); \
> printf PRINT; \
> printf("\n"); \
> } \
> } while (0)
>
> enum {
> DBG_INIT = 0x0001, /* debug attach/detach */
> DBG_TX = 0x0002, /* debug transmitting */
> DBG_SERV = 0x0004, /* debug service interrupts */
> DBG_IOCTL = 0x0008, /* debug ioctls */
> DBG_VC = 0x0010, /* debug VC handling */
> DBG_INTR = 0x0020, /* debug interrupts */
> DBG_DMA = 0x0040, /* debug DMA probing */
> DBG_IPACKETS = 0x0080, /* print input packets */
> DBG_REG = 0x0100, /* print all register access */
> DBG_LOCK = 0x0200, /* debug locking */
> };
>
106,107c114,116
< #define STATIC static
< #define INLINE __inline
---
>
> #define DBG(SC, FL, PRINT) do { } while (0)
>
110d118
< #ifdef __FreeBSD__
114,115c122
< /* enable DDBHOOK when DDB is available */
< #undef EN_DDBHOOK
---
>
116a124
> #undef EN_DDBHOOK
119d126
< #endif
124,126d130
< #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
< #include <sys/device.h>
< #endif
128d131
< #include <sys/mbuf.h>
129a133,137
> #include <sys/mbuf.h>
> #include <sys/endian.h>
> #include <sys/sbuf.h>
> #include <sys/stdint.h>
> #include <vm/uma.h>
134,135d141
< #include <vm/vm.h>
<
145,149d150
< #if defined(__NetBSD__) || defined(__OpenBSD__)
< #include <machine/bus.h>
< #include <dev/ic/midwayreg.h>
< #include <dev/ic/midwayvar.h>
< #elif defined(__FreeBSD__)
152a154,156
> #include <sys/module.h>
> #include <sys/sysctl.h>
> #include <sys/malloc.h>
156d159
< #include <vm/pmap.h> /* for vtophys proto */
158,175d160
< #ifndef IFF_NOTRAILERS
< #define IFF_NOTRAILERS 0
< #endif
<
< #endif /* __FreeBSD__ */
<
< #if defined(__alpha__)
< /* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
< #undef vtophys
< #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
< #endif
<
< #ifdef __FreeBSD__
< #define NBPF 1
< #else
< #include "bpf.h"
< #endif
< #if NBPF > 0
177,183d161
< #ifdef __FreeBSD__
< #define BPFATTACH(ifp, dlt, hlen) bpfattach((ifp), (dlt), (hlen))
< #else
< #define BPFATTACH(ifp, dlt, hlen) bpfattach(&(ifp)->if_bpf, (ifp), (dlt), (hlen))
< #define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
< #endif
< #endif /* NBPF > 0 */
188d165
<
190c167
< #define EN_TXHIWAT (64*1024) /* max 64 KB waiting to be DMAd out */
---
> #define EN_TXHIWAT (64 * 1024) /* max 64 KB waiting to be DMAd out */
193,195c170
< #ifndef EN_MINDMA
< #define EN_MINDMA 32 /* don't DMA anything less than this (bytes) */
< #endif
---
> #define RX_NONE 0xffff /* recv VC not in use */
197,201d171
< #define RX_NONE 0xffff /* recv VC not in use */
<
< #define EN_OBHDR ATM_PH_DRIVER7 /* TBD in first mbuf ! */
< #define EN_OBTRL ATM_PH_DRIVER8 /* PDU trailier in last mbuf ! */
<
204d173
< #define ENOTHER_RAW 0x04 /* 'raw' access (aka boodi mode) */
207c176
< static int en_dma = EN_DMA; /* use DMA (switch off for dbg) */
---
> SYSCTL_NODE(_hw, OID_AUTO, en, CTLFLAG_RW, 0, "ENI 155p");
209d177
< #ifndef __FreeBSD__
211,242c179
< * autoconfig attachments
< */
<
< struct cfdriver en_cd = {
< 0, "en", DV_IFNET,
< };
< #endif
<
< /*
< * local structures
< */
<
< /*
< * params to en_txlaunch() function
< */
<
< struct en_launch {
< u_int32_t tbd1; /* TBD 1 */
< u_int32_t tbd2; /* TBD 2 */
< u_int32_t pdu1; /* PDU 1 (aal5) */
< int nodma; /* don't use DMA */
< int need; /* total space we need (pad out if less data) */
< int mlen; /* length of mbuf (for dtq) */
< struct mbuf *t; /* data */
< u_int32_t aal; /* aal code */
< u_int32_t atm_vci; /* vci */
< u_int8_t atm_flags; /* flags */
< };
<
<
< /*
< * dma table (index by # of words)
---
> * dma tables
244,245c181,182
< * plan A: use WMAYBE (obsolete)
< * plan B: avoid WMAYBE
---
> * The plan is indexed by the number of words to transfer.
> * The maximum index is 15 for 60 words.
247d183
<
249,250c185,186
< u_int8_t bcode; /* code */
< u_int8_t divshift; /* byte divisor */
---
> uint8_t bcode; /* code */
> uint8_t divshift; /* byte divisor */
253c189
< static struct en_dmatab en_dma_planB[] = {
---
> static const struct en_dmatab en_dmaplan[] = {
262c198
< { MIDDMA_16WORD, 6}, /* 16 */
---
> { MIDDMA_16WORD,6}, /* 16 */
265,266d200
< static struct en_dmatab *en_dmaplan = en_dma_planB;
<
270,271d203
<
< STATIC INLINE int en_b2sz(int) __attribute__ ((unused));
273,274c205,206
< int en_dump(int,int);
< int en_dumpmem(int,int,int);
---
> int en_dump(int unit, int level);
> int en_dumpmem(int,int,int);
276,298d207
< STATIC void en_dmaprobe(struct en_softc *);
< STATIC int en_dmaprobe_doit(struct en_softc *, u_int8_t *,
< u_int8_t *, int);
< STATIC INLINE int en_dqneed(struct en_softc *, caddr_t, u_int,
< u_int) __attribute__ ((unused));
< STATIC void en_init(struct en_softc *);
< STATIC int en_ioctl(struct ifnet *, EN_IOCTL_CMDT, caddr_t);
< STATIC INLINE int en_k2sz(int) __attribute__ ((unused));
< STATIC void en_loadvc(struct en_softc *, int);
< STATIC int en_mfix(struct en_softc *, struct mbuf **, struct mbuf *);
< STATIC INLINE struct mbuf *en_mget(struct en_softc *, u_int,
< u_int *) __attribute__ ((unused));
< STATIC INLINE u_int32_t en_read(struct en_softc *,
< u_int32_t) __attribute__ ((unused));
< STATIC int en_rxctl(struct en_softc *, struct atm_pseudoioctl *, int);
< STATIC void en_txdma(struct en_softc *, int);
< STATIC void en_txlaunch(struct en_softc *, int,
< struct en_launch *);
< STATIC void en_service(struct en_softc *);
< STATIC void en_start(struct ifnet *);
< STATIC INLINE int en_sz2b(int) __attribute__ ((unused));
< STATIC INLINE void en_write(struct en_softc *, u_int32_t,
< u_int32_t) __attribute__ ((unused));
300,302c209,216
< /*
< * macros/inline
< */
---
> #define EN_LOCK(SC) do { \
> DBG(SC, LOCK, ("ENLOCK %d\n", __LINE__)); \
> mtx_lock(&sc->en_mtx); \
> } while (0)
> #define EN_UNLOCK(SC) do { \
> DBG(SC, LOCK, ("ENUNLOCK %d\n", __LINE__)); \
> mtx_unlock(&sc->en_mtx); \
> } while (0)
305c219,223
< * raw read/write macros
---
> * While a transmit mbuf is waiting to get transmit DMA resources we
> * need to keep some information with it. We don't want to allocate
> * additional memory for this so we stuff it into free fields in the
> * mbuf packet header. Neither the checksum fields nor the rcvif field are used
> * so use these.
306a225,228
> #define TX_AAL5 0x1 /* transmit AAL5 PDU */
> #define TX_HAS_TBD 0x2 /* TBD did fit into mbuf */
> #define TX_HAS_PAD 0x4 /* padding did fit into mbuf */
> #define TX_HAS_PDU 0x8 /* PDU trailer did fit into mbuf */
308,309c230,235
< #define EN_READDAT(SC,R) en_read(SC,R)
< #define EN_WRITEDAT(SC,R,V) en_write(SC,R,V)
---
> #define MBUF_SET_TX(M, VCI, FLAGS, DATALEN, PAD, MAP) do { \
> (M)->m_pkthdr.csum_data = (VCI) | ((FLAGS) << MID_VCI_BITS); \
> (M)->m_pkthdr.csum_flags = ((DATALEN) & 0xffff) | \
> ((PAD & 0x3f) << 16); \
> (M)->m_pkthdr.rcvif = (void *)(MAP); \
> } while (0)
311,313c237,243
< /*
< * cooked read/write macros
< */
---
> #define MBUF_GET_TX(M, VCI, FLAGS, DATALEN, PAD, MAP) do { \
> (VCI) = (M)->m_pkthdr.csum_data & ((1 << MID_VCI_BITS) - 1); \
> (FLAGS) = ((M)->m_pkthdr.csum_data >> MID_VCI_BITS) & 0xf; \
> (DATALEN) = (M)->m_pkthdr.csum_flags & 0xffff; \
> (PAD) = ((M)->m_pkthdr.csum_flags >> 16) & 0x3f; \
> (MAP) = (void *)((M)->m_pkthdr.rcvif); \
> } while (0)
315,316d244
< #define EN_READ(SC,R) (u_int32_t)ntohl(en_read(SC,R))
< #define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V))
318,322c246,250
< #define EN_WRAPADD(START,STOP,CUR,VAL) { \
< (CUR) = (CUR) + (VAL); \
< if ((CUR) >= (STOP)) \
< (CUR) = (START) + ((CUR) - (STOP)); \
< }
---
> #define EN_WRAPADD(START, STOP, CUR, VAL) do { \
> (CUR) = (CUR) + (VAL); \
> if ((CUR) >= (STOP)) \
> (CUR) = (START) + ((CUR) - (STOP)); \
> } while (0)
324c252
< #define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t))
---
> #define WORD_IDX(START, X) (((X) - (START)) / sizeof(uint32_t))
326,330c254,256
< /* we store sc->dtq and sc->drq data in the following format... */
< #define EN_DQ_MK(SLOT,LEN) (((SLOT) << 20)|(LEN)|(0x80000))
< /* the 0x80000 ensures we != 0 */
< #define EN_DQ_SLOT(X) ((X) >> 20)
< #define EN_DQ_LEN(X) ((X) & 0x3ffff)
---
> #define SETQ_END(SC, VAL) ((SC)->is_adaptec ? \
> ((VAL) | (MID_DMA_END >> 4)) : \
> ((VAL) | (MID_DMA_END)))
332,400d257
< /* format of DTQ/DRQ word 1 differs between ENI and ADP */
< #if defined(MIDWAY_ENIONLY)
<
< #define MID_MK_TXQ(SC,CNT,CHAN,END,BCODE) \
< EN_WRITE((SC), (SC)->dtq_us, \
< MID_MK_TXQ_ENI((CNT), (CHAN), (END), (BCODE)));
<
< #define MID_MK_RXQ(SC,CNT,VCI,END,BCODE) \
< EN_WRITE((SC), (SC)->drq_us, \
< MID_MK_RXQ_ENI((CNT), (VCI), (END), (BCODE)));
<
< #elif defined(MIDWAY_ADPONLY)
<
< #define MID_MK_TXQ(SC,CNT,CHAN,END,JK) \
< EN_WRITE((SC), (SC)->dtq_us, \
< MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK)));
<
< #define MID_MK_RXQ(SC,CNT,VCI,END,JK) \
< EN_WRITE((SC), (SC)->drq_us, \
< MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK)));
<
< #else
<
< #define MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE) { \
< if ((SC)->is_adaptec) \
< EN_WRITE((SC), (SC)->dtq_us, \
< MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK_OR_BCODE))); \
< else \
< EN_WRITE((SC), (SC)->dtq_us, \
< MID_MK_TXQ_ENI((CNT), (CHAN), (END), (JK_OR_BCODE))); \
< }
<
< #define MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE) { \
< if ((SC)->is_adaptec) \
< EN_WRITE((SC), (SC)->drq_us, \
< MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK_OR_BCODE))); \
< else \
< EN_WRITE((SC), (SC)->drq_us, \
< MID_MK_RXQ_ENI((CNT), (VCI), (END), (JK_OR_BCODE))); \
< }
<
< #endif
<
< /* add an item to the DTQ */
< #define EN_DTQADD(SC,CNT,CHAN,JK_OR_BCODE,ADDR,LEN,END) { \
< if (END) \
< (SC)->dtq[MID_DTQ_A2REG((SC)->dtq_us)] = EN_DQ_MK(CHAN,LEN); \
< MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE); \
< (SC)->dtq_us += 4; \
< EN_WRITE((SC), (SC)->dtq_us, (ADDR)); \
< EN_WRAPADD(MID_DTQOFF, MID_DTQEND, (SC)->dtq_us, 4); \
< (SC)->dtq_free--; \
< if (END) \
< EN_WRITE((SC), MID_DMA_WRTX, MID_DTQ_A2REG((SC)->dtq_us)); \
< }
<
< /* DRQ add macro */
< #define EN_DRQADD(SC,CNT,VCI,JK_OR_BCODE,ADDR,LEN,SLOT,END) { \
< if (END) \
< (SC)->drq[MID_DRQ_A2REG((SC)->drq_us)] = EN_DQ_MK(SLOT,LEN); \
< MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE); \
< (SC)->drq_us += 4; \
< EN_WRITE((SC), (SC)->drq_us, (ADDR)); \
< EN_WRAPADD(MID_DRQOFF, MID_DRQEND, (SC)->drq_us, 4); \
< (SC)->drq_free--; \
< if (END) \
< EN_WRITE((SC), MID_DMA_WRRX, MID_DRQ_A2REG((SC)->drq_us)); \
< }
<
402c259,261
< * the driver code
---
> * The dtq and drq members are set for each END entry in the corresponding
> * card queue entry. It is used to find out, when a buffer has been
> * finished DMAing and can be freed.
404,409c263,264
< * the code is arranged in a specific way:
< * [1] short/inline functions
< * [2] autoconfig stuff
< * [3] ioctl stuff
< * [4] reset -> init -> trasmit -> intr -> receive functions
< *
---
> * We store sc->dtq and sc->drq data in the following format...
> * the 0x80000 ensures we != 0
410a266,268
> #define EN_DQ_MK(SLOT, LEN) (((SLOT) << 20) | (LEN) | (0x80000))
> #define EN_DQ_SLOT(X) ((X) >> 20)
> #define EN_DQ_LEN(X) ((X) & 0x3ffff)
415,416c273,274
< * en_read: read a word from the card. this is the only function
< * that reads from the card.
---
> * en_read{x}: read a word from the card. These are the only functions
> * that read from the card.
417a276,279
> static __inline uint32_t
> en_readx(struct en_softc *sc, uint32_t r)
> {
> uint32_t v;
419c281,287
< STATIC INLINE u_int32_t en_read(sc, r)
---
> #ifdef EN_DIAG
> if (r > MID_MAXOFF || (r % 4))
> panic("en_read out of range, r=0x%x", r);
> #endif
> v = bus_space_read_4(sc->en_memt, sc->en_base, r);
> return (v);
> }
421,423c289,290
< struct en_softc *sc;
< u_int32_t r;
<
---
> static __inline uint32_t
> en_read(struct en_softc *sc, uint32_t r)
424a292
> uint32_t v;
426,428c294,296
< #ifdef EN_DEBUG_RANGE
< if (r > MID_MAXOFF || (r % 4))
< panic("en_read out of range, r=0x%x", r);
---
> #ifdef EN_DIAG
> if (r > MID_MAXOFF || (r % 4))
> panic("en_read out of range, r=0x%x", r);
430,431c298,300
<
< return(bus_space_read_4(sc->en_memt, sc->en_base, r));
---
> v = bus_space_read_4(sc->en_memt, sc->en_base, r);
> DBG(sc, REG, ("en_read(%#x) -> %08x", r, v));
> return (v);
435c304
< * en_write: write a word to the card. this is the only function that
---
> * en_write: write a word to the card. This is the only function that
438,443c307,308
<
< STATIC INLINE void en_write(sc, r, v)
<
< struct en_softc *sc;
< u_int32_t r, v;
<
---
> static __inline void
> en_write(struct en_softc *sc, uint32_t r, uint32_t v)
445,447c310,312
< #ifdef EN_DEBUG_RANGE
< if (r > MID_MAXOFF || (r % 4))
< panic("en_write out of range, r=0x%x", r);
---
> #ifdef EN_DIAG
> if (r > MID_MAXOFF || (r % 4))
> panic("en_write out of range, r=0x%x", r);
449,450c314,315
<
< bus_space_write_4(sc->en_memt, sc->en_base, r, v);
---
> DBG(sc, REG, ("en_write(%#x) <- %08x", r, v));
> bus_space_write_4(sc->en_memt, sc->en_base, r, v);
456,460c321,322
<
< STATIC INLINE int en_k2sz(k)
<
< int k;
<
---
> static __inline int
> en_k2sz(int k)
462,473c324,336
< switch(k) {
< case 1: return(0);
< case 2: return(1);
< case 4: return(2);
< case 8: return(3);
< case 16: return(4);
< case 32: return(5);
< case 64: return(6);
< case 128: return(7);
< default: panic("en_k2sz");
< }
< return(0);
---
> switch(k) {
> case 1: return (0);
> case 2: return (1);
> case 4: return (2);
> case 8: return (3);
> case 16: return (4);
> case 32: return (5);
> case 64: return (6);
> case 128: return (7);
> default:
> panic("en_k2sz");
> }
> return (0);
477d339
<
481,485c343,344
<
< STATIC INLINE int en_b2sz(b)
<
< int b;
<
---
> static __inline int
> en_b2sz(int b)
487,499c346,359
< switch (b) {
< case MIDDMA_WORD: return(1*4);
< case MIDDMA_2WMAYBE:
< case MIDDMA_2WORD: return(2*4);
< case MIDDMA_4WMAYBE:
< case MIDDMA_4WORD: return(4*4);
< case MIDDMA_8WMAYBE:
< case MIDDMA_8WORD: return(8*4);
< case MIDDMA_16WMAYBE:
< case MIDDMA_16WORD: return(16*4);
< default: panic("en_b2sz");
< }
< return(0);
---
> switch (b) {
> case MIDDMA_WORD: return (1*4);
> case MIDDMA_2WMAYBE:
> case MIDDMA_2WORD: return (2*4);
> case MIDDMA_4WMAYBE:
> case MIDDMA_4WORD: return (4*4);
> case MIDDMA_8WMAYBE:
> case MIDDMA_8WORD: return (8*4);
> case MIDDMA_16WMAYBE:
> case MIDDMA_16WORD: return (16*4);
> default:
> panic("en_b2sz");
> }
> return (0);
502d361
<
506,510c365,366
<
< STATIC INLINE int en_sz2b(sz)
<
< int sz;
<
---
> static __inline int
> en_sz2b(int sz)
512,520c368,377
< switch (sz) {
< case 1*4: return(MIDDMA_WORD);
< case 2*4: return(MIDDMA_2WORD);
< case 4*4: return(MIDDMA_4WORD);
< case 8*4: return(MIDDMA_8WORD);
< case 16*4: return(MIDDMA_16WORD);
< default: panic("en_sz2b");
< }
< return(0);
---
> switch (sz) {
> case 1*4: return (MIDDMA_WORD);
> case 2*4: return (MIDDMA_2WORD);
> case 4*4: return (MIDDMA_4WORD);
> case 8*4: return (MIDDMA_8WORD);
> case 16*4: return (MIDDMA_16WORD);
> default:
> panic("en_sz2b");
> }
> return(0);
523c380
<
---
> #ifdef EN_DEBUG
525c382
< * en_dqneed: calculate number of DTQ/DRQ's needed for a buffer
---
> * Dump a packet
527,533c384,385
<
< STATIC INLINE int en_dqneed(sc, data, len, tx)
<
< struct en_softc *sc;
< caddr_t data;
< u_int len, tx;
<
---
> static void
> en_dump_packet(struct en_softc *sc, struct mbuf *m)
535c387,391
< int result, needalign, sz;
---
> int plen = m->m_pkthdr.len;
> u_int pos = 0;
> u_int totlen = 0;
> int len;
> u_char *ptr;
537,541c393,409
< #if !defined(MIDWAY_ENIONLY)
< #if !defined(MIDWAY_ADPONLY)
< if (sc->is_adaptec)
< #endif /* !MIDWAY_ADPONLY */
< return(1); /* adaptec can DMA anything in one go */
---
> if_printf(&sc->enif, "packet len=%d", plen);
> while (m != NULL) {
> totlen += m->m_len;
> ptr = mtod(m, u_char *);
> for (len = 0; len < m->m_len; len++, pos++, ptr++) {
> if (pos % 16 == 8)
> printf(" ");
> if (pos % 16 == 0)
> printf("\n");
> printf(" %02x", *ptr);
> }
> m = m->m_next;
> }
> printf("\n");
> if (totlen != plen);
> printf("sum of m_len=%u\n", totlen);
> }
543,549d410
<
< #if !defined(MIDWAY_ADPONLY)
< result = 0;
< if (len < EN_MINDMA) {
< if (!tx) /* XXX: conservative */
< return(1); /* will copy/DMA_JK */
< }
551,559c412,415
< if (tx) { /* byte burst? */
< needalign = (((uintptr_t) (void *) data) % sizeof(u_int32_t));
< if (needalign) {
< result++;
< sz = min(len, sizeof(u_int32_t) - needalign);
< len -= sz;
< data += sz;
< }
< }
---
> /*********************************************************************/
> /*
> * DMA maps
> */
561,568c417,439
< if (sc->alburst && len) {
< needalign = (((uintptr_t) (void *) data) & sc->bestburstmask);
< if (needalign) {
< result++; /* alburst */
< sz = min(len, sc->bestburstlen - needalign);
< len -= sz;
< }
< }
---
> /*
> * Map constructor for a MAP.
> *
> * This is called each time when a map is allocated
> * from the pool and about to be returned to the user. Here we actually
> * allocate the map if there isn't one. The problem is that we may fail
> * to allocate the DMA map yet have no means to signal this error. Therefor
> * when allocating a map, the call must check that there is a map. An
> * additional problem is, that i386 maps will be NULL, yet are ok and must
> * be freed so let's use a flag to signal allocation.
> *
> * Caveat: we have no way to know that we are called from an interrupt context
> * here. We rely on the fact, that bus_dmamap_create uses M_NOWAIT in all
> * its allocations.
> *
> * LOCK: any, not needed
> */
> static void
> en_map_ctor(void *mem, int size, void *arg)
> {
> struct en_softc *sc = arg;
> struct en_map *map = mem;
> int err;
570,581c441,442
< if (len >= sc->bestburstlen) {
< sz = len / sc->bestburstlen;
< sz = sz * sc->bestburstlen;
< len -= sz;
< result++; /* best shot */
< }
<
< if (len) {
< result++; /* clean up */
< if (tx && (len % sizeof(u_int32_t)) != 0)
< result++; /* byte cleanup */
< }
---
> if (map->sc == NULL)
> map->sc = sc;
583,584c444,451
< return(result);
< #endif /* !MIDWAY_ADPONLY */
---
> if (!(map->flags & ENMAP_ALLOC)) {
> err = bus_dmamap_create(sc->txtag, 0, &map->map);
> if (err != 0)
> if_printf(&sc->enif, "cannot create DMA map %d\n", err);
> else
> map->flags |= ENMAP_ALLOC;
> }
> map->flags &= ~ENMAP_LOADED;
587d453
<
589,591c455,460
< * en_mget: get an mbuf chain that can hold totlen bytes and return it
< * (for recv) [based on am7990_get from if_le and ieget from if_ie]
< * after this call the sum of all the m_len's in the chain will be totlen.
---
> * Map destructor.
> *
> * Called when a map is disposed into the zone. If the map is loaded, unload
> * it.
> *
> * LOCK: any, not needed
592a462,465
> static void
> en_map_dtor(void *mem, int size, void *arg)
> {
> struct en_map *map = mem;
594c467,471
< STATIC INLINE struct mbuf *en_mget(sc, totlen, drqneed)
---
> if (map->flags & ENMAP_LOADED) {
> bus_dmamap_unload(map->sc->txtag, map->map);
> map->flags &= ~ENMAP_LOADED;
> }
> }
596,598c473,482
< struct en_softc *sc;
< u_int totlen, *drqneed;
<
---
> /*
> * Map finializer.
> *
> * This is called each time a map is returned from the zone to the system.
> * Get rid of the dmamap here.
> *
> * LOCK: any, not needed
> */
> static void
> en_map_fini(void *mem, int size)
600,602c484
< struct mbuf *m;
< struct mbuf *top, **mp;
< *drqneed = 0;
---
> struct en_map *map = mem;
604,640c486,487
< MGETHDR(m, M_DONTWAIT, MT_DATA);
< if (m == NULL)
< return(NULL);
< m->m_pkthdr.rcvif = &sc->enif;
< m->m_pkthdr.len = totlen;
< m->m_len = MHLEN;
< top = NULL;
< mp = &top;
<
< /* if (top != NULL) then we've already got 1 mbuf on the chain */
< while (totlen > 0) {
< if (top) {
< MGET(m, M_DONTWAIT, MT_DATA);
< if (!m) {
< m_freem(top);
< return(NULL); /* out of mbufs */
< }
< m->m_len = MLEN;
< }
< if (totlen >= MINCLSIZE) {
< MCLGET(m, M_DONTWAIT);
< if ((m->m_flags & M_EXT) == 0) {
< m_free(m);
< m_freem(top);
< return(NULL); /* out of mbuf clusters */
< }
< m->m_len = MCLBYTES;
< }
< m->m_len = min(totlen, m->m_len);
< totlen -= m->m_len;
< *mp = m;
< mp = &m->m_next;
<
< *drqneed += en_dqneed(sc, m->m_data, m->m_len, 0);
<
< }
< return(top);
---
> if (map->flags & ENMAP_ALLOC)
> bus_dmamap_destroy(map->sc->txtag, map->map);
643c490,493
< /***********************************************************************/
---
> /*********************************************************************/
> /*
> * Transmission
> */
646c496
< * autoconfig stuff
---
> * Argument structure to load a transmit DMA map
647a498,506
> struct txarg {
> struct en_softc *sc;
> struct mbuf *m;
> u_int vci;
> u_int chan; /* transmit channel */
> u_int datalen; /* length of user data */
> u_int flags;
> u_int wait; /* return: out of resources */
> };
649,652c508,516
< void en_attach(sc)
<
< struct en_softc *sc;
<
---
> /*
> * TX DMA map loader helper. This function is the callback when the map
> * is loaded. It should fill the DMA segment descriptors into the hardware.
> *
> * LOCK: locked, needed
> */
> static void
> en_txdma_load(void *uarg, bus_dma_segment_t *segs, int nseg, bus_size_t mapsize,
> int error)
654,656c518,531
< struct ifnet *ifp = &sc->enif;
< int sz;
< u_int32_t reg, lcv, check, ptr, sav, midvloc;
---
> struct txarg *tx = uarg;
> struct en_softc *sc = tx->sc;
> struct en_txslot *slot = &sc->txslot[tx->chan];
> uint32_t cur; /* on-card buffer position (bytes offset) */
> uint32_t dtq; /* on-card queue position (byte offset) */
> uint32_t last_dtq; /* last DTQ we have written */
> uint32_t tmp;
> u_int free; /* free queue entries on card */
> u_int needalign, cnt;
> bus_size_t rest; /* remaining bytes in current segment */
> bus_addr_t addr;
> bus_dma_segment_t *s;
> uint32_t count, bcode;
> int i;
658,664c533,534
< /*
< * probe card to determine memory size. the stupid ENI card always
< * reports to PCI that it needs 4MB of space (2MB regs and 2MB RAM).
< * if it has less than 2MB RAM the addresses wrap in the RAM address space.
< * (i.e. on a 512KB card addresses 0x3ffffc, 0x37fffc, and 0x2ffffc
< * are aliases for 0x27fffc [note that RAM starts at offset 0x200000]).
< */
---
> if (error != 0)
> return;
666,680c536,538
< if (sc->en_busreset)
< sc->en_busreset(sc);
< EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */
< for (lcv = MID_PROBEOFF; lcv <= MID_MAXOFF ; lcv += MID_PROBSIZE) {
< EN_WRITE(sc, lcv, lcv); /* data[address] = address */
< for (check = MID_PROBEOFF ; check < lcv ; check += MID_PROBSIZE) {
< reg = EN_READ(sc, check);
< if (reg != check) { /* found an alias! */
< goto done_probe; /* and quit */
< }
< }
< }
< done_probe:
< lcv -= MID_PROBSIZE; /* take one step back */
< sc->en_obmemsz = (lcv + 4) - MID_RAMOFF;
---
> cur = slot->cur;
> dtq = sc->dtq_us;
> free = sc->dtq_free;
682,684c540
< /*
< * determine the largest DMA burst supported
< */
---
> last_dtq = 0; /* make gcc happy */
686c542,560
< en_dmaprobe(sc);
---
> /*
> * Local macro to add an entry to the transmit DMA area. If there
> * are no entries left, return. Save the byte offset of the entry
> * in last_dtq for later use.
> */
> #define PUT_DTQ_ENTRY(ENI, BCODE, COUNT, ADDR) \
> if (free == 0) { \
> EN_COUNT(sc->stats.txdtqout); \
> tx->wait = 1; \
> return; \
> } \
> last_dtq = dtq; \
> en_write(sc, dtq + 0, (ENI || !sc->is_adaptec) ? \
> MID_MK_TXQ_ENI(COUNT, tx->chan, 0, BCODE) : \
> MID_MK_TXQ_ADP(COUNT, tx->chan, 0, BCODE)); \
> en_write(sc, dtq + 4, ADDR); \
> \
> EN_WRAPADD(MID_DTQOFF, MID_DTQEND, dtq, 8); \
> free--;
688,690c562,575
< /*
< * "hello world"
< */
---
> /*
> * Local macro to generate a DMA entry to DMA cnt bytes. Updates
> * the current buffer byte offset accordingly.
> */
> #define DO_DTQ(TYPE) do { \
> rest -= cnt; \
> EN_WRAPADD(slot->start, slot->stop, cur, cnt); \
> DBG(sc, TX, ("tx%d: "TYPE" %u bytes, %ju left, cur %#x", \
> tx->chan, cnt, (uintmax_t)rest, cur)); \
> \
> PUT_DTQ_ENTRY(1, bcode, count, addr); \
> \
> addr += cnt; \
> } while (0)
692,696c577,586
< if (sc->en_busreset)
< sc->en_busreset(sc);
< EN_WRITE(sc, MID_RESID, 0x0); /* reset */
< for (lcv = MID_RAMOFF ; lcv < MID_RAMOFF + sc->en_obmemsz ; lcv += 4)
< EN_WRITE(sc, lcv, 0); /* zero memory */
---
> if (!(tx->flags & TX_HAS_TBD)) {
> /*
> * Prepend the TBD - it did not fit into the first mbuf
> */
> tmp = MID_TBD_MK1((tx->flags & TX_AAL5) ?
> MID_TBD_AAL5 : MID_TBD_NOAAL5,
> sc->txspeed[tx->vci],
> tx->m->m_pkthdr.len / MID_ATMDATASZ);
> en_write(sc, cur, tmp);
> EN_WRAPADD(slot->start, slot->stop, cur, 4);
698c588,590
< reg = EN_READ(sc, MID_RESID);
---
> tmp = MID_TBD_MK2(tx->vci, 0, 0);
> en_write(sc, cur, tmp);
> EN_WRAPADD(slot->start, slot->stop, cur, 4);
700,705c592,594
< printf("%s: ATM midway v%d, board IDs %d.%d, %s%s%s, %ldKB on-board RAM\n",
< sc->sc_dev.dv_xname, MID_VER(reg), MID_MID(reg), MID_DID(reg),
< (MID_IS_SABRE(reg)) ? "sabre controller, " : "",
< (MID_IS_SUNI(reg)) ? "SUNI" : "Utopia",
< (!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "",
< (long)sc->en_obmemsz / 1024);
---
> /* update DMA address */
> PUT_DTQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0);
> }
707,716c596,598
< if (sc->is_adaptec) {
< if (sc->bestburstlen == 64 && sc->alburst == 0)
< printf("%s: passed 64 byte DMA test\n", sc->sc_dev.dv_xname);
< else
< printf("%s: FAILED DMA TEST: burst=%d, alburst=%d\n",
< sc->sc_dev.dv_xname, sc->bestburstlen, sc->alburst);
< } else {
< printf("%s: maximum DMA burst length = %d bytes%s\n", sc->sc_dev.dv_xname,
< sc->bestburstlen, (sc->alburst) ? " (must align)" : "");
< }
---
> for (i = 0, s = segs; i < nseg; i++, s++) {
> rest = s->ds_len;
> addr = s->ds_addr;
718,720c600,601
< /*
< * link into network subsystem and prepare card
< */
---
> if (sc->is_adaptec) {
> /* adaptec card - simple */
722,729c603,606
< #if defined(__NetBSD__) || defined(__OpenBSD__)
< bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ);
< #endif
< sc->enif.if_softc = sc;
< ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS;
< ifp->if_ioctl = en_ioctl;
< ifp->if_output = atm_output;
< ifp->if_start = en_start;
---
> /* advance the on-card buffer pointer */
> EN_WRAPADD(slot->start, slot->stop, cur, rest);
> DBG(sc, TX, ("tx%d: adp %ju bytes %#jx (cur now 0x%x)",
> tx->chan, (uintmax_t)rest, (uintmax_t)addr, cur));
731,733c608
< /*
< * init softc
< */
---
> PUT_DTQ_ENTRY(0, 0, rest, addr);
735,739c610,611
< for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
< sc->rxvc2slot[lcv] = RX_NONE;
< sc->txspeed[lcv] = 0; /* full */
< sc->txvc2slot[lcv] = 0; /* full speed == slot 0 */
< }
---
> continue;
> }
741,762c613,631
< sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF);
< ptr = sav = MID_BUFOFF;
< ptr = roundup(ptr, EN_TXSZ * 1024); /* align */
< sz = sz - (ptr - sav);
< if (EN_TXSZ*1024 * EN_NTX > sz) {
< printf("%s: EN_NTX/EN_TXSZ too big\n", sc->sc_dev.dv_xname);
< return;
< }
< for (lcv = 0 ; lcv < EN_NTX ; lcv++) {
< sc->txslot[lcv].mbsize = 0;
< sc->txslot[lcv].start = ptr;
< ptr += (EN_TXSZ * 1024);
< sz -= (EN_TXSZ * 1024);
< sc->txslot[lcv].stop = ptr;
< sc->txslot[lcv].nref = 0;
< bzero(&sc->txslot[lcv].indma, sizeof(sc->txslot[lcv].indma));
< bzero(&sc->txslot[lcv].q, sizeof(sc->txslot[lcv].q));
< #ifdef EN_DEBUG
< printf("%s: tx%d: start 0x%x, stop 0x%x\n", sc->sc_dev.dv_xname, lcv,
< sc->txslot[lcv].start, sc->txslot[lcv].stop);
< #endif
< }
---
> /*
> * do we need to do a DMA op to align to the maximum
> * burst? Note, that we are alway 32-bit aligned.
> */
> if (sc->alburst &&
> (needalign = (addr & sc->bestburstmask)) != 0) {
> /* compute number of bytes, words and code */
> cnt = sc->bestburstlen - needalign;
> if (cnt > rest)
> cnt = rest;
> count = cnt / sizeof(uint32_t);
> if (sc->noalbursts) {
> bcode = MIDDMA_WORD;
> } else {
> bcode = en_dmaplan[count].bcode;
> count = cnt >> en_dmaplan[count].divshift;
> }
> DO_DTQ("al_dma");
> }
764,771c633,639
< sav = ptr;
< ptr = roundup(ptr, EN_RXSZ * 1024); /* align */
< sz = sz - (ptr - sav);
< sc->en_nrx = sz / (EN_RXSZ * 1024);
< if (sc->en_nrx <= 0) {
< printf("%s: EN_NTX/EN_TXSZ/EN_RXSZ too big\n", sc->sc_dev.dv_xname);
< return;
< }
---
> /* do we need to do a max-sized burst? */
> if (rest >= sc->bestburstlen) {
> count = rest >> sc->bestburstshift;
> cnt = count << sc->bestburstshift;
> bcode = sc->bestburstcode;
> DO_DTQ("best_dma");
> }
773,778c641,653
< /*
< * ensure that there is always one VC slot on the service list free
< * so that we can tell the difference between a full and empty list.
< */
< if (sc->en_nrx >= MID_N_VC)
< sc->en_nrx = MID_N_VC - 1;
---
> /* do we need to do a cleanup burst? */
> if (rest != 0) {
> cnt = rest;
> count = rest / sizeof(uint32_t);
> if (sc->noalbursts) {
> bcode = MIDDMA_WORD;
> } else {
> bcode = en_dmaplan[count].bcode;
> count = cnt >> en_dmaplan[count].divshift;
> }
> DO_DTQ("clean_dma");
> }
> }
780,794c655
< for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) {
< sc->rxslot[lcv].rxhand = NULL;
< sc->rxslot[lcv].oth_flags = ENOTHER_FREE;
< bzero(&sc->rxslot[lcv].indma, sizeof(sc->rxslot[lcv].indma));
< bzero(&sc->rxslot[lcv].q, sizeof(sc->rxslot[lcv].q));
< midvloc = sc->rxslot[lcv].start = ptr;
< ptr += (EN_RXSZ * 1024);
< sz -= (EN_RXSZ * 1024);
< sc->rxslot[lcv].stop = ptr;
< midvloc = midvloc - MID_RAMOFF;
< midvloc = (midvloc & ~((EN_RXSZ*1024) - 1)) >> 2; /* mask, cvt to words */
< midvloc = midvloc >> MIDV_LOCTOPSHFT; /* we only want the top 11 bits */
< midvloc = (midvloc & MIDV_LOCMASK) << MIDV_LOCSHIFT;
< sc->rxslot[lcv].mode = midvloc |
< (en_k2sz(EN_RXSZ) << MIDV_SZSHIFT) | MIDV_TRASH;
---
> KASSERT (tx->flags & TX_HAS_PAD, ("PDU not padded"));
796,800c657,663
< #ifdef EN_DEBUG
< printf("%s: rx%d: start 0x%x, stop 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname,
< lcv, sc->rxslot[lcv].start, sc->rxslot[lcv].stop, sc->rxslot[lcv].mode);
< #endif
< }
---
> if ((tx->flags & TX_AAL5) && !(tx->flags & TX_HAS_PDU)) {
> /*
> * Append the AAL5 PDU trailer
> */
> tmp = MID_PDU_MK1(0, 0, tx->datalen);
> en_write(sc, cur, tmp);
> EN_WRAPADD(slot->start, slot->stop, cur, 4);
802,809c665,666
< #ifdef EN_STAT
< sc->vtrash = sc->otrash = sc->mfix = sc->txmbovr = sc->dmaovr = 0;
< sc->txoutspace = sc->txdtqout = sc->launch = sc->lheader = sc->ltail = 0;
< sc->hwpull = sc->swadd = sc->rxqnotus = sc->rxqus = sc->rxoutboth = 0;
< sc->rxdrqout = sc->ttrash = sc->rxmbufout = sc->mfixfail = 0;
< sc->headbyte = sc->tailbyte = sc->tailflush = 0;
< #endif
< sc->need_drqs = sc->need_dtqs = 0;
---
> en_write(sc, cur, 0);
> EN_WRAPADD(slot->start, slot->stop, cur, 4);
811,812c668,670
< printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n",
< sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
---
> /* update DMA address */
> PUT_DTQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0);
> }
814,815c672,674
< printf("%s: End Station Identifier (mac address) %6D\n",
< sc->sc_dev.dv_xname, sc->macaddr, ":");
---
> /* record the end for the interrupt routine */
> sc->dtq[MID_DTQ_A2REG(last_dtq)] =
> EN_DQ_MK(tx->chan, tx->m->m_pkthdr.len);
817,819c676,677
< /*
< * final commit
< */
---
> /* set the end flag in the last descriptor */
> en_write(sc, last_dtq + 0, SETQ_END(sc, en_read(sc, last_dtq + 0)));
821,822c679,680
< if_attach(ifp);
< atm_ifattach(ifp);
---
> #undef PUT_DTQ_ENTRY
> #undef DO_DTQ
824,826c682,688
< #if NBPF > 0
< BPFATTACH(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
< #endif
---
> /* commit */
> slot->cur = cur;
> sc->dtq_free = free;
> sc->dtq_us = dtq;
>
> /* tell card */
> en_write(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_us));
829d690
<
831c692
< * en_dmaprobe: helper function for en_attach.
---
> * en_txdma: start transmit DMA on the given channel, if possible
833,836c694,696
< * see how the card handles DMA by running a few DMA tests. we need
< * to figure out the largest number of bytes we can DMA in one burst
< * ("bestburstlen"), and if the starting address for a burst needs to
< * be aligned on any sort of boundary or not ("alburst").
---
> * This is called from two places: when we got new packets from the upper
> * layer or when we found that buffer space has freed up during interrupt
> * processing.
838,841c698
< * typical findings:
< * sparc1: bestburstlen=4, alburst=0 (ick, broken DMA!)
< * sparc2: bestburstlen=64, alburst=1
< * p166: bestburstlen=64, alburst=0
---
> * LOCK: locked, needed
843,847c700,701
<
< STATIC void en_dmaprobe(sc)
<
< struct en_softc *sc;
<
---
> static void
> en_txdma(struct en_softc *sc, struct en_txslot *slot)
849,851c703,707
< u_int32_t srcbuf[64], dstbuf[64];
< u_int8_t *sp, *dp;
< int bestalgn, bestnotalgn, lcv, try;
---
> struct en_map *map;
> struct mbuf *lastm;
> struct txarg tx;
> u_int pad;
> int error;
853c709,713
< sc->alburst = 0;
---
> DBG(sc, TX, ("tx%td: starting ...", slot - sc->txslot));
> again:
> bzero(&tx, sizeof(tx));
> tx.chan = slot - sc->txslot;
> tx.sc = sc;
855,860c715,723
< sp = (u_int8_t *) srcbuf;
< while ((((unsigned long) sp) % MIDDMA_MAXBURST) != 0)
< sp += 4;
< dp = (u_int8_t *) dstbuf;
< while ((((unsigned long) dp) % MIDDMA_MAXBURST) != 0)
< dp += 4;
---
> /*
> * get an mbuf waiting for DMA
> */
> _IF_DEQUEUE(&slot->q, tx.m);
> if (tx.m == NULL) {
> DBG(sc, TX, ("tx%td: ...done!", slot - sc->txslot));
> return;
> }
> MBUF_GET_TX(tx.m, tx.vci, tx.flags, tx.datalen, pad, map);
862c725,744
< bestalgn = bestnotalgn = en_dmaprobe_doit(sc, sp, dp, 0);
---
> /*
> * note: don't use the entire buffer space. if WRTX becomes equal
> * to RDTX, the transmitter stops assuming the buffer is empty! --kjc
> */
> if (tx.m->m_pkthdr.len >= slot->bfree) {
> EN_COUNT(sc->stats.txoutspace);
> DBG(sc, TX, ("tx%td: out of transmit space", slot - sc->txslot));
> goto waitres;
> }
>
> lastm = NULL;
> if (!(tx.flags & TX_HAS_PAD)) {
> if (pad != 0) {
> /* Append the padding buffer */
> (void)m_length(tx.m, &lastm);
> lastm->m_next = sc->padbuf;
> sc->padbuf->m_len = pad;
> }
> tx.flags |= TX_HAS_PAD;
> }
864,868c746,750
< for (lcv = 4 ; lcv < MIDDMA_MAXBURST ; lcv += 4) {
< try = en_dmaprobe_doit(sc, sp+lcv, dp+lcv, 0);
< if (try < bestnotalgn)
< bestnotalgn = try;
< }
---
> /*
> * Try to load that map
> */
> error = bus_dmamap_load_mbuf(sc->txtag, map->map, tx.m,
> en_txdma_load, &tx, 0);
870,871c752,753
< if (bestalgn != bestnotalgn) /* need bursts aligned */
< sc->alburst = 1;
---
> if (lastm != NULL)
> lastm->m_next = NULL;
873,876c755,763
< sc->bestburstlen = bestalgn;
< sc->bestburstshift = en_log2(bestalgn);
< sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */
< sc->bestburstcode = en_sz2b(bestalgn);
---
> if (error != 0) {
> if_printf(&sc->enif, "loading TX map failed %d\n", error);
> goto dequeue_drop;
> }
> map->flags |= ENMAP_LOADED;
> if (tx.wait) {
> /* probably not enough space */
> bus_dmamap_unload(map->sc->txtag, map->map);
> map->flags &= ~ENMAP_LOADED;
878,893c765,768
< #if 1 /* __FreeBSD__ */
< /*
< * correct pci chipsets should be able to handle misaligned-64-byte DMA.
< * but there are too many broken chipsets around. we try to work around
< * by finding the best workable dma size, but still some broken machines
< * exhibit the problem later. so warn it here.
< */
< if (bestalgn != 64 || sc->alburst != 0) {
< printf("%s: WARNING: DMA test detects a broken PCI chipset!\n",
< sc->sc_dev.dv_xname);
< printf(" trying to work around the problem... but if this doesn't\n");
< printf(" work for you, you'd better switch to a newer motherboard.\n");
< }
< #endif /* 1 */
< return;
< }
---
> sc->need_dtqs = 1;
> DBG(sc, TX, ("tx%td: out of transmit DTQs", slot - sc->txslot));
> goto waitres;
> }
894a770,790
> EN_COUNT(sc->stats.launch);
> sc->enif.if_opackets++;
>
> #ifdef ENABLE_BPF
> if (sc->enif.if_bpf != NULL) {
> /*
> * adjust the top of the mbuf to skip the TBD if present
> * before passing the packet to bpf.
> * Also remove padding and the PDU trailer. Assume both of
> * them to be in the same mbuf. pktlen, m_len and m_data
> * are not needed anymore so we can change them.
> */
> if (tx.flags & TX_HAS_TBD) {
> tx.m->m_data += MID_TBD_SIZE;
> tx.m->m_len -= MID_TBD_SIZE;
> }
> tx.m->m_pkthdr.len = m_length(tx.m, &lastm);
> if (tx.m->m_pkthdr.len > tx.datalen) {
> lastm->m_len -= tx.m->m_pkthdr.len - tx.datalen;
> tx.m->m_pkthdr.len = tx.datalen;
> }
896,898c792,794
< /*
< * en_dmaprobe_doit: do actual testing
< */
---
> BPF_MTAP(&sc->enif, tx.m);
> }
> #endif
900,901c796,800
< STATIC int
< en_dmaprobe_doit(sc, sp, dp, wmtry)
---
> /*
> * do some housekeeping and get the next packet
> */
> slot->bfree -= tx.m->m_pkthdr.len;
> _IF_ENQUEUE(&slot->indma, tx.m);
903,905c802
< struct en_softc *sc;
< u_int8_t *sp, *dp;
< int wmtry;
---
> goto again;
907,909c804,810
< {
< int lcv, retval = 4, cnt, count;
< u_int32_t reg, bcode, midvloc;
---
> /*
> * error handling. This is jumped to when we just want to drop
> * the packet. Must be unlocked here.
> */
> dequeue_drop:
> if (map != NULL)
> uma_zfree(sc->map_zone, map);
911,913c812
< /*
< * set up a 1k buffer at MID_BUFOFF
< */
---
> slot->mbsize -= tx.m->m_pkthdr.len;
915,917c814
< if (sc->en_busreset)
< sc->en_busreset(sc);
< EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */
---
> m_freem(tx.m);
919,924c816
< midvloc = ((MID_BUFOFF - MID_RAMOFF) / sizeof(u_int32_t)) >> MIDV_LOCTOPSHFT;
< EN_WRITE(sc, MIDX_PLACE(0), MIDX_MKPLACE(en_k2sz(1), midvloc));
< EN_WRITE(sc, MID_VC(0), (midvloc << MIDV_LOCSHIFT)
< | (en_k2sz(1) << MIDV_SZSHIFT) | MIDV_TRASH);
< EN_WRITE(sc, MID_DST_RP(0), 0);
< EN_WRITE(sc, MID_WP_ST_CNT(0), 0);
---
> goto again;
926,928c818,820
< for (lcv = 0 ; lcv < 68 ; lcv++) /* set up sample data */
< sp[lcv] = lcv+1;
< EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* enable DMA (only) */
---
> waitres:
> _IF_PREPEND(&slot->q, tx.m);
> }
930,931c822,832
< sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX));
< sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX));
---
> /*
> * Create a copy of a single mbuf. It can have either internal or
> * external data, it may have a packet header. External data is really
> * copied, so the new buffer is writeable.
> *
> * LOCK: any, not needed
> */
> static struct mbuf *
> copy_mbuf(struct mbuf *m)
> {
> struct mbuf *new;
933,944c834,836
< /*
< * try it now . . . DMA it out, then DMA it back in and compare
< *
< * note: in order to get the dma stuff to reverse directions it wants
< * the "end" flag set! since we are not dma'ing valid data we may
< * get an ident mismatch interrupt (which we will ignore).
< *
< * note: we've got two different tests rolled up in the same loop
< * if (wmtry)
< * then we are doing a wmaybe test and wmtry is a byte count
< * else we are doing a burst test
< */
---
> MGET(new, M_TRYWAIT, MT_DATA);
> if (new == NULL)
> return (NULL);
946c838,855
< for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) {
---
> if (m->m_flags & M_PKTHDR) {
> M_MOVE_PKTHDR(new, m);
> if (m->m_len > MHLEN) {
> MCLGET(new, M_TRYWAIT);
> if ((m->m_flags & M_EXT) == 0) {
> m_free(new);
> return (NULL);
> }
> }
> } else {
> if (m->m_len > MLEN) {
> MCLGET(new, M_TRYWAIT);
> if ((m->m_flags & M_EXT) == 0) {
> m_free(new);
> return (NULL);
> }
> }
> }
948,951c857,859
< #ifdef EN_DEBUG
< printf("DMA test lcv=%d, sp=0x%lx, dp=0x%lx, wmtry=%d\n",
< lcv, (unsigned long)sp, (unsigned long)dp, wmtry);
< #endif
---
> bcopy(m->m_data, new->m_data, m->m_len);
> new->m_len = m->m_len;
> new->m_flags &= ~M_RDONLY;
953,957c861,862
< /* zero SRAM and dest buffer */
< for (cnt = 0 ; cnt < 1024; cnt += 4)
< EN_WRITE(sc, MID_BUFOFF+cnt, 0); /* zero memory */
< for (cnt = 0 ; cnt < 68 ; cnt++)
< dp[cnt] = 0;
---
> return (new);
> }
959,989c864,883
< if (wmtry) {
< count = (sc->bestburstlen - sizeof(u_int32_t)) / sizeof(u_int32_t);
< bcode = en_dmaplan[count].bcode;
< count = wmtry >> en_dmaplan[count].divshift;
< } else {
< bcode = en_sz2b(lcv);
< count = 1;
< }
< if (sc->is_adaptec)
< EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0));
< else
< EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ENI(count, 0, MID_DMA_END, bcode));
< EN_WRITE(sc, sc->dtq_chip+4, vtophys(sp));
< EN_WRITE(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip+8));
< cnt = 1000;
< while (EN_READ(sc, MID_DMA_RDTX) == MID_DTQ_A2REG(sc->dtq_chip)) {
< DELAY(1);
< cnt--;
< if (cnt == 0) {
< printf("%s: unexpected timeout in tx DMA test\n", sc->sc_dev.dv_xname);
< return(retval); /* timeout, give up */
< }
< }
< EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
< reg = EN_READ(sc, MID_INTACK);
< if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) {
< printf("%s: unexpected status in tx DMA test: 0x%x\n",
< sc->sc_dev.dv_xname, reg);
< return(retval);
< }
< EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* re-enable DMA (only) */
---
> /*
> * This function is called when we have an ENI adapter. It fixes the
> * mbuf chain, so that all addresses and lengths are 4 byte aligned.
> * The overall length is already padded to multiple of cells plus the
> * TBD so this must always succeed. The routine can fail, when it
> * needs to copy an mbuf (this may happen if an mbuf is readonly).
> *
> * We assume here, that aligning the virtual addresses to 4 bytes also
> * aligns the physical addresses.
> *
> * LOCK: locked, needed
> */
> static struct mbuf *
> en_fix_mchain(struct en_softc *sc, struct mbuf *m0, u_int *pad)
> {
> struct mbuf **prev = &m0;
> struct mbuf *m = m0;
> struct mbuf *new;
> u_char *d;
> int off;
991c885,901
< /* "return to sender..." address is known ... */
---
> while (m != NULL) {
> d = mtod(m, u_char *);
> if ((off = (uintptr_t)d % sizeof(uint32_t)) != 0) {
> EN_COUNT(sc->stats.mfixaddr);
> if (M_WRITABLE(m)) {
> bcopy(d, d - off, m->m_len);
> m->m_data -= off;
> } else {
> if ((new = copy_mbuf(m)) == NULL) {
> EN_COUNT(sc->stats.mfixfail);
> m_freem(m0);
> return (NULL);
> }
> new->m_next = m_free(m);
> *prev = m = new;
> }
> }
993,1015c903,918
< if (sc->is_adaptec)
< EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0));
< else
< EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ENI(count, 0, MID_DMA_END, bcode));
< EN_WRITE(sc, sc->drq_chip+4, vtophys(dp));
< EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip+8));
< cnt = 1000;
< while (EN_READ(sc, MID_DMA_RDRX) == MID_DRQ_A2REG(sc->drq_chip)) {
< DELAY(1);
< cnt--;
< if (cnt == 0) {
< printf("%s: unexpected timeout in rx DMA test\n", sc->sc_dev.dv_xname);
< return(retval); /* timeout, give up */
< }
< }
< EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
< reg = EN_READ(sc, MID_INTACK);
< if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) {
< printf("%s: unexpected status in rx DMA test: 0x%x\n",
< sc->sc_dev.dv_xname, reg);
< return(retval);
< }
< EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* re-enable DMA (only) */
---
> if ((off = m->m_len % sizeof(uint32_t)) != 0) {
> EN_COUNT(sc->stats.mfixlen);
> if (!M_WRITABLE(m)) {
> if ((new = copy_mbuf(m)) == NULL) {
> EN_COUNT(sc->stats.mfixfail);
> m_freem(m0);
> return (NULL);
> }
> new->m_next = m_free(m);
> *prev = m = new;
> }
> d = mtod(m, u_char *) + m->m_len;
> off = 4 - off;
> while (off) {
> while (m->m_next && m->m_next->m_len == 0)
> m->m_next = m_free(m->m_next);
1017,1022c920,932
< if (wmtry) {
< return(bcmp(sp, dp, wmtry)); /* wmtry always exits here, no looping */
< }
<
< if (bcmp(sp, dp, lcv))
< return(retval); /* failed, use last value */
---
> if (m->m_next == NULL) {
> *d++ = 0;
> KASSERT(*pad > 0, ("no padding space"));
> (*pad)--;
> } else {
> *d++ = *mtod(m->m_next, u_char *);
> m->m_next->m_len--;
> m->m_next->m_data++;
> }
> m->m_len++;
> off--;
> }
> }
1024c934,936
< retval = lcv;
---
> prev = &m->m_next;
> m = m->m_next;
> }
1026,1027c938
< }
< return(retval); /* studly 64 byte DMA present! oh baby!! */
---
> return (m0);
1030,1031d940
< /***********************************************************************/
<
1033c942,944
< * en_ioctl: handle ioctl requests
---
> * en_start: start transmitting the next packet that needs to go out
> * if there is one. We take off all packets from the interface's queue and
> * put them into the channels queue.
1035,1039c946,957
< * NOTE: if you add an ioctl to set txspeed, you should choose a new
< * TX channel/slot. Choose the one with the lowest sc->txslot[slot].nref
< * value, subtract one from sc->txslot[0].nref, add one to the
< * sc->txslot[slot].nref, set sc->txvc2slot[vci] = slot, and then set
< * txspeed[vci].
---
> * Here we also prepend the transmit packet descriptor and append the padding
> * and (for aal5) the PDU trailer. This is different from the original driver:
> * we assume, that allocating one or two additional mbufs is actually cheaper
> * than all this algorithmic fiddling we would need otherwise.
> *
> * While the packet is on the channels wait queue we use the csum_* fields
> * in the packet header to hold the original datalen, the AAL5 flag and the
> * VCI. The packet length field in the header holds the needed buffer space.
> * This may actually be more than the length of the current mbuf chain (when
> * one or more of TBD, padding and PDU do not fit).
> *
> * LOCK: unlocked, needed
1041,1047c959,960
<
< STATIC int en_ioctl(ifp, cmd, data)
<
< struct ifnet *ifp;
< EN_IOCTL_CMDT cmd;
< caddr_t data;
<
---
> static void
> en_start(struct ifnet *ifp)
1049,1057c962,972
< struct en_softc *sc = (struct en_softc *) ifp->if_softc;
< struct ifaddr *ifa = (struct ifaddr *) data;
< struct ifreq *ifr = (struct ifreq *) data;
< struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data;
< #ifdef NATM
< struct atm_rawioctl *ario = (struct atm_rawioctl *)data;
< int slot;
< #endif
< int s, error = 0;
---
> struct en_softc *sc = (struct en_softc *)ifp->if_softc;
> struct mbuf *m, *lastm;
> struct atm_pseudohdr *ap;
> u_int pad; /* 0-bytes to pad at PDU end */
> u_int datalen; /* length of user data */
> u_int vci; /* the VCI we are transmitting on */
> u_int chan; /* the transmit channel */
> u_int flags;
> uint32_t tbd[2];
> uint32_t pdu[2];
> struct en_map *map;
1059c974,977
< s = splnet();
---
> while (1) {
> IF_DEQUEUE(&ifp->if_snd, m);
> if (m == NULL)
> return;
1061,1064c979
< switch (cmd) {
< case SIOCATMENA: /* enable circuit for recv */
< error = en_rxctl(sc, api, 1);
< break;
---
> flags = 0;
1066,1068c981,984
< case SIOCATMDIS: /* disable circuit for recv */
< error = en_rxctl(sc, api, 0);
< break;
---
> ap = mtod(m, struct atm_pseudohdr *);
> vci = ATM_PH_VCI(ap);
> if (ATM_PH_FLAGS(ap) & ATM_PH_AAL5)
> flags |= TX_AAL5;
1070,1074c986,990
< #ifdef NATM
< case SIOCXRAWATM:
< if ((slot = sc->rxvc2slot[ario->npcb->npcb_vci]) == RX_NONE) {
< error = EINVAL;
< break;
---
> if (ATM_PH_VPI(ap) != 0 || vci > MID_N_VC) {
> DBG(sc, TX, ("output vpi=%u, vci=%u -- drop",
> ATM_PH_VPI(ap), vci));
> m_freem(m);
> continue;
1076,1106c992
< if (ario->rawvalue > EN_RXSZ*1024)
< ario->rawvalue = EN_RXSZ*1024;
< if (ario->rawvalue) {
< sc->rxslot[slot].oth_flags |= ENOTHER_RAW;
< sc->rxslot[slot].raw_threshold = ario->rawvalue;
< } else {
< sc->rxslot[slot].oth_flags &= (~ENOTHER_RAW);
< sc->rxslot[slot].raw_threshold = 0;
< }
< #ifdef EN_DEBUG
< printf("%s: rxvci%d: turn %s raw (boodi) mode\n",
< sc->sc_dev.dv_xname, ario->npcb->npcb_vci,
< (ario->rawvalue) ? "on" : "off");
< #endif
< break;
< #endif
< case SIOCSIFADDR:
< ifp->if_flags |= IFF_UP;
< #if defined(INET) || defined(INET6)
< if (ifa->ifa_addr->sa_family == AF_INET
< || ifa->ifa_addr->sa_family == AF_INET6) {
< en_reset(sc);
< en_init(sc);
< ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
< break;
< }
< #endif /* INET */
< /* what to do if not INET? */
< en_reset(sc);
< en_init(sc);
< break;
---
> m_adj(m, sizeof(struct atm_pseudohdr));
1108,1110c994,997
< case SIOCGIFADDR:
< error = EINVAL;
< break;
---
> /*
> * (re-)calculate size of packet (in bytes)
> */
> m->m_pkthdr.len = datalen = m_length(m, &lastm);
1112,1114c999,1011
< case SIOCSIFFLAGS:
< error = EINVAL;
< break;
---
> /*
> * computing how much padding we need on the end of the mbuf,
> * then see if we can put the TBD at the front of the mbuf
> * where the link header goes (well behaved protocols will
> * reserve room for us). Last, check if room for PDU tail.
> */
> if (flags & TX_AAL5)
> m->m_pkthdr.len += MID_PDU_SIZE;
> m->m_pkthdr.len = roundup(m->m_pkthdr.len, MID_ATMDATASZ);
> pad = m->m_pkthdr.len - datalen;
> if (flags & TX_AAL5)
> pad -= MID_PDU_SIZE;
> m->m_pkthdr.len += MID_TBD_SIZE;
1116,1135c1013,1015
< #if defined(SIOCSIFMTU) /* ??? copied from if_de */
< #if !defined(ifr_mtu)
< #define ifr_mtu ifr_metric
< #endif
< case SIOCSIFMTU:
< /*
< * Set the interface MTU.
< */
< #ifdef notsure
< if (ifr->ifr_mtu > ATMMTU) {
< error = EINVAL;
< break;
< }
< #endif
< ifp->if_mtu = ifr->ifr_mtu;
< /* XXXCDC: do we really need to reset on MTU size change? */
< en_reset(sc);
< en_init(sc);
< break;
< #endif /* SIOCSIFMTU */
---
> DBG(sc, TX, ("txvci%d: buflen=%u datalen=%u lead=%d trail=%d",
> vci, m->m_pkthdr.len, datalen, (int)M_LEADINGSPACE(m),
> (int)M_TRAILINGSPACE(lastm)));
1137,1143c1017,1032
< default:
< error = EINVAL;
< break;
< }
< splx(s);
< return error;
< }
---
> /*
> * Allocate a map. We do this here rather then in en_txdma,
> * because en_txdma is also called from the interrupt handler
> * and we are going to have a locking problem then. We must
> * use NOWAIT here, because the ip_output path holds various
> * locks.
> */
> map = uma_zalloc_arg(sc->map_zone, sc, M_NOWAIT);
> if (map == NULL || !(map->flags & ENMAP_ALLOC)) {
> /* drop that packet */
> EN_COUNT(sc->stats.txnomap);
> if (map != NULL)
> uma_zfree(sc->map_zone, map);
> m_freem(m);
> continue;
> }
1144a1034,1043
> /*
> * From here on we need access to sc
> */
> EN_LOCK(sc);
> if ((ifp->if_flags & IFF_RUNNING) == 0) {
> EN_UNLOCK(sc);
> uma_zfree(sc->map_zone, map);
> m_freem(m);
> continue;
> }
1146,1148c1045,1053
< /*
< * en_rxctl: turn on and off VCs for recv.
< */
---
> /*
> * Look, whether we can prepend the TBD (8 byte)
> */
> if (M_WRITABLE(m) && M_LEADINGSPACE(m) >= MID_TBD_SIZE) {
> tbd[0] = htobe32(MID_TBD_MK1((flags & TX_AAL5) ?
> MID_TBD_AAL5 : MID_TBD_NOAAL5,
> sc->txspeed[vci],
> m->m_pkthdr.len / MID_ATMDATASZ));
> tbd[1] = htobe32(MID_TBD_MK2(vci, 0, 0));
1150c1055,1059
< STATIC int en_rxctl(sc, pi, on)
---
> m->m_data -= MID_TBD_SIZE;
> bcopy(tbd, m->m_data, MID_TBD_SIZE);
> m->m_len += MID_TBD_SIZE;
> flags |= TX_HAS_TBD;
> }
1152,1154c1061,1068
< struct en_softc *sc;
< struct atm_pseudoioctl *pi;
< int on;
---
> /*
> * Check whether the padding fits (must be writeable -
> * we pad with zero).
> */
> if (M_WRITABLE(lastm) && M_TRAILINGSPACE(lastm) >= pad) {
> bzero(lastm->m_data + lastm->m_len, pad);
> lastm->m_len += pad;
> flags |= TX_HAS_PAD;
1156,1158c1070,1079
< {
< u_int s, vci, flags, slot;
< u_int32_t oldmode, newmode;
---
> if ((flags & TX_AAL5) &&
> M_TRAILINGSPACE(lastm) > MID_PDU_SIZE) {
> pdu[0] = htobe32(MID_PDU_MK1(0, 0, datalen));
> pdu[1] = 0;
> bcopy(pdu, lastm->m_data + lastm->m_len,
> MID_PDU_SIZE);
> lastm->m_len += MID_PDU_SIZE;
> flags |= TX_HAS_PDU;
> }
> }
1160,1161c1081,1086
< vci = ATM_PH_VCI(&pi->aph);
< flags = ATM_PH_FLAGS(&pi->aph);
---
> if (!sc->is_adaptec &&
> (m = en_fix_mchain(sc, m, &pad)) == NULL) {
> EN_UNLOCK(sc);
> uma_zfree(sc->map_zone, map);
> continue;
> }
1163,1166c1088,1092
< #ifdef EN_DEBUG
< printf("%s: %s vpi=%d, vci=%d, flags=%d\n", sc->sc_dev.dv_xname,
< (on) ? "enable" : "disable", ATM_PH_VPI(&pi->aph), vci, flags);
< #endif
---
> /*
> * get assigned channel (will be zero unless
> * txspeed[atm_vci] is set)
> */
> chan = sc->txvc2slot[vci];
1168,1169c1094,1102
< if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC)
< return(EINVAL);
---
> if (m->m_pkthdr.len > EN_TXSZ * 1024) {
> DBG(sc, TX, ("tx%d: packet larger than xmit buffer "
> "(%d > %d)\n", chan, m->m_pkthdr.len,
> EN_TXSZ * 1024));
> EN_UNLOCK(sc);
> m_freem(m);
> uma_zfree(sc->map_zone, map);
> continue;
> }
1171,1173c1104,1111
< /*
< * turn on VCI!
< */
---
> if (sc->txslot[chan].mbsize > EN_TXHIWAT) {
> EN_COUNT(sc->stats.txmbovr);
> DBG(sc, TX, ("tx%d: buffer space shortage", chan));
> EN_UNLOCK(sc);
> m_freem(m);
> uma_zfree(sc->map_zone, map);
> continue;
> }
1175,1199c1113,1114
< if (on) {
< if (sc->rxvc2slot[vci] != RX_NONE)
< return(EINVAL);
< for (slot = 0 ; slot < sc->en_nrx ; slot++)
< if (sc->rxslot[slot].oth_flags & ENOTHER_FREE)
< break;
< if (slot == sc->en_nrx)
< return(ENOSPC);
< sc->rxvc2slot[vci] = slot;
< sc->rxslot[slot].rxhand = NULL;
< oldmode = sc->rxslot[slot].mode;
< newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL;
< sc->rxslot[slot].mode = MIDV_SETMODE(oldmode, newmode);
< sc->rxslot[slot].atm_vci = vci;
< sc->rxslot[slot].atm_flags = flags;
< sc->rxslot[slot].oth_flags = 0;
< sc->rxslot[slot].rxhand = pi->rxhand;
< if (sc->rxslot[slot].indma.ifq_head || sc->rxslot[slot].q.ifq_head)
< panic("en_rxctl: left over mbufs on enable");
< sc->txspeed[vci] = 0; /* full speed to start */
< sc->txvc2slot[vci] = 0; /* init value */
< sc->txslot[0].nref++; /* bump reference count */
< en_loadvc(sc, vci); /* does debug printf for us */
< return(0);
< }
---
> /* commit */
> sc->txslot[chan].mbsize += m->m_pkthdr.len;
1201,1203c1116,1118
< /*
< * turn off VCI
< */
---
> DBG(sc, TX, ("tx%d: VCI=%d, speed=0x%x, buflen=%d, mbsize=%d",
> chan, vci, sc->txspeed[vci], m->m_pkthdr.len,
> sc->txslot[chan].mbsize));
1205,1217c1120
< if (sc->rxvc2slot[vci] == RX_NONE)
< return(EINVAL);
< slot = sc->rxvc2slot[vci];
< if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0)
< return(EINVAL);
< s = splimp(); /* block out enintr() */
< oldmode = EN_READ(sc, MID_VC(vci));
< newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE;
< EN_WRITE(sc, MID_VC(vci), (newmode | (oldmode & MIDV_INSERVICE)));
< /* halt in tracks, be careful to preserve inserivce bit */
< DELAY(27);
< sc->rxslot[slot].rxhand = NULL;
< sc->rxslot[slot].mode = newmode;
---
> MBUF_SET_TX(m, vci, flags, datalen, pad, map);
1219,1221c1122
< sc->txslot[sc->txvc2slot[vci]].nref--;
< sc->txspeed[vci] = 0;
< sc->txvc2slot[vci] = 0;
---
> _IF_ENQUEUE(&sc->txslot[chan].q, m);
1223,1238c1124,1127
< /* if stuff is still going on we are going to have to drain it out */
< if (sc->rxslot[slot].indma.ifq_head ||
< sc->rxslot[slot].q.ifq_head ||
< (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) != 0) {
< sc->rxslot[slot].oth_flags |= ENOTHER_DRAIN;
< } else {
< sc->rxslot[slot].oth_flags = ENOTHER_FREE;
< sc->rxslot[slot].atm_vci = RX_NONE;
< sc->rxvc2slot[vci] = RX_NONE;
< }
< splx(s); /* enable enintr() */
< #ifdef EN_DEBUG
< printf("%s: rx%d: VCI %d is now %s\n", sc->sc_dev.dv_xname, slot, vci,
< (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) ? "draining" : "free");
< #endif
< return(0);
---
> en_txdma(sc, &sc->txslot[chan]);
>
> EN_UNLOCK(sc);
> }
1241,1242c1130
< /***********************************************************************/
<
---
> /*********************************************************************/
1244,1245c1132
< * en_reset: reset the board, throw away work in progress.
< * must en_init to recover.
---
> * VCs
1248,1251c1135,1141
< void en_reset(sc)
<
< struct en_softc *sc;
<
---
> /*
> * en_loadvc: load a vc tab entry from a slot
> *
> * LOCK: locked, needed
> */
> static void
> en_loadvc(struct en_softc *sc, int vc)
1253,1254c1143,1144
< struct mbuf *m;
< int lcv, slot;
---
> int slot;
> uint32_t reg = en_read(sc, MID_VC(vc));
1256,1258c1146,1148
< #ifdef EN_DEBUG
< printf("%s: reset\n", sc->sc_dev.dv_xname);
< #endif
---
> reg = MIDV_SETMODE(reg, MIDV_TRASH);
> en_write(sc, MID_VC(vc), reg);
> DELAY(27);
1260,1262c1150,1151
< if (sc->en_busreset)
< sc->en_busreset(sc);
< EN_WRITE(sc, MID_RESID, 0x0); /* reset hardware */
---
> if ((slot = sc->rxvc2slot[vc]) == RX_NONE)
> return;
1264,1267c1153
< /*
< * recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset
< * will free us!
< */
---
> /* no need to set CRC */
1269,1293c1155,1160
< for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
< if (sc->rxvc2slot[lcv] == RX_NONE)
< continue;
< slot = sc->rxvc2slot[lcv];
< while (1) {
< _IF_DEQUEUE(&sc->rxslot[slot].indma, m);
< if (m == NULL)
< break; /* >>> exit 'while(1)' here <<< */
< m_freem(m);
< }
< while (1) {
< _IF_DEQUEUE(&sc->rxslot[slot].q, m);
< if (m == NULL)
< break; /* >>> exit 'while(1)' here <<< */
< m_freem(m);
< }
< sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL;
< if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {
< sc->rxslot[slot].oth_flags = ENOTHER_FREE;
< sc->rxvc2slot[lcv] = RX_NONE;
< #ifdef EN_DEBUG
< printf("%s: rx%d: VCI %d is now free\n", sc->sc_dev.dv_xname, slot, lcv);
< #endif
< }
< }
---
> /* read pointer = 0, desc. start = 0 */
> en_write(sc, MID_DST_RP(vc), 0);
> /* write pointer = 0 */
> en_write(sc, MID_WP_ST_CNT(vc), 0);
> /* set mode, size, loc */
> en_write(sc, MID_VC(vc), sc->rxslot[slot].mode);
1295,1297c1162
< /*
< * xmit: dump everything
< */
---
> sc->rxslot[slot].cur = sc->rxslot[slot].start;
1299,1316c1164
< for (lcv = 0 ; lcv < EN_NTX ; lcv++) {
< while (1) {
< _IF_DEQUEUE(&sc->txslot[lcv].indma, m);
< if (m == NULL)
< break; /* >>> exit 'while(1)' here <<< */
< m_freem(m);
< }
< while (1) {
< _IF_DEQUEUE(&sc->txslot[lcv].q, m);
< if (m == NULL)
< break; /* >>> exit 'while(1)' here <<< */
< m_freem(m);
< }
<
< sc->txslot[lcv].mbsize = 0;
< }
<
< return;
---
> DBG(sc, VC, ("rx%d: assigned to VCI %d", slot, vc));
1319d1166
<
1321c1168,1170
< * en_init: init board and sync the card with the data in the softc.
---
> * en_rxctl: turn on and off VCs for recv.
> *
> * LOCK: unlocked, needed
1322a1172,1176
> static int
> en_rxctl(struct en_softc *sc, struct atm_pseudoioctl *pi, int on)
> {
> u_int vci, flags, slot;
> uint32_t oldmode, newmode;
1324c1178,1179
< STATIC void en_init(sc)
---
> vci = ATM_PH_VCI(&pi->aph);
> flags = ATM_PH_FLAGS(&pi->aph);
1326c1181,1182
< struct en_softc *sc;
---
> DBG(sc, IOCTL, ("%s vpi=%d, vci=%d, flags=%#x",
> (on) ? "enable" : "disable", ATM_PH_VPI(&pi->aph), vci, flags));
1328,1330c1184,1185
< {
< int vc, slot;
< u_int32_t loc;
---
> if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC)
> return (EINVAL);
1332,1339c1187
< if ((sc->enif.if_flags & IFF_UP) == 0) {
< #ifdef EN_DEBUG
< printf("%s: going down\n", sc->sc_dev.dv_xname);
< #endif
< en_reset(sc); /* to be safe */
< sc->enif.if_flags &= ~IFF_RUNNING; /* disable */
< return;
< }
---
> EN_LOCK(sc);
1341,1344c1189,1201
< #ifdef EN_DEBUG
< printf("%s: going up\n", sc->sc_dev.dv_xname);
< #endif
< sc->enif.if_flags |= IFF_RUNNING; /* enable */
---
> if (on) {
> /*
> * turn on VCI!
> */
> if (sc->rxvc2slot[vci] != RX_NONE)
> return (EINVAL);
> for (slot = 0; slot < sc->en_nrx; slot++)
> if (sc->rxslot[slot].oth_flags & ENOTHER_FREE)
> break;
> if (slot == sc->en_nrx) {
> EN_UNLOCK(sc);
> return (ENOSPC);
> }
1346,1348c1203,1211
< if (sc->en_busreset)
< sc->en_busreset(sc);
< EN_WRITE(sc, MID_RESID, 0x0); /* reset */
---
> sc->rxvc2slot[vci] = slot;
> sc->rxslot[slot].rxhand = NULL;
> oldmode = sc->rxslot[slot].mode;
> newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL;
> sc->rxslot[slot].mode = MIDV_SETMODE(oldmode, newmode);
> sc->rxslot[slot].atm_vci = vci;
> sc->rxslot[slot].atm_flags = flags;
> sc->rxslot[slot].oth_flags = 0;
> sc->rxslot[slot].rxhand = pi->rxhand;
1350,1362c1213,1219
< /*
< * init obmem data structures: vc tab, dma q's, slist.
< *
< * note that we set drq_free/dtq_free to one less than the total number
< * of DTQ/DRQs present. we do this because the card uses the condition
< * (drq_chip == drq_us) to mean "list is empty"... but if you allow the
< * circular list to be completely full then (drq_chip == drq_us) [i.e.
< * the drq_us pointer will wrap all the way around]. by restricting
< * the number of active requests to (N - 1) we prevent the list from
< * becoming completely full. note that the card will sometimes give
< * us an interrupt for a DTQ/DRQ we have already processes... this helps
< * keep that interrupt from messing us up.
< */
---
> if (_IF_QLEN(&sc->rxslot[slot].indma) != 0 ||
> _IF_QLEN(&sc->rxslot[slot].q) != 0)
> panic("en_rxctl: left over mbufs on enable");
> sc->txspeed[vci] = 0; /* full speed to start */
> sc->txvc2slot[vci] = 0; /* init value */
> sc->txslot[0].nref++; /* bump reference count */
> en_loadvc(sc, vci); /* does debug printf for us */
1364,1365c1221,1223
< for (vc = 0 ; vc < MID_N_VC ; vc++)
< en_loadvc(sc, vc);
---
> EN_UNLOCK(sc);
> return (0);
> }
1367,1372c1225,1236
< bzero(&sc->drq, sizeof(sc->drq));
< sc->drq_free = MID_DRQ_N - 1; /* N - 1 */
< sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX));
< EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
< /* ensure zero queue */
< sc->drq_us = sc->drq_chip;
---
> /*
> * turn off VCI
> */
> if (sc->rxvc2slot[vci] == RX_NONE) {
> EN_UNLOCK(sc);
> return (EINVAL);
> }
> slot = sc->rxvc2slot[vci];
> if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0) {
> EN_UNLOCK(sc);
> return (EINVAL);
> }
1374,1379c1238,1240
< bzero(&sc->dtq, sizeof(sc->dtq));
< sc->dtq_free = MID_DTQ_N - 1; /* N - 1 */
< sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX));
< EN_WRITE(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip));
< /* ensure zero queue */
< sc->dtq_us = sc->dtq_chip;
---
> oldmode = en_read(sc, MID_VC(vci));
> newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE;
> en_write(sc, MID_VC(vci), (newmode | (oldmode & MIDV_INSERVICE)));
1381,1382c1242,1245
< sc->hwslistp = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE));
< sc->swsl_size = sc->swsl_head = sc->swsl_tail = 0;
---
> /* halt in tracks, be careful to preserve inservice bit */
> DELAY(27);
> sc->rxslot[slot].rxhand = NULL;
> sc->rxslot[slot].mode = newmode;
1384,1388c1247,1249
< #ifdef EN_DEBUG
< printf("%s: drq free/chip: %d/0x%x, dtq free/chip: %d/0x%x, hwslist: 0x%x\n",
< sc->sc_dev.dv_xname, sc->drq_free, sc->drq_chip,
< sc->dtq_free, sc->dtq_chip, sc->hwslistp);
< #endif
---
> sc->txslot[sc->txvc2slot[vci]].nref--;
> sc->txspeed[vci] = 0;
> sc->txvc2slot[vci] = 0;
1390,1403c1251,1261
< for (slot = 0 ; slot < EN_NTX ; slot++) {
< sc->txslot[slot].bfree = EN_TXSZ * 1024;
< EN_WRITE(sc, MIDX_READPTR(slot), 0);
< EN_WRITE(sc, MIDX_DESCSTART(slot), 0);
< loc = sc->txslot[slot].cur = sc->txslot[slot].start;
< loc = loc - MID_RAMOFF;
< loc = (loc & ~((EN_TXSZ*1024) - 1)) >> 2; /* mask, cvt to words */
< loc = loc >> MIDV_LOCTOPSHFT; /* top 11 bits */
< EN_WRITE(sc, MIDX_PLACE(slot), MIDX_MKPLACE(en_k2sz(EN_TXSZ), loc));
< #ifdef EN_DEBUG
< printf("%s: tx%d: place 0x%x\n", sc->sc_dev.dv_xname, slot,
< (u_int)EN_READ(sc, MIDX_PLACE(slot)));
< #endif
< }
---
> /* if stuff is still going on we are going to have to drain it out */
> if (_IF_QLEN(&sc->rxslot[slot].indma) != 0 ||
> _IF_QLEN(&sc->rxslot[slot].q) != 0 ||
> (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) != 0) {
> sc->rxslot[slot].oth_flags |= ENOTHER_DRAIN;
> } else {
> sc->rxslot[slot].oth_flags = ENOTHER_FREE;
> sc->rxslot[slot].atm_vci = RX_NONE;
> sc->rxvc2slot[vci] = RX_NONE;
> }
> EN_UNLOCK(sc);
1405,1407c1263,1264
< /*
< * enable!
< */
---
> DBG(sc, IOCTL, ("rx%d: VCI %d is now %s", slot, vci,
> (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) ? "draining" : "free"));
1409,1414c1266
< EN_WRITE(sc, MID_INTENA, MID_INT_TX|MID_INT_DMA_OVR|MID_INT_IDENT|
< MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_DMA_RX|MID_INT_DMA_TX|
< MID_INT_SERVICE| /* >>> MID_INT_SUNI| XXXCDC<<< */ MID_INT_STATS);
< EN_WRITE(sc, MID_MAST_CSR, MID_SETIPL(sc->ipl)|MID_MCSR_ENDMA|
< MID_MCSR_ENTX|MID_MCSR_ENRX);
<
---
> return (0);
1416a1269,1272
> /*********************************************************************/
> /*
> * starting/stopping the card
> */
1419c1275,1278
< * en_loadvc: load a vc tab entry from a slot
---
> * en_reset_ul: reset the board, throw away work in progress.
> * must en_init to recover.
> *
> * LOCK: locked, needed
1420a1280,1285
> static void
> en_reset_ul(struct en_softc *sc)
> {
> struct en_map *map;
> struct mbuf *m;
> int lcv, slot;
1422c1287
< STATIC void en_loadvc(sc, vc)
---
> if_printf(&sc->enif, "reset\n");
1424,1425c1289,1291
< struct en_softc *sc;
< int vc;
---
> if (sc->en_busreset)
> sc->en_busreset(sc);
> en_write(sc, MID_RESID, 0x0); /* reset hardware */
1427,1433c1293,1300
< {
< int slot;
< u_int32_t reg = EN_READ(sc, MID_VC(vc));
<
< reg = MIDV_SETMODE(reg, MIDV_TRASH);
< EN_WRITE(sc, MID_VC(vc), reg);
< DELAY(27);
---
> /*
> * recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset
> * will free us!
> */
> for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
> if (sc->rxvc2slot[lcv] == RX_NONE)
> continue;
> slot = sc->rxvc2slot[lcv];
1435,1436c1302,1322
< if ((slot = sc->rxvc2slot[vc]) == RX_NONE)
< return;
---
> for (;;) {
> _IF_DEQUEUE(&sc->rxslot[slot].indma, m);
> if (m == NULL)
> break;
> map = (void *)m->m_pkthdr.rcvif;
> uma_zfree(sc->map_zone, map);
> m_freem(m);
> }
> for (;;) {
> _IF_DEQUEUE(&sc->rxslot[slot].q, m);
> if (m == NULL)
> break;
> m_freem(m);
> }
> sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL;
> if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {
> sc->rxslot[slot].oth_flags = ENOTHER_FREE;
> sc->rxvc2slot[lcv] = RX_NONE;
> DBG(sc, INIT, ("rx%d: VCI %d is now free", slot, lcv));
> }
> }
1438,1442c1324,1346
< /* no need to set CRC */
< EN_WRITE(sc, MID_DST_RP(vc), 0); /* read pointer = 0, desc. start = 0 */
< EN_WRITE(sc, MID_WP_ST_CNT(vc), 0); /* write pointer = 0 */
< EN_WRITE(sc, MID_VC(vc), sc->rxslot[slot].mode); /* set mode, size, loc */
< sc->rxslot[slot].cur = sc->rxslot[slot].start;
---
> /*
> * xmit: dump everything
> */
> for (lcv = 0 ; lcv < EN_NTX ; lcv++) {
> for (;;) {
> _IF_DEQUEUE(&sc->txslot[lcv].indma, m);
> if (m == NULL)
> break;
> map = (void *)m->m_pkthdr.rcvif;
> uma_zfree(sc->map_zone, map);
> m_freem(m);
> }
> for (;;) {
> _IF_DEQUEUE(&sc->txslot[lcv].q, m);
> if (m == NULL)
> break;
> map = (void *)m->m_pkthdr.rcvif;
> uma_zfree(sc->map_zone, map);
> m_freem(m);
> }
> sc->txslot[lcv].mbsize = 0;
> }
> }
1444,1446c1348,1361
< #ifdef EN_DEBUG
< printf("%s: rx%d: assigned to VCI %d\n", sc->sc_dev.dv_xname, slot, vc);
< #endif
---
> /*
> * en_reset: reset the board, throw away work in progress.
> * must en_init to recover.
> *
> * LOCK: unlocked, needed
> *
> * Use en_reset_ul if you alreay have the lock
> */
> void
> en_reset(struct en_softc *sc)
> {
> EN_LOCK(sc);
> en_reset_ul(sc);
> EN_UNLOCK(sc);
1451,1452c1366,1368
< * en_start: start transmitting the next packet that needs to go out
< * if there is one. note that atm_output() has already splimp()'d us.
---
> * en_init: init board and sync the card with the data in the softc.
> *
> * LOCK: locked, needed
1453a1370,1374
> static void
> en_init(struct en_softc *sc)
> {
> int vc, slot;
> uint32_t loc;
1455c1376,1381
< STATIC void en_start(ifp)
---
> if ((sc->enif.if_flags & IFF_UP) == 0) {
> DBG(sc, INIT, ("going down"));
> en_reset(sc); /* to be safe */
> sc->enif.if_flags &= ~IFF_RUNNING; /* disable */
> return;
> }
1457c1383,1384
< struct ifnet *ifp;
---
> DBG(sc, INIT, ("going up"));
> sc->enif.if_flags |= IFF_RUNNING; /* enable */
1459,1466c1386,1388
< {
< struct en_softc *sc = (struct en_softc *) ifp->if_softc;
< struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */
< struct mbuf *m, *lastm, *prev;
< struct atm_pseudohdr *ap, *new_ap;
< int txchan, mlen, got, need, toadd, cellcnt, first;
< u_int32_t atm_vpi, atm_vci, atm_flags, *dat, aal;
< u_int8_t *cp;
---
> if (sc->en_busreset)
> sc->en_busreset(sc);
> en_write(sc, MID_RESID, 0x0); /* reset */
1468,1469c1390,1402
< if ((ifp->if_flags & IFF_RUNNING) == 0)
< return;
---
> /*
> * init obmem data structures: vc tab, dma q's, slist.
> *
> * note that we set drq_free/dtq_free to one less than the total number
> * of DTQ/DRQs present. we do this because the card uses the condition
> * (drq_chip == drq_us) to mean "list is empty"... but if you allow the
> * circular list to be completely full then (drq_chip == drq_us) [i.e.
> * the drq_us pointer will wrap all the way around]. by restricting
> * the number of active requests to (N - 1) we prevent the list from
> * becoming completely full. note that the card will sometimes give
> * us an interrupt for a DTQ/DRQ we have already processes... this helps
> * keep that interrupt from messing us up.
> */
1471,1474c1404,1405
< /*
< * remove everything from interface queue since we handle all queueing
< * locally ...
< */
---
> for (vc = 0; vc < MID_N_VC; vc++)
> en_loadvc(sc, vc);
1476c1407,1411
< while (1) {
---
> bzero(&sc->drq, sizeof(sc->drq));
> sc->drq_free = MID_DRQ_N - 1;
> sc->drq_chip = MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX));
> en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
> sc->drq_us = sc->drq_chip;
1478,1490c1413,1417
< IF_DEQUEUE(ifq, m);
< if (m == NULL)
< return; /* EMPTY: >>> exit here <<< */
<
< /*
< * calculate size of packet (in bytes)
< * also, if we are not doing transmit DMA we eliminate all stupid
< * (non-word) alignments here using en_mfix(). calls to en_mfix()
< * seem to be due to tcp retransmits for the most part.
< *
< * after this loop mlen total length of mbuf chain (including atm_ph),
< * and lastm is a pointer to the last mbuf on the chain.
< */
---
> bzero(&sc->dtq, sizeof(sc->dtq));
> sc->dtq_free = MID_DTQ_N - 1;
> sc->dtq_chip = MID_DTQ_REG2A(en_read(sc, MID_DMA_RDTX));
> en_write(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip));
> sc->dtq_us = sc->dtq_chip;
1492,1510c1419,1420
< lastm = m;
< mlen = 0;
< prev = NULL;
< while (1) {
< /* no DMA? */
< if ((!sc->is_adaptec && EN_ENIDMAFIX) || EN_NOTXDMA || !en_dma) {
< if ( ((uintptr_t)mtod(lastm, void *) % sizeof(u_int32_t)) != 0 ||
< ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) {
< first = (lastm == m);
< if (en_mfix(sc, &lastm, prev) == 0) { /* failed? */
< m_freem(m);
< m = NULL;
< break;
< }
< if (first)
< m = lastm; /* update */
< }
< prev = lastm;
< }
---
> sc->hwslistp = MID_SL_REG2A(en_read(sc, MID_SERV_WRITE));
> sc->swsl_size = sc->swsl_head = sc->swsl_tail = 0;
1512,1516c1422,1424
< mlen += lastm->m_len;
< if (lastm->m_next == NULL)
< break;
< lastm = lastm->m_next;
< }
---
> DBG(sc, INIT, ("drq free/chip: %d/0x%x, dtq free/chip: %d/0x%x, "
> "hwslist: 0x%x", sc->drq_free, sc->drq_chip, sc->dtq_free,
> sc->dtq_chip, sc->hwslistp));
1518,1519c1426,1440
< if (m == NULL) /* happens only if mfix fails */
< continue;
---
> for (slot = 0 ; slot < EN_NTX ; slot++) {
> sc->txslot[slot].bfree = EN_TXSZ * 1024;
> en_write(sc, MIDX_READPTR(slot), 0);
> en_write(sc, MIDX_DESCSTART(slot), 0);
> loc = sc->txslot[slot].cur = sc->txslot[slot].start;
> loc = loc - MID_RAMOFF;
> /* mask, cvt to words */
> loc = (loc & ~((EN_TXSZ * 1024) - 1)) >> 2;
> /* top 11 bits */
> loc = loc >> MIDV_LOCTOPSHFT;
> en_write(sc, MIDX_PLACE(slot), MIDX_MKPLACE(en_k2sz(EN_TXSZ),
> loc));
> DBG(sc, INIT, ("tx%d: place 0x%x", slot,
> (u_int)en_read(sc, MIDX_PLACE(slot))));
> }
1521c1442,1450
< ap = mtod(m, struct atm_pseudohdr *);
---
> /*
> * enable!
> */
> en_write(sc, MID_INTENA, MID_INT_TX | MID_INT_DMA_OVR | MID_INT_IDENT |
> MID_INT_LERR | MID_INT_DMA_ERR | MID_INT_DMA_RX | MID_INT_DMA_TX |
> MID_INT_SERVICE | /* MID_INT_SUNI | */ MID_INT_STATS);
> en_write(sc, MID_MAST_CSR, MID_SETIPL(sc->ipl) | MID_MCSR_ENDMA |
> MID_MCSR_ENTX | MID_MCSR_ENRX);
> }
1523,1527c1452,1455
< atm_vpi = ATM_PH_VPI(ap);
< atm_vci = ATM_PH_VCI(ap);
< atm_flags = ATM_PH_FLAGS(ap) & ~(EN_OBHDR|EN_OBTRL);
< aal = ((atm_flags & ATM_PH_AAL5) != 0)
< ? MID_TBD_AAL5 : MID_TBD_NOAAL5;
---
> /*********************************************************************/
> /*
> * Ioctls
> */
1529,1531c1457,1475
< /*
< * check that vpi/vci is one we can use
< */
---
> /*
> * en_ioctl: handle ioctl requests
> *
> * NOTE: if you add an ioctl to set txspeed, you should choose a new
> * TX channel/slot. Choose the one with the lowest sc->txslot[slot].nref
> * value, subtract one from sc->txslot[0].nref, add one to the
> * sc->txslot[slot].nref, set sc->txvc2slot[vci] = slot, and then set
> * txspeed[vci].
> *
> * LOCK: unlocked, needed
> */
> static int
> en_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
> {
> struct en_softc *sc = (struct en_softc *)ifp->if_softc;
> struct ifaddr *ifa = (struct ifaddr *)data;
> struct ifreq *ifr = (struct ifreq *)data;
> struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data;
> int error = 0;
1533,1538c1477
< if (atm_vpi || atm_vci > MID_N_VC) {
< printf("%s: output vpi=%d, vci=%d out of card range, dropping...\n",
< sc->sc_dev.dv_xname, atm_vpi, atm_vci);
< m_freem(m);
< continue;
< }
---
> switch (cmd) {
1540,1551c1479,1481
< /*
< * computing how much padding we need on the end of the mbuf, then
< * see if we can put the TBD at the front of the mbuf where the
< * link header goes (well behaved protocols will reserve room for us).
< * last, check if room for PDU tail.
< *
< * got = number of bytes of data we have
< * cellcnt = number of cells in this mbuf
< * need = number of bytes of data + padding we need (excludes TBD)
< * toadd = number of bytes of data we need to add to end of mbuf,
< * [including AAL5 PDU, if AAL5]
< */
---
> case SIOCATMENA: /* enable circuit for recv */
> error = en_rxctl(sc, api, 1);
> break;
1553,1557c1483,1485
< got = mlen - sizeof(struct atm_pseudohdr);
< toadd = (aal == MID_TBD_AAL5) ? MID_PDU_SIZE : 0; /* PDU */
< cellcnt = (got + toadd + (MID_ATMDATASZ - 1)) / MID_ATMDATASZ;
< need = cellcnt * MID_ATMDATASZ;
< toadd = need - got; /* recompute, including zero padding */
---
> case SIOCATMDIS: /* disable circuit for recv */
> error = en_rxctl(sc, api, 0);
> break;
1559,1564c1487,1507
< #ifdef EN_DEBUG
< printf("%s: txvci%d: mlen=%d, got=%d, need=%d, toadd=%d, cell#=%d\n",
< sc->sc_dev.dv_xname, atm_vci, mlen, got, need, toadd, cellcnt);
< printf(" leading_space=%d, trailing_space=%d\n",
< (int)M_LEADINGSPACE(m), (int)M_TRAILINGSPACE(lastm));
< #endif
---
> case SIOCSIFADDR:
> EN_LOCK(sc);
> ifp->if_flags |= IFF_UP;
> #if defined(INET) || defined(INET6)
> if (ifa->ifa_addr->sa_family == AF_INET
> || ifa->ifa_addr->sa_family == AF_INET6) {
> if (!(ifp->if_flags & IFF_RUNNING)) {
> en_reset_ul(sc);
> en_init(sc);
> }
> ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
> EN_UNLOCK(sc);
> break;
> }
> #endif /* INET */
> if (!(ifp->if_flags & IFF_RUNNING)) {
> en_reset_ul(sc);
> en_init(sc);
> }
> EN_UNLOCK(sc);
> break;
1566c1509,1519
< #ifdef EN_MBUF_OPT
---
> case SIOCSIFFLAGS:
> EN_LOCK(sc);
> if (ifp->if_flags & IFF_UP) {
> if (!(ifp->if_flags & IFF_RUNNING))
> en_init(sc);
> } else {
> if (ifp->if_flags & IFF_RUNNING)
> en_reset_ul(sc);
> }
> EN_UNLOCK(sc);
> break;
1568,1573c1521,1530
< /*
< * note: external storage (M_EXT) can be shared between mbufs
< * to avoid copying (see m_copym()). this means that the same
< * data buffer could be shared by several mbufs, and thus it isn't
< * a good idea to try and write TBDs or PDUs to M_EXT data areas.
< */
---
> case SIOCSIFMTU:
> /*
> * Set the interface MTU.
> */
> if (ifr->ifr_mtu > ATMMTU) {
> error = EINVAL;
> break;
> }
> ifp->if_mtu = ifr->ifr_mtu;
> break;
1575,1600c1532,1534
< if (M_LEADINGSPACE(m) >= MID_TBD_SIZE && (m->m_flags & M_EXT) == 0) {
< m->m_data -= MID_TBD_SIZE;
< m->m_len += MID_TBD_SIZE;
< mlen += MID_TBD_SIZE;
< new_ap = mtod(m, struct atm_pseudohdr *);
< *new_ap = *ap; /* move it back */
< ap = new_ap;
< dat = ((u_int32_t *) ap) + 1;
< /* make sure the TBD is in proper byte order */
< *dat++ = htonl(MID_TBD_MK1(aal, sc->txspeed[atm_vci], cellcnt));
< *dat = htonl(MID_TBD_MK2(atm_vci, 0, 0));
< atm_flags |= EN_OBHDR;
< }
<
< if (toadd && (lastm->m_flags & M_EXT) == 0 &&
< M_TRAILINGSPACE(lastm) >= toadd) {
< cp = mtod(lastm, u_int8_t *) + lastm->m_len;
< lastm->m_len += toadd;
< mlen += toadd;
< if (aal == MID_TBD_AAL5) {
< bzero(cp, toadd - MID_PDU_SIZE);
< dat = (u_int32_t *)(cp + toadd - MID_PDU_SIZE);
< /* make sure the PDU is in proper byte order */
< *dat = htonl(MID_PDU_MK1(0, 0, got));
< } else {
< bzero(cp, toadd);
---
> default:
> error = EINVAL;
> break;
1602,1605c1536,1537
< atm_flags |= EN_OBTRL;
< }
< ATM_PH_FLAGS(ap) = atm_flags; /* update EN_OBHDR/EN_OBTRL bits */
< #endif /* EN_MBUF_OPT */
---
> return (error);
> }
1607,1609c1539,1542
< /*
< * get assigned channel (will be zero unless txspeed[atm_vci] is set)
< */
---
> /*********************************************************************/
> /*
> * Sysctl's
> */
1611c1544,1554
< txchan = sc->txvc2slot[atm_vci];
---
> /*
> * Sysctl handler for internal statistics
> *
> * LOCK: unlocked, needed
> */
> static int
> en_sysctl_istats(SYSCTL_HANDLER_ARGS)
> {
> struct en_softc *sc = arg1;
> struct sbuf *sb;
> int error;
1613,1621c1556,1557
< if (sc->txslot[txchan].mbsize > EN_TXHIWAT) {
< EN_COUNT(sc->txmbovr);
< m_freem(m);
< #ifdef EN_DEBUG
< printf("%s: tx%d: buffer space shortage\n", sc->sc_dev.dv_xname,
< txchan);
< #endif
< continue;
< }
---
> sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
> sbuf_clear(sb);
1623c1559
< sc->txslot[txchan].mbsize += mlen;
---
> EN_LOCK(sc);
1625,1631c1561,1580
< #ifdef EN_DEBUG
< printf("%s: tx%d: VPI=%d, VCI=%d, FLAGS=0x%x, speed=0x%x\n",
< sc->sc_dev.dv_xname, txchan, atm_vpi, atm_vci, atm_flags,
< sc->txspeed[atm_vci]);
< printf(" adjusted mlen=%d, mbsize=%d\n", mlen,
< sc->txslot[txchan].mbsize);
< #endif
---
> #define DO(NAME) sbuf_printf(sb, #NAME": %u\n", sc->stats.NAME)
> DO(vtrash);
> DO(otrash);
> DO(ttrash);
> DO(mfixaddr);
> DO(mfixlen);
> DO(mfixfail);
> DO(txmbovr);
> DO(dmaovr);
> DO(txoutspace);
> DO(txdtqout);
> DO(launch);
> DO(hwpull);
> DO(swadd);
> DO(rxqnotus);
> DO(rxqus);
> DO(rxdrqout);
> DO(rxmbufout);
> DO(txnomap);
> #undef DO
1633c1582
< _IF_ENQUEUE(&sc->txslot[txchan].q, m);
---
> EN_UNLOCK(sc);
1635,1638c1584,1587
< en_txdma(sc, txchan);
<
< }
< /*NOTREACHED*/
---
> sbuf_finish(sb);
> error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
> sbuf_delete(sb);
> return (error);
1641c1590
<
---
> /*********************************************************************/
1643c1592
< * en_mfix: fix a stupid mbuf
---
> * Interrupts
1646,1652c1595,1605
< #ifndef __FreeBSD__
<
< STATIC int en_mfix(sc, mm, prev)
<
< struct en_softc *sc;
< struct mbuf **mm, *prev;
<
---
> /*
> * Transmit interrupt handler
> *
> * check for tx complete, if detected then this means that some space
> * has come free on the card. we must account for it and arrange to
> * kick the channel to life (in case it is stalled waiting on the card).
> *
> * LOCK: locked, needed
> */
> static uint32_t
> en_intr_tx(struct en_softc *sc, uint32_t reg)
1654,1657c1607,1610
< struct mbuf *m, *new;
< u_char *d, *cp;
< int off;
< struct mbuf *nxt;
---
> uint32_t kick;
> uint32_t mask;
> uint32_t val;
> int chan;
1659c1612
< m = *mm;
---
> kick = 0; /* bitmask of channels to kick */
1661,1665c1614,1616
< EN_COUNT(sc->mfix); /* count # of calls */
< #ifdef EN_DEBUG
< printf("%s: mfix mbuf m_data=%p, m_len=%d\n", sc->sc_dev.dv_xname,
< m->m_data, m->m_len);
< #endif
---
> for (mask = 1, chan = 0; chan < EN_NTX; chan++, mask *= 2) {
> if (!(reg & MID_TXCHAN(chan)))
> continue;
1667,1668c1618
< d = mtod(m, u_char *);
< off = ((unsigned long) d) % sizeof(u_int32_t);
---
> kick = kick | mask;
1670,1696c1620,1633
< if (off) {
< if ((m->m_flags & M_EXT) == 0) {
< bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */
< d -= off;
< m->m_data = (caddr_t)d;
< } else {
< /* can't write to an M_EXT mbuf since it may be shared */
< MGET(new, M_DONTWAIT, MT_DATA);
< if (!new) {
< EN_COUNT(sc->mfixfail);
< return(0);
< }
< MCLGET(new, M_DONTWAIT);
< if ((new->m_flags & M_EXT) == 0) {
< m_free(new);
< EN_COUNT(sc->mfixfail);
< return(0);
< }
< bcopy(d, new->m_data, m->m_len); /* ALIGN! (with costly data copy...) */
< new->m_len = m->m_len;
< new->m_next = m->m_next;
< if (prev)
< prev->m_next = new;
< m_free(m);
< *mm = m = new; /* note: 'd' now invalid */
< }
< }
---
> /* current read pointer */
> val = en_read(sc, MIDX_READPTR(chan));
> /* as offset */
> val = (val * sizeof(uint32_t)) + sc->txslot[chan].start;
> if (val > sc->txslot[chan].cur)
> sc->txslot[chan].bfree = val - sc->txslot[chan].cur;
> else
> sc->txslot[chan].bfree = (val + (EN_TXSZ * 1024)) -
> sc->txslot[chan].cur;
> DBG(sc, INTR, ("tx%d: transmit done. %d bytes now free in "
> "buffer", chan, sc->txslot[chan].bfree));
> }
> return (kick);
> }
1698,1700c1635,1653
< off = m->m_len % sizeof(u_int32_t);
< if (off == 0)
< return(1);
---
> /*
> * TX DMA interrupt
> *
> * check for TX DMA complete, if detected then this means
> * that some DTQs are now free. it also means some indma
> * mbufs can be freed. if we needed DTQs, kick all channels.
> *
> * LOCK: locked, needed
> */
> static uint32_t
> en_intr_tx_dma(struct en_softc *sc)
> {
> uint32_t kick = 0;
> uint32_t val;
> uint32_t idx;
> uint32_t slot;
> uint32_t dtq;
> struct en_map *map;
> struct mbuf *m;
1702,1720c1655,1656
< d = mtod(m, u_char *) + m->m_len;
< off = sizeof(u_int32_t) - off;
<
< nxt = m->m_next;
< while (off--) {
< for ( ; nxt != NULL && nxt->m_len == 0 ; nxt = nxt->m_next)
< /*null*/;
< if (nxt == NULL) { /* out of data, zero fill */
< *d++ = 0;
< continue; /* next "off" */
< }
< cp = mtod(nxt, u_char *);
< *d++ = *cp++;
< m->m_len++;
< nxt->m_len--;
< nxt->m_data = (caddr_t)cp;
< }
< return(1);
< }
---
> val = en_read(sc, MID_DMA_RDTX); /* chip's current location */
> idx = MID_DTQ_A2REG(sc->dtq_chip); /* where we last saw chip */
1722c1658,1662
< #else /* __FreeBSD__ */
---
> if (sc->need_dtqs) {
> kick = MID_NTX_CH - 1; /* assume power of 2, kick all! */
> sc->need_dtqs = 0; /* recalculated in "kick" loop below */
> DBG(sc, INTR, ("cleared need DTQ condition"));
> }
1724c1664,1669
< STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *);
---
> while (idx != val) {
> sc->dtq_free++;
> if ((dtq = sc->dtq[idx]) != 0) {
> /* don't forget to zero it out when done */
> sc->dtq[idx] = 0;
> slot = EN_DQ_SLOT(dtq);
1726,1730c1671,1676
< STATIC int en_makeexclusive(sc, mm, prev)
< struct en_softc *sc;
< struct mbuf **mm, *prev;
< {
< struct mbuf *m, *new;
---
> _IF_DEQUEUE(&sc->txslot[slot].indma, m);
> if (m == NULL)
> panic("enintr: dtqsync");
> map = (void *)m->m_pkthdr.rcvif;
> uma_zfree(sc->map_zone, map);
> m_freem(m);
1732,1739c1678,1683
< m = *mm;
<
< if (m->m_flags & M_EXT) {
< if (m->m_ext.ext_type != EXT_CLUSTER) {
< /* external buffer isn't an ordinary mbuf cluster! */
< printf("%s: mfix: special buffer! can't make a copy!\n",
< sc->sc_dev.dv_xname);
< return (0);
---
> sc->txslot[slot].mbsize -= EN_DQ_LEN(dtq);
> DBG(sc, INTR, ("tx%d: free %d dma bytes, mbsize now "
> "%d", slot, EN_DQ_LEN(dtq),
> sc->txslot[slot].mbsize));
> }
> EN_WRAPADD(0, MID_DTQ_N, idx, 1);
1741,1769c1685
<
< if (MEXT_IS_REF(m)) {
< /* make a real copy of the M_EXT mbuf since it is shared */
< MGET(new, M_DONTWAIT, MT_DATA);
< if (!new) {
< EN_COUNT(sc->mfixfail);
< return(0);
< }
< if (m->m_flags & M_PKTHDR)
< M_MOVE_PKTHDR(new, m);
< MCLGET(new, M_DONTWAIT);
< if ((new->m_flags & M_EXT) == 0) {
< m_free(new);
< EN_COUNT(sc->mfixfail);
< return(0);
< }
< bcopy(m->m_data, new->m_data, m->m_len);
< new->m_len = m->m_len;
< new->m_next = m->m_next;
< if (prev)
< prev->m_next = new;
< m_free(m);
< *mm = new;
< }
< else {
< /* the buffer is not shared, align the data offset using
< this buffer. */
< u_char *d = mtod(m, u_char *);
< int off = ((uintptr_t)(void *)d) % sizeof(u_int32_t);
---
> sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */
1771,1777c1687
< if (off > 0) {
< bcopy(d, d - off, m->m_len);
< m->m_data = (caddr_t)d - off;
< }
< }
< }
< return (1);
---
> return (kick);
1780,1784c1690,1696
< STATIC int en_mfix(sc, mm, prev)
<
< struct en_softc *sc;
< struct mbuf **mm, *prev;
<
---
> /*
> * Service interrupt
> *
> * LOCK: locked, needed
> */
> static int
> en_intr_service(struct en_softc *sc)
1786,1789c1698,1701
< struct mbuf *m;
< u_char *d, *cp;
< int off;
< struct mbuf *nxt;
---
> uint32_t chip;
> uint32_t slot;
> uint32_t vci;
> int need_softserv = 0;
1791c1703
< m = *mm;
---
> chip = MID_SL_REG2A(en_read(sc, MID_SERV_WRITE));
1793,1797c1705,1708
< EN_COUNT(sc->mfix); /* count # of calls */
< #ifdef EN_DEBUG
< printf("%s: mfix mbuf m_data=%p, m_len=%d\n", sc->sc_dev.dv_xname,
< m->m_data, m->m_len);
< #endif
---
> while (sc->hwslistp != chip) {
> /* fetch and remove it from hardware service list */
> vci = en_read(sc, sc->hwslistp);
> EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4);
1799,1800c1710,1716
< d = mtod(m, u_char *);
< off = ((uintptr_t) (void *) d) % sizeof(u_int32_t);
---
> slot = sc->rxvc2slot[vci];
> if (slot == RX_NONE) {
> DBG(sc, INTR, ("unexpected rx interrupt on VCI %d",
> vci));
> en_write(sc, MID_VC(vci), MIDV_TRASH); /* rx off */
> continue;
> }
1802,1813c1718,1720
< if (off) {
< if ((m->m_flags & M_EXT) == 0) {
< bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */
< d -= off;
< m->m_data = (caddr_t)d;
< } else {
< /* can't write to an M_EXT mbuf since it may be shared */
< if (en_makeexclusive(sc, &m, prev) == 0)
< return (0);
< *mm = m; /* note: 'd' now invalid */
< }
< }
---
> /* remove from hwsl */
> en_write(sc, MID_VC(vci), sc->rxslot[slot].mode);
> EN_COUNT(sc->stats.hwpull);
1815,1817c1722
< off = m->m_len % sizeof(u_int32_t);
< if (off == 0)
< return(1);
---
> DBG(sc, INTR, ("pulled VCI %d off hwslist", vci));
1819,1848c1724,1735
< if (m->m_flags & M_EXT) {
< /* can't write to an M_EXT mbuf since it may be shared */
< if (en_makeexclusive(sc, &m, prev) == 0)
< return (0);
< *mm = m; /* note: 'd' now invalid */
< }
<
< d = mtod(m, u_char *) + m->m_len;
< off = sizeof(u_int32_t) - off;
<
< nxt = m->m_next;
< while (off--) {
< if (nxt != NULL && nxt->m_len == 0) {
< /* remove an empty mbuf. this avoids odd byte padding to an empty
< last mbuf. */
< m->m_next = nxt = m_free(nxt);
< }
< if (nxt == NULL) { /* out of data, zero fill */
< *d++ = 0;
< continue; /* next "off" */
< }
< cp = mtod(nxt, u_char *);
< *d++ = *cp++;
< m->m_len++;
< nxt->m_len--;
< nxt->m_data = (caddr_t)cp;
< }
< if (nxt != NULL && nxt->m_len == 0)
< m->m_next = m_free(nxt);
< return(1);
---
> /* add it to the software service list (if needed) */
> if ((sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) {
> EN_COUNT(sc->stats.swadd);
> need_softserv = 1;
> sc->rxslot[slot].oth_flags |= ENOTHER_SWSL;
> sc->swslist[sc->swsl_tail] = slot;
> EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1);
> sc->swsl_size++;
> DBG(sc, INTR, ("added VCI %d to swslist", vci));
> }
> }
> return (need_softserv);
1851,1852d1737
< #endif /* __FreeBSD__ */
<
1854c1739,1741
< * en_txdma: start trasmit DMA, if possible
---
> * check for RX DMA complete, and pass the data "upstairs"
> *
> * LOCK: locked, needed
1855a1743,1753
> static int
> en_intr_rx_dma(struct en_softc *sc)
> {
> uint32_t val;
> uint32_t idx;
> uint32_t drq;
> uint32_t slot;
> uint32_t vci;
> struct atm_pseudohdr ah;
> struct mbuf *m;
> struct en_map *map;
1857c1755,1756
< STATIC void en_txdma(sc, chan)
---
> val = en_read(sc, MID_DMA_RDRX); /* chip's current location */
> idx = MID_DRQ_A2REG(sc->drq_chip); /* where we last saw chip */
1859,1860c1758,1794
< struct en_softc *sc;
< int chan;
---
> while (idx != val) {
> sc->drq_free++;
> if ((drq = sc->drq[idx]) != 0) {
> /* don't forget to zero it out when done */
> sc->drq[idx] = 0;
> slot = EN_DQ_SLOT(drq);
> if (EN_DQ_LEN(drq) == 0) { /* "JK" trash DMA? */
> m = NULL;
> map = NULL;
> } else {
> _IF_DEQUEUE(&sc->rxslot[slot].indma, m);
> if (m == NULL)
> panic("enintr: drqsync: %s%d: lost mbuf"
> " in slot %d!", sc->enif.if_name,
> sc->enif.if_unit, slot);
> map = (void *)m->m_pkthdr.rcvif;
> uma_zfree(sc->map_zone, map);
> }
> /* do something with this mbuf */
> if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {
> /* drain? */
> if (m != NULL)
> m_freem(m);
> vci = sc->rxslot[slot].atm_vci;
> if (!_IF_QLEN(&sc->rxslot[slot].indma) &&
> !_IF_QLEN(&sc->rxslot[slot].q) &&
> (en_read(sc, MID_VC(vci)) & MIDV_INSERVICE)
> == 0 &&
> (sc->rxslot[slot].oth_flags & ENOTHER_SWSL)
> == 0) {
> sc->rxslot[slot].oth_flags =
> ENOTHER_FREE; /* done drain */
> sc->rxslot[slot].atm_vci = RX_NONE;
> sc->rxvc2slot[vci] = RX_NONE;
> DBG(sc, INTR, ("rx%d: VCI %d now free",
> slot, vci));
> }
1862,1868c1796,1803
< {
< struct mbuf *tmp;
< struct atm_pseudohdr *ap;
< struct en_launch launch;
< int datalen = 0, dtqneed, len, ncells;
< u_int8_t *cp;
< struct ifnet *ifp;
---
> } else if (m != NULL) {
> ATM_PH_FLAGS(&ah) = sc->rxslot[slot].atm_flags;
> ATM_PH_VPI(&ah) = 0;
> ATM_PH_SETVCI(&ah, sc->rxslot[slot].atm_vci);
> DBG(sc, INTR, ("rx%d: rxvci%d: atm_input, "
> "mbuf %p, len %d, hand %p", slot,
> sc->rxslot[slot].atm_vci, m,
> EN_DQ_LEN(drq), sc->rxslot[slot].rxhand));
1869a1805,1806
> m->m_pkthdr.rcvif = &sc->enif;
> sc->enif.if_ipackets++;
1871c1808,1809
< printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan);
---
> if (sc->debug & DBG_IPACKETS)
> en_dump_packet(sc, m);
1872a1811,1820
> #ifdef ENABLE_BPF
> BPF_MTAP(&sc->enif, m);
> #endif
> atm_input(&sc->enif, &ah, m,
> sc->rxslot[slot].rxhand);
> }
> }
> EN_WRAPADD(0, MID_DRQ_N, idx, 1);
> }
> sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */
1874,1878c1822,1829
< /*
< * note: now that txlaunch handles non-word aligned/sized requests
< * the only time you can safely set launch.nodma is if you've en_mfix()'d
< * the mbuf chain. this happens only if EN_NOTXDMA || !en_dma.
< */
---
> if (sc->need_drqs) {
> /* true if we had a DRQ shortage */
> sc->need_drqs = 0;
> DBG(sc, INTR, ("cleared need DRQ condition"));
> return (1);
> } else
> return (0);
> }
1880c1831,1845
< launch.nodma = (EN_NOTXDMA || !en_dma);
---
> /*
> * en_mget: get an mbuf chain that can hold totlen bytes and return it
> * (for recv). For the actual allocation totlen is rounded up to a multiple
> * of 4. We also ensure, that each mbuf has a multiple of 4 bytes.
> *
> * After this call the sum of all the m_len's in the chain will be totlen.
> * This is called at interrupt time, so we can't wait here.
> *
> * LOCK: any, not needed
> */
> static struct mbuf *
> en_mget(struct en_softc *sc, u_int pktlen)
> {
> struct mbuf *m, *tmp;
> u_int totlen, pad;
1882c1847,1848
< again:
---
> totlen = roundup(pktlen, sizeof(uint32_t));
> pad = totlen - pktlen;
1884,1886c1850,1857
< /*
< * get an mbuf waiting for DMA
< */
---
> /*
> * First get an mbuf with header. Keep space for a couple of
> * words at the begin.
> */
> /* called from interrupt context */
> MGETHDR(m, M_DONTWAIT, MT_DATA);
> if (m == NULL)
> return (NULL);
1888c1859,1864
< launch.t = sc->txslot[chan].q.ifq_head; /* peek at head of queue */
---
> m->m_pkthdr.rcvif = NULL;
> m->m_pkthdr.len = pktlen;
> m->m_len = EN_RX1BUF;
> MH_ALIGN(m, EN_RX1BUF);
> if (m->m_len >= totlen) {
> m->m_len = totlen;
1890,1895c1866,1867
< if (launch.t == NULL) {
< #ifdef EN_DEBUG
< printf("%s: tx%d: ...done!\n", sc->sc_dev.dv_xname, chan);
< #endif
< return; /* >>> exit here if no data waiting for DMA <<< */
< }
---
> } else {
> totlen -= m->m_len;
1897,1903c1869,1882
< /*
< * get flags, vci
< *
< * note: launch.need = # bytes we need to get on the card
< * dtqneed = # of DTQs we need for this packet
< * launch.mlen = # of bytes in in mbuf chain (<= launch.need)
< */
---
> /* called from interrupt context */
> tmp = m_getm(m, totlen, M_DONTWAIT, MT_DATA);
> if (tmp == NULL) {
> m_free(m);
> return (NULL);
> }
> tmp = m->m_next;
> /* m_getm could do this for us */
> while (tmp != NULL) {
> tmp->m_len = min(MCLBYTES, totlen);
> totlen -= tmp->m_len;
> tmp = tmp->m_next;
> }
> }
1905,1909c1884,1885
< ap = mtod(launch.t, struct atm_pseudohdr *);
< launch.atm_vci = ATM_PH_VCI(ap);
< launch.atm_flags = ATM_PH_FLAGS(ap);
< launch.aal = ((launch.atm_flags & ATM_PH_AAL5) != 0) ?
< MID_TBD_AAL5 : MID_TBD_NOAAL5;
---
> return (m);
> }
1911,1915c1887,1897
< /*
< * XXX: have to recompute the length again, even though we already did
< * it in en_start(). might as well compute dtqneed here as well, so
< * this isn't that bad.
< */
---
> /*
> * Argument for RX DMAMAP loader.
> */
> struct rxarg {
> struct en_softc *sc;
> struct mbuf *m;
> u_int pre_skip; /* number of bytes to skip at begin */
> u_int post_skip; /* number of bytes to skip at end */
> struct en_rxslot *slot; /* slot we are receiving on */
> int wait; /* wait for DRQ entries */
> };
1917,1923c1899,1919
< if ((launch.atm_flags & EN_OBHDR) == 0) {
< dtqneed = 1; /* header still needs to be added */
< launch.need = MID_TBD_SIZE; /* not includeded with mbuf */
< } else {
< dtqneed = 0; /* header on-board, dma with mbuf */
< launch.need = 0;
< }
---
> /*
> * Copy the segment table to the buffer for later use. And compute the
> * number of dma queue entries we need.
> *
> * LOCK: locked, needed
> */
> static void
> en_rxdma_load(void *uarg, bus_dma_segment_t *segs, int nseg,
> bus_size_t mapsize, int error)
> {
> struct rxarg *rx = uarg;
> struct en_softc *sc = rx->sc;
> struct en_rxslot *slot = rx->slot;
> u_int free; /* number of free DRQ entries */
> uint32_t cur; /* current buffer offset */
> uint32_t drq; /* DRQ entry pointer */
> uint32_t last_drq; /* where we have written last */
> u_int needalign, cnt, count, bcode;
> bus_addr_t addr;
> bus_size_t rest;
> int i;
1925,1936c1921,1924
< launch.mlen = 0;
< for (tmp = launch.t ; tmp != NULL ; tmp = tmp->m_next) {
< len = tmp->m_len;
< launch.mlen += len;
< cp = mtod(tmp, u_int8_t *);
< if (tmp == launch.t) {
< len -= sizeof(struct atm_pseudohdr); /* don't count this! */
< cp += sizeof(struct atm_pseudohdr);
< }
< launch.need += len;
< if (len == 0)
< continue; /* atm_pseudohdr alone in first mbuf */
---
> if (error != 0)
> return;
> if (nseg > EN_MAX_DMASEG)
> panic("too many DMA segments");
1938,1939c1926
< dtqneed += en_dqneed(sc, (caddr_t) cp, len, 1);
< }
---
> rx->wait = 0;
1941,1942c1928,1930
< if ((launch.need % sizeof(u_int32_t)) != 0)
< dtqneed++; /* need DTQ to FLUSH internal buffer */
---
> free = sc->drq_free;
> drq = sc->drq_us;
> cur = slot->cur;
1944,1950c1932
< if ((launch.atm_flags & EN_OBTRL) == 0) {
< if (launch.aal == MID_TBD_AAL5) {
< datalen = launch.need - MID_TBD_SIZE;
< launch.need += MID_PDU_SIZE; /* AAL5: need PDU tail */
< }
< dtqneed++; /* need to work on the end a bit */
< }
---
> last_drq = 0;
1952,1957c1934,1952
< /*
< * finish calculation of launch.need (need to figure out how much padding
< * we will need). launch.need includes MID_TBD_SIZE, but we need to
< * remove that to so we can round off properly. we have to add
< * MID_TBD_SIZE back in after calculating ncells.
< */
---
> /*
> * Local macro to add an entry to the receive DMA area. If there
> * are no entries left, return. Save the byte offset of the entry
> * in last_drq for later use.
> */
> #define PUT_DRQ_ENTRY(ENI, BCODE, COUNT, ADDR) \
> if (free == 0) { \
> EN_COUNT(sc->stats.rxdrqout); \
> rx->wait = 1; \
> return; \
> } \
> last_drq = drq; \
> en_write(sc, drq + 0, (ENI || !sc->is_adaptec) ? \
> MID_MK_RXQ_ENI(COUNT, slot->atm_vci, 0, BCODE) : \
> MID_MK_RXQ_ADP(COUNT, slot->atm_vci, 0, BCODE)); \
> en_write(sc, drq + 4, ADDR); \
> \
> EN_WRAPADD(MID_DRQOFF, MID_DRQEND, drq, 8); \
> free--;
1959,1961c1954,1967
< launch.need = roundup(launch.need - MID_TBD_SIZE, MID_ATMDATASZ);
< ncells = launch.need / MID_ATMDATASZ;
< launch.need += MID_TBD_SIZE;
---
> /*
> * Local macro to generate a DMA entry to DMA cnt bytes. Updates
> * the current buffer byte offset accordingly.
> */
> #define DO_DRQ(TYPE) do { \
> rest -= cnt; \
> EN_WRAPADD(slot->start, slot->stop, cur, cnt); \
> DBG(sc, SERV, ("rx%td: "TYPE" %u bytes, %ju left, cur %#x", \
> slot - sc->rxslot, cnt, (uintmax_t)rest, cur)); \
> \
> PUT_DRQ_ENTRY(1, bcode, count, addr); \
> \
> addr += cnt; \
> } while (0)
1963,1967c1969,1974
< if (launch.need > EN_TXSZ * 1024) {
< printf("%s: tx%d: packet larger than xmit buffer (%d > %d)\n",
< sc->sc_dev.dv_xname, chan, launch.need, EN_TXSZ * 1024);
< goto dequeue_drop;
< }
---
> /*
> * Skip the RBD at the beginning
> */
> if (rx->pre_skip > 0) {
> /* update DMA address */
> EN_WRAPADD(slot->start, slot->stop, cur, rx->pre_skip);
1969,1983c1976,1977
< /*
< * note: don't use the entire buffer space. if WRTX becomes equal
< * to RDTX, the transmitter stops assuming the buffer is empty! --kjc
< */
< if (launch.need >= sc->txslot[chan].bfree) {
< EN_COUNT(sc->txoutspace);
< #ifdef EN_DEBUG
< printf("%s: tx%d: out of transmit space\n", sc->sc_dev.dv_xname, chan);
< #endif
< return; /* >>> exit here if out of obmem buffer space <<< */
< }
<
< /*
< * ensure we have enough dtqs to go, if not, wait for more.
< */
---
> PUT_DRQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0);
> }
1985,1995c1979,1981
< if (launch.nodma) {
< dtqneed = 1;
< }
< if (dtqneed > sc->dtq_free) {
< sc->need_dtqs = 1;
< EN_COUNT(sc->txdtqout);
< #ifdef EN_DEBUG
< printf("%s: tx%d: out of transmit DTQs\n", sc->sc_dev.dv_xname, chan);
< #endif
< return; /* >>> exit here if out of dtqs <<< */
< }
---
> for (i = 0; i < nseg; i++, segs++) {
> addr = segs->ds_addr;
> rest = segs->ds_len;
1997,1999c1983,1984
< /*
< * it is a go, commit! dequeue mbuf start working on the xfer.
< */
---
> if (sc->is_adaptec) {
> /* adaptec card - simple */
2001,2005c1986,1990
< _IF_DEQUEUE(&sc->txslot[chan].q, tmp);
< #ifdef EN_DIAG
< if (launch.t != tmp)
< panic("en dequeue");
< #endif /* EN_DIAG */
---
> /* advance the on-card buffer pointer */
> EN_WRAPADD(slot->start, slot->stop, cur, rest);
> DBG(sc, SERV, ("rx%td: adp %ju bytes %#jx "
> "(cur now 0x%x)", slot - sc->rxslot,
> (uintmax_t)rest, (uintmax_t)addr, cur));
2007,2009c1992
< /*
< * launch!
< */
---
> PUT_DRQ_ENTRY(0, 0, rest, addr);
2011,2024c1994,1995
< EN_COUNT(sc->launch);
< ifp = &sc->enif;
< ifp->if_opackets++;
<
< if ((launch.atm_flags & EN_OBHDR) == 0) {
< EN_COUNT(sc->lheader);
< /* store tbd1/tbd2 in host byte order */
< launch.tbd1 = MID_TBD_MK1(launch.aal, sc->txspeed[launch.atm_vci], ncells);
< launch.tbd2 = MID_TBD_MK2(launch.atm_vci, 0, 0);
< }
< if ((launch.atm_flags & EN_OBTRL) == 0 && launch.aal == MID_TBD_AAL5) {
< EN_COUNT(sc->ltail);
< launch.pdu1 = MID_PDU_MK1(0, 0, datalen); /* host byte order */
< }
---
> continue;
> }
2026c1997,2015
< en_txlaunch(sc, chan, &launch);
---
> /*
> * do we need to do a DMA op to align to the maximum
> * burst? Note, that we are alway 32-bit aligned.
> */
> if (sc->alburst &&
> (needalign = (addr & sc->bestburstmask)) != 0) {
> /* compute number of bytes, words and code */
> cnt = sc->bestburstlen - needalign;
> if (cnt > rest)
> cnt = rest;
> count = cnt / sizeof(uint32_t);
> if (sc->noalbursts) {
> bcode = MIDDMA_WORD;
> } else {
> bcode = en_dmaplan[count].bcode;
> count = cnt >> en_dmaplan[count].divshift;
> }
> DO_DRQ("al_dma");
> }
2028,2037c2017,2023
< #if NBPF > 0
< if (ifp->if_bpf) {
< /*
< * adjust the top of the mbuf to skip the pseudo atm header
< * (and TBD, if present) before passing the packet to bpf,
< * restore it afterwards.
< */
< int size = sizeof(struct atm_pseudohdr);
< if (launch.atm_flags & EN_OBHDR)
< size += MID_TBD_SIZE;
---
> /* do we need to do a max-sized burst? */
> if (rest >= sc->bestburstlen) {
> count = rest >> sc->bestburstshift;
> cnt = count << sc->bestburstshift;
> bcode = sc->bestburstcode;
> DO_DRQ("best_dma");
> }
2039,2040c2025,2037
< launch.t->m_data += size;
< launch.t->m_len -= size;
---
> /* do we need to do a cleanup burst? */
> if (rest != 0) {
> cnt = rest;
> count = rest / sizeof(uint32_t);
> if (sc->noalbursts) {
> bcode = MIDDMA_WORD;
> } else {
> bcode = en_dmaplan[count].bcode;
> count = cnt >> en_dmaplan[count].divshift;
> }
> DO_DRQ("clean_dma");
> }
> }
2042c2039,2044
< BPF_MTAP(ifp, launch.t);
---
> /*
> * Skip stuff at the end
> */
> if (rx->post_skip > 0) {
> /* update DMA address */
> EN_WRAPADD(slot->start, slot->stop, cur, rx->post_skip);
2044,2050c2046,2047
< launch.t->m_data -= size;
< launch.t->m_len += size;
< }
< #endif /* NBPF > 0 */
< /*
< * do some housekeeping and get the next packet
< */
---
> PUT_DRQ_ENTRY(0, MIDDMA_JK, WORD_IDX(slot->start, cur), 0);
> }
2052,2054c2049,2051
< sc->txslot[chan].bfree -= launch.need;
< _IF_ENQUEUE(&sc->txslot[chan].indma, launch.t);
< goto again;
---
> /* record the end for the interrupt routine */
> sc->drq[MID_DRQ_A2REG(last_drq)] =
> EN_DQ_MK(slot - sc->rxslot, rx->m->m_pkthdr.len);
2056,2058c2053,2054
< /*
< * END of txdma loop!
< */
---
> /* set the end flag in the last descriptor */
> en_write(sc, last_drq + 0, SETQ_END(sc, en_read(sc, last_drq + 0)));
2060,2062c2056,2057
< /*
< * error handles
< */
---
> #undef PUT_DRQ_ENTRY
> #undef DO_DRQ
2064,2070c2059,2065
< dequeue_drop:
< _IF_DEQUEUE(&sc->txslot[chan].q, tmp);
< if (launch.t != tmp)
< panic("en dequeue drop");
< m_freem(launch.t);
< sc->txslot[chan].mbsize -= launch.mlen;
< goto again;
---
> /* commit */
> slot->cur = cur;
> sc->drq_free = free;
> sc->drq_us = drq;
>
> /* signal to card */
> en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_us));
2073d2067
<
2075c2069,2084
< * en_txlaunch: launch an mbuf into the dma pool!
---
> * en_service: handle a service interrupt
> *
> * Q: why do we need a software service list?
> *
> * A: if we remove a VCI from the hardware list and we find that we are
> * out of DRQs we must defer processing until some DRQs become free.
> * so we must remember to look at this RX VCI/slot later, but we can't
> * put it back on the hardware service list (since that isn't allowed).
> * so we instead save it on the software service list. it would be nice
> * if we could peek at the VCI on top of the hwservice list without removing
> * it, however this leads to a race condition: if we peek at it and
> * decide we are done with it new data could come in before we have a
> * chance to remove it from the hwslist. by the time we get it out of
> * the list the interrupt for the new data will be lost. oops!
> *
> * LOCK: locked, needed
2076a2086,2098
> static void
> en_service(struct en_softc *sc)
> {
> struct mbuf *m, *lastm;
> struct en_map *map;
> struct rxarg rx;
> uint32_t cur;
> uint32_t dstart; /* data start (as reported by card) */
> uint32_t rbd; /* receive buffer descriptor */
> uint32_t pdu; /* AAL5 trailer */
> int mlen;
> struct en_rxslot *slot;
> int error;
2078c2100
< STATIC void en_txlaunch(sc, chan, l)
---
> rx.sc = sc;
2080,2082c2102,2106
< struct en_softc *sc;
< int chan;
< struct en_launch *l;
---
> next_vci:
> if (sc->swsl_size == 0) {
> DBG(sc, SERV, ("en_service done"));
> return;
> }
2084,2090c2108,2111
< {
< struct mbuf *tmp;
< u_int32_t cur = sc->txslot[chan].cur,
< start = sc->txslot[chan].start,
< stop = sc->txslot[chan].stop,
< dma, *data, *datastop, count, bcode;
< int pad, addtail, need, len, needalign, cnt, end, mx;
---
> /*
> * get slot to service
> */
> rx.slot = slot = &sc->rxslot[sc->swslist[sc->swsl_head]];
2091a2113,2114
> KASSERT (sc->rxvc2slot[slot->atm_vci] == slot - sc->rxslot,
> ("en_service: rx slot/vci sync"));
2093,2110c2116,2121
< /*
< * vars:
< * need = # bytes card still needs (decr. to zero)
< * len = # of bytes left in current mbuf
< * cur = our current pointer
< * dma = last place we programmed into the DMA
< * data = pointer into data area of mbuf that needs to go next
< * cnt = # of bytes to transfer in this DTQ
< * bcode/count = DMA burst code, and chip's version of cnt
< *
< * a single buffer can require up to 5 DTQs depending on its size
< * and alignment requirements. the 5 possible requests are:
< * [1] 1, 2, or 3 byte DMA to align src data pointer to word boundary
< * [2] alburst DMA to align src data pointer to bestburstlen
< * [3] 1 or more bestburstlen DMAs
< * [4] clean up burst (to last word boundary)
< * [5] 1, 2, or 3 byte final clean up DMA
< */
---
> /*
> * determine our mode and if we've got any work to do
> */
> DBG(sc, SERV, ("rx%td: service vci=%d start/stop/cur=0x%x 0x%x "
> "0x%x", slot - sc->rxslot, slot->atm_vci,
> slot->start, slot->stop, slot->cur));
2112,2114c2123,2124
< need = l->need;
< dma = cur;
< addtail = (l->atm_flags & EN_OBTRL) == 0; /* add a tail? */
---
> same_vci:
> cur = slot->cur;
2116,2129c2126,2127
< #ifdef EN_DIAG
< if ((need - MID_TBD_SIZE) % MID_ATMDATASZ)
< printf("%s: tx%d: bogus trasmit needs (%d)\n", sc->sc_dev.dv_xname, chan,
< need);
< #endif
< #ifdef EN_DEBUG
< printf("%s: tx%d: launch mbuf %p! cur=0x%x[%d], need=%d, addtail=%d\n",
< sc->sc_dev.dv_xname, chan, l->t, cur, (cur-start)/4, need, addtail);
< count = EN_READ(sc, MIDX_PLACE(chan));
< printf(" HW: base_address=0x%x, size=%d, read=%d, descstart=%d\n",
< (u_int)MIDX_BASE(count), MIDX_SZ(count),
< (int)EN_READ(sc, MIDX_READPTR(chan)),
< (int)EN_READ(sc, MIDX_DESCSTART(chan)));
< #endif
---
> dstart = MIDV_DSTART(en_read(sc, MID_DST_RP(slot->atm_vci)));
> dstart = (dstart * sizeof(uint32_t)) + slot->start;
2131,2134c2129,2138
< /*
< * do we need to insert the TBD by hand?
< * note that tbd1/tbd2/pdu1 are in host byte order.
< */
---
> /* check to see if there is any data at all */
> if (dstart == cur) {
> EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1);
> /* remove from swslist */
> slot->oth_flags &= ~ENOTHER_SWSL;
> sc->swsl_size--;
> DBG(sc, SERV, ("rx%td: remove vci %d from swslist",
> slot - sc->rxslot, slot->atm_vci));
> goto next_vci;
> }
2136,2146c2140,2146
< if ((l->atm_flags & EN_OBHDR) == 0) {
< #ifdef EN_DEBUG
< printf("%s: tx%d: insert header 0x%x 0x%x\n", sc->sc_dev.dv_xname,
< chan, l->tbd1, l->tbd2);
< #endif
< EN_WRITE(sc, cur, l->tbd1);
< EN_WRAPADD(start, stop, cur, 4);
< EN_WRITE(sc, cur, l->tbd2);
< EN_WRAPADD(start, stop, cur, 4);
< need -= 8;
< }
---
> /*
> * figure out how many bytes we need
> * [mlen = # bytes to go in mbufs]
> */
> rbd = en_read(sc, cur);
> if (MID_RBD_ID(rbd) != MID_RBD_STDID)
> panic("en_service: id mismatch");
2148,2150c2148,2153
< /*
< * now do the mbufs...
< */
---
> if (rbd & MID_RBD_T) {
> mlen = 0; /* we've got trash */
> rx.pre_skip = MID_RBD_SIZE;
> rx.post_skip = 0;
> EN_COUNT(sc->stats.ttrash);
> DBG(sc, SERV, ("RX overflow lost %d cells!", MID_RBD_CNT(rbd)));
2152c2155,2159
< for (tmp = l->t ; tmp != NULL ; tmp = tmp->m_next) {
---
> } else if (!(slot->atm_flags & ATM_PH_AAL5)) {
> /* 1 cell (ick!) */
> mlen = MID_CHDR_SIZE + MID_ATMDATASZ;
> rx.pre_skip = MID_RBD_SIZE;
> rx.post_skip = 0;
2154,2160c2161,2162
< /* get pointer to data and length */
< data = mtod(tmp, u_int32_t *);
< len = tmp->m_len;
< if (tmp == l->t) {
< data += sizeof(struct atm_pseudohdr)/sizeof(u_int32_t);
< len -= sizeof(struct atm_pseudohdr);
< }
---
> } else {
> rx.pre_skip = MID_RBD_SIZE;
2162,2165c2164,2169
< /* now, determine if we should copy it */
< if (l->nodma || (len < EN_MINDMA &&
< (len % 4) == 0 && ((uintptr_t) (void *) data % 4) == 0 &&
< (cur % 4) == 0)) {
---
> /* get PDU trailer in correct byte order */
> pdu = cur + MID_RBD_CNT(rbd) * MID_ATMDATASZ +
> MID_RBD_SIZE - MID_PDU_SIZE;
> if (pdu >= slot->stop)
> pdu -= EN_RXSZ * 1024;
> pdu = en_read(sc, pdu);
2167,2189c2171,2176
< /*
< * roundup len: the only time this will change the value of len
< * is when l->nodma is true, tmp is the last mbuf, and there is
< * a non-word number of bytes to transmit. in this case it is
< * safe to round up because we've en_mfix'd the mbuf (so the first
< * byte is word aligned there must be enough free bytes at the end
< * to round off to the next word boundary)...
< */
< len = roundup(len, sizeof(u_int32_t));
< datastop = data + (len / sizeof(u_int32_t));
< /* copy loop: preserve byte order!!! use WRITEDAT */
< while (data != datastop) {
< EN_WRITEDAT(sc, cur, *data);
< data++;
< EN_WRAPADD(start, stop, cur, 4);
< }
< need -= len;
< #ifdef EN_DEBUG
< printf("%s: tx%d: copied %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, len, need, cur);
< #endif
< continue; /* continue on to next mbuf */
< }
---
> if (MID_RBD_CNT(rbd) * MID_ATMDATASZ <
> MID_PDU_LEN(pdu)) {
> if_printf(&sc->enif, "invalid AAL5 length\n");
> rx.post_skip = MID_RBD_CNT(rbd) * MID_ATMDATASZ;
> mlen = 0;
> sc->enif.if_ierrors++;
2191,2198c2178,2182
< /* going to do DMA, first make sure the dtq is in sync. */
< if (dma != cur) {
< EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0, 0, 0);
< #ifdef EN_DEBUG
< printf("%s: tx%d: dtq_sync: advance pointer to %d\n",
< sc->sc_dev.dv_xname, chan, cur);
< #endif
< }
---
> } else if (rbd & MID_RBD_CRCERR) {
> if_printf(&sc->enif, "CRC error\n");
> rx.post_skip = MID_RBD_CNT(rbd) * MID_ATMDATASZ;
> mlen = 0;
> sc->enif.if_ierrors++;
2200,2204c2184,2188
< /*
< * if this is the last buffer, and it looks like we are going to need to
< * flush the internal buffer, can we extend the length of this mbuf to
< * avoid the FLUSH?
< */
---
> } else {
> mlen = MID_PDU_LEN(pdu);
> rx.post_skip = MID_RBD_CNT(rbd) * MID_ATMDATASZ - mlen;
> }
> }
2206,2212c2190,2221
< if (tmp->m_next == NULL) {
< cnt = (need - len) % sizeof(u_int32_t);
< if (cnt && M_TRAILINGSPACE(tmp) >= cnt)
< len += cnt; /* pad for FLUSH */
< }
<
< #if !defined(MIDWAY_ENIONLY)
---
> /*
> * now allocate mbufs for mlen bytes of data, if out of mbufs, trash all
> *
> * notes:
> * 1. it is possible that we've already allocated an mbuf for this pkt
> * but ran out of DRQs, in which case we saved the allocated mbuf
> * on "q".
> * 2. if we save an buf in "q" we store the "cur" (pointer) in the
> * buf as an identity (that we can check later).
> * 3. after this block of code, if m is still NULL then we ran out of
> * mbufs
> */
> _IF_DEQUEUE(&slot->q, m);
> if (m != NULL) {
> if (m->m_pkthdr.csum_data != cur) {
> /* wasn't ours */
> DBG(sc, SERV, ("rx%td: q'ed buf %p not ours",
> slot - sc->rxslot, m));
> _IF_PREPEND(&slot->q, m);
> m = NULL;
> EN_COUNT(sc->stats.rxqnotus);
> } else {
> EN_COUNT(sc->stats.rxqus);
> DBG(sc, SERV, ("rx%td: recovered q'ed buf %p",
> slot - sc->rxslot, m));
> }
> }
> if (mlen == 0 && m != NULL) {
> /* should not happen */
> m_freem(m);
> m = NULL;
> }
2214,2216c2223,2232
< /*
< * the adaptec DMA engine is smart and handles everything for us.
< */
---
> if (mlen != 0 && m == NULL) {
> m = en_mget(sc, mlen);
> if (m == NULL) {
> rx.post_skip += mlen;
> mlen = 0;
> EN_COUNT(sc->stats.rxmbufout);
> DBG(sc, SERV, ("rx%td: out of mbufs",
> slot - sc->rxslot));
> } else
> rx.post_skip -= roundup(mlen, sizeof(uint32_t)) - mlen;
2218,2233c2234,2236
< if (sc->is_adaptec) {
< /* need to DMA "len" bytes out to card */
< need -= len;
< EN_WRAPADD(start, stop, cur, len);
< #ifdef EN_DEBUG
< printf("%s: tx%d: adp_dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, len, need, cur);
< #endif
< end = (need == 0) ? MID_DMA_END : 0;
< EN_DTQADD(sc, len, chan, 0, vtophys(data), l->mlen, end);
< if (end)
< goto done;
< dma = cur; /* update dma pointer */
< continue;
< }
< #endif /* !MIDWAY_ENIONLY */
---
> DBG(sc, SERV, ("rx%td: allocate buf %p, mlen=%d",
> slot - sc->rxslot, m, mlen));
> }
2235c2238,2240
< #if !defined(MIDWAY_ADPONLY)
---
> DBG(sc, SERV, ("rx%td: VCI %d, rbuf %p, mlen %d, skip %u/%u",
> slot - sc->rxslot, slot->atm_vci, m, mlen, rx.pre_skip,
> rx.post_skip));
2237,2239c2242,2256
< /*
< * the ENI DMA engine is not so smart and need more help from us
< */
---
> if (m != NULL) {
> /* M_NOWAIT - called from interrupt context */
> map = uma_zalloc_arg(sc->map_zone, sc, M_NOWAIT);
> if (map == NULL || !(map->flags & ENMAP_ALLOC)) {
> rx.post_skip += mlen;
> m_freem(m);
> DBG(sc, SERV, ("rx%td: out of maps",
> slot - sc->rxslot));
> if (map->map != NULL)
> uma_zfree(sc->map_zone, map);
> goto skip;
> }
> rx.m = m;
> error = bus_dmamap_load_mbuf(sc->txtag, map->map, m,
> en_rxdma_load, &rx, 0);
2241,2266c2258,2264
< /* do we need to do a DMA op to align to word boundary? */
< needalign = (uintptr_t) (void *) data % sizeof(u_int32_t);
< if (needalign) {
< EN_COUNT(sc->headbyte);
< cnt = sizeof(u_int32_t) - needalign;
< if (cnt == 2 && len >= cnt) {
< count = 1;
< bcode = MIDDMA_2BYTE;
< } else {
< cnt = min(cnt, len); /* prevent overflow */
< count = cnt;
< bcode = MIDDMA_BYTE;
< }
< need -= cnt;
< EN_WRAPADD(start, stop, cur, cnt);
< #ifdef EN_DEBUG
< printf("%s: tx%d: small al_dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, cnt, need, cur);
< #endif
< len -= cnt;
< end = (need == 0) ? MID_DMA_END : 0;
< EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
< if (end)
< goto done;
< data = (u_int32_t *) ((u_char *)data + cnt);
< }
---
> if (error != 0) {
> if_printf(&sc->enif, "loading RX map failed "
> "%d\n", error);
> uma_zfree(sc->map_zone, map);
> m_freem(m);
> rx.post_skip += mlen;
> goto skip;
2268,2295c2266,2267
< /* do we need to do a DMA op to align? */
< if (sc->alburst &&
< (needalign = (((uintptr_t) (void *) data) & sc->bestburstmask)) != 0
< && len >= sizeof(u_int32_t)) {
< cnt = sc->bestburstlen - needalign;
< mx = len & ~(sizeof(u_int32_t)-1); /* don't go past end */
< if (cnt > mx) {
< cnt = mx;
< count = cnt / sizeof(u_int32_t);
< bcode = MIDDMA_WORD;
< } else {
< count = cnt / sizeof(u_int32_t);
< bcode = en_dmaplan[count].bcode;
< count = cnt >> en_dmaplan[count].divshift;
< }
< need -= cnt;
< EN_WRAPADD(start, stop, cur, cnt);
< #ifdef EN_DEBUG
< printf("%s: tx%d: al_dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, cnt, need, cur);
< #endif
< len -= cnt;
< end = (need == 0) ? MID_DMA_END : 0;
< EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
< if (end)
< goto done;
< data = (u_int32_t *) ((u_char *)data + cnt);
< }
---
> }
> map->flags |= ENMAP_LOADED;
2297,2314c2269,2271
< /* do we need to do a max-sized burst? */
< if (len >= sc->bestburstlen) {
< count = len >> sc->bestburstshift;
< cnt = count << sc->bestburstshift;
< bcode = sc->bestburstcode;
< need -= cnt;
< EN_WRAPADD(start, stop, cur, cnt);
< #ifdef EN_DEBUG
< printf("%s: tx%d: best_dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, cnt, need, cur);
< #endif
< len -= cnt;
< end = (need == 0) ? MID_DMA_END : 0;
< EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
< if (end)
< goto done;
< data = (u_int32_t *) ((u_char *)data + cnt);
< }
---
> if (rx.wait) {
> /* out of DRQs - wait */
> uma_zfree(sc->map_zone, map);
2316,2334c2273,2275
< /* do we need to do a cleanup burst? */
< cnt = len & ~(sizeof(u_int32_t)-1);
< if (cnt) {
< count = cnt / sizeof(u_int32_t);
< bcode = en_dmaplan[count].bcode;
< count = cnt >> en_dmaplan[count].divshift;
< need -= cnt;
< EN_WRAPADD(start, stop, cur, cnt);
< #ifdef EN_DEBUG
< printf("%s: tx%d: cleanup_dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, cnt, need, cur);
< #endif
< len -= cnt;
< end = (need == 0) ? MID_DMA_END : 0;
< EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
< if (end)
< goto done;
< data = (u_int32_t *) ((u_char *)data + cnt);
< }
---
> m->m_pkthdr.csum_data = cur;
> _IF_ENQUEUE(&slot->q, m);
> EN_COUNT(sc->stats.rxdrqout);
2336,2356c2277,2278
< /* any word fragments left? */
< if (len) {
< EN_COUNT(sc->tailbyte);
< if (len == 2) {
< count = 1;
< bcode = MIDDMA_2BYTE; /* use 2byte mode */
< } else {
< count = len;
< bcode = MIDDMA_BYTE; /* use 1 byte mode */
< }
< need -= len;
< EN_WRAPADD(start, stop, cur, len);
< #ifdef EN_DEBUG
< printf("%s: tx%d: byte cleanup_dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, len, need, cur);
< #endif
< end = (need == 0) ? MID_DMA_END : 0;
< EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end);
< if (end)
< goto done;
< }
---
> sc->need_drqs = 1; /* flag condition */
> return;
2358,2359c2280,2282
< dma = cur; /* update dma pointer */
< #endif /* !MIDWAY_ADPONLY */
---
> }
> (void)m_length(m, &lastm);
> lastm->m_len -= roundup(mlen, sizeof(uint32_t)) - mlen;
2361c2284,2285
< } /* next mbuf, please */
---
> m->m_pkthdr.rcvif = (void *)map;
> _IF_ENQUEUE(&slot->indma, m);
2363,2375c2287,2301
< /*
< * all mbuf data has been copied out to the obmem (or set up to be DMAd).
< * if the trailer or padding needs to be put in, do it now.
< *
< * NOTE: experimental results reveal the following fact:
< * if you DMA "X" bytes to the card, where X is not a multiple of 4,
< * then the card will internally buffer the last (X % 4) bytes (in
< * hopes of getting (4 - (X % 4)) more bytes to make a complete word).
< * it is imporant to make sure we don't leave any important data in
< * this internal buffer because it is discarded on the last (end) DTQ.
< * one way to do this is to DMA in (4 - (X % 4)) more bytes to flush
< * the darn thing out.
< */
---
> /* get next packet in this slot */
> goto same_vci;
> }
> skip:
> /*
> * Here we end if we should drop the packet from the receive buffer.
> * The number of bytes to drop is in fill. We can do this with on
> * JK entry. If we don't even have that one - wait.
> */
> if (sc->drq_free == 0) {
> sc->need_drqs = 1; /* flag condition */
> return;
> }
> rx.post_skip += rx.pre_skip;
> DBG(sc, SERV, ("rx%td: skipping %u", slot - sc->rxslot, rx.post_skip));
2377c2303,2304
< if (addtail) {
---
> /* advance buffer address */
> EN_WRAPADD(slot->start, slot->stop, cur, rx.post_skip);
2379,2394c2306,2317
< pad = need % sizeof(u_int32_t);
< if (pad) {
< /*
< * FLUSH internal data buffer. pad out with random data from the front
< * of the mbuf chain...
< */
< bcode = (sc->is_adaptec) ? 0 : MIDDMA_BYTE;
< EN_COUNT(sc->tailflush);
< EN_WRAPADD(start, stop, cur, pad);
< EN_DTQADD(sc, pad, chan, bcode, vtophys(l->t->m_data), 0, 0);
< need -= pad;
< #ifdef EN_DEBUG
< printf("%s: tx%d: pad/FLUSH dma %d bytes (%d left, cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, pad, need, cur);
< #endif
< }
---
> /* write DRQ entry */
> if (sc->is_adaptec)
> en_write(sc, sc->drq_us,
> MID_MK_RXQ_ADP(WORD_IDX(slot->start, cur),
> slot->atm_vci, MID_DMA_END, MIDDMA_JK));
> else
> en_write(sc, sc->drq_us,
> MID_MK_RXQ_ENI(WORD_IDX(slot->start, cur),
> slot->atm_vci, MID_DMA_END, MIDDMA_JK));
> en_write(sc, sc->drq_us + 4, 0);
> EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_us, 8);
> sc->drq_free--;
2396,2412c2319,2321
< /* copy data */
< pad = need / sizeof(u_int32_t); /* round *down* */
< if (l->aal == MID_TBD_AAL5)
< pad -= 2;
< #ifdef EN_DEBUG
< printf("%s: tx%d: padding %d bytes (cur now 0x%x)\n",
< sc->sc_dev.dv_xname, chan, (int)(pad * sizeof(u_int32_t)), cur);
< #endif
< while (pad--) {
< EN_WRITEDAT(sc, cur, 0); /* no byte order issues with zero */
< EN_WRAPADD(start, stop, cur, 4);
< }
< if (l->aal == MID_TBD_AAL5) {
< EN_WRITE(sc, cur, l->pdu1); /* in host byte order */
< EN_WRAPADD(start, stop, cur, 8);
< }
< }
---
> /* signal to RX interrupt */
> sc->drq[MID_DRQ_A2REG(sc->drq_us)] = EN_DQ_MK(slot - sc->rxslot, 0);
> slot->cur = cur;
2414,2419c2323,2324
< if (addtail || dma != cur) {
< /* write final descritor */
< EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0,
< l->mlen, MID_DMA_END);
< /* dma = cur; */ /* not necessary since we are done */
< }
---
> /* signal to card */
> en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_us));
2421,2429c2326
< done:
< /* update current pointer */
< sc->txslot[chan].cur = cur;
< #ifdef EN_DEBUG
< printf("%s: tx%d: DONE! cur now = 0x%x\n",
< sc->sc_dev.dv_xname, chan, cur);
< #endif
<
< return;
---
> goto same_vci;
2432d2328
<
2434a2331,2332
> *
> * LOCK: unlocked, needed
2436,2440c2334,2335
<
< EN_INTR_TYPE en_intr(arg)
<
< void *arg;
<
---
> void
> en_intr(void *arg)
2442,2447c2337,2339
< struct en_softc *sc = (struct en_softc *) arg;
< struct mbuf *m;
< struct atm_pseudohdr ah;
< struct ifnet *ifp;
< u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq;
< int lcv, idx, need_softserv = 0;
---
> struct en_softc *sc = arg;
> uint32_t reg, kick, mask;
> int lcv, need_softserv;
2449c2341
< reg = EN_READ(sc, MID_INTACK);
---
> EN_LOCK(sc);
2451,2452c2343,2344
< if ((reg & MID_INT_ANY) == 0)
< EN_INTR_RET(0); /* not us */
---
> reg = en_read(sc, MID_INTACK);
> DBG(sc, INTR, ("interrupt=0x%b", reg, MID_INTBITS));
2454,2456c2346,2349
< #ifdef EN_DEBUG
< printf("%s: interrupt=0x%b\n", sc->sc_dev.dv_xname, reg, MID_INTBITS);
< #endif
---
> if ((reg & MID_INT_ANY) == 0) {
> EN_UNLOCK(sc);
> return;
> }
2458,2464c2351,2356
< /*
< * unexpected errors that need a reset
< */
<
< if ((reg & (MID_INT_IDENT|MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_SUNI)) != 0) {
< printf("%s: unexpected interrupt=0x%b, resetting card\n",
< sc->sc_dev.dv_xname, reg, MID_INTBITS);
---
> /*
> * unexpected errors that need a reset
> */
> if ((reg & (MID_INT_IDENT | MID_INT_LERR | MID_INT_DMA_ERR)) != 0) {
> if_printf(&sc->enif, "unexpected interrupt=0x%b, resetting\n",
> reg, MID_INTBITS);
2467,2471c2359
< #ifdef __FreeBSD__
< Debugger("en: unexpected error");
< #else
< Debugger();
< #endif
---
> Debugger("en: unexpected error");
2473c2361
< sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */
---
> sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */
2475,2476c2363,2364
< en_reset(sc);
< en_init(sc);
---
> en_reset_ul(sc);
> en_init(sc);
2478,2479c2366,2368
< EN_INTR_RET(1); /* for us */
< }
---
> EN_UNLOCK(sc);
> return;
> }
2481,2505c2370,2373
< /*******************
< * xmit interrupts *
< ******************/
<
< kick = 0; /* bitmask of channels to kick */
< if (reg & MID_INT_TX) { /* TX done! */
<
< /*
< * check for tx complete, if detected then this means that some space
< * has come free on the card. we must account for it and arrange to
< * kick the channel to life (in case it is stalled waiting on the card).
< */
< for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) {
< if (reg & MID_TXCHAN(lcv)) {
< kick = kick | mask; /* want to kick later */
< val = EN_READ(sc, MIDX_READPTR(lcv)); /* current read pointer */
< val = (val * sizeof(u_int32_t)) + sc->txslot[lcv].start;
< /* convert to offset */
< if (val > sc->txslot[lcv].cur)
< sc->txslot[lcv].bfree = val - sc->txslot[lcv].cur;
< else
< sc->txslot[lcv].bfree = (val + (EN_TXSZ*1024)) - sc->txslot[lcv].cur;
< #ifdef EN_DEBUG
< printf("%s: tx%d: trasmit done. %d bytes now free in buffer\n",
< sc->sc_dev.dv_xname, lcv, sc->txslot[lcv].bfree);
---
> #if 0
> if (reg & MID_INT_SUNI)
> if_printf(&sc->enif, "interrupt from SUNI (probably carrier "
> "change)\n");
2507,2509d2374
< }
< }
< }
2511c2376,2378
< if (reg & MID_INT_DMA_TX) { /* TX DMA done! */
---
> kick = 0;
> if (reg & MID_INT_TX)
> kick |= en_intr_tx(sc, reg);
2513,2545c2380,2381
< /*
< * check for TX DMA complete, if detected then this means that some DTQs
< * are now free. it also means some indma mbufs can be freed.
< * if we needed DTQs, kick all channels.
< */
< val = EN_READ(sc, MID_DMA_RDTX); /* chip's current location */
< idx = MID_DTQ_A2REG(sc->dtq_chip);/* where we last saw chip */
< if (sc->need_dtqs) {
< kick = MID_NTX_CH - 1; /* assume power of 2, kick all! */
< sc->need_dtqs = 0; /* recalculated in "kick" loop below */
< #ifdef EN_DEBUG
< printf("%s: cleared need DTQ condition\n", sc->sc_dev.dv_xname);
< #endif
< }
< while (idx != val) {
< sc->dtq_free++;
< if ((dtq = sc->dtq[idx]) != 0) {
< sc->dtq[idx] = 0; /* don't forget to zero it out when done */
< slot = EN_DQ_SLOT(dtq);
< _IF_DEQUEUE(&sc->txslot[slot].indma, m);
< if (!m) panic("enintr: dtqsync");
< sc->txslot[slot].mbsize -= EN_DQ_LEN(dtq);
< #ifdef EN_DEBUG
< printf("%s: tx%d: free %d dma bytes, mbsize now %d\n",
< sc->sc_dev.dv_xname, slot, EN_DQ_LEN(dtq),
< sc->txslot[slot].mbsize);
< #endif
< m_freem(m);
< }
< EN_WRAPADD(0, MID_DTQ_N, idx, 1);
< };
< sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */
< }
---
> if (reg & MID_INT_DMA_TX)
> kick |= en_intr_tx_dma(sc);
2546a2383,2391
> /*
> * kick xmit channels as needed.
> */
> if (kick) {
> DBG(sc, INTR, ("tx kick mask = 0x%x", kick));
> for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2)
> if ((kick & mask) && _IF_QLEN(&sc->txslot[lcv].q) != 0)
> en_txdma(sc, &sc->txslot[lcv]);
> }
2548,2550c2393,2395
< /*
< * kick xmit channels as needed
< */
---
> need_softserv = 0;
> if (reg & MID_INT_DMA_RX)
> need_softserv |= en_intr_rx_dma(sc);
2552,2561c2397,2398
< if (kick) {
< #ifdef EN_DEBUG
< printf("%s: tx kick mask = 0x%x\n", sc->sc_dev.dv_xname, kick);
< #endif
< for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) {
< if ((kick & mask) && sc->txslot[lcv].q.ifq_head) {
< en_txdma(sc, lcv); /* kick it! */
< }
< } /* for each slot */
< } /* if kick */
---
> if (reg & MID_INT_SERVICE)
> need_softserv |= en_intr_service(sc);
2562a2400,2401
> if (need_softserv)
> en_service(sc);
2564,2566c2403,2412
< /*******************
< * recv interrupts *
< ******************/
---
> /*
> * keep our stats
> */
> if (reg & MID_INT_DMA_OVR) {
> EN_COUNT(sc->stats.dmaovr);
> DBG(sc, INTR, ("MID_INT_DMA_OVR"));
> }
> reg = en_read(sc, MID_STAT);
> sc->stats.otrash += MID_OTRASH(reg);
> sc->stats.vtrash += MID_VTRASH(reg);
2568,2570c2414,2415
< /*
< * check for RX DMA complete, and pass the data "upstairs"
< */
---
> EN_UNLOCK(sc);
> }
2572,2613c2417,2420
< if (reg & MID_INT_DMA_RX) {
< val = EN_READ(sc, MID_DMA_RDRX); /* chip's current location */
< idx = MID_DRQ_A2REG(sc->drq_chip);/* where we last saw chip */
< while (idx != val) {
< sc->drq_free++;
< if ((drq = sc->drq[idx]) != 0) {
< sc->drq[idx] = 0; /* don't forget to zero it out when done */
< slot = EN_DQ_SLOT(drq);
< if (EN_DQ_LEN(drq) == 0) { /* "JK" trash DMA? */
< m = NULL;
< } else {
< _IF_DEQUEUE(&sc->rxslot[slot].indma, m);
< if (!m)
< panic("enintr: drqsync: %s: lost mbuf in slot %d!",
< sc->sc_dev.dv_xname, slot);
< }
< /* do something with this mbuf */
< if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { /* drain? */
< if (m)
< m_freem(m);
< vci = sc->rxslot[slot].atm_vci;
< if (sc->rxslot[slot].indma.ifq_head == NULL &&
< sc->rxslot[slot].q.ifq_head == NULL &&
< (EN_READ(sc, MID_VC(vci)) & MIDV_INSERVICE) == 0 &&
< (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) {
< sc->rxslot[slot].oth_flags = ENOTHER_FREE; /* done drain */
< sc->rxslot[slot].atm_vci = RX_NONE;
< sc->rxvc2slot[vci] = RX_NONE;
< #ifdef EN_DEBUG
< printf("%s: rx%d: VCI %d now free\n", sc->sc_dev.dv_xname,
< slot, vci);
< #endif
< }
< } else if (m != NULL) {
< ATM_PH_FLAGS(&ah) = sc->rxslot[slot].atm_flags;
< ATM_PH_VPI(&ah) = 0;
< ATM_PH_SETVCI(&ah, sc->rxslot[slot].atm_vci);
< #ifdef EN_DEBUG
< printf("%s: rx%d: rxvci%d: atm_input, mbuf %p, len %d, hand %p\n",
< sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m,
< EN_DQ_LEN(drq), sc->rxslot[slot].rxhand);
< #endif
---
> /*********************************************************************/
> /*
> * Probing the DMA brokeness of the card
> */
2615,2616c2422,2432
< ifp = &sc->enif;
< ifp->if_ipackets++;
---
> /*
> * Physical address load helper function for DMA probe
> *
> * LOCK: unlocked, not needed
> */
> static void
> en_dmaprobe_load(void *uarg, bus_dma_segment_t *segs, int nseg, int error)
> {
> if (error == 0)
> *(bus_addr_t *)uarg = segs[0].ds_addr;
> }
2618,2621c2434,2449
< #if NBPF > 0
< if (ifp->if_bpf)
< BPF_MTAP(ifp, m);
< #endif
---
> /*
> * en_dmaprobe: helper function for en_attach.
> *
> * see how the card handles DMA by running a few DMA tests. we need
> * to figure out the largest number of bytes we can DMA in one burst
> * ("bestburstlen"), and if the starting address for a burst needs to
> * be aligned on any sort of boundary or not ("alburst").
> *
> * Things turn out more complex than that, because on my (harti) brand
> * new motherboard (2.4GHz) we can do 64byte aligned DMAs, but everything
> * we more than 4 bytes fails (with an RX DMA timeout) for physical
> * addresses that end with 0xc. Therefor we search not only the largest
> * burst that is supported (hopefully 64) but also check what is the largerst
> * unaligned supported size. If that appears to be lesser than 4 words,
> * set the noalbursts flag. That will be set only if also alburst is set.
> */
2623,2624c2451,2464
< atm_input(ifp, &ah, m, sc->rxslot[slot].rxhand);
< }
---
> /*
> * en_dmaprobe_doit: do actual testing for the DMA test.
> * Cycle through all bursts sizes from 8 up to 64 and try whether it works.
> * Return the largest one that works.
> *
> * LOCK: unlocked, not needed
> */
> static int
> en_dmaprobe_doit(struct en_softc *sc, uint8_t *sp, bus_addr_t psp)
> {
> uint8_t *dp = sp + MIDDMA_MAXBURST;
> bus_addr_t pdp = psp + MIDDMA_MAXBURST;
> int lcv, retval = 4, cnt;
> uint32_t reg, bcode, midvloc;
2626,2629c2466,2468
< }
< EN_WRAPADD(0, MID_DRQ_N, idx, 1);
< };
< sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */
---
> if (sc->en_busreset)
> sc->en_busreset(sc);
> en_write(sc, MID_RESID, 0x0); /* reset card before touching RAM */
2631,2638c2470,2479
< if (sc->need_drqs) { /* true if we had a DRQ shortage */
< need_softserv = 1;
< sc->need_drqs = 0;
< #ifdef EN_DEBUG
< printf("%s: cleared need DRQ condition\n", sc->sc_dev.dv_xname);
< #endif
< }
< }
---
> /*
> * set up a 1k buffer at MID_BUFOFF
> */
> midvloc = ((MID_BUFOFF - MID_RAMOFF) / sizeof(uint32_t))
> >> MIDV_LOCTOPSHFT;
> en_write(sc, MIDX_PLACE(0), MIDX_MKPLACE(en_k2sz(1), midvloc));
> en_write(sc, MID_VC(0), (midvloc << MIDV_LOCSHIFT)
> | (en_k2sz(1) << MIDV_SZSHIFT) | MIDV_TRASH);
> en_write(sc, MID_DST_RP(0), 0);
> en_write(sc, MID_WP_ST_CNT(0), 0);
2640,2642c2481,2483
< /*
< * handle service interrupts
< */
---
> /* set up sample data */
> for (lcv = 0 ; lcv < MIDDMA_MAXBURST; lcv++)
> sp[lcv] = lcv + 1;
2644,2645c2485,2486
< if (reg & MID_INT_SERVICE) {
< chip = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE));
---
> /* enable DMA (only) */
> en_write(sc, MID_MAST_CSR, MID_MCSR_ENDMA);
2647c2488,2489
< while (sc->hwslistp != chip) {
---
> sc->drq_chip = MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX));
> sc->dtq_chip = MID_DTQ_REG2A(en_read(sc, MID_DMA_RDTX));
2649,2662c2491,2501
< /* fetch and remove it from hardware service list */
< vci = EN_READ(sc, sc->hwslistp);
< EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4);/* advance hw ptr */
< slot = sc->rxvc2slot[vci];
< if (slot == RX_NONE) {
< #ifdef EN_DEBUG
< printf("%s: unexpected rx interrupt on VCI %d\n",
< sc->sc_dev.dv_xname, vci);
< #endif
< EN_WRITE(sc, MID_VC(vci), MIDV_TRASH); /* rx off, damn it! */
< continue; /* next */
< }
< EN_WRITE(sc, MID_VC(vci), sc->rxslot[slot].mode); /* remove from hwsl */
< EN_COUNT(sc->hwpull);
---
> /*
> * try it now . . . DMA it out, then DMA it back in and compare
> *
> * note: in order to get the dma stuff to reverse directions it wants
> * the "end" flag set! since we are not dma'ing valid data we may
> * get an ident mismatch interrupt (which we will ignore).
> */
> DBG(sc, DMA, ("test sp=%p/%#lx, dp=%p/%#lx",
> sp, (u_long)psp, dp, (u_long)pdp));
> for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) {
> DBG(sc, DMA, ("test lcv=%d", lcv));
2664,2666c2503,2506
< #ifdef EN_DEBUG
< printf("%s: pulled VCI %d off hwslist\n", sc->sc_dev.dv_xname, vci);
< #endif
---
> /* zero SRAM and dest buffer */
> bus_space_set_region_4(sc->en_memt, sc->en_base,
> MID_BUFOFF, 0, 1024 / 4);
> bzero(dp, MIDDMA_MAXBURST);
2668,2681c2508
< /* add it to the software service list (if needed) */
< if ((sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) {
< EN_COUNT(sc->swadd);
< need_softserv = 1;
< sc->rxslot[slot].oth_flags |= ENOTHER_SWSL;
< sc->swslist[sc->swsl_tail] = slot;
< EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1);
< sc->swsl_size++;
< #ifdef EN_DEBUG
< printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci);
< #endif
< }
< };
< }
---
> bcode = en_sz2b(lcv);
2683,2685c2510,2519
< /*
< * now service (function too big to include here)
< */
---
> /* build lcv-byte-DMA x NBURSTS */
> if (sc->is_adaptec)
> en_write(sc, sc->dtq_chip,
> MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0));
> else
> en_write(sc, sc->dtq_chip,
> MID_MK_TXQ_ENI(1, 0, MID_DMA_END, bcode));
> en_write(sc, sc->dtq_chip + 4, psp);
> EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
> en_write(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip));
2687,2688c2521,2534
< if (need_softserv)
< en_service(sc);
---
> cnt = 1000;
> while ((reg = en_readx(sc, MID_DMA_RDTX)) !=
> MID_DTQ_A2REG(sc->dtq_chip)) {
> DELAY(1);
> if (--cnt == 0) {
> DBG(sc, DMA, ("unexpected timeout in tx "
> "DMA test\n alignment=0x%lx, burst size=%d"
> ", dma addr reg=%#x, rdtx=%#x, stat=%#x\n",
> (u_long)sp & 63, lcv,
> en_read(sc, MID_DMA_ADDR), reg,
> en_read(sc, MID_INTSTAT)));
> return (retval);
> }
> }
2690,2692c2536,2543
< /*
< * keep our stats
< */
---
> reg = en_read(sc, MID_INTACK);
> if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) {
> DBG(sc, DMA, ("unexpected status in tx DMA test: %#x\n",
> reg));
> return (retval);
> }
> /* re-enable DMA (only) */
> en_write(sc, MID_MAST_CSR, MID_MCSR_ENDMA);
2694,2704c2545
< if (reg & MID_INT_DMA_OVR) {
< EN_COUNT(sc->dmaovr);
< #ifdef EN_DEBUG
< printf("%s: MID_INT_DMA_OVR\n", sc->sc_dev.dv_xname);
< #endif
< }
< reg = EN_READ(sc, MID_STAT);
< #ifdef EN_STAT
< sc->otrash += MID_OTRASH(reg);
< sc->vtrash += MID_VTRASH(reg);
< #endif
---
> /* "return to sender..." address is known ... */
2706c2547,2582
< EN_INTR_RET(1); /* for us */
---
> /* build lcv-byte-DMA x NBURSTS */
> if (sc->is_adaptec)
> en_write(sc, sc->drq_chip,
> MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0));
> else
> en_write(sc, sc->drq_chip,
> MID_MK_RXQ_ENI(1, 0, MID_DMA_END, bcode));
> en_write(sc, sc->drq_chip + 4, pdp);
> EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
> en_write(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
> cnt = 1000;
> while ((reg = en_readx(sc, MID_DMA_RDRX)) !=
> MID_DRQ_A2REG(sc->drq_chip)) {
> DELAY(1);
> cnt--;
> if (--cnt == 0) {
> DBG(sc, DMA, ("unexpected timeout in rx "
> "DMA test, rdrx=%#x\n", reg));
> return (retval);
> }
> }
> reg = en_read(sc, MID_INTACK);
> if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) {
> DBG(sc, DMA, ("unexpected status in rx DMA "
> "test: 0x%x\n", reg));
> return (retval);
> }
> if (bcmp(sp, dp, lcv)) {
> DBG(sc, DMA, ("DMA test failed! lcv=%d, sp=%p, "
> "dp=%p", lcv, sp, dp));
> return (retval);
> }
>
> retval = lcv;
> }
> return (retval); /* studly 64 byte DMA present! oh baby!! */
2709d2584
<
2711c2586
< * en_service: handle a service interrupt
---
> * Find the best DMA parameters
2713,2725c2588
< * Q: why do we need a software service list?
< *
< * A: if we remove a VCI from the hardware list and we find that we are
< * out of DRQs we must defer processing until some DRQs become free.
< * so we must remember to look at this RX VCI/slot later, but we can't
< * put it back on the hardware service list (since that isn't allowed).
< * so we instead save it on the software service list. it would be nice
< * if we could peek at the VCI on top of the hwservice list without removing
< * it, however this leads to a race condition: if we peek at it and
< * decide we are done with it new data could come in before we have a
< * chance to remove it from the hwslist. by the time we get it out of
< * the list the interrupt for the new data will be lost. oops!
< *
---
> * LOCK: unlocked, not needed
2727,2731c2590,2591
<
< STATIC void en_service(sc)
<
< struct en_softc *sc;
<
---
> static void
> en_dmaprobe(struct en_softc *sc)
2733,2736c2593,2599
< struct mbuf *m, *tmp;
< u_int32_t cur, dstart, rbd, pdu, *sav, dma, bcode, count, *data, *datastop;
< u_int32_t start, stop, cnt, needalign;
< int slot, raw, aal5, llc, vci, fill, mlen, tlen, drqneed, need, needfill, end;
---
> bus_dma_tag_t tag;
> bus_dmamap_t map;
> int err;
> void *buffer;
> int bestalgn, lcv, try, bestnoalgn;
> bus_addr_t phys;
> uint8_t *addr;
2738,2745c2601,2602
< aal5 = 0; /* Silence gcc */
< next_vci:
< if (sc->swsl_size == 0) {
< #ifdef EN_DEBUG
< printf("%s: en_service done\n", sc->sc_dev.dv_xname);
< #endif
< return; /* >>> exit here if swsl now empty <<< */
< }
---
> sc->alburst = 0;
> sc->noalbursts = 0;
2747,2749c2604,2612
< /*
< * get slot/vci to service
< */
---
> /*
> * Allocate some DMA-able memory.
> * We need 3 times the max burst size aligned to the max burst size.
> */
> err = bus_dma_tag_create(NULL, MIDDMA_MAXBURST, 0,
> BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
> 3 * MIDDMA_MAXBURST, 1, 3 * MIDDMA_MAXBURST, 0, &tag);
> if (err)
> panic("%s: cannot create test DMA tag %d", __func__, err);
2751,2755c2614,2616
< slot = sc->swslist[sc->swsl_head];
< vci = sc->rxslot[slot].atm_vci;
< #ifdef EN_DIAG
< if (sc->rxvc2slot[vci] != slot) panic("en_service rx slot/vci sync");
< #endif
---
> err = bus_dmamem_alloc(tag, &buffer, 0, &map);
> if (err)
> panic("%s: cannot allocate test DMA memory %d", __func__, err);
2757,2759c2618,2623
< /*
< * determine our mode and if we've got any work to do
< */
---
> err = bus_dmamap_load(tag, map, buffer, 3 * MIDDMA_MAXBURST,
> en_dmaprobe_load, &phys, 0);
> if (err)
> panic("%s: cannot load test DMA map %d", __func__, err);
> addr = buffer;
> DBG(sc, DMA, ("phys=%#lx addr=%p", (u_long)phys, addr));
2761,2764c2625,2628
< raw = sc->rxslot[slot].oth_flags & ENOTHER_RAW;
< start= sc->rxslot[slot].start;
< stop= sc->rxslot[slot].stop;
< cur = sc->rxslot[slot].cur;
---
> /*
> * Now get the best burst size of the aligned case.
> */
> bestalgn = bestnoalgn = en_dmaprobe_doit(sc, addr, phys);
2766,2769c2630,2634
< #ifdef EN_DEBUG
< printf("%s: rx%d: service vci=%d raw=%d start/stop/cur=0x%x 0x%x 0x%x\n",
< sc->sc_dev.dv_xname, slot, vci, raw, start, stop, cur);
< #endif
---
> /*
> * Now try unaligned.
> */
> for (lcv = 4; lcv < MIDDMA_MAXBURST; lcv += 4) {
> try = en_dmaprobe_doit(sc, addr + lcv, phys + lcv);
2771,2773c2636,2638
< same_vci:
< dstart = MIDV_DSTART(EN_READ(sc, MID_DST_RP(vci)));
< dstart = (dstart * sizeof(u_int32_t)) + start;
---
> if (try < bestnoalgn)
> bestnoalgn = try;
> }
2775,2787c2640,2644
< /* check to see if there is any data at all */
< if (dstart == cur) {
< defer: /* defer processing */
< EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1);
< sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL;
< sc->swsl_size--;
< /* >>> remove from swslist <<< */
< #ifdef EN_DEBUG
< printf("%s: rx%d: remove vci %d from swslist\n",
< sc->sc_dev.dv_xname, slot, vci);
< #endif
< goto next_vci;
< }
---
> if (bestnoalgn < bestalgn) {
> sc->alburst = 1;
> if (bestnoalgn < 32)
> sc->noalbursts = 1;
> }
2789,2792c2646,2649
< /*
< * figure out how many bytes we need
< * [mlen = # bytes to go in mbufs, fill = # bytes to dump (MIDDMA_JK)]
< */
---
> sc->bestburstlen = bestalgn;
> sc->bestburstshift = en_log2(bestalgn);
> sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */
> sc->bestburstcode = en_sz2b(bestalgn);
2794c2651,2657
< if (raw) {
---
> /*
> * Reset the chip before freeing the buffer. It may still be trying
> * to DMA.
> */
> if (sc->en_busreset)
> sc->en_busreset(sc);
> en_write(sc, MID_RESID, 0x0); /* reset card before touching RAM */
2796,2801c2659
< /* raw mode (aka boodi mode) */
< fill = 0;
< if (dstart > cur)
< mlen = dstart - cur;
< else
< mlen = (dstart + (EN_RXSZ*1024)) - cur;
---
> DELAY(10000); /* may still do DMA */
2803,2804c2661,2667
< if (mlen < sc->rxslot[slot].raw_threshold)
< goto defer; /* too little data to deal with */
---
> /*
> * Free the DMA stuff
> */
> bus_dmamap_unload(tag, map);
> bus_dmamem_free(tag, buffer, map);
> bus_dma_tag_destroy(tag);
> }
2806c2669,2672
< } else {
---
> /*********************************************************************/
> /*
> * Attach/detach.
> */
2808,2813c2674,2684
< /* normal mode */
< aal5 = (sc->rxslot[slot].atm_flags & ATM_PH_AAL5);
< llc = (aal5 && (sc->rxslot[slot].atm_flags & ATM_PH_LLCSNAP)) ? 1 : 0;
< rbd = EN_READ(sc, cur);
< if (MID_RBD_ID(rbd) != MID_RBD_STDID)
< panic("en_service: id mismatch");
---
> /*
> * Attach to the card.
> *
> * LOCK: unlocked, not needed (but initialized)
> */
> int
> en_attach(struct en_softc *sc)
> {
> struct ifnet *ifp = &sc->enif;
> int sz;
> uint32_t reg, lcv, check, ptr, sav, midvloc;
2815,2818d2685
< if (rbd & MID_RBD_T) {
< mlen = 0; /* we've got trash */
< fill = MID_RBD_SIZE;
< EN_COUNT(sc->ttrash);
2820c2687
< printf("RX overflow lost %d cells!\n", MID_RBD_CNT(rbd));
---
> sc->debug = EN_DEBUG;
2822,2826c2689,2697
< } else if (!aal5) {
< mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */
< fill = 0;
< } else {
< struct ifnet *ifp;
---
> /*
> * Probe card to determine memory size.
> *
> * The stupid ENI card always reports to PCI that it needs 4MB of
> * space (2MB regs and 2MB RAM). If it has less than 2MB RAM the
> * addresses wrap in the RAM address space (i.e. on a 512KB card
> * addresses 0x3ffffc, 0x37fffc, and 0x2ffffc are aliases for
> * 0x27fffc [note that RAM starts at offset 0x200000]).
> */
2828,2835c2699,2702
< tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE;
< pdu = cur + tlen - MID_PDU_SIZE;
< if (pdu >= stop)
< pdu -= (EN_RXSZ*1024);
< pdu = EN_READ(sc, pdu); /* get PDU in correct byte order */
< fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu);
< if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) {
< static int first = 1;
---
> /* reset card before touching RAM */
> if (sc->en_busreset)
> sc->en_busreset(sc);
> en_write(sc, MID_RESID, 0x0);
2837,2847c2704,2711
< if (first) {
< printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
< (rbd & MID_RBD_CRCERR) ?
< "CRC error" : "invalid AAL5 PDU length");
< printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
< sc->sc_dev.dv_xname, MID_RBD_CNT(rbd),
< tlen - MID_RBD_SIZE, MID_PDU_LEN(pdu), pdu);
< #ifndef EN_DEBUG
< printf("CRC error report disabled from now on!\n");
< first = 0;
< #endif
---
> for (lcv = MID_PROBEOFF; lcv <= MID_MAXOFF ; lcv += MID_PROBSIZE) {
> en_write(sc, lcv, lcv); /* data[address] = address */
> for (check = MID_PROBEOFF; check < lcv ;check += MID_PROBSIZE) {
> reg = en_read(sc, check);
> if (reg != check)
> /* found an alias! - quit */
> goto done_probe;
> }
2849c2713,2715
< fill = tlen;
---
> done_probe:
> lcv -= MID_PROBSIZE; /* take one step back */
> sc->en_obmemsz = (lcv + 4) - MID_RAMOFF;
2851,2852c2717,2720
< ifp = &sc->enif;
< ifp->if_ierrors++;
---
> /*
> * determine the largest DMA burst supported
> */
> en_dmaprobe(sc);
2854,2856c2722,2724
< }
< mlen = tlen - fill;
< }
---
> /*
> * "hello world"
> */
2858c2726,2729
< }
---
> /* reset */
> if (sc->en_busreset)
> sc->en_busreset(sc);
> en_write(sc, MID_RESID, 0x0); /* reset */
2860,2893c2731,2733
< /*
< * now allocate mbufs for mlen bytes of data, if out of mbufs, trash all
< *
< * notes:
< * 1. it is possible that we've already allocated an mbuf for this pkt
< * but ran out of DRQs, in which case we saved the allocated mbuf on
< * "q".
< * 2. if we save an mbuf in "q" we store the "cur" (pointer) in the front
< * of the mbuf as an identity (that we can check later), and we also
< * store drqneed (so we don't have to recompute it).
< * 3. after this block of code, if m is still NULL then we ran out of mbufs
< */
<
< m = sc->rxslot[slot].q.ifq_head;
< drqneed = 1;
< if (m) {
< sav = mtod(m, u_int32_t *);
< if (sav[0] != cur) {
< #ifdef EN_DEBUG
< printf("%s: rx%d: q'ed mbuf %p not ours\n",
< sc->sc_dev.dv_xname, slot, m);
< #endif
< m = NULL; /* wasn't ours */
< EN_COUNT(sc->rxqnotus);
< } else {
< EN_COUNT(sc->rxqus);
< _IF_DEQUEUE(&sc->rxslot[slot].q, m);
< drqneed = sav[1];
< #ifdef EN_DEBUG
< printf("%s: rx%d: recovered q'ed mbuf %p (drqneed=%d)\n",
< sc->sc_dev.dv_xname, slot, m, drqneed);
< #endif
< }
< }
---
> /* zero memory */
> bus_space_set_region_4(sc->en_memt, sc->en_base,
> MID_RAMOFF, 0, sc->en_obmemsz / 4);
2895,2909c2735
< if (mlen != 0 && m == NULL) {
< m = en_mget(sc, mlen, &drqneed); /* allocate! */
< if (m == NULL) {
< fill += mlen;
< mlen = 0;
< EN_COUNT(sc->rxmbufout);
< #ifdef EN_DEBUG
< printf("%s: rx%d: out of mbufs\n", sc->sc_dev.dv_xname, slot);
< #endif
< }
< #ifdef EN_DEBUG
< printf("%s: rx%d: allocate mbuf %p, mlen=%d, drqneed=%d\n",
< sc->sc_dev.dv_xname, slot, m, mlen, drqneed);
< #endif
< }
---
> reg = en_read(sc, MID_RESID);
2911,2914c2737,2742
< #ifdef EN_DEBUG
< printf("%s: rx%d: VCI %d, mbuf_chain %p, mlen %d, fill %d\n",
< sc->sc_dev.dv_xname, slot, vci, m, mlen, fill);
< #endif
---
> if_printf(&sc->enif, "ATM midway v%d, board IDs %d.%d, %s%s%s, "
> "%ldKB on-board RAM\n", MID_VER(reg), MID_MID(reg), MID_DID(reg),
> (MID_IS_SABRE(reg)) ? "sabre controller, " : "",
> (MID_IS_SUNI(reg)) ? "SUNI" : "Utopia",
> (!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "",
> (long)sc->en_obmemsz / 1024);
2916,2919c2744,2754
< /*
< * now check to see if we've got the DRQs needed. if we are out of
< * DRQs we must quit (saving our mbuf, if we've got one).
< */
---
> if (sc->is_adaptec) {
> if (sc->bestburstlen == 64 && sc->alburst == 0)
> if_printf(&sc->enif, "passed 64 byte DMA test\n");
> else
> if_printf(&sc->enif, "FAILED DMA TEST: burst=%d, "
> "alburst=%d\n", sc->bestburstlen, sc->alburst);
> } else {
> if_printf(&sc->enif, "maximum DMA burst length = %d bytes%s\n",
> sc->bestburstlen, sc->alburst ? sc->noalbursts ?
> " (no large bursts)" : " (must align)" : "");
> }
2921,2940c2756,2762
< needfill = (fill) ? 1 : 0;
< if (drqneed + needfill > sc->drq_free) {
< sc->need_drqs = 1; /* flag condition */
< if (m == NULL) {
< EN_COUNT(sc->rxoutboth);
< #ifdef EN_DEBUG
< printf("%s: rx%d: out of DRQs *and* mbufs!\n", sc->sc_dev.dv_xname, slot);
< #endif
< return; /* >>> exit here if out of both mbufs and DRQs <<< */
< }
< sav = mtod(m, u_int32_t *);
< sav[0] = cur;
< sav[1] = drqneed;
< _IF_ENQUEUE(&sc->rxslot[slot].q, m);
< EN_COUNT(sc->rxdrqout);
< #ifdef EN_DEBUG
< printf("%s: rx%d: out of DRQs\n", sc->sc_dev.dv_xname, slot);
< #endif
< return; /* >>> exit here if out of DRQs <<< */
< }
---
> /*
> * link into network subsystem and prepare card
> */
> sc->enif.if_softc = sc;
> ifp->if_flags = IFF_SIMPLEX;
> ifp->if_ioctl = en_ioctl;
> ifp->if_start = en_start;
2942,2955c2764,2767
< /*
< * at this point all resources have been allocated and we are commited
< * to servicing this slot.
< *
< * dma = last location we told chip about
< * cur = current location
< * mlen = space in the mbuf we want
< * need = bytes to xfer in (decrs to zero)
< * fill = how much fill we need
< * tlen = how much data to transfer to this mbuf
< * cnt/bcode/count = <same as xmit>
< *
< * 'needfill' not used after this point
< */
---
> /*
> * Make the sysctl tree
> */
> sysctl_ctx_init(&sc->sysctl_ctx);
2957,2959c2769,2772
< dma = cur; /* dma = last location we told chip about */
< need = roundup(mlen, sizeof(u_int32_t));
< fill = fill - (need - mlen); /* note: may invalidate 'needfill' */
---
> if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
> SYSCTL_STATIC_CHILDREN(_hw_en), OID_AUTO,
> device_get_nameunit(sc->dev), CTLFLAG_RD, 0, "")) == NULL)
> goto fail;
2961,2963c2774,2777
< for (tmp = m ; tmp != NULL && need > 0 ; tmp = tmp->m_next) {
< tlen = roundup(tmp->m_len, sizeof(u_int32_t)); /* m_len set by en_mget */
< data = mtod(tmp, u_int32_t *);
---
> if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
> OID_AUTO, "istats", CTLFLAG_RD, sc, 0, en_sysctl_istats,
> "A", "internal statistics") == NULL)
> goto fail;
2966,2967c2780,2782
< printf("%s: rx%d: load mbuf %p, m_len=%d, m_data=%p, tlen=%d\n",
< sc->sc_dev.dv_xname, slot, tmp, tmp->m_len, tmp->m_data, tlen);
---
> if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
> OID_AUTO, "debug", CTLFLAG_RW , &sc->debug, 0, "") == NULL)
> goto fail;
2969,2985d2783
<
< /* copy data */
< if (EN_NORXDMA || !en_dma || tlen < EN_MINDMA) {
< datastop = (u_int32_t *)((u_char *) data + tlen);
< /* copy loop: preserve byte order!!! use READDAT */
< while (data != datastop) {
< *data = EN_READDAT(sc, cur);
< data++;
< EN_WRAPADD(start, stop, cur, 4);
< }
< need -= tlen;
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: copied %d bytes (%d left)\n",
< sc->sc_dev.dv_xname, slot, vci, tlen, need);
< #endif
< continue;
< }
2987,2994c2785,2786
< /* DMA data (check to see if we need to sync DRQ first) */
< if (dma != cur) {
< EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, 0, 0, 0);
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: drq_sync: advance pointer to %d\n",
< sc->sc_dev.dv_xname, slot, vci, cur);
< #endif
< }
---
> mtx_init(&sc->en_mtx, device_get_nameunit(sc->dev),
> MTX_NETWORK_LOCK, MTX_DEF);
2996,3016c2788,2791
< #if !defined(MIDWAY_ENIONLY)
<
< /*
< * the adaptec DMA engine is smart and handles everything for us.
< */
<
< if (sc->is_adaptec) {
< need -= tlen;
< EN_WRAPADD(start, stop, cur, tlen);
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: adp_dma %d bytes (%d left)\n",
< sc->sc_dev.dv_xname, slot, vci, tlen, need);
< #endif
< end = (need == 0 && !fill) ? MID_DMA_END : 0;
< EN_DRQADD(sc, tlen, vci, 0, vtophys(data), mlen, slot, end);
< if (end)
< goto done;
< dma = cur; /* update dma pointer */
< continue;
< }
< #endif /* !MIDWAY_ENIONLY */
---
> MGET(sc->padbuf, M_TRYWAIT, MT_DATA);
> if (sc->padbuf == NULL)
> goto fail;
> bzero(sc->padbuf->m_data, MLEN);
3017a2793,2796
> if (bus_dma_tag_create(NULL, 1, 0,
> BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
> EN_TXSZ * 1024, EN_MAX_DMASEG, EN_TXSZ * 1024, 0, &sc->txtag))
> goto fail;
3019c2798,2803
< #if !defined(MIDWAY_ADPONLY)
---
> sc->map_zone = uma_zcreate("en dma maps", sizeof(struct en_map),
> en_map_ctor, en_map_dtor, NULL, en_map_fini, UMA_ALIGN_PTR,
> UMA_ZONE_ZINIT);
> if (sc->map_zone == NULL)
> goto fail;
> uma_zone_set_max(sc->map_zone, EN_MAX_MAPS);
3021,3023c2805,2812
< /*
< * the ENI DMA engine is not so smart and need more help from us
< */
---
> /*
> * init softc
> */
> for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
> sc->rxvc2slot[lcv] = RX_NONE;
> sc->txspeed[lcv] = 0; /* full */
> sc->txvc2slot[lcv] = 0; /* full speed == slot 0 */
> }
3025,3050c2814,2831
< /* do we need to do a DMA op to align? */
< if (sc->alburst &&
< (needalign = (((uintptr_t) (void *) data) & sc->bestburstmask)) != 0) {
< cnt = sc->bestburstlen - needalign;
< if (cnt > tlen) {
< cnt = tlen;
< count = cnt / sizeof(u_int32_t);
< bcode = MIDDMA_WORD;
< } else {
< count = cnt / sizeof(u_int32_t);
< bcode = en_dmaplan[count].bcode;
< count = cnt >> en_dmaplan[count].divshift;
< }
< need -= cnt;
< EN_WRAPADD(start, stop, cur, cnt);
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: al_dma %d bytes (%d left)\n",
< sc->sc_dev.dv_xname, slot, vci, cnt, need);
< #endif
< tlen -= cnt;
< end = (need == 0 && !fill) ? MID_DMA_END : 0;
< EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end);
< if (end)
< goto done;
< data = (u_int32_t *)((u_char *) data + cnt);
< }
---
> sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF);
> ptr = sav = MID_BUFOFF;
> ptr = roundup(ptr, EN_TXSZ * 1024); /* align */
> sz = sz - (ptr - sav);
> if (EN_TXSZ*1024 * EN_NTX > sz) {
> if_printf(&sc->enif, "EN_NTX/EN_TXSZ too big\n");
> goto fail;
> }
> for (lcv = 0 ;lcv < EN_NTX ;lcv++) {
> sc->txslot[lcv].mbsize = 0;
> sc->txslot[lcv].start = ptr;
> ptr += (EN_TXSZ * 1024);
> sz -= (EN_TXSZ * 1024);
> sc->txslot[lcv].stop = ptr;
> sc->txslot[lcv].nref = 0;
> DBG(sc, INIT, ("tx%d: start 0x%x, stop 0x%x", lcv,
> sc->txslot[lcv].start, sc->txslot[lcv].stop));
> }
3052,3069c2833,2840
< /* do we need a max-sized burst? */
< if (tlen >= sc->bestburstlen) {
< count = tlen >> sc->bestburstshift;
< cnt = count << sc->bestburstshift;
< bcode = sc->bestburstcode;
< need -= cnt;
< EN_WRAPADD(start, stop, cur, cnt);
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: best_dma %d bytes (%d left)\n",
< sc->sc_dev.dv_xname, slot, vci, cnt, need);
< #endif
< tlen -= cnt;
< end = (need == 0 && !fill) ? MID_DMA_END : 0;
< EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end);
< if (end)
< goto done;
< data = (u_int32_t *)((u_char *) data + cnt);
< }
---
> sav = ptr;
> ptr = roundup(ptr, EN_RXSZ * 1024); /* align */
> sz = sz - (ptr - sav);
> sc->en_nrx = sz / (EN_RXSZ * 1024);
> if (sc->en_nrx <= 0) {
> if_printf(&sc->enif, "EN_NTX/EN_TXSZ/EN_RXSZ too big\n");
> goto fail;
> }
3071,3086c2842,2847
< /* do we need to do a cleanup burst? */
< if (tlen) {
< count = tlen / sizeof(u_int32_t);
< bcode = en_dmaplan[count].bcode;
< count = tlen >> en_dmaplan[count].divshift;
< need -= tlen;
< EN_WRAPADD(start, stop, cur, tlen);
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: cleanup_dma %d bytes (%d left)\n",
< sc->sc_dev.dv_xname, slot, vci, tlen, need);
< #endif
< end = (need == 0 && !fill) ? MID_DMA_END : 0;
< EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end);
< if (end)
< goto done;
< }
---
> /*
> * ensure that there is always one VC slot on the service list free
> * so that we can tell the difference between a full and empty list.
> */
> if (sc->en_nrx >= MID_N_VC)
> sc->en_nrx = MID_N_VC - 1;
3088c2849,2863
< dma = cur; /* update dma pointer */
---
> for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) {
> sc->rxslot[lcv].rxhand = NULL;
> sc->rxslot[lcv].oth_flags = ENOTHER_FREE;
> midvloc = sc->rxslot[lcv].start = ptr;
> ptr += (EN_RXSZ * 1024);
> sz -= (EN_RXSZ * 1024);
> sc->rxslot[lcv].stop = ptr;
> midvloc = midvloc - MID_RAMOFF;
> /* mask, cvt to words */
> midvloc = (midvloc & ~((EN_RXSZ*1024) - 1)) >> 2;
> /* we only want the top 11 bits */
> midvloc = midvloc >> MIDV_LOCTOPSHFT;
> midvloc = (midvloc & MIDV_LOCMASK) << MIDV_LOCSHIFT;
> sc->rxslot[lcv].mode = midvloc |
> (en_k2sz(EN_RXSZ) << MIDV_SZSHIFT) | MIDV_TRASH;
3090c2865,2868
< #endif /* !MIDWAY_ADPONLY */
---
> DBG(sc, INIT, ("rx%d: start 0x%x, stop 0x%x, mode 0x%x", lcv,
> sc->rxslot[lcv].start, sc->rxslot[lcv].stop,
> sc->rxslot[lcv].mode));
> }
3092c2870
< }
---
> bzero(&sc->stats, sizeof(sc->stats));
3094,3102c2872,2884
< /* skip the end */
< if (fill || dma != cur) {
< #ifdef EN_DEBUG
< if (fill)
< printf("%s: rx%d: vci%d: skipping %d bytes of fill\n",
< sc->sc_dev.dv_xname, slot, vci, fill);
< else
< printf("%s: rx%d: vci%d: syncing chip from 0x%x to 0x%x [cur]\n",
< sc->sc_dev.dv_xname, slot, vci, dma, cur);
---
> if_printf(&sc->enif, "%d %dKB receive buffers, %d %dKB transmit "
> "buffers\n", sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
> if_printf(&sc->enif, "end station identifier (mac address) %6D\n",
> sc->macaddr, ":");
>
> /*
> * final commit
> */
> if_attach(ifp);
> atm_ifattach(ifp);
>
> #ifdef ENABLE_BPF
> bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
3104,3108d2885
< EN_WRAPADD(start, stop, cur, fill);
< EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, mlen,
< slot, MID_DMA_END);
< /* dma = cur; */ /* not necessary since we are done */
< }
3110,3115c2887
< /*
< * done, remove stuff we don't want to pass up:
< * raw mode (boodi mode): pass everything up for later processing
< * aal5: remove RBD
< * aal0: remove RBD + cell header
< */
---
> return (0);
3117,3128c2889,2892
< done:
< if (m) {
< if (!raw) {
< cnt = MID_RBD_SIZE;
< if (!aal5) cnt += MID_CHDR_SIZE;
< m->m_len -= cnt; /* chop! */
< m->m_pkthdr.len -= cnt;
< m->m_data += cnt;
< }
< _IF_ENQUEUE(&sc->rxslot[slot].indma, m);
< }
< sc->rxslot[slot].cur = cur; /* update master copy of 'cur' */
---
> fail:
> en_destroy(sc);
> return (-1);
> }
3130,3133c2894,2904
< #ifdef EN_DEBUG
< printf("%s: rx%d: vci%d: DONE! cur now =0x%x\n",
< sc->sc_dev.dv_xname, slot, vci, cur);
< #endif
---
> /*
> * Free all internal resources. No access to bus resources here.
> * No locking required here (interrupt is already disabled).
> *
> * LOCK: unlocked, not needed (but destroyed)
> */
> void
> en_destroy(struct en_softc *sc)
> {
> if (sc->padbuf != NULL)
> m_free(sc->padbuf);
3135c2906,2918
< goto same_vci; /* get next packet in this slot */
---
> /*
> * Destroy the map zone before the tag (the fini function will
> * destroy the DMA maps using the tag)
> */
> if (sc->map_zone != NULL)
> uma_zdestroy(sc->map_zone);
>
> if (sc->txtag != NULL)
> bus_dma_tag_destroy(sc->txtag);
>
> (void)sysctl_ctx_free(&sc->sysctl_ctx);
>
> mtx_destroy(&sc->en_mtx);
3137a2921,2924
> /*********************************************************************/
> /*
> * Debugging support
> */
3147d2933
<
3158,3162c2944,2945
< /* Do not staticize - meant for calling from DDB! */
< int en_dump(unit, level)
<
< int unit, level;
<
---
> static void
> en_dump_stats(const struct en_stats *s)
3164,3219c2947,2965
< struct en_softc *sc;
< int lcv, cnt, slot;
< u_int32_t ptr, reg;
< #ifdef __FreeBSD__
< devclass_t dc;
< int maxunit;
<
< dc = devclass_find("en");
< if (dc == NULL) {
< printf("en_dump: can't find devclass!\n");
< return 0;
< }
< maxunit = devclass_get_maxunit(dc);
< for (lcv = 0 ; lcv < maxunit ; lcv++) {
< sc = devclass_get_softc(dc, lcv);
< #else
< for (lcv = 0 ; lcv < en_cd.cd_ndevs ; lcv++) {
< sc = (struct en_softc *) en_cd.cd_devs[lcv];
< #endif
< if (sc == NULL) continue;
< if (unit != -1 && unit != lcv)
< continue;
<
< printf("dumping device %s at level 0x%b\n", sc->sc_dev.dv_xname, level,
< END_BITS);
<
< if (sc->dtq_us == 0) {
< printf("<hasn't been en_init'd yet>\n");
< continue;
< }
<
< if (level & END_STATS) {
< printf(" en_stats:\n");
< printf(" %d mfix (%d failed); %d/%d head/tail byte DMAs, %d flushes\n",
< sc->mfix, sc->mfixfail, sc->headbyte, sc->tailbyte, sc->tailflush);
< printf(" %d rx dma overflow interrupts\n", sc->dmaovr);
< printf(" %d times we ran out of TX space and stalled\n",
< sc->txoutspace);
< printf(" %d times we ran out of DTQs\n", sc->txdtqout);
< printf(" %d times we launched a packet\n", sc->launch);
< printf(" %d times we launched without on-board header\n", sc->lheader);
< printf(" %d times we launched without on-board tail\n", sc->ltail);
< printf(" %d times we pulled the hw service list\n", sc->hwpull);
< printf(" %d times we pushed a vci on the sw service list\n",
< sc->swadd);
< printf(" %d times RX pulled an mbuf from Q that wasn't ours\n",
< sc->rxqnotus);
< printf(" %d times RX pulled a good mbuf from Q\n", sc->rxqus);
< printf(" %d times we ran out of mbufs *and* DRQs\n", sc->rxoutboth);
< printf(" %d times we ran out of DRQs\n", sc->rxdrqout);
<
< printf(" %d trasmit packets dropped due to mbsize\n", sc->txmbovr);
< printf(" %d cells trashed due to turned off rxvc\n", sc->vtrash);
< printf(" %d cells trashed due to totally full buffer\n", sc->otrash);
< printf(" %d cells trashed due almost full buffer\n", sc->ttrash);
< printf(" %d rx mbuf allocation failures\n", sc->rxmbufout);
---
> printf("en_stats:\n");
> printf("\t%d/%d mfix (%d failed)\n", s->mfixaddr, s->mfixlen,
> s->mfixfail);
> printf("\t%d rx dma overflow interrupts\n", s->dmaovr);
> printf("\t%d times out of TX space and stalled\n", s->txoutspace);
> printf("\t%d times out of DTQs\n", s->txdtqout);
> printf("\t%d times launched a packet\n", s->launch);
> printf("\t%d times pulled the hw service list\n", s->hwpull);
> printf("\t%d times pushed a vci on the sw service list\n", s->swadd);
> printf("\t%d times RX pulled an mbuf from Q that wasn't ours\n",
> s->rxqnotus);
> printf("\t%d times RX pulled a good mbuf from Q\n", s->rxqus);
> printf("\t%d times ran out of DRQs\n", s->rxdrqout);
> printf("\t%d transmit packets dropped due to mbsize\n", s->txmbovr);
> printf("\t%d cells trashed due to turned off rxvc\n", s->vtrash);
> printf("\t%d cells trashed due to totally full buffer\n", s->otrash);
> printf("\t%d cells trashed due almost full buffer\n", s->ttrash);
> printf("\t%d rx mbuf allocation failures\n", s->rxmbufout);
> printf("\t%d times out of tx maps\n", s->txnomap);
3221,3223d2966
< #if 0
< printf(" %d drops at natmintrq\n", natmintrq.ifq_drops);
< #endif
3225,3226c2968,2969
< printf(" natmintr so_rcv: ok/drop cnt: %d/%d, ok/drop bytes: %d/%d\n",
< natm_sookcnt, natm_sodropcnt, natm_sookbytes, natm_sodropbytes);
---
> printf("\tnatmintr so_rcv: ok/drop cnt: %d/%d, ok/drop bytes: %d/%d\n",
> natm_sookcnt, natm_sodropcnt, natm_sookbytes, natm_sodropbytes);
3229c2972
< }
---
> }
3231,3239c2974,2986
< if (level & END_MREGS) {
< printf("mregs:\n");
< printf("resid = 0x%x\n", EN_READ(sc, MID_RESID));
< printf("interrupt status = 0x%b\n",
< (int)EN_READ(sc, MID_INTSTAT), MID_INTBITS);
< printf("interrupt enable = 0x%b\n",
< (int)EN_READ(sc, MID_INTENA), MID_INTBITS);
< printf("mcsr = 0x%b\n", (int)EN_READ(sc, MID_MAST_CSR), MID_MCSRBITS);
< printf("serv_write = [chip=%u] [us=%u]\n", EN_READ(sc, MID_SERV_WRITE),
---
> static void
> en_dump_mregs(struct en_softc *sc)
> {
> u_int cnt;
>
> printf("mregs:\n");
> printf("resid = 0x%x\n", en_read(sc, MID_RESID));
> printf("interrupt status = 0x%b\n",
> (int)en_read(sc, MID_INTSTAT), MID_INTBITS);
> printf("interrupt enable = 0x%b\n",
> (int)en_read(sc, MID_INTENA), MID_INTBITS);
> printf("mcsr = 0x%b\n", (int)en_read(sc, MID_MAST_CSR), MID_MCSRBITS);
> printf("serv_write = [chip=%u] [us=%u]\n", en_read(sc, MID_SERV_WRITE),
3241,3247c2988,2994
< printf("dma addr = 0x%x\n", EN_READ(sc, MID_DMA_ADDR));
< printf("DRQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n",
< MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)),
< MID_DRQ_REG2A(EN_READ(sc, MID_DMA_WRRX)), sc->drq_chip, sc->drq_us);
< printf("DTQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n",
< MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)),
< MID_DTQ_REG2A(EN_READ(sc, MID_DMA_WRTX)), sc->dtq_chip, sc->dtq_us);
---
> printf("dma addr = 0x%x\n", en_read(sc, MID_DMA_ADDR));
> printf("DRQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n",
> MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX)),
> MID_DRQ_REG2A(en_read(sc, MID_DMA_WRRX)), sc->drq_chip, sc->drq_us);
> printf("DTQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n",
> MID_DTQ_REG2A(en_read(sc, MID_DMA_RDTX)),
> MID_DTQ_REG2A(en_read(sc, MID_DMA_WRTX)), sc->dtq_chip, sc->dtq_us);
3249,3253c2996,3000
< printf(" unusal txspeeds: ");
< for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
< if (sc->txspeed[cnt])
< printf(" vci%d=0x%x", cnt, sc->txspeed[cnt]);
< printf("\n");
---
> printf(" unusal txspeeds:");
> for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
> if (sc->txspeed[cnt])
> printf(" vci%d=0x%x", cnt, sc->txspeed[cnt]);
> printf("\n");
3255,3259c3002,3007
< printf(" rxvc slot mappings: ");
< for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
< if (sc->rxvc2slot[cnt] != RX_NONE)
< printf(" %d->%d", cnt, sc->rxvc2slot[cnt]);
< printf("\n");
---
> printf(" rxvc slot mappings:");
> for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
> if (sc->rxvc2slot[cnt] != RX_NONE)
> printf(" %d->%d", cnt, sc->rxvc2slot[cnt]);
> printf("\n");
> }
3261c3009,3012
< }
---
> static void
> en_dump_tx(struct en_softc *sc)
> {
> u_int slot;
3263,3276c3014,3029
< if (level & END_TX) {
< printf("tx:\n");
< for (slot = 0 ; slot < EN_NTX; slot++) {
< printf("tx%d: start/stop/cur=0x%x/0x%x/0x%x [%d] ", slot,
< sc->txslot[slot].start, sc->txslot[slot].stop, sc->txslot[slot].cur,
< (sc->txslot[slot].cur - sc->txslot[slot].start)/4);
< printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize,
< sc->txslot[slot].bfree);
< printf("txhw: base_address=0x%x, size=%u, read=%u, descstart=%u\n",
< (u_int)MIDX_BASE(EN_READ(sc, MIDX_PLACE(slot))),
< MIDX_SZ(EN_READ(sc, MIDX_PLACE(slot))),
< EN_READ(sc, MIDX_READPTR(slot)), EN_READ(sc, MIDX_DESCSTART(slot)));
< }
< }
---
> printf("tx:\n");
> for (slot = 0 ; slot < EN_NTX; slot++) {
> printf("tx%d: start/stop/cur=0x%x/0x%x/0x%x [%d] ", slot,
> sc->txslot[slot].start, sc->txslot[slot].stop,
> sc->txslot[slot].cur,
> (sc->txslot[slot].cur - sc->txslot[slot].start) / 4);
> printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize,
> sc->txslot[slot].bfree);
> printf("txhw: base_address=0x%x, size=%u, read=%u, "
> "descstart=%u\n",
> (u_int)MIDX_BASE(en_read(sc, MIDX_PLACE(slot))),
> MIDX_SZ(en_read(sc, MIDX_PLACE(slot))),
> en_read(sc, MIDX_READPTR(slot)),
> en_read(sc, MIDX_DESCSTART(slot)));
> }
> }
3278,3292c3031,3034
< if (level & END_RX) {
< printf(" recv slots:\n");
< for (slot = 0 ; slot < sc->en_nrx; slot++) {
< printf("rx%d: vci=%d: start/stop/cur=0x%x/0x%x/0x%x ", slot,
< sc->rxslot[slot].atm_vci, sc->rxslot[slot].start,
< sc->rxslot[slot].stop, sc->rxslot[slot].cur);
< printf("mode=0x%x, atm_flags=0x%x, oth_flags=0x%x\n",
< sc->rxslot[slot].mode, sc->rxslot[slot].atm_flags,
< sc->rxslot[slot].oth_flags);
< printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n",
< EN_READ(sc, MID_VC(sc->rxslot[slot].atm_vci)),
< EN_READ(sc, MID_DST_RP(sc->rxslot[slot].atm_vci)),
< EN_READ(sc, MID_WP_ST_CNT(sc->rxslot[slot].atm_vci)));
< }
< }
---
> static void
> en_dump_rx(struct en_softc *sc)
> {
> u_int slot;
3294,3328c3036,3050
< if (level & END_DTQ) {
< printf(" dtq [need_dtqs=%d,dtq_free=%d]:\n",
< sc->need_dtqs, sc->dtq_free);
< ptr = sc->dtq_chip;
< while (ptr != sc->dtq_us) {
< reg = EN_READ(sc, ptr);
< printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n",
< sc->dtq[MID_DTQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_TXCHAN(reg),
< (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4));
< EN_WRAPADD(MID_DTQOFF, MID_DTQEND, ptr, 8);
< }
< }
<
< if (level & END_DRQ) {
< printf(" drq [need_drqs=%d,drq_free=%d]:\n",
< sc->need_drqs, sc->drq_free);
< ptr = sc->drq_chip;
< while (ptr != sc->drq_us) {
< reg = EN_READ(sc, ptr);
< printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n",
< sc->drq[MID_DRQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_RXVCI(reg),
< (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4));
< EN_WRAPADD(MID_DRQOFF, MID_DRQEND, ptr, 8);
< }
< }
<
< if (level & END_SWSL) {
< printf(" swslist [size=%d]: ", sc->swsl_size);
< for (cnt = sc->swsl_head ; cnt != sc->swsl_tail ;
< cnt = (cnt + 1) % MID_SL_N)
< printf("0x%x ", sc->swslist[cnt]);
< printf("\n");
< }
< }
< return(0);
---
> printf(" recv slots:\n");
> for (slot = 0 ; slot < sc->en_nrx; slot++) {
> printf("rx%d: vci=%d: start/stop/cur=0x%x/0x%x/0x%x ",
> slot, sc->rxslot[slot].atm_vci,
> sc->rxslot[slot].start, sc->rxslot[slot].stop,
> sc->rxslot[slot].cur);
> printf("mode=0x%x, atm_flags=0x%x, oth_flags=0x%x\n",
> sc->rxslot[slot].mode, sc->rxslot[slot].atm_flags,
> sc->rxslot[slot].oth_flags);
> printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n",
> en_read(sc, MID_VC(sc->rxslot[slot].atm_vci)),
> en_read(sc, MID_DST_RP(sc->rxslot[slot].atm_vci)),
> en_read(sc,
> MID_WP_ST_CNT(sc->rxslot[slot].atm_vci)));
> }
3332c3054
< * en_dumpmem: dump the memory
---
> * This is only correct for non-adaptec adapters
3333a3056,3059
> static void
> en_dump_dtqs(struct en_softc *sc)
> {
> uint32_t ptr, reg;
3334a3061,3091
> printf(" dtq [need_dtqs=%d,dtq_free=%d]:\n", sc->need_dtqs,
> sc->dtq_free);
> ptr = sc->dtq_chip;
> while (ptr != sc->dtq_us) {
> reg = en_read(sc, ptr);
> printf("\t0x%x=[%#x cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n",
> sc->dtq[MID_DTQ_A2REG(ptr)], reg, MID_DMA_CNT(reg),
> MID_DMA_TXCHAN(reg), (reg & MID_DMA_END) != 0,
> MID_DMA_TYPE(reg), en_read(sc, ptr + 4));
> EN_WRAPADD(MID_DTQOFF, MID_DTQEND, ptr, 8);
> }
> }
>
> static void
> en_dump_drqs(struct en_softc *sc)
> {
> uint32_t ptr, reg;
>
> printf(" drq [need_drqs=%d,drq_free=%d]:\n", sc->need_drqs,
> sc->drq_free);
> ptr = sc->drq_chip;
> while (ptr != sc->drq_us) {
> reg = en_read(sc, ptr);
> printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n",
> sc->drq[MID_DRQ_A2REG(ptr)], MID_DMA_CNT(reg),
> MID_DMA_RXVCI(reg), (reg & MID_DMA_END) != 0,
> MID_DMA_TYPE(reg), en_read(sc, ptr + 4));
> EN_WRAPADD(MID_DRQOFF, MID_DRQEND, ptr, 8);
> }
> }
>
3336c3093,3099
< int en_dumpmem(unit, addr, len)
---
> int
> en_dump(int unit, int level)
> {
> struct en_softc *sc;
> int lcv, cnt;
> devclass_t dc;
> int maxunit;
3338c3101,3112
< int unit, addr, len;
---
> dc = devclass_find("en");
> if (dc == NULL) {
> printf("%s: can't find devclass!\n", __func__);
> return (0);
> }
> maxunit = devclass_get_maxunit(dc);
> for (lcv = 0 ; lcv < maxunit ; lcv++) {
> sc = devclass_get_softc(dc, lcv);
> if (sc == NULL)
> continue;
> if (unit != -1 && unit != lcv)
> continue;
3339a3114,3152
> if_printf(&sc->enif, "dumping device at level 0x%b\n",
> level, END_BITS);
>
> if (sc->dtq_us == 0) {
> printf("<hasn't been en_init'd yet>\n");
> continue;
> }
>
> if (level & END_STATS)
> en_dump_stats(&sc->stats);
> if (level & END_MREGS)
> en_dump_mregs(sc);
> if (level & END_TX)
> en_dump_tx(sc);
> if (level & END_RX)
> en_dump_rx(sc);
> if (level & END_DTQ)
> en_dump_dtqs(sc);
> if (level & END_DRQ)
> en_dump_drqs(sc);
>
> if (level & END_SWSL) {
> printf(" swslist [size=%d]: ", sc->swsl_size);
> for (cnt = sc->swsl_head ; cnt != sc->swsl_tail ;
> cnt = (cnt + 1) % MID_SL_N)
> printf("0x%x ", sc->swslist[cnt]);
> printf("\n");
> }
> }
> return (0);
> }
>
> /*
> * en_dumpmem: dump the memory
> *
> * Do not staticize - meant for calling from DDB!
> */
> int
> en_dumpmem(int unit, int addr, int len)
3341,3344c3154,3156
< struct en_softc *sc;
< u_int32_t reg;
< #ifdef __FreeBSD__
< devclass_t dc;
---
> struct en_softc *sc;
> uint32_t reg;
> devclass_t dc;
3346,3358c3158,3167
< dc = devclass_find("en");
< if (dc == NULL) {
< printf("en_dumpmem: can't find devclass!\n");
< return 0;
< }
< sc = devclass_get_softc(dc, unit);
< #else
< if (unit < 0 || unit > en_cd.cd_ndevs ||
< (sc = (struct en_softc *) en_cd.cd_devs[unit]) == NULL) {
< printf("invalid unit number: %d\n", unit);
< return(0);
< }
< #endif
---
> dc = devclass_find("en");
> if (dc == NULL) {
> printf("%s: can't find devclass\n", __func__);
> return (0);
> }
> sc = devclass_get_softc(dc, unit);
> if (sc == NULL) {
> printf("%s: invalid unit number: %d\n", __func__, unit);
> return (0);
> }
3360,3371c3169,3180
< addr = addr & ~3;
< if (addr < MID_RAMOFF || addr + len*4 > MID_MAXOFF || len <= 0) {
< printf("invalid addr/len number: %d, %d\n", addr, len);
< return(0);
< }
< printf("dumping %d words starting at offset 0x%x\n", len, addr);
< while (len--) {
< reg = EN_READ(sc, addr);
< printf("mem[0x%x] = 0x%x\n", addr, reg);
< addr += 4;
< }
< return(0);
---
> addr = addr & ~3;
> if (addr < MID_RAMOFF || addr + len * 4 > MID_MAXOFF || len <= 0) {
> printf("invalid addr/len number: %d, %d\n", addr, len);
> return (0);
> }
> printf("dumping %d words starting at offset 0x%x\n", len, addr);
> while (len--) {
> reg = en_read(sc, addr);
> printf("mem[0x%x] = 0x%x\n", addr, reg);
> addr += 4;
> }
> return (0);