mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-16 15:11:52 +00:00
rewrote interrupt code to be cleaner, fixed up some other parts
to make it easier to add future board types.
This commit is contained in:
parent
931407698e
commit
60381058cd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=498
@ -13,10 +13,26 @@
|
||||
* and the 3Com 3c503
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: if_ed.c,v 1.29 93/09/12 04:43:31 davidg Exp Locker: davidg $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -59,6 +75,7 @@
|
||||
|
||||
#include "ed.h"
|
||||
#if NED > 0
|
||||
/* bpfilter included here in case it is needed in future net includes */
|
||||
#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_short vector; /* interrupt vector */
|
||||
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 */
|
||||
@ -125,22 +149,16 @@ struct ed_softc {
|
||||
|
||||
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 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 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 */
|
||||
/*
|
||||
* 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(),
|
||||
@ -193,37 +211,13 @@ ed_probe(isa_dev)
|
||||
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;
|
||||
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->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);
|
||||
@ -257,58 +265,58 @@ ed_probe_WD80x3(isa_dev)
|
||||
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;
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
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) {
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
memsize = 16384;
|
||||
sc->type_str = "WD8013EP";
|
||||
} else {
|
||||
sc->type_str = "WD8003EP";
|
||||
isa16bit = 0;
|
||||
memsize = 8192;
|
||||
memwidth = 8;
|
||||
sc->type_str = "WD8003EP";
|
||||
}
|
||||
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;
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
break;
|
||||
case ED_TYPE_WD8013EPC:
|
||||
sc->type_str = "WD8013EPC";
|
||||
memsize = 16384;
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
break;
|
||||
default:
|
||||
sc->type_str = "unknown";
|
||||
sc->type_str = "";
|
||||
memsize = 8192;
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
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)) {
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
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
|
||||
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
|
||||
@ -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)
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
sc->memwidth = memwidth;
|
||||
sc->isa16bit = isa16bit;
|
||||
sc->smem_start = (caddr_t)isa_dev->id_maddr;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
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)));
|
||||
} 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
|
||||
*/
|
||||
if (memwidth == 16)
|
||||
if (isa16bit)
|
||||
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.
|
||||
*/
|
||||
if (memwidth == 16)
|
||||
if (isa16bit)
|
||||
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;
|
||||
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->type_str = "3c503";
|
||||
|
||||
memsize = 8192;
|
||||
|
||||
/*
|
||||
* Verify that the kernel configured I/O address matches the board
|
||||
* configured address
|
||||
@ -529,9 +534,15 @@ ed_probe_3Com(isa_dev)
|
||||
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);
|
||||
|
||||
@ -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)
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
else
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
|
||||
/*
|
||||
* 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->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->memwidth = memwidth;
|
||||
sc->isa16bit = isa16bit;
|
||||
|
||||
/*
|
||||
* Initialize GA page start/stop registers. Probably only needed
|
||||
@ -748,10 +760,18 @@ ed_attach(isa_dev)
|
||||
/*
|
||||
* 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
|
||||
@ -856,7 +876,7 @@ ed_init(unit)
|
||||
*/
|
||||
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,
|
||||
@ -1088,12 +1108,12 @@ ed_start(ifp)
|
||||
* 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;
|
||||
@ -1106,10 +1126,8 @@ ed_start(ifp)
|
||||
/*
|
||||
* 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);
|
||||
|
||||
@ -1125,6 +1143,9 @@ ed_start(ifp)
|
||||
* 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) {
|
||||
@ -1207,7 +1228,7 @@ ed_start(ifp)
|
||||
/*
|
||||
* 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;
|
||||
{
|
||||
@ -1310,40 +1331,55 @@ edintr(unit)
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -1355,111 +1391,98 @@ edintr(unit)
|
||||
* 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
|
||||
*/
|
||||
ed_reset(unit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmission completed normally.
|
||||
*/
|
||||
if (isr & ED_ISR_PTX) {
|
||||
|
||||
/*
|
||||
* reset tx busy and output active flags
|
||||
*/
|
||||
sc->xmit_busy = 0;
|
||||
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||
|
||||
/*
|
||||
* clear watchdog timer
|
||||
*/
|
||||
sc->arpcom.ac_if.if_timer = 0;
|
||||
|
||||
/*
|
||||
* Update total number of successfully transmitted
|
||||
* packets.
|
||||
*/
|
||||
++sc->arpcom.ac_if.if_opackets;
|
||||
|
||||
/*
|
||||
* Add in total number of collisions on last
|
||||
* transmission.
|
||||
*/
|
||||
sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr +
|
||||
ED_P0_TBCR0);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
* Handle receiver interrupts
|
||||
*/
|
||||
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) {
|
||||
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 {
|
||||
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enable 16bit access to shared memory first
|
||||
* on WD/SMC boards.
|
||||
*/
|
||||
if (sc->isa16bit &&
|
||||
(sc->vendor == ED_VENDOR_WD_SMC)) {
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
/*
|
||||
* 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)
|
||||
|
@ -13,10 +13,26 @@
|
||||
* and the 3Com 3c503
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: if_ed.c,v 1.29 93/09/12 04:43:31 davidg Exp Locker: davidg $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -59,6 +75,7 @@
|
||||
|
||||
#include "ed.h"
|
||||
#if NED > 0
|
||||
/* bpfilter included here in case it is needed in future net includes */
|
||||
#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_short vector; /* interrupt vector */
|
||||
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 */
|
||||
@ -125,22 +149,16 @@ struct ed_softc {
|
||||
|
||||
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 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 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 */
|
||||
/*
|
||||
* 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(),
|
||||
@ -193,37 +211,13 @@ ed_probe(isa_dev)
|
||||
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;
|
||||
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->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);
|
||||
@ -257,58 +265,58 @@ ed_probe_WD80x3(isa_dev)
|
||||
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;
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
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) {
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
memsize = 16384;
|
||||
sc->type_str = "WD8013EP";
|
||||
} else {
|
||||
sc->type_str = "WD8003EP";
|
||||
isa16bit = 0;
|
||||
memsize = 8192;
|
||||
memwidth = 8;
|
||||
sc->type_str = "WD8003EP";
|
||||
}
|
||||
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;
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
break;
|
||||
case ED_TYPE_WD8013EPC:
|
||||
sc->type_str = "WD8013EPC";
|
||||
memsize = 16384;
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
break;
|
||||
default:
|
||||
sc->type_str = "unknown";
|
||||
sc->type_str = "";
|
||||
memsize = 8192;
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
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)) {
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
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
|
||||
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
|
||||
@ -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)
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
sc->memwidth = memwidth;
|
||||
sc->isa16bit = isa16bit;
|
||||
sc->smem_start = (caddr_t)isa_dev->id_maddr;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
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)));
|
||||
} 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
|
||||
*/
|
||||
if (memwidth == 16)
|
||||
if (isa16bit)
|
||||
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.
|
||||
*/
|
||||
if (memwidth == 16)
|
||||
if (isa16bit)
|
||||
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;
|
||||
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->type_str = "3c503";
|
||||
|
||||
memsize = 8192;
|
||||
|
||||
/*
|
||||
* Verify that the kernel configured I/O address matches the board
|
||||
* configured address
|
||||
@ -529,9 +534,15 @@ ed_probe_3Com(isa_dev)
|
||||
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);
|
||||
|
||||
@ -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)
|
||||
memwidth = 16;
|
||||
isa16bit = 1;
|
||||
else
|
||||
memwidth = 8;
|
||||
isa16bit = 0;
|
||||
|
||||
/*
|
||||
* 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->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->memwidth = memwidth;
|
||||
sc->isa16bit = isa16bit;
|
||||
|
||||
/*
|
||||
* Initialize GA page start/stop registers. Probably only needed
|
||||
@ -748,10 +760,18 @@ ed_attach(isa_dev)
|
||||
/*
|
||||
* 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
|
||||
@ -856,7 +876,7 @@ ed_init(unit)
|
||||
*/
|
||||
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,
|
||||
@ -1088,12 +1108,12 @@ ed_start(ifp)
|
||||
* 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;
|
||||
@ -1106,10 +1126,8 @@ ed_start(ifp)
|
||||
/*
|
||||
* 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);
|
||||
|
||||
@ -1125,6 +1143,9 @@ ed_start(ifp)
|
||||
* 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) {
|
||||
@ -1207,7 +1228,7 @@ ed_start(ifp)
|
||||
/*
|
||||
* 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;
|
||||
{
|
||||
@ -1310,40 +1331,55 @@ edintr(unit)
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -1355,111 +1391,98 @@ edintr(unit)
|
||||
* 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
|
||||
*/
|
||||
ed_reset(unit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmission completed normally.
|
||||
*/
|
||||
if (isr & ED_ISR_PTX) {
|
||||
|
||||
/*
|
||||
* reset tx busy and output active flags
|
||||
*/
|
||||
sc->xmit_busy = 0;
|
||||
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||
|
||||
/*
|
||||
* clear watchdog timer
|
||||
*/
|
||||
sc->arpcom.ac_if.if_timer = 0;
|
||||
|
||||
/*
|
||||
* Update total number of successfully transmitted
|
||||
* packets.
|
||||
*/
|
||||
++sc->arpcom.ac_if.if_opackets;
|
||||
|
||||
/*
|
||||
* Add in total number of collisions on last
|
||||
* transmission.
|
||||
*/
|
||||
sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr +
|
||||
ED_P0_TBCR0);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
* Handle receiver interrupts
|
||||
*/
|
||||
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) {
|
||||
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 {
|
||||
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enable 16bit access to shared memory first
|
||||
* on WD/SMC boards.
|
||||
*/
|
||||
if (sc->isa16bit &&
|
||||
(sc->vendor == ED_VENDOR_WD_SMC)) {
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
/*
|
||||
* 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)
|
||||
|
Loading…
Reference in New Issue
Block a user