rewrote interrupt code to be cleaner, fixed up some other parts
authorDavid Greenman <davidg@Root.COM>
Wed, 22 Sep 1993 17:47:43 +0000 (17:47 +0000)
committerDavid Greenman <davidg@Root.COM>
Wed, 22 Sep 1993 17:47:43 +0000 (17:47 +0000)
to make it easier to add future board types.

sys/i386/isa/if_ed.c
sys/i386/isa/if_edreg.h

index 85524fa..eccee0f 100644 (file)
  *   and the 3Com 3c503
  */
 
  *   and the 3Com 3c503
  */
 
+/*
+ * $Id: if_ed.c,v 1.29 93/09/12 04:43:31 davidg Exp Locker: davidg $
+ */
+
 /*
  * Modification history
  *
 /*
  * Modification history
  *
- * $Log:       if_ed.c,v $
+ * Revision 1.29  93/09/12  04:43:31  davidg
+ * cleaned-up probe routine to make it easier to add future board types
+ * 
+ * Revision 1.28  93/09/11  19:17:56  davidg
+ * rewrote interrupt code; leaner and meaner.
+ * 
+ * Revision 1.27  93/09/10  19:15:09  davidg
+ * changed probe/attach so that the type code is printed if the board
+ * type isn't unknown
+ * 
+ * Revision 1.26  93/09/09  02:12:08  davidg
+ * cleaned up header comments a little
+ * 
  * Revision 1.25  93/09/08  23:04:25  davidg
  * fixed problem where 3c503 boards lock up if the cable is 
  * disconnected at boot time. Added printing of irq number if
  * Revision 1.25  93/09/08  23:04:25  davidg
  * fixed problem where 3c503 boards lock up if the cable is 
  * disconnected at boot time. Added printing of irq number if
@@ -59,6 +75,7 @@
  
 #include "ed.h"
 #if    NED > 0
  
 #include "ed.h"
 #if    NED > 0
+/* bpfilter included here in case it is needed in future net includes */
 #include "bpfilter.h"
 
 #include "param.h"
 #include "bpfilter.h"
 
 #include "param.h"
@@ -114,10 +131,17 @@ struct    ed_softc {
        u_char  vendor;         /* interface vendor */
        u_char  type;           /* interface type code */
 
        u_char  vendor;         /* interface vendor */
        u_char  type;           /* interface type code */
 
-       u_short vector;         /* interrupt vector */
        u_short asic_addr;      /* ASIC I/O bus address */
        u_short nic_addr;       /* NIC (DS8390) I/O bus address */
 
        u_short asic_addr;      /* ASIC I/O bus address */
        u_short nic_addr;       /* NIC (DS8390) I/O bus address */
 
+/*
+ * The following 'proto' variable is part of a work-around for 8013EBT asics
+ *     being write-only. It's sort of a prototype/shadow of the real thing.
+ */
+       u_char  wd_laar_proto;
+
+       u_char  isa16bit;       /* width of access to card mem 0=8 or 1=16 */
+
        caddr_t smem_start;     /* shared memory start address */
        caddr_t smem_end;       /* shared memory end address */
        u_long  smem_size;      /* total shared memory size */
        caddr_t smem_start;     /* shared memory start address */
        caddr_t smem_end;       /* shared memory end address */
        u_long  smem_size;      /* total shared memory size */
@@ -125,22 +149,16 @@ struct    ed_softc {
 
        caddr_t bpf;            /* BPF "magic cookie" */
 
 
        caddr_t bpf;            /* BPF "magic cookie" */
 
-       u_char  memwidth;       /* width of access to card mem 8 or 16 */
        u_char  xmit_busy;      /* transmitter is busy */
        u_char  xmit_busy;      /* transmitter is busy */
+       u_char  data_buffered;  /* data has been buffered in interface memory */
        u_char  txb_cnt;        /* Number of transmit buffers */
        u_char  txb_next;       /* Pointer to next buffer ready to xmit */
        u_short txb_next_len;   /* next xmit buffer length */
        u_char  txb_cnt;        /* Number of transmit buffers */
        u_char  txb_next;       /* Pointer to next buffer ready to xmit */
        u_short txb_next_len;   /* next xmit buffer length */
-       u_char  data_buffered;  /* data has been buffered in interface memory */
        u_char  tx_page_start;  /* first page of TX buffer area */
 
        u_char  rec_page_start; /* first page of RX ring-buffer */
        u_char  rec_page_stop;  /* last page of RX ring-buffer */
        u_char  next_packet;    /* pointer to next unread RX packet */
        u_char  tx_page_start;  /* first page of TX buffer area */
 
        u_char  rec_page_start; /* first page of RX ring-buffer */
        u_char  rec_page_stop;  /* last page of RX ring-buffer */
        u_char  next_packet;    /* pointer to next unread RX packet */
-/*
- * The following 'proto' variable is part of a work-around for 8013EBT asics
- *     being write-only. It's sort of a prototype/shadow of the real thing.
- */
-       u_char  wd_laar_proto;
 } ed_softc[NED];
 
 int    ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
 } ed_softc[NED];
 
 int    ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
