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:
parent
aeee0bf5a5
commit
63c14f2d75
@ -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 */
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user