MAJOR CHANGES: [contributed by Chuck Cranor <chuck@ccrc.wustl.edu> and
authorchuck <chuck@openbsd.org>
Thu, 20 Mar 1997 22:03:03 +0000 (22:03 +0000)
committerchuck <chuck@openbsd.org>
Thu, 20 Mar 1997 22:03:03 +0000 (22:03 +0000)
                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>

    - if aal5 frame has a CRC error then the length field in the aal5 trailer
          may not be valid, so we can not use it [and we must dump the frame]
                  contributed by: Yuhang Sun <sunyh@dworkin.wustl.edu> & chuck

   - 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:
   - add some extra support for a few more versions of FreeBSD
                  contributed by: Kenjiro Cho <kjc@csl.sony.co.jp>

   - 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

sys/dev/ic/midway.c
sys/dev/ic/midwayreg.h
sys/dev/ic/midwayvar.h

index dac6867..c3f5c8b 100644 (file)
@@ -1,5 +1,5 @@
-/*     $OpenBSD: midway.c,v 1.19 1997/01/24 20:57:52 chuck Exp $       */
-/*     (sync'd to midway.c 1.65)       */
+/*     $OpenBSD: midway.c,v 1.20 1997/03/20 22:03:03 chuck Exp $       */
+/*     (sync'd to midway.c 1.67)       */
 
 /*
  *
 #include <pci/midwayreg.h>
 #include <pci/midwayvar.h>
 #include <vm/pmap.h>                   /* for vtophys proto */
+
+/* 
+ * 2.1.x does not have if_softc.   detect this by seeing if IFF_NOTRAILERS
+ * is defined, as per kjc.
+ */
+#ifdef IFF_NOTRAILERS
+#define MISSING_IF_SOFTC
+#else
 #define IFF_NOTRAILERS 0
 #endif
 
+#endif /* __FreeBSD__ */
+
 /*
  * params
  */
@@ -227,70 +237,113 @@ static struct en_dmatab en_dma_planB[] = {
 static struct en_dmatab *en_dmaplan = en_dma_planA;
   
 /*
- * macros/inline
+ * prototypes
  */
 
-#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)
+STATIC int en_b2sz __P((int));
+#ifdef EN_DDBHOOK
+int    en_dump __P((int,int));
+int    en_dumpmem __P((int,int,int));
+#endif
+STATIC void en_dmaprobe __P((struct en_softc *));
+STATIC int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 
+                                                       u_int8_t *, int));
+STATIC int en_dqneed __P((struct en_softc *, caddr_t, u_int, u_int));
+STATIC void en_init __P((struct en_softc *));
+STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
+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));
 
-void en_write(sc, r, v)
+/*
+ * macros/inline
+ */
 
-struct en_softc *sc;
-u_int32_t r, v;
+/*
+ * raw read/write macros
+ */
 
-{
-  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_READDAT(SC,R) en_read(SC,R)
 #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)))
+/*
+ * cooked read/write macros
+ */
 
-#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_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)); \
        }
-#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_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) & 0xfffff)
+#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,BCODE,ADDR,LEN,END) { \
+#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); \
-       EN_WRITE((SC), (SC)->dtq_us, \
-               MID_MK_TXQ((CNT), (CHAN), (END), (BCODE))); \
+       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); \
@@ -300,11 +353,10 @@ u_int32_t r, v;
 }
 
 /* DRQ add macro */
-#define EN_DRQADD(SC,CNT,VCI,BCODE,ADDR,LEN,SLOT,END) { \
+#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); \
-       EN_WRITE((SC), (SC)->drq_us, \
-               MID_MK_RXQ((CNT), (VCI), (END), (BCODE))); \
+       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); \
@@ -313,32 +365,6 @@ u_int32_t r, v;
          EN_WRITE((SC), MID_DMA_WRRX, MID_DRQ_A2REG((SC)->drq_us)); \
 }
 
-/*
- * prototypes
- */
-
-STATIC int en_b2sz __P((int));
-#ifdef EN_DDBHOOK
-int    en_dump __P((int,int));
-int    en_dumpmem __P((int,int,int));
-#endif
-STATIC void en_dmaprobe __P((struct en_softc *));
-STATIC int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 
-                                                       u_int8_t *, int));
-STATIC int en_dqneed __P((struct en_softc *, caddr_t, u_int, u_int));
-STATIC void en_init __P((struct en_softc *));
-STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
-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 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));
-
 /*
  * the driver code
  *
@@ -352,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)
  */
@@ -434,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 */
@@ -474,6 +552,7 @@ u_int len, tx;
     }
 
     return(result);
+#endif /* !MIDWAY_ADPONLY */
 }
 
 
@@ -551,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 */
@@ -575,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 */
@@ -587,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)
@@ -602,7 +695,9 @@ done_probe:
 #if defined(__NetBSD__) || defined(__OpenBSD__)
   bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ);
 #endif
+#if !defined(MISSING_IF_SOFTC)
   sc->enif.if_softc = sc;
+#endif
   ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS;
   ifp->if_ioctl = en_ioctl;
   ifp->if_output = atm_output;
@@ -614,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);
@@ -631,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
@@ -742,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)
@@ -784,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) 
@@ -817,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;
@@ -825,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;
@@ -848,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;
@@ -886,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)
@@ -895,7 +1020,11 @@ EN_IOCTL_CMDT cmd;
 caddr_t data;
 
 {
+#ifdef MISSING_IF_SOFTC
+    struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
+#else
     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
+#endif
     struct ifaddr *ifa = (struct ifaddr *) data;
     struct ifreq *ifr = (struct ifreq *) data;
     struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data;
@@ -1040,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);
   }