@@ -193,37 +211,13 @@ ed_probe(isa_dev)
        struct isa_device *isa_dev;
 {
        struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
        struct isa_device *isa_dev;
 {
        struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
-       int i;
-       u_char sum;
+       int nports;
 
 
-       /*
-        * Setup initial i/o address for ASIC and NIC
-        */
-       sc->asic_addr = isa_dev->id_iobase;
-       sc->vector = isa_dev->id_irq;
-       sc->smem_start = (caddr_t)isa_dev->id_maddr;
-       /*
-        * Attempt to do a checksum over the station address PROM.
-        * This is mapped differently on the WD80x3 and 3C503, so if
-        *      it fails, it might be a 3C503. There is a problem with
-        *      this, though: some clone WD boards don't pass the
-        *      checksum test. Danpex boards for one. We need to do
-        *      additional checking for this case.
-        */
-       for (sum = 0, i = 0; i < 8; ++i) {
-               sum += inb(sc->asic_addr + ED_WD_PROM + i);
-       }
-       
-       if (sum == ED_WD_ROM_CHECKSUM_TOTAL) {
-               return (ed_probe_WD80x3(isa_dev));
-       } else {
-               /*
-                * XXX - Should do additional checking to make sure its a 3Com
-                *      and not a broken WD clone
-                */
-               return (ed_probe_3Com(isa_dev));
-       }
+       if (nports = ed_probe_WD80x3(isa_dev))
+               return (nports);
+
+       if (nports = ed_probe_3Com(isa_dev))
+               return (nports);
 }
 
 /*
 }
 
 /*
@@ -236,13 +230,27 @@ ed_probe_WD80x3(isa_dev)
        struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
        int i;
        u_int memsize;
        struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
        int i;
        u_int memsize;
-       u_char iptr, memwidth, sum, tmp;
+       u_char iptr, isa16bit, sum;
+
+       sc->asic_addr = isa_dev->id_iobase;
+       sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
 
 
+       /*
+        * Attempt to do a checksum over the station address PROM.
+        *      If it fails, it's probably not a SMC/WD board. There
+        *      is a problem with this, though: some clone WD boards
+        *      don't pass the checksum test. Danpex boards for one.
+        *      XXX - We need to do additional checking for this case.
+        */
+       for (sum = 0, i = 0; i < 8; ++i)
+               sum += inb(sc->asic_addr + ED_WD_PROM + i);
+       
+       if (sum != ED_WD_ROM_CHECKSUM_TOTAL)
+               return(0);
+       
        sc->vendor = ED_VENDOR_WD_SMC;
        sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
 
        sc->vendor = ED_VENDOR_WD_SMC;
        sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
 
-       sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
-
        /* reset card to force it into a known state. */
        outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST);
        DELAY(100);
        /* reset card to force it into a known state. */
        outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST);
        DELAY(100);
