MAJOR CHANGES: [contributed by Chuck Cranor <chuck@ccrc.wustl.edu> and

Anne Hutton <hutton@isi.edu>]:
   - add support for Adaptec 155 PCI ATM cards (e.g. ANA-5940)
          - add sc->is_adaptec to handle differences between cards.
          - break out MID_MK_TXQ/MID_MK_RXQ seperate macros to handle
                  the new Adaptec format TXQ/RXQ.
          - adjust en_dqneed to return 1 on ADP (since the Adaptec can
                  DMA anything in one DRQ/DTQ!)
          - add hook for a bus specific reset function (adaptec has
                  a seperate reset register that needs to be hit when
                  resettting the midway).
          - adjust DMA test to not worry about burst sizes on the
                  adaptec (since it handles it all for us!) and to handle
                  the new DTQ/DRQ format.
          - add Adaptec DMA support to en_txlaunch() and en_service()


BUG FIXES:
   - fixed receiver panic under heavy load ("lost mbuf in slot 0!").
          when the reassembly buffer overflows, the T-bit is set in
          the RDB and the data field is empty.  en_service() sets up
          a 4-byte (RDB size) dummy DMA without IF_ENQUEUE.  but the
          recv intr handling in en_intr() always does IF_DEQUEUE.
          as a result, a successive recv intr loses its mbuf and
          leads to a panic.  the solution is to only IF_DEQUEUE if
          the interrupt has non-zero length (indicating that there
          is an mbuf to get).   in order for this to work, EN_DQ_MK
          must always be non-zero.   we do this by or'ing in an unused
          bit (0x80000).
                  reported by: Kenjiro Cho <kjc@csl.sony.co.jp>

   - fix setting of transmit channel when txspeed[] is non-zero
          (e.g. traffic shaping).    the old scheme didn't work
          properly (it allowed the same VCI to use multiple tx channels
          thus defeating the txspeed[] parameter).   the new scheme
          statically assigns a VC to a channel when txspeed[] is set.
          [note that the code to set txspeed[] isn't in the driver right
          now since a MI interface to do this hasn't been made yet]
          we add sc->txvc2slot[] and sc->txslot[n].nref for this.
                  reported by: Kenjiro Cho <kjc@csl.sony.co.jp>,
                                  Milind M Buddihikot <milind@ccrc.wustl.edu>,
                                  Dong Lin <dong@eecs.harvard.edu>

   - when doing SRAM copies, be sure to round up the length to the next
          largest word (otherwise the driver will try to do a byte clean
          up DMA and then get an ID error interrupt).


MINOR CLEANUPS:
   - clean up loops in DMA test
                  contributed by: Kenjiro Cho <kjc@csl.sony.co.jp>

   - restructure and cleanup of en_read/en_write macros/inlines

   - clean up some byte ordering stuff so that we are consistant throughout
          the driver
This commit is contained in:
chuck 1997-03-20 21:34:42 +00:00
parent aeee0bf5a5
commit 63c14f2d75
3 changed files with 337 additions and 137 deletions

View File

@ -1,5 +1,5 @@
/* $NetBSD: midway.c,v 1.24 1997/03/11 23:30:19 chuck Exp $ */
/* (sync'd to midway.c 1.66) */
/* $NetBSD: midway.c,v 1.25 1997/03/20 21:34:42 chuck Exp $ */
/* (sync'd to midway.c 1.67) */
/*
*
@ -236,93 +236,6 @@ static struct en_dmatab en_dma_planB[] = {
static struct en_dmatab *en_dmaplan = en_dma_planA;
/*
* macros/inline
*/
#ifdef EN_DEBUG_RANGE
u_int32_t en_read(sc, r)
struct en_softc *sc;
u_int32_t r;
{
if (r > MID_MAXOFF || (r % 4)) {
printf("en_read out of range, r=0x%x\n", r);
panic("en_read");
}
return(bus_space_read_4(sc->en_memt, sc->en_base, r));
}
#define EN_READ(SC,R) ntohl(en_read(SC,R))
#define EN_READDAT(SC,R) en_read(SC,R)
void en_write(sc, r, v)
struct en_softc *sc;
u_int32_t r, v;
{
if (r > MID_MAXOFF || (r % 4)) {
printf("en_write out of range, r=0x%x\n", r);
panic("en_write");
}
bus_space_write_4(sc->en_memt, sc->en_base, r, v);
}
#define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V))
#define EN_WRITEDAT(SC,R,V) en_write(SC,R,V)
#else /* EN_DEBUG_RANGE */
#define EN_READ(SC,R) ntohl(bus_space_read_4((SC)->en_memt, (SC)->en_base, (R)))
#define EN_WRITE(SC,R,V) \
bus_space_write_4((SC)->en_memt, (SC)->en_base, (R), htonl((V)))
#define EN_READDAT(SC,R) bus_space_read_4((SC)->en_memt, (SC)->en_base, (R))
#define EN_WRITEDAT(SC,R,V) \
bus_space_write_4((SC)->en_memt, (SC)->en_base, (R), (V))
#define EN_WRAPADD(START,STOP,CUR,VAL) { \
(CUR) = (CUR) + (VAL); \
if ((CUR) >= (STOP)) \
(CUR) = (START) + ((CUR) - (STOP)); \
}
#endif /* EN_DEBUG_RANGE */
#define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t))
/* we store sc->dtq and sc->drq data in the following format... */
#define EN_DQ_MK(SLOT,LEN) (((SLOT) << 20)|(LEN))
#define EN_DQ_SLOT(X) ((X) >> 20)
#define EN_DQ_LEN(X) ((X) & 0xfffff)
/* add an item to the DTQ */
#define EN_DTQADD(SC,CNT,CHAN,BCODE,ADDR,LEN,END) { \
if (END) \
(SC)->dtq[MID_DTQ_A2REG((SC)->dtq_us)] = EN_DQ_MK(CHAN,LEN); \
EN_WRITE((SC), (SC)->dtq_us, \
MID_MK_TXQ((CNT), (CHAN), (END), (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,BCODE,ADDR,LEN,SLOT,END) { \
if (END) \
(SC)->drq[MID_DRQ_A2REG((SC)->drq_us)] = EN_DQ_MK(SLOT,LEN); \
EN_WRITE((SC), (SC)->drq_us, \
MID_MK_RXQ((CNT), (VCI), (END), (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)); \
}
/*
* prototypes
*/
@ -342,12 +255,115 @@ STATIC int en_k2sz __P((int));
STATIC void en_loadvc __P((struct en_softc *, int));
STATIC int en_mfix __P((struct en_softc *, struct mbuf **, struct mbuf *));
STATIC struct mbuf *en_mget __P((struct en_softc *, u_int, u_int *));
STATIC u_int32_t en_read __P((struct en_softc *, u_int32_t));
STATIC int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *, int));
STATIC void en_txdma __P((struct en_softc *, int));
STATIC void en_txlaunch __P((struct en_softc *, int, struct en_launch *));
STATIC void en_service __P((struct en_softc *));
STATIC void en_start __P((struct ifnet *));
STATIC int en_sz2b __P((int));
STATIC void en_write __P((struct en_softc *, u_int32_t, u_int32_t));
/*
* macros/inline
*/
/*
* raw read/write macros
*/
#define EN_READDAT(SC,R) en_read(SC,R)
#define EN_WRITEDAT(SC,R,V) en_write(SC,R,V)
/*
* cooked read/write macros
*/
#define EN_READ(SC,R) ntohl(en_read(SC,R))
#define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V))
#define EN_WRAPADD(START,STOP,CUR,VAL) { \
(CUR) = (CUR) + (VAL); \
if ((CUR) >= (STOP)) \
(CUR) = (START) + ((CUR) - (STOP)); \
}
#define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t))
/* 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)
/* 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)); \
}
/*
* the driver code
@ -362,6 +378,49 @@ STATIC int en_sz2b __P((int));
/***********************************************************************/
/*
* en_read: read a word from the card. this is the only function
* that reads from the card.
*/
STATIC INLINE u_int32_t en_read(sc, r)
struct en_softc *sc;
u_int32_t r;
{
#ifdef EN_DEBUG_RANGE
if (r > MID_MAXOFF || (r % 4)) {
printf("en_read out of range, r=0x%x\n", r);
panic("en_read");
}
#endif
return(bus_space_read_4(sc->en_memt, sc->en_base, r));
}
/*
* en_write: write a word to the card. this is the only function that
* writes to the card.
*/
STATIC INLINE void en_write(sc, r, v)
struct en_softc *sc;
u_int32_t r, v;
{
#ifdef EN_DEBUG_RANGE
if (r > MID_MAXOFF || (r % 4)) {
printf("en_write out of range, r=0x%x\n", r);
panic("en_write");
}
#endif
bus_space_write_4(sc->en_memt, sc->en_base, r, v);
}
/*
* en_k2sz: convert KBytes to a size parameter (a log2)
*/
@ -444,8 +503,17 @@ caddr_t data;
u_int len, tx;
{
int result = 0, needalign, sz;
int result, needalign, sz;
#if !defined(MIDWAY_ENIONLY)
#if !defined(MIDWAY_ADPONLY)
if (sc->is_adaptec)
#endif /* !MIDWAY_ADPONLY */
return(1); /* adaptec can DMA anything in one go */
#endif
#if !defined(MIDWAY_ADPONLY)
result = 0;
if (len < EN_MINDMA) {
if (!tx) /* XXX: conservative */
return(1); /* will copy/DMA_JK */
@ -484,6 +552,7 @@ u_int len, tx;
}
return(result);
#endif /* !MIDWAY_ADPONLY */
}
@ -561,6 +630,8 @@ struct en_softc *sc;
* are aliases for 0x27fffc [note that RAM starts at offset 0x200000]).
*/
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 */
@ -585,6 +656,8 @@ done_probe:
* "hello world"
*/
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 */
@ -597,8 +670,18 @@ done_probe:
(MID_IS_SUNI(reg)) ? "SUNI" : "Utopia",
(!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "",
sc->en_obmemsz / 1024);
printf("%s: maximum DMA burst length = %d bytes%s\n", sc->sc_dev.dv_xname,
sc->bestburstlen, (sc->alburst) ? " (must align)" : "");
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)" : "");
}
#if 0 /* WMAYBE doesn't work, don't complain about it */
/* check if en_dmaprobe disabled wmaybe */
if (en_dmaplan == en_dma_planB)
@ -626,7 +709,8 @@ done_probe:
for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
sc->rxvc2slot[lcv] = RX_NONE;
sc->txspeed[lcv] = 0; /* full */
sc->txspeed[lcv] = 0; /* full */
sc->txvc2slot[lcv] = 0; /* full speed == slot 0 */
}
sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF);
@ -643,6 +727,7 @@ done_probe:
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
@ -754,6 +839,16 @@ struct en_softc *sc;
if (sc->bestburstlen <= 2*sizeof(u_int32_t))
return; /* won't be using WMAYBE */
/*
* adaptec does not have (or need) wmaybe. do not bother testing
* for it.
*/
if (sc->is_adaptec) {
/* XXX, actually don't need a DMA plan: adaptec is smarter than that */
en_dmaplan = en_dma_planB;
return;
}
/*
* test that WMAYBE dma works like we think it should
* (i.e. no alignment restrictions on host address other than alburst)
@ -796,11 +891,10 @@ int wmtry;
* set up a 1k buffer at MID_BUFOFF
*/
if (sc->en_busreset)
sc->en_busreset(sc);
EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */
for (lcv = MID_BUFOFF ; lcv < 1024; lcv += 4)
EN_WRITE(sc, lcv, 0); /* zero memory */
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)
@ -829,6 +923,13 @@ int wmtry;
*/
for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) {
/* 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;
if (wmtry) {
count = (sc->bestburstlen - sizeof(u_int32_t)) / sizeof(u_int32_t);
bcode = en_dmaplan[count].bcode;
@ -837,7 +938,10 @@ int wmtry;
bcode = en_sz2b(lcv);
count = 1;
}
EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ(count, 0, MID_DMA_END, bcode));
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;
@ -860,7 +964,10 @@ int wmtry;
/* "return to sender..." address is known ... */
EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ(count, 0, MID_DMA_END, bcode));
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;
@ -898,6 +1005,12 @@ int wmtry;
/*
* 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].
*/
STATIC int en_ioctl(ifp, cmd, data)
@ -1056,6 +1169,8 @@ int on;
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);
}
@ -1078,6 +1193,10 @@ int on;
sc->rxslot[slot].rxhand = NULL;
sc->rxslot[slot].mode = newmode;
sc->txslot[sc->txvc2slot[vci]].nref--;
sc->txspeed[vci] = 0;
sc->txvc2slot[vci] = 0;
/* 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 ||
@ -1115,6 +1234,8 @@ struct en_softc *sc;
printf("%s: reset\n", sc->sc_dev.dv_xname);
#endif
if (sc->en_busreset)
sc->en_busreset(sc);
EN_WRITE(sc, MID_RESID, 0x0); /* reset hardware */
/*
@ -1198,6 +1319,8 @@ struct en_softc *sc;
#endif
sc->enif.if_flags |= IFF_RUNNING; /* enable */
if (sc->en_busreset)
sc->en_busreset(sc);
EN_WRITE(sc, MID_RESID, 0x0); /* reset */
/*
@ -1308,7 +1431,7 @@ struct ifnet *ifp;
struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */
struct mbuf *m, *lastm, *prev;
struct atm_pseudohdr *ap, *new_ap;
int txchan, c, mlen, got, need, toadd, cellcnt, first;
int txchan, mlen, got, need, toadd, cellcnt, first;
u_int32_t atm_vpi, atm_vci, atm_flags, *dat, aal;
u_int8_t *cp;
@ -1450,19 +1573,10 @@ struct ifnet *ifp;
#endif /* EN_MBUF_OPT */
/*
* choose channel with smallest # of bytes waiting for DMA
* get assigned channel (will be zero unless txspeed[atm_vci] is set)
*/
if (sc->txspeed[atm_vci]) {
txchan = 1;
for (c = 1 ; c < EN_NTX; c++) {
if (sc->txslot[c].mbsize < sc->txslot[txchan].mbsize)
txchan = c;
if (sc->txslot[txchan].mbsize == 0) break; /* zero length!!! */
}
} else {
txchan = 0;
}
txchan = sc->txvc2slot[atm_vci];
if (sc->txslot[txchan].mbsize > EN_TXHIWAT) {
EN_COUNT(sc->txmbovr);
@ -1728,15 +1842,13 @@ again:
sc->enif.if_opackets++;
if ((launch.atm_flags & EN_OBHDR) == 0) {
EN_COUNT(sc->lheader);
/* store tbd1/tbd2 in network byte order */
launch.tbd1 = htonl(MID_TBD_MK1(launch.aal, sc->txspeed[launch.atm_vci],
ncells));
launch.tbd2 = htonl(MID_TBD_MK2(launch.atm_vci, 0, 0));
/* 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);
/* store pdu1 in network byte order */
launch.pdu1 = htonl(MID_PDU_MK1(0, 0, datalen));
launch.pdu1 = MID_PDU_MK1(0, 0, datalen); /* host byte order */
}
en_txlaunch(sc, chan, &launch);
@ -1825,17 +1937,17 @@ struct en_launch *l;
/*
* do we need to insert the TBD by hand?
* note that tbd1/tbd2/pdu1 are in host byte order.
*/
if ((l->atm_flags & EN_OBHDR) == 0) {
/* note: data already in correct byte order. use WRITEDAT to xfer */
#ifdef EN_DEBUG
printf("%s: tx%d: insert header 0x%x 0x%x\n", sc->sc_dev.dv_xname,
chan, ntohl(l->tbd1), ntohl(l->tbd2));
chan, l->tbd1, l->tbd2);
#endif
EN_WRITEDAT(sc, cur, l->tbd1);
EN_WRITE(sc, cur, l->tbd1);
EN_WRAPADD(start, stop, cur, 4);
EN_WRITEDAT(sc, cur, l->tbd2);
EN_WRITE(sc, cur, l->tbd2);
EN_WRAPADD(start, stop, cur, 4);
need -= 8;
}
@ -1857,6 +1969,16 @@ struct en_launch *l;
/* now, determine if we should copy it */
if (l->nodma || (len < EN_MINDMA &&
(len % 4) == 0 && ((unsigned long) data % 4) == 0 && (cur % 4) == 0)) {
/*
* 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) {
@ -1893,6 +2015,35 @@ struct en_launch *l;
len += cnt; /* pad for FLUSH */
}
#if !defined(MIDWAY_ENIONLY)
/*
* the adaptec DMA engine is smart and handles everything for us.
*/
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 */
#if !defined(MIDWAY_ADPONLY)
/*
* the ENI DMA engine is not so smart and need more help from us
*/
/* do we need to do a DMA op to align to word boundary? */
needalign = (unsigned long) data % sizeof(u_int32_t);
if (needalign) {
@ -2011,6 +2162,7 @@ struct en_launch *l;
}
dma = cur; /* update dma pointer */
#endif /* !MIDWAY_ADPONLY */
} /* next mbuf, please */
@ -2036,9 +2188,10 @@ struct en_launch *l;
* 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, MIDDMA_BYTE, vtophys(l->t->m_data), 0, 0);
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",
@ -2051,15 +2204,15 @@ struct en_launch *l;
if (l->aal == MID_TBD_AAL5)
pad -= 2;
#ifdef EN_DEBUG
printf("%s: tx%d: padding %d bytes\n",
sc->sc_dev.dv_xname, chan, pad * sizeof(u_int32_t));
printf("%s: tx%d: padding %d bytes (cur now 0x%x)\n",
sc->sc_dev.dv_xname, chan, 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_WRITEDAT(sc, cur, l->pdu1); /* already in network order */
EN_WRITE(sc, cur, l->pdu1); /* in host byte order */
EN_WRAPADD(start, stop, cur, 8);
}
}
@ -2225,15 +2378,19 @@ void *arg;
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_DEQUEUE(&sc->rxslot[slot].indma, m);
if (!m) {
printf("%s: lost mbuf in slot %d!\n", sc->sc_dev.dv_xname, slot);
panic("enintr: drqsync");
}
if (EN_DQ_LEN(drq) == 0) { /* "JK" trash DMA? */
m = NULL;
} else {
IF_DEQUEUE(&sc->rxslot[slot].indma, m);
if (!m) {
printf("%s: lost mbuf in slot %d!\n", sc->sc_dev.dv_xname, slot);
panic("enintr: drqsync");
}
}
/* do something with this mbuf */
if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { /* drain? */
m_freem(m);
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 &&
@ -2247,7 +2404,7 @@ void *arg;
slot, vci);
#endif
}
} else {
} 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);
@ -2257,6 +2414,7 @@ void *arg;
EN_DQ_LEN(drq), sc->rxslot[slot].rxhand);
#endif
sc->enif.if_ipackets++;
atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand);
}
@ -2461,7 +2619,7 @@ defer: /* defer processing */
pdu = cur + tlen - MID_PDU_SIZE;
if (pdu >= stop)
pdu -= (EN_RXSZ*1024);
pdu = EN_READ(sc, pdu); /* READ swaps to proper byte order */
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) {
printf("%s: invalid AAL5 PDU length or CRC detected, dropping frame\n",
@ -2612,6 +2770,35 @@ defer: /* defer processing */
#endif
}
#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 */
#if !defined(MIDWAY_ADPONLY)
/*
* the ENI DMA engine is not so smart and need more help from us
*/
/* do we need to do a DMA op to align? */
if (sc->alburst &&
(needalign = (((unsigned long) data) & sc->bestburstmask)) != 0) {
@ -2677,6 +2864,8 @@ defer: /* defer processing */
dma = cur; /* update dma pointer */
#endif /* !MIDWAY_ADPONLY */
}
/* skip the end */

View File

@ -1,4 +1,4 @@
/* $NetBSD: midwayreg.h,v 1.5 1996/10/21 22:34:30 thorpej Exp $ */
/* $NetBSD: midwayreg.h,v 1.6 1997/03/20 21:34:47 chuck Exp $ */
/*
* m i d w a y r e g . h
@ -208,9 +208,12 @@ typedef caddr_t bus_addr_t;
/* convert byte offset to reg value */
#define MID_DRQ_REG2A(N) (((N) << 3) + MID_DRQOFF) /* and back */
#define MID_MK_RXQ(CNT,VC,END,TYPE) \
/* note: format of word 1 of RXQ is different beween ENI and ADP cards */
#define MID_MK_RXQ_ENI(CNT,VC,END,TYPE) \
( ((CNT) << 16)|((VC) << 6)|(END)|(TYPE) )
#define MID_MK_RXQ_ADP(CNT,VC,END,JK) \
( ((CNT) << 12)|((VC) << 2)|((END) >> 4)|(((JK) != 0) ? 1 : 0))
/*
* dma xmit q.
*/
@ -221,9 +224,13 @@ typedef caddr_t bus_addr_t;
#define MID_DTQ_REG2A(N) (((N) << 3) + MID_DTQOFF) /* and back */
#define MID_MK_TXQ(CNT,CHN,END,TYPE) \
/* note: format of word 1 of TXQ is different beween ENI and ADP cards */
#define MID_MK_TXQ_ENI(CNT,CHN,END,TYPE) \
( ((CNT) << 16)|((CHN) << 6)|(END)|(TYPE) )
#define MID_MK_TXQ_ADP(CNT,CHN,END,JK) \
( ((CNT) << 12)|((CHN) << 2)|((END) >> 4)|(((JK) != 0) ? 1 : 0) )
/*
* dma types
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: midwayvar.h,v 1.9 1997/03/11 23:30:21 chuck Exp $ */
/* $NetBSD: midwayvar.h,v 1.10 1997/03/20 21:34:46 chuck Exp $ */
/*
*
@ -104,6 +104,8 @@ struct en_softc {
bus_space_tag_t en_memt; /* for EN_READ/EN_WRITE */
bus_space_handle_t en_base; /* base of en card */
bus_size_t en_obmemsz; /* size of en card (bytes) */
void (*en_busreset) __P((void *));
/* bus specific reset function */
/* serv list */
u_int32_t hwslistp; /* hw pointer to service list (byte offset) */
@ -133,12 +135,14 @@ struct en_softc {
u_int32_t bfree; /* # free bytes in buffer (not dma or xmit) */
u_int32_t start, stop; /* ends of buffer area (byte offset) */
u_int32_t cur; /* next free area (byte offset) */
u_int32_t nref; /* # of VCs using this channel */
struct ifqueue indma; /* mbufs being dma'd now */
struct ifqueue q; /* mbufs waiting for dma now */
} txslot[MID_NTX_CH];
/* xmit vc ctrl. (per vc) */
u_int8_t txspeed[MID_N_VC]; /* speed of tx on a VC */
u_int8_t txvc2slot[MID_N_VC]; /* map VC to slot */
/* recv vc ctrl. (per vc). maps VC number to recv slot */
u_int16_t rxvc2slot[MID_N_VC];