diff options
Diffstat (limited to 'drivers/net/ne.c')
-rw-r--r-- | drivers/net/ne.c | 115 |
1 files changed, 91 insertions, 24 deletions
diff --git a/drivers/net/ne.c b/drivers/net/ne.c index c2c97ff28..2d787895e 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -1,4 +1,3 @@ -#define rw_bugfix /* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */ /* Written 1992-94 by Donald Becker. @@ -14,8 +13,16 @@ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 This driver should work with many programmed-I/O 8390-based ethernet - boards. Currently it support the NE1000, NE2000, many clones, + boards. Currently it supports the NE1000, NE2000, many clones, and some Cabletron products. + + 13/04/95 -- Change in philosophy. We now monitor ENISR_RDC for + handshaking the Tx PIO xfers. If we don't get a RDC within a + reasonable period of time, we know the 8390 has gone south, and we + kick the board before it locks the system. Also use set_bit() to + create atomic locks on the PIO xfers, and added some defines + that the end user can play with to save memory. -- Paul Gortmaker + */ /* Routines for the NatSemi-based designs (NE[12]000). */ @@ -23,7 +30,6 @@ static char *version = "ne.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> @@ -32,6 +38,20 @@ static char *version = #include <linux/netdevice.h> #include "8390.h" + +/* Some defines that people can play with if so inclined. */ + +/* Do we support clones that don't adhere to 14,15 of the SAprom ? */ +#define CONFIG_NE_BAD_CLONES + +/* Do we perform extra sanity checks on stuff ? */ +/* #define CONFIG_NE_SANITY */ + +/* Do we implement the read before write bugfix ? */ +/* #define CONFIG_NE_RW_BUGFIX */ + +/* ---- No user-serviceable parts below ---- */ + extern struct device *init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp); @@ -40,14 +60,20 @@ extern struct device *init_etherdev(struct device *dev, int sizeof_private, static unsigned int netcard_portlist[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0}; +#ifdef CONFIG_NE_BAD_CLONES /* A list of bad clones that we none-the-less recognize. */ static struct { char *name8, *name16; unsigned char SAprefix[4];} bad_clone_list[] = { {"DE100", "DE200", {0x00, 0xDE, 0x01,}}, {"DE120", "DE220", {0x00, 0x80, 0xc8,}}, {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh? */ + {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}}, + {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */ + {"NN1000", "NN2000", {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */ + {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}}, /* Outlaw 4-Dimension cards. */ {0,} }; +#endif #define NE_BASE (dev->base_addr) #define NE_CMD 0x00 @@ -60,6 +86,8 @@ bad_clone_list[] = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ +#define NE_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ + int ne_probe(struct device *dev); static int ne_probe1(struct device *dev, int ioaddr); @@ -126,9 +154,9 @@ static int ne_probe1(struct device *dev, int ioaddr) char *name = NULL; int start_page, stop_page; int neX000, ctron; - int reg0 = inb(ioaddr); + int reg0 = inb_p(ioaddr); - if ( reg0 == 0xFF) + if (reg0 == 0xFF) return ENODEV; /* Do a preliminary verification that we have a 8390. */ @@ -140,7 +168,7 @@ static int ne_probe1(struct device *dev, int ioaddr) inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ if (inb_p(ioaddr + EN0_COUNTER0) != 0) { outb_p(reg0, ioaddr); - outb(regd, ioaddr + 0x0d); /* Restore the old values. */ + outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */ return ENODEV; } } @@ -169,6 +197,7 @@ static int ne_probe1(struct device *dev, int ioaddr) }; for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); + } for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { SA_prom[i] = inb(ioaddr + NE_DATAPORT); @@ -208,6 +237,7 @@ static int ne_probe1(struct device *dev, int ioaddr) start_page = 0x01; stop_page = (wordlength == 2) ? 0x40 : 0x20; } else { +#ifdef CONFIG_NE_BAD_CLONES /* Ack! Well, there might be a *bad* NE*000 clone there. Check for total bogus addresses. */ for (i = 0; bad_clone_list[i].name8; i++) { @@ -227,6 +257,11 @@ static int ne_probe1(struct device *dev, int ioaddr) SA_prom[14], SA_prom[15]); return ENXIO; } +#else + printk(" not found.\n"); + return ENXIO; +#endif + } @@ -242,7 +277,7 @@ static int ne_probe1(struct device *dev, int ioaddr) outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ dev->irq = autoirq_report(0); if (ei_debug > 2) - printk(" autoirq is %d", dev->irq); + printk(" autoirq is %d\n", dev->irq); } else if (dev->irq == 2) /* Fixup for users that don't know that IRQ 2 is really IRQ 9, or don't know which one to set. */ @@ -251,7 +286,7 @@ static int ne_probe1(struct device *dev, int ioaddr) /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ { - int irqval = request_irq (dev->irq, ei_interrupt, 0, "ne"); + int irqval = request_irq (dev->irq, ei_interrupt, 0, wordlength==2 ? "ne2000":"ne1000"); if (irqval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); return EAGAIN; @@ -260,7 +295,7 @@ static int ne_probe1(struct device *dev, int ioaddr) dev->base_addr = ioaddr; - snarf_region(ioaddr, NE_IO_EXTENT); + request_region(ioaddr, NE_IO_EXTENT, wordlength==2 ? "ne2000":"ne1000"); for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; @@ -318,10 +353,13 @@ ne_reset_8390(struct device *dev) static int ne_block_input(struct device *dev, int count, char *buf, int ring_offset) { +#ifdef CONFIG_NE_SANITY int xfer_count = count; +#endif int nic_base = dev->base_addr; - if (ei_status.dmaing) { + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (set_bit(0,(void*)&ei_status.dmaing)) { if (ei_debug > 0) printk("%s: DMAing conflict in ne_block_input " "[DMAstat:%d][irqlock:%d][intr:%d].\n", @@ -329,7 +367,7 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset) dev->interrupt); return 0; } - ei_status.dmaing |= 0x01; + ei_status.dmaing |= 0x02; outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); outb_p(count & 0xff, nic_base + EN0_RCNTLO); outb_p(count >> 8, nic_base + EN0_RCNTHI); @@ -338,21 +376,26 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset) outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { insw(NE_BASE + NE_DATAPORT,buf,count>>1); - if (count & 0x01) - buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++; + if (count & 0x01) { + buf[count-1] = inb(NE_BASE + NE_DATAPORT); +#ifdef CONFIG_NE_SANITY + xfer_count++; +#endif + } } else { insb(NE_BASE + NE_DATAPORT, buf, count); } /* This was for the ALPHA version only, but enough people have - encountering problems that it is still here. If you see + been encountering problems so it is still here. If you see this message you either 1) have a slightly incompatible clone or 2) have noise/speed problems with your bus. */ +#ifdef CONFIG_NE_SANITY if (ei_debug > 1) { /* DMA termination address check... */ int addr, tries = 20; do { /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here - -- it's broken! Check the "DMA" address instead. */ + -- it's broken for Rx on some cards! */ int high = inb_p(nic_base + EN0_RSARHI); int low = inb_p(nic_base + EN0_RSARLO); addr = (high << 8) + low; @@ -364,7 +407,9 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset) "%#4.4x (expected) vs. %#4.4x (actual).\n", dev->name, ring_offset + xfer_count, addr); } - ei_status.dmaing &= ~0x01; +#endif + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x03; return ring_offset + count; } @@ -372,15 +417,20 @@ static void ne_block_output(struct device *dev, int count, const unsigned char *buf, const int start_page) { +#ifdef CONFIG_NE_SANITY int retries = 0; +#endif int nic_base = NE_BASE; + unsigned long dma_start; /* Round the count up for word writes. Do we need to do this? What effect will an odd byte count have on the 8390? I should check someday. */ if (ei_status.word16 && (count & 0x01)) count++; - if (ei_status.dmaing) { + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (set_bit(0,(void*)&ei_status.dmaing)) { if (ei_debug > 0) printk("%s: DMAing conflict in ne_block_output." "[DMAstat:%d][irqlock:%d][intr:%d]\n", @@ -388,12 +438,15 @@ ne_block_output(struct device *dev, int count, dev->interrupt); return; } - ei_status.dmaing |= 0x02; + ei_status.dmaing |= 0x04; /* We should already be in page 0, but to be safe... */ outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); +#ifdef CONFIG_NE_SANITY retry: -#if defined(rw_bugfix) +#endif + +#ifdef CONFIG_NE_RW_BUGFIX /* Handle the read-before-write bug the same way as the Crynwr packet driver -- the NatSemi method doesn't work. Actually this doesn't always work either, but if you have @@ -409,7 +462,9 @@ ne_block_output(struct device *dev, int count, SLOW_DOWN_IO; #endif /* rw_bugfix */ - /* Now the normal output. */ + outb_p(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ outb_p(count & 0xff, nic_base + EN0_RCNTLO); outb_p(count >> 8, nic_base + EN0_RCNTHI); outb_p(0x00, nic_base + EN0_RSARLO); @@ -422,13 +477,14 @@ ne_block_output(struct device *dev, int count, outsb(NE_BASE + NE_DATAPORT, buf, count); } + dma_start = jiffies; + +#ifdef CONFIG_NE_SANITY /* This was for the ALPHA version only, but enough people have - encountering problems that it is still here. */ + been encountering problems so it is still here. */ if (ei_debug > 1) { /* DMA termination address check... */ int addr, tries = 20; do { - /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here - -- it's broken! Check the "DMA" address instead. */ int high = inb_p(nic_base + EN0_RSARHI); int low = inb_p(nic_base + EN0_RSARLO); addr = (high << 8) + low; @@ -443,7 +499,18 @@ ne_block_output(struct device *dev, int count, goto retry; } } - ei_status.dmaing &= ~0x02; +#endif + + while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > NE_RDC_TIMEOUT) { + printk("%s: timeout waiting for Tx RDC.\n", dev->name); + ne_reset_8390(dev); + NS8390_init(dev,1); + break; + } + + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x05; return; } |