@@ -257,58 +265,58 @@ ed_probe_WD80x3(isa_dev)
        case ED_TYPE_WD8003S:
                sc->type_str = "WD8003S";
                memsize = 8192;
        case ED_TYPE_WD8003S:
                sc->type_str = "WD8003S";
                memsize = 8192;
-               memwidth = 8;
+               isa16bit = 0;
                break;
        case ED_TYPE_WD8003E:
                sc->type_str = "WD8003E";
                memsize = 8192;
                break;
        case ED_TYPE_WD8003E:
                sc->type_str = "WD8003E";
                memsize = 8192;
-               memwidth = 8;
+               isa16bit = 0;
                break;
        case ED_TYPE_WD8013EBT:
                sc->type_str = "WD8013EBT";
                memsize = 16384;
                break;
        case ED_TYPE_WD8013EBT:
                sc->type_str = "WD8013EBT";
                memsize = 16384;
-               memwidth = 16;
+               isa16bit = 1;
                break;
        case ED_TYPE_WD8013EP:          /* also WD8003EP */
                if (inb(sc->asic_addr + ED_WD_ICR)
                        & ED_WD_ICR_16BIT) {
                break;
        case ED_TYPE_WD8013EP:          /* also WD8003EP */
                if (inb(sc->asic_addr + ED_WD_ICR)
                        & ED_WD_ICR_16BIT) {
-                       memwidth = 16;
+                       isa16bit = 1;
                        memsize = 16384;
                        sc->type_str = "WD8013EP";
                } else {
                        memsize = 16384;
                        sc->type_str = "WD8013EP";
                } else {
-                       sc->type_str = "WD8003EP";
+                       isa16bit = 0;
                        memsize = 8192;
                        memsize = 8192;
-                       memwidth = 8;
+                       sc->type_str = "WD8003EP";
                }
                break;
        case ED_TYPE_WD8013WC:
                sc->type_str = "WD8013WC";
                memsize = 16384;
                }
                break;
        case ED_TYPE_WD8013WC:
                sc->type_str = "WD8013WC";
                memsize = 16384;
-               memwidth = 16;
+               isa16bit = 1;
                break;
        case ED_TYPE_WD8013EBP:
                sc->type_str = "WD8013EBP";
                memsize = 16384;
                break;
        case ED_TYPE_WD8013EBP:
                sc->type_str = "WD8013EBP";
                memsize = 16384;
-               memwidth = 16;
+               isa16bit = 1;
                break;
        case ED_TYPE_WD8013EPC:
                sc->type_str = "WD8013EPC";
                memsize = 16384;
                break;
        case ED_TYPE_WD8013EPC:
                sc->type_str = "WD8013EPC";
                memsize = 16384;
-               memwidth = 16;
+               isa16bit = 1;
                break;
        default:
                break;
        default:
-               sc->type_str = "unknown";
+               sc->type_str = "";
                memsize = 8192;
                memsize = 8192;
-               memwidth = 8;
+               isa16bit = 0;
                break;
        }
        /*
         * Make some adjustments to initial values depending on what is
         *      found in the ICR.
         */
                break;
        }
        /*
         * Make some adjustments to initial values depending on what is
         *      found in the ICR.
         */
-       if ((memwidth == 16) && (sc->type != ED_TYPE_WD8013EBT)
+       if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
                && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
                && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
-               memwidth = 8;
+               isa16bit = 0;
                memsize = 8192;
        }
 #if 0 /* This has caused more problems than it's worth */
                memsize = 8192;
        }
 #if 0 /* This has caused more problems than it's worth */
@@ -318,8 +326,8 @@ ed_probe_WD80x3(isa_dev)
 #endif
 
 #if ED_DEBUG
 #endif
 
 #if ED_DEBUG
-       printf("type=%s memwidth=%d memsize=%d id_msize=%d\n",
-               sc->type_str,memwidth,memsize,isa_dev->id_msize);
+       printf("type=%s isa16bit=%d memsize=%d id_msize=%d\n",
+               sc->type_str,isa16bit,memsize,isa_dev->id_msize);
        for (i=0; i<8; i++)
                printf("%x -> %x\n", i, inb(sc->asic_addr + i));
 #endif
        for (i=0; i<8; i++)
                printf("%x -> %x\n", i, inb(sc->asic_addr + i));
 #endif
@@ -333,9 +341,9 @@ ed_probe_WD80x3(isa_dev)
         *      that '8bit' mode intentionally has precedence)
         */
        if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
         *      that '8bit' mode intentionally has precedence)
         */
        if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
-               memwidth = 16;
+               isa16bit = 1;
        if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
        if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
-               memwidth = 8;
+               isa16bit = 0;
 
        /*
         * Check 83C584 interrupt configuration register if this board has one
 
        /*
         * Check 83C584 interrupt configuration register if this board has one
@@ -364,7 +372,9 @@ ed_probe_WD80x3(isa_dev)
                        inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
        }
 
                        inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
        }
 
-       sc->memwidth = memwidth;
+       sc->isa16bit = isa16bit;
+       sc->smem_start = (caddr_t)isa_dev->id_maddr;
+
        /*
         * allocate one xmit buffer if < 16k, two buffers otherwise
         */
        /*
         * allocate one xmit buffer if < 16k, two buffers otherwise
         */
@@ -398,13 +408,13 @@ ed_probe_WD80x3(isa_dev)
         * Set upper address bits and 8/16 bit access to shared memory
         */
        if ((sc->type & ED_WD_SOFTCONFIG) || (sc->type == ED_TYPE_WD8013EBT)) {
         * Set upper address bits and 8/16 bit access to shared memory
         */
        if ((sc->type & ED_WD_SOFTCONFIG) || (sc->type == ED_TYPE_WD8013EBT)) {
-               if (memwidth == 8) {
-                       outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
-                       ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
-               } else {
+               if (isa16bit) {
                        outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
                                ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
                                ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
                        outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
                                ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
                                ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+               } else {
+                       outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+                       ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
                }
        }
 
                }
        }
 
@@ -421,7 +431,7 @@ ed_probe_WD80x3(isa_dev)
                        /*
                         * Disable 16 bit access to shared memory
                         */
                        /*
                         * Disable 16 bit access to shared memory
                         */
-                       if (memwidth == 16)
+                       if (isa16bit)
                                outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
                                        ~ED_WD_LAAR_M16EN));
 
                                outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
                                        ~ED_WD_LAAR_M16EN));
 
@@ -436,7 +446,7 @@ ed_probe_WD80x3(isa_dev)
         *      memory. and 2) so that other 8 bit devices with shared
         *      memory can be used in this 128k region, too.
         */
         *      memory. and 2) so that other 8 bit devices with shared
         *      memory can be used in this 128k region, too.
         */
-       if (memwidth == 16)
+       if (isa16bit)
                outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
                        ~ED_WD_LAAR_M16EN));
 
                outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
                        ~ED_WD_LAAR_M16EN));
 
@@ -453,16 +463,11 @@ ed_probe_3Com(isa_dev)
        struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
        int i;
        u_int memsize;
        struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
        int i;
        u_int memsize;
-       u_char memwidth, sum;
+       u_char isa16bit, sum;
 
 
-       sc->vendor = ED_VENDOR_3COM;
        sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
        sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
 
        sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
        sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
 
-       sc->type_str = "3c503";
-
-       memsize = 8192;
-
        /*
         * Verify that the kernel configured I/O address matches the board
         *      configured address
        /*
         * Verify that the kernel configured I/O address matches the board
         *      configured address
@@ -529,9 +534,15 @@ ed_probe_3Com(isa_dev)
                return(0);
        }
 
                return(0);
        }
 
+       sc->vendor = ED_VENDOR_3COM;
+       sc->type_str = "3c503";
+
+       memsize = 8192;
+
        /*
        /*
-        * Reset NIC and ASIC. Enable on-board transceiver through reset sequence
-        *      because it'll lock up if the cable isn't connected if we don't.
+        * Reset NIC and ASIC. Enable on-board transceiver throughout reset
+        *      sequence because it'll lock up if the cable isn't connected
+        *      if we don't.
         */
        outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
 
         */
        outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
 