@@ -1062,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 ||
@@ -1099,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 */
 
   /*
@@ -1182,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 */
 
   /*
@@ -1284,11 +1423,15 @@ STATIC void en_start(ifp)
 struct ifnet *ifp;
 
 {
+#ifdef MISSING_IF_SOFTC
+    struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
+#else
     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
+#endif
     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;
 
@@ -1430,25 +1573,16 @@ 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);
        m_freem(m);
 #ifdef EN_DEBUG
-       printf("%s: tx%d: buffer space shortage\n", ifp->if_xname,
+       printf("%s: tx%d: buffer space shortage\n", sc->sc_dev.dv_xname,
                txchan);
 #endif
        continue;
@@ -1708,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);
@@ -1805,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;
   }
@@ -1837,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) {
@@ -1873,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) {
@@ -1991,6 +2162,7 @@ struct en_launch *l;
     }
 
     dma = cur;         /* update dma pointer */
+#endif /* !MIDWAY_ADPONLY */
 
   } /* next mbuf, please */
 
@@ -2016,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", 
@@ -2031,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);
     }
   }
@@ -2205,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 &&
@@ -2227,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);
@@ -2237,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);
        }
 
@@ -2441,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", 
@@ -2592,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) {
@@ -2657,6 +2864,8 @@ defer:                                    /* defer processing */
 
     dma = cur;         /* update dma pointer */
 
+#endif /* !MIDWAY_ADPONLY */
+
   }
 
   /* skip the end */
index 27fc0b2..13a28ca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: midwayreg.h,v 1.6 1996/11/12 22:46:25 niklas Exp $    */
+/*     $OpenBSD: midwayreg.h,v 1.7 1997/03/20 22:03:04 chuck Exp $     */
 
 /*
  * m i d w a y r e g . h
 
 #if defined(sparc) || defined(__FreeBSD__)
 /* XXX: gross.   netbsd/sparc doesn't have machine/bus.h yet. */
-typedef void * bus_chipset_tag_t;
+typedef void * bus_space_tag_t;
 typedef u_int32_t pci_chipset_tag_t;
-typedef caddr_t bus_mem_handle_t;
-typedef u_int32_t bus_mem_size_t;
-typedef caddr_t bus_mem_addr_t;
+typedef caddr_t bus_space_handle_t;
+typedef u_int32_t bus_size_t;
+typedef caddr_t bus_addr_t;
 
-#define bus_mem_read_4(t, h, o) ((void) t, (*(volatile u_int32_t *)((h) + (o))))
-#define bus_mem_write_4(t, h, o, v)                                     \
+#define bus_space_read_4(t, h, o) ((void) t,                            \
+    (*(volatile u_int32_t *)((h) + (o))))
+#define bus_space_write_4(t, h, o, v)                                   \
     ((void) t, ((void)(*(volatile u_int32_t *)((h) + (o)) = (v))))
 
 #if defined(sparc)
@@ -38,12 +39,12 @@ typedef caddr_t bus_mem_addr_t;
  * card data structures, top down
  *
  * in order to have a portable driver, the netbsd guys will not let us
- * use structs.   we have a bus_mem_handle_t which is the en_base address.
+ * use structs.   we have a bus_space_handle_t which is the en_base address.
  * everything else is an offset from that base.   all card data must be 
- * accessed with bus_mem_read_4()/bus_mem_write_4():
+ * accessed with bus_space_read_4()/bus_space_write_4():
  *
- * rv = bus_mem_read_4(sc->en_bc, sc->en_base, BYTE_OFFSET);
- * bus_mem_write_4(sc->en_bc, sc->en_base, BYTE_OFFSET, VALUE);
+ * rv = bus_space_read_4(sc->en_memt, sc->en_base, BYTE_OFFSET);
+ * bus_space_write_4(sc->en_memt, sc->en_base, BYTE_OFFSET, VALUE);
  *
  * en_card: the whole card (prom + phy + midway + obmem)
  *     obmem contains: vci tab + dma queues (rx & tx) + service list + bufs
@@ -207,9 +208,12 @@ typedef caddr_t bus_mem_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.
  */
@@ -220,9 +224,13 @@ typedef caddr_t bus_mem_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
  */
index 2866160..2b5061d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: midwayvar.h,v 1.8 1996/07/16 22:08:16 chuck Exp $     */
+/*     $OpenBSD: midwayvar.h,v 1.9 1997/03/20 22:03:05 chuck Exp $     */
 
 /*
  *
@@ -101,9 +101,11 @@ struct en_softc {
   struct ifnet enif;           /* network ifnet handle */
 
   /* bus glue */
-  bus_chipset_tag_t en_bc;     /* for EN_READ/EN_WRITE */
-  bus_mem_handle_t en_base;    /* base of en card */
-  bus_mem_size_t en_obmemsz;   /* size of en card (bytes) */
+  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];
@@ -189,6 +193,7 @@ struct en_softc {
   u_int8_t bestburstshift;     /* (x >> shift) == (x / bestburstlen) */
   u_int8_t bestburstmask;      /* bits to check if not multiple of burst */
   u_int8_t alburst;            /* align dma bursts? */
+  u_int8_t is_adaptec;         /* adaptec version of midway? */
 };
 
 /*