@@ -595,9 +606,9 @@ ed_probe_3Com(isa_dev)
         * The 3c503 forces the WTS bit to a one if this is a 16bit board
         */
        if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS)
         * The 3c503 forces the WTS bit to a one if this is a 16bit board
         */
        if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS)
-               memwidth = 16;
+               isa16bit = 1;
        else
        else
-               memwidth = 8;
+               isa16bit = 0;
 
        /*
         * select page 0 registers
 
        /*
         * select page 0 registers
@@ -610,11 +621,12 @@ ed_probe_3Com(isa_dev)
        sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_PAGE_OFFSET;
        sc->rec_page_stop = memsize / ED_PAGE_SIZE + ED_3COM_PAGE_OFFSET;
 
        sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_PAGE_OFFSET;
        sc->rec_page_stop = memsize / ED_PAGE_SIZE + ED_3COM_PAGE_OFFSET;
 
+       sc->smem_start = (caddr_t)isa_dev->id_maddr;
        sc->smem_size = memsize;
        sc->smem_end = sc->smem_start + memsize;
        sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
 
        sc->smem_size = memsize;
        sc->smem_end = sc->smem_start + memsize;
        sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
 
-       sc->memwidth = memwidth;
+       sc->isa16bit = isa16bit;
 
        /*
         * Initialize GA page start/stop registers. Probably only needed
 
        /*
         * Initialize GA page start/stop registers. Probably only needed
@@ -748,10 +760,18 @@ ed_attach(isa_dev)
        /*
         * Print additional info when attached
         */
        /*
         * Print additional info when attached
         */
-       printf("ed%d: address %s, type %s (%dbit) %s\n", isa_dev->id_unit,
-               ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str,
-               sc->memwidth, ((sc->vendor == ED_VENDOR_3COM) &&
-                       (ifp->if_flags & IFF_ALTPHYS)) ? "tranceiver disabled" : "");
+       printf("ed%d: address %s, ", isa_dev->id_unit,
+               ether_sprintf(sc->arpcom.ac_enaddr));
+
+       if (sc->type_str && (*sc->type_str != 0))
+               printf("type %s ", sc->type_str);
+       else
+               printf("type unknown (0x%x) ", sc->type);
+
+       printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)");
+
+       printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
+               (ifp->if_flags & IFF_ALTPHYS)) ? "tranceiver disabled" : "");
 
        /*
         * If BPF is in the kernel, call the attach for it
 
        /*
         * If BPF is in the kernel, call the attach for it
@@ -856,7 +876,7 @@ ed_init(unit)
         */
        outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
 
         */
        outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
 
-       if (sc->memwidth == 16) {
+       if (sc->isa16bit) {
                /*
                 * Set FIFO threshold to 8, No auto-init Remote DMA,
                 *      byte order=80x86, word-wide DMA xfers,
                /*
                 * Set FIFO threshold to 8, No auto-init Remote DMA,
                 *      byte order=80x86, word-wide DMA xfers,
@@ -1088,12 +1108,12 @@ outloop:
         *      Don't update wd_laar_proto because we want to restore the
         *      previous state (because an arp reply in the input code
         *      may cause a call-back to ed_start)
         *      Don't update wd_laar_proto because we want to restore the
         *      previous state (because an arp reply in the input code
         *      may cause a call-back to ed_start)
+        * XXX - the call-back to 'start' is a bug, IMHO.
         */
         */
-       if (sc->memwidth == 16)
-               if (sc->vendor == ED_VENDOR_WD_SMC) {
-                       outb(sc->asic_addr + ED_WD_LAAR,
-                               (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
-               }
+       if (sc->isa16bit && (sc->vendor == ED_VENDOR_WD_SMC)) {
+               outb(sc->asic_addr + ED_WD_LAAR,
+                       (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
+       }
 
        buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE);
        len = 0;
 
        buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE);
        len = 0;
@@ -1106,10 +1126,8 @@ outloop:
        /*
         * Restore previous shared mem access type
         */
        /*
         * Restore previous shared mem access type
         */
-       if (sc->memwidth == 16)
-               if (sc->vendor == ED_VENDOR_WD_SMC) {
-                       outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
-               }
+       if (sc->isa16bit && (sc->vendor == ED_VENDOR_WD_SMC))
+               outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
 
        sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
 
 
        sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
 
@@ -1125,6 +1143,9 @@ outloop:
         * If there is BPF support in the configuration, tap off here.
         *   The following has support for converting trailer packets
         *   back to normal.
         * If there is BPF support in the configuration, tap off here.
         *   The following has support for converting trailer packets
         *   back to normal.
+        * XXX - support for trailer packets in BPF should be moved into
+        *      the bpf code proper to avoid code duplication in all of
+        *      the drivers.
         */
 #if NBPFILTER > 0
        if (sc->bpf) {
         */
 #if NBPFILTER > 0
        if (sc->bpf) {
@@ -1207,7 +1228,7 @@ outloop:
 /*
  * Ethernet interface receiver interrupt.
  */
 /*
  * Ethernet interface receiver interrupt.
  */
-static inline void /* only called from one place, so may as well integrate */
+static inline void
 ed_rint(unit)
        int unit;
 {
 ed_rint(unit)
        int unit;
 {
@@ -1310,40 +1331,55 @@ edintr(unit)
        while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
 
                /*
        while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
 
                /*
-                * reset all the bits that we are 'acknowleging'
+                * reset all the bits that we are 'acknowledging'
                 *      by writing a '1' to each bit position that was set
                 * (writing a '1' *clears* the bit)
                 */
                outb(sc->nic_addr + ED_P0_ISR, isr);
 
                /*
                 *      by writing a '1' to each bit position that was set
                 * (writing a '1' *clears* the bit)
                 */
                outb(sc->nic_addr + ED_P0_ISR, isr);
 
                /*
-                * Transmit error. If a TX completed with an error, we end up
-                *      throwing the packet away. Really the only error that is
-                *      possible is excessive collisions, and in this case it is
-                *      best to allow the automatic mechanisms of TCP to backoff
-                *      the flow. Of course, with UDP we're screwed, but this is
-                *      expected when a network is heavily loaded.
+                * Handle transmitter interrupts. Handle these first
+                *      because the receiver will reset the board under
+                *      some conditions.
                 */
                 */
-               if (isr & ED_ISR_TXE) {
-                       u_char tsr = inb(sc->nic_addr + ED_P0_TSR);
-                       u_char ncr = inb(sc->nic_addr + ED_P0_NCR);
+               if (isr & (ED_ISR_PTX|ED_ISR_TXE)) {
+                       u_char collisions = inb(sc->nic_addr + ED_P0_NCR);
 
                        /*
 
                        /*
-                        * Excessive collisions (16)
+                        * Check for transmit error. If a TX completed with an
+                        * error, we end up throwing the packet away. Really
+                        * the only error that is possible is excessive
+                        * collisions, and in this case it is best to allow the
+                        * automatic mechanisms of TCP to backoff the flow. Of
+                        * course, with UDP we're screwed, but this is expected
+                        * when a network is heavily loaded.
                         */
                         */
-                       if ((tsr & ED_TSR_ABT) && (ncr == 0)) {
+                       if (isr & ED_ISR_TXE) {
+
                                /*
                                /*
-                                *    When collisions total 16, the P0_NCR will
-                                * indicate 0, and the TSR_ABT is set.
+                                * Excessive collisions (16)
                                 */
                                 */
-                               sc->arpcom.ac_if.if_collisions += 16;
-                       } else
-                               sc->arpcom.ac_if.if_collisions += ncr;
+                               if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT)
+                                       && (collisions == 0)) {
+                                       /*
+                                        *    When collisions total 16, the
+                                        * P0_NCR will indicate 0, and the
+                                        * TSR_ABT is set.
+                                        */
+                                       collisions = 16;
+                               }
 
 
-                       /*
-                        * update output errors counter
-                        */
-                       ++sc->arpcom.ac_if.if_oerrors;
+                               /*
+                                * update output errors counter
+                                */
+                               ++sc->arpcom.ac_if.if_oerrors;
+                       } else {
+                               /*
+                                * Update total number of successfully
+                                *      transmitted packets.
+                                */
+                               ++sc->arpcom.ac_if.if_opackets;
+                       }
 
                        /*
                         * reset tx busy and output active flags
 
                        /*
                         * reset tx busy and output active flags
@@ -1355,111 +1391,98 @@ edintr(unit)
                         * clear watchdog timer
                         */
                        sc->arpcom.ac_if.if_timer = 0;
                         * clear watchdog timer
                         */
                        sc->arpcom.ac_if.if_timer = 0;
-               }
-                               
-                       
-               /*
-                * Receiver Error. One or more of: CRC error, frame alignment error
-                *      FIFO overrun, or missed packet.
-                */
-               if (isr & ED_ISR_RXE) {
-                       ++sc->arpcom.ac_if.if_ierrors;
-#ifdef ED_DEBUG
-                       printf("ed%d: receive error %x\n", unit,
-                               inb(sc->nic_addr + ED_P0_RSR));
-#endif
-               }
 
 
-               /*
-                * Overwrite warning. In order to make sure that a lockup
-                *      of the local DMA hasn't occurred, we reset and
-                *      re-init the NIC. The NSC manual suggests only a
-                *      partial reset/re-init is necessary - but some
-                *      chips seem to want more. The DMA lockup has been
-                *      seen only with early rev chips - Methinks this
-                *      bug was fixed in later revs. -DG
-                */
-               if (isr & ED_ISR_OVW) {
-                       ++sc->arpcom.ac_if.if_ierrors;
-                       log(LOG_WARNING,
-                               "ed%d: warning - receiver ring buffer overrun\n",
-                               unit);
                        /*
                        /*
-                        * Stop/reset/re-init NIC
+                        * Add in total number of collisions on last
+                        *      transmission.
                         */
                         */
-                       ed_reset(unit);
+                       sc->arpcom.ac_if.if_collisions += collisions;
+
+                       /*
+                        * If data is ready to transmit, start it transmitting,
+                        *      otherwise defer until after handling receiver
+                        */
+                       if (sc->data_buffered)
+                               ed_xmit(&sc->arpcom.ac_if);
                }
 
                /*
                }
 
                /*
-                * Transmission completed normally.
+                * Handle receiver interrupts
                 */
                 */
-               if (isr & ED_ISR_PTX) {
-
-                       /*
-                        * reset tx busy and output active flags
-                        */
-                       sc->xmit_busy = 0;
-                       sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+               if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) {
+                   /*
+                    * Overwrite warning. In order to make sure that a lockup
+                    *  of the local DMA hasn't occurred, we reset and
+                    *  re-init the NIC. The NSC manual suggests only a
+                    *  partial reset/re-init is necessary - but some
+                    *  chips seem to want more. The DMA lockup has been
+                    *  seen only with early rev chips - Methinks this
+                    *  bug was fixed in later revs. -DG
+                    */
+                       if (isr & ED_ISR_OVW) {
+                               ++sc->arpcom.ac_if.if_ierrors;
+                               log(LOG_WARNING,
+                                       "ed%d: warning - receiver ring buffer overrun\n",
+                                       unit);
+                               /*
+                                * Stop/reset/re-init NIC
+                                */
+                               ed_reset(unit);
+                       } else {
 
 
-                       /*
-                        * clear watchdog timer
-                        */
-                       sc->arpcom.ac_if.if_timer = 0;
+                           /*
+                            * Receiver Error. One or more of: CRC error, frame
+                            *  alignment error FIFO overrun, or missed packet.
+                            */
+                               if (isr & ED_ISR_RXE) {
+                                       ++sc->arpcom.ac_if.if_ierrors;
+#ifdef ED_DEBUG
+                                       printf("ed%d: receive error %x\n", unit,
+                                               inb(sc->nic_addr + ED_P0_RSR));
+#endif
+                               }
 
 
-                       /*
-                        * Update total number of successfully transmitted
-                        *      packets.
-                        */
-                       ++sc->arpcom.ac_if.if_opackets;
+                               /*
+                                * Go get the packet(s)
+                                * XXX - Doing this on an error is dubious
+                                *    because there shouldn't be any data to
+                                *    get (we've configured the interface to
+                                *    not accept packets with errors).
+                                */
 
 
-                       /*
-                        * Add in total number of collisions on last
-                        *      transmission.
-                        */
-                       sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr +
-                               ED_P0_TBCR0);
-               }
+                               /*
+                                * Enable 16bit access to shared memory first
+                                *      on WD/SMC boards.
+                                */
+                               if (sc->isa16bit &&
+                                       (sc->vendor == ED_VENDOR_WD_SMC)) {
 
 
-               /*
-                * Receive Completion. Go and get the packet. 
-                *      XXX - Doing this on an error is dubious because there
-                *         shouldn't be any data to get (we've configured the
-                *         interface to not accept packets with errors).
-                */
-               if (isr & (ED_ISR_PRX|ED_ISR_RXE)) {
-                       /*
-                        * Enable access to shared memory on WD/SMC boards
-                        */
-                       if (sc->memwidth == 16)
-                               if (sc->vendor == ED_VENDOR_WD_SMC) {
                                        outb(sc->asic_addr + ED_WD_LAAR,
                                                (sc->wd_laar_proto |=
                                                 ED_WD_LAAR_M16EN));
                                }
 
                                        outb(sc->asic_addr + ED_WD_LAAR,
                                                (sc->wd_laar_proto |=
                                                 ED_WD_LAAR_M16EN));
                                }
 
-                       ed_rint (unit);
+                               ed_rint (unit);
+
+                               /* disable 16bit access */
+                               if (sc->isa16bit &&
+                                       (sc->vendor == ED_VENDOR_WD_SMC)) {
 
 
-                       /*
-                        * Disable access to shared memory
-                        */
-                       if (sc->memwidth == 16)
-                               if (sc->vendor == ED_VENDOR_WD_SMC) {
                                        outb(sc->asic_addr + ED_WD_LAAR,
                                                (sc->wd_laar_proto &=
                                                 ~ED_WD_LAAR_M16EN));
                                }
                                        outb(sc->asic_addr + ED_WD_LAAR,
                                                (sc->wd_laar_proto &=
                                                 ~ED_WD_LAAR_M16EN));
                                }
+                       }
                }
 
                /*
                 * If it looks like the transmitter can take more data,
                }
 
                /*
                 * If it looks like the transmitter can take more data,
-                *      attempt to start output on the interface. If data is
-                *      already buffered and ready to go, send it first.
+                *      attempt to start output on the interface.
+                *      This is done after handling the receiver to
+                *      give the receiver priority.
                 */
                 */
-               if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) {
-                       if (sc->data_buffered)
-                               ed_xmit(&sc->arpcom.ac_if);
+               if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0)
                        ed_start(&sc->arpcom.ac_if);
                        ed_start(&sc->arpcom.ac_if);
-               }
 
                /*
                 * return NIC CR to standard state: page 0, remote DMA complete,
 
                /*
                 * return NIC CR to standard state: page 0, remote DMA complete,
@@ -1835,4 +1858,3 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
        return (m);
 }
 #endif
        return (m);
 }
 #endif
-
index 79f84c2..949acb4 100644 (file)
@@ -1,6 +1,10 @@
 /*
  * National Semiconductor DS8390 NIC register definitions 
  *
 /*
  * National Semiconductor DS8390 NIC register definitions 
  *
+ * $Id$
+ *
+ * Modification history
+ *
  * $Log:       if_edreg.h,v $
  * Revision 1.5  93/08/25  20:38:34  davidg
  * added define for card type WD8013WC (10BaseT)
  * $Log:       if_edreg.h,v $
  * Revision 1.5  93/08/25  20:38:34  davidg
  * added define for card type WD8013WC (10BaseT)