[200] in linux-net channel archive
Patch to fix NE2000 hangs
daemon@ATHENA.MIT.EDU (Paul Gortmaker)
Fri Apr 14 05:18:46 1995
From: Paul Gortmaker <paul@rasty.anu.edu.au>
To: linux-net@vger.rutgers.edu
Date: Fri, 14 Apr 1995 17:09:38 +1000 (EST)
Okay, here is my latest attempt at solving everybody's problems
with ne2000 cards. These patches are against 1.2.5, and will *fail*
against any earlier versions. Let me quickly run through the changes.
1) Most important: We now handshake with ENISR_RDC, instead of ignoring
it. If we are expecting an RDC interrupt, but don't get one, the 8390
will hang the machine if we try to do another PIO xfer. Now we reset the
card if we timeout (>10 jiffies) waiting for the RDC. If you see the
message "kicking board" in your system log (or via dmesg) you just
avoided a hard lockup. It took me *ages* to find this one. The
delays caused by cli/sti pairs (c.f. 1.2.4) mask the symptoms
for some people, but just hide the problem deeper...
2) Should fix problems with some ne2k cards not detected at boot. Don's
ne2k diagnostic program would find these cards because it used inb_p
when reading the SA PROM, wheras the driver used inb.
As Nat Semi says not to use back to back i/o on 8390 chips,
any i/o code that is not in the Rx/Tx path should use pausing i/o.
This goes for all 8390 cards, and not just the ne2k. As for code
that is the Rx/Tx path, well pausing i/o is a bit of a performance
hit, so we just write things so there is no back to back outb/inb
calls that could kill us.
3) Move the Tx timeout to a define in 8390.h, and bump it up from 10
jiffies to 15. Under heavy net-abuse, I was getting lots of Tx timeouts
with a status of 0x04, meaning we got at least one collision, but
didn't get the max of 16 before we gave up and stomped on the
board (needlessly, I might add). See an Ethernet spec sheet if you are
confused. At 15 jiffies it is much better, with only a few 0x04
timeouts happening. Probably could run 20, but most people don't
bash the code as bad as I do, so we'll leave it for now....
4) Move the max number of 8390 interrupt service routines to be done
per physical interrupt to a define in 8390.h -- also bumped it up
to 12, from 9. This minor increase cuts the "Too much work..."
messages to nil, even under heavy abuse, and since all of the ISR
runs with interrupts enabled, it won't starve anything else.
5) Don't get the stats from a card that hasn't been started, as
the 8390 will return garbage. (We should then have a dev->stop
function that calls get_stats() and also leaves the 8390
in a sane state to avoid warm boot probe hangs, but I'll look
into that later...)
6) Speeeeleng typeoos and othar miscalaneoous stuf I cnt rember now.
Please test it with ne cards (and other 8390 based cards) and let me
know the results via here or e-mail.
NB: If you are using a 3c503 in programmed i/o mode, and not shared
memory mode, you may get messages like "unexpected RDC interrupt",
but you are an idiot if you use a 3c503 in PIO mode anyway, as
it is tons slower, and the driver hasn't been updated to support PIO
since its conception. I don't know if it even works. Rejumper it for
shared mem, like the message in the kernel says...
Paul.
== begin patch against 1.2.5 ==
--- /tmp/linux-oem/drivers/net/8390.h Mon Jan 16 16:17:36 1995
+++ linux/drivers/net/8390.h Fri Apr 14 14:04:12 1995
@@ -44,9 +44,10 @@
unsigned open:1;
unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
unsigned txing:1; /* Transmit Active */
- unsigned dmaing:2; /* Remote DMA Active */
unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
unsigned pingpong:1; /* Using the ping-pong driver */
+ unsigned char dmaing; /* Remote DMA (Tx/Rx/Active) */
+ unsigned long dma_start; /* Remote DMA start (in jiffies) */
unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */
unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
@@ -61,6 +62,15 @@
struct enet_statistics stat;
};
+/* The maximum number of 8390 interrupt serivce routines called per IRQ. */
+#define MAX_SERVICE 12
+
+/* The maximum number of jiffies waited before assuming a Tx failed. */
+#define TX_TIMEOUT 15
+
+/* The maximum number of jiffies waited before assuming a PIO xfer failed. */
+#define DMA_TIMEOUT 10
+
#define ei_status (*(struct ei_device *)(dev->priv))
/* Some generic ethernet register configurations. */
--- /tmp/linux-oem/drivers/net/8390.c Mon Jan 23 19:38:28 1995
+++ linux/drivers/net/8390.c Fri Apr 14 14:04:13 1995
@@ -15,6 +15,11 @@
This is the chip-specific code for many 8390-based ethernet adaptors.
This is not a complete driver, it must be combined with board-specific
code such as ne.c, wd.c, 3c503.c, etc.
+
+ 13/04/95 -- Don't blindly swallow ENISR_RDC interrupts for non-shared
+ memory cards. We need to follow these closely for neX000 cards.
+ Plus other minor cleanups. -- Paul Gortmaker
+
*/
static char *version =
@@ -125,15 +130,16 @@
struct ei_device *ei_local = (struct ei_device *) dev->priv;
int length, send_length;
- /* We normally shouldn't be called if dev->tbusy is set, but the
- existing code does anyway.
- If it has been too long (> 100 or 150ms.) since the last Tx we assume
- the board has died and kick it. */
+/*
+ * We normally shouldn't be called if dev->tbusy is set, but the
+ * existing code does anyway. If it has been too long since the
+ * last Tx, we assume the board has died and kick it.
+ */
if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
int txsr = inb(e8390_base+EN0_TSR), isr;
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
+ if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT + 5) && ! (txsr & ENTSR_PTX))) {
return 1;
}
isr = inb(e8390_base+EN0_ISR);
@@ -177,7 +183,7 @@
}
/* Mask interrupts from the ethercard. */
- outb(0x00, e8390_base + EN0_IMR);
+ outb(0x00, e8390_base + EN0_IMR);
ei_local->irqlock = 1;
send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
@@ -204,7 +210,7 @@
dev->name);
ei_local->irqlock = 0;
dev->tbusy = 1;
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
return 1;
}
ei_block_output(dev, length, skb->data, output_page);
@@ -242,7 +248,7 @@
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
int e8390_base;
- int interrupts, boguscount = 0;
+ int interrupts, nr_serviced = 0;
struct ei_device *ei_local;
if (dev == NULL) {
@@ -253,7 +259,6 @@
ei_local = (struct ei_device *) dev->priv;
if (dev->interrupt || ei_local->irqlock) {
/* The "irqlock" check is only for testing. */
- sti();
printk(ei_local->irqlock
? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
: "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
@@ -263,7 +268,6 @@
}
dev->interrupt = 1;
- sti(); /* Allow other interrupts. */
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
@@ -273,14 +277,17 @@
/* !!Assumption!! -- we stay in page 0. Don't break this. */
while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
- && ++boguscount < 9) {
+ && ++nr_serviced < MAX_SERVICE) {
if (dev->start == 0) {
printk("%s: interrupt from stopped card\n", dev->name);
interrupts = 0;
break;
}
if (interrupts & ENISR_RDC) {
- /* Ack meaningless DMA complete. */
+ if (dev->mem_start == 0) { /* Shared mem card? */
+ if (ei_local->dmaing) ei_local->dmaing = 0;
+ else printk("%s: unexpected RDC interrupt\n", dev->name);
+ }
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
}
if (interrupts & ENISR_OVER) {
@@ -303,17 +310,20 @@
if (interrupts & ENISR_TX_ERR) {
outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
}
+
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
}
if (interrupts && ei_debug) {
- if (boguscount == 9)
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ if (nr_serviced == MAX_SERVICE) {
printk("%s: Too much work at interrupt, status %#2.2x\n",
dev->name, interrupts);
- else
+ outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
+ } else {
printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
- outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+ outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+ }
}
dev->interrupt = 0;
return;
@@ -402,7 +412,7 @@
rxing_page = inb_p(e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
- /* Remove one frame from the ring. Boundary is alway a page behind. */
+ /* Remove one frame from the ring. Boundary is always a page behind. */
this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
if (this_frame >= ei_local->stop_page)
this_frame = ei_local->rx_start_page;
@@ -475,12 +485,12 @@
/* This _should_ never happen: it's here for avoiding bad clones. */
if (next_frame >= ei_local->stop_page) {
- printk("%s: next frame inconsistency, %#2x..", dev->name,
+ printk("%s: next frame inconsistency, %#2x\n", dev->name,
next_frame);
next_frame = ei_local->rx_start_page;
}
ei_local->current_page = next_frame;
- outb(next_frame-1, e8390_base+EN0_BOUNDARY);
+ outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
}
/* If any worth-while packets have been received, dev_rint()
has done a mark_bh(NET_BH) for us and will work on them
@@ -538,13 +548,18 @@
{
short ioaddr = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ /* If the card is stopped, just return the present stats. */
+ if (dev->start == 0) return &ei_local->stat;
- /* Read the counter registers, assuming we are in page 0. */
+ /* Read the counter registers, after putting us in page 0. */
+ outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
return &ei_local->stat;
+
}
#ifdef HAVE_MULTICAST
@@ -628,8 +643,8 @@
ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
/* Clear the pending interrupts and mask. */
- outb_p(0xFF, e8390_base + EN0_ISR);
- outb_p(0x00, e8390_base + EN0_IMR);
+ outb_p(0xff, e8390_base + EN0_ISR);
+ outb_p(0x00, e8390_base + EN0_IMR);
/* Copy the station address into the DS8390 registers,
and set the multicast hash bitmap to receive all multicasts. */
@@ -650,9 +665,10 @@
dev->interrupt = 0;
ei_local->tx1 = ei_local->tx2 = 0;
ei_local->txing = 0;
+ ei_local->dmaing = 0;
if (startp) {
- outb_p(0xff, e8390_base + EN0_ISR);
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ outb_p(0xff, e8390_base + EN0_ISR);
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
--- /tmp/linux-oem/drivers/net/ne.c Fri Apr 14 13:12:59 1995
+++ linux/drivers/net/ne.c Fri Apr 14 16:35:55 1995
@@ -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 carefully monitor ENISR_RDC
+ for handshaking the 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). */
@@ -31,6 +38,23 @@
#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 init the 8390 before trying to read the SAprom ? */
+#define CONFIG_NE_INIT_4_SAPROM
+
+/* Do we implement the read before write bugfix ? */
+/* #define CONFIG_NE_RW_BUGFIX */
+
+/* ---- No user-servicable parts below ---- */
+
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
unsigned long *mem_startp);
@@ -39,6 +63,7 @@
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[] = {
@@ -48,6 +73,7 @@
{"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}},
{0,}
};
+#endif
#define NE_BASE (dev->base_addr)
#define NE_CMD 0x00
@@ -68,6 +94,7 @@
char *buf, int ring_offset);
static void ne_block_output(struct device *dev, const int count,
const unsigned char *buf, const int start_page);
+void check_dma_lock(struct device *dev);
/* Probe for various non-shared-memory ethercards.
@@ -126,7 +153,7 @@
char *name = NULL;
int start_page, stop_page;
int neX000, ctron;
- int reg0 = inb(ioaddr);
+ int reg0 = inb_p(ioaddr);
if ( reg0 == 0xFF)
return ENODEV;
@@ -140,13 +167,14 @@
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;
}
}
printk("NE*000 ethercard probe at %#3x:", ioaddr);
+#ifdef CONFIG_NE_INIT_4_SAPROM
/* Read the 16 bytes of station address PROM.
We must first initialize registers, similar to NS8390_init(eifdev, 0).
We can't reliably read the SAPROM address without this.
@@ -169,10 +197,12 @@
};
for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+#endif
+
}
for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
- SA_prom[i] = inb(ioaddr + NE_DATAPORT);
- SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
+ SA_prom[i] = inb_p(ioaddr + NE_DATAPORT);
+ SA_prom[i+1] = inb_p(ioaddr + NE_DATAPORT);
if (SA_prom[i] != SA_prom[i+1])
wordlength = 1;
}
@@ -208,6 +238,7 @@
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 +258,11 @@
SA_prom[14], SA_prom[15]);
return ENXIO;
}
+#else
+ printk(" not found.\n");
+ return ENXIO;
+#endif
+
}
@@ -242,7 +278,7 @@
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. */
@@ -260,7 +296,7 @@
dev->base_addr = ioaddr;
- request_region(ioaddr, NE_IO_EXTENT,"ne2000");
+ request_region(ioaddr, NE_IO_EXTENT, "ne");
for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
@@ -299,9 +335,11 @@
int reset_start_time = jiffies;
if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies);
+ outb_p(tmp, NE_BASE + NE_RESET);
+
ei_status.txing = 0;
+ ei_status.dmaing = 0;
- outb_p(tmp, NE_BASE + NE_RESET);
/* This check _should_not_ be necessary, omit eventually. */
while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2) {
@@ -310,26 +348,66 @@
}
}
-/* Block input and output, similar to the Crynwr packet driver. If you
- porting to a new ethercard look at the packet driver source for hints.
+/*
+ Block input and output, similar to the Crynwr packet driver. If you
+ are porting to a new ethercard look at the packet driver source for hints.
The NEx000 doesn't share it on-board packet memory -- you have to put
- the packet out through the "remote DMA" dataport using outb. */
+ the packet out through the "remote DMA" dataport using outb.
+
+ We use bit zero of ei_status.dmaing to indicate xfer in progress,
+ bit one to indicate Rx xfer and bit two to indicate Tx xfer. Atomic
+ locks are done by set_bit(). We keep a close eye on the 8390 with
+ check_dma_lock(), as it will hang the system if we try to start
+ another PIO xfer without the 8390 ack'ing the 1st. -- Paul.
+ */
+
+void check_dma_lock(struct device *dev)
+{
+ int e8390_base = dev->base_addr;
+
+ if (inb_p(e8390_base+EN0_ISR) & ENISR_RDC) {
+ if (ei_status.dmaing) ei_status.dmaing = 0;
+ else printk("%s: unexpected RDC interrupt\n", dev->name);
+ outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+ } else if ((ei_status.dmaing) && (jiffies - ei_status.dma_start > DMA_TIMEOUT)) {
+ printk("%s: timed out waiting for RDC, kicking board.\n", dev->name);
+ ne_reset_8390(dev);
+ NS8390_init(dev, 1);
+ }
+}
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) {
+ check_dma_lock(dev);
+
+ if (set_bit(0,(void*)&(ei_status.dmaing))) {
+ if (ei_debug > 0)
+ printk("%s: DMA lock already set in ne_block_input "
+ "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return 0;
+ }
+
+#ifdef CONFIG_NE_SANITY
+ if (set_bit(1,(void*)&ei_status.dmaing)) {
if (ei_debug > 0)
- printk("%s: DMAing conflict in ne_block_input "
+ printk("%s: Already Rx DMAing in ne_block_input "
"[DMAstat:%d][irqlock:%d][intr:%d].\n",
dev->name, ei_status.dmaing, ei_status.irqlock,
dev->interrupt);
return 0;
}
- ei_status.dmaing |= 0x01;
+#else
+ ei_status.dmaing |= 0x02;
+#endif
+
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,22 +416,24 @@
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);
}
+#ifdef CONFIG_NE_SANITY
/* This was for the ALPHA version only, but enough people have
encountering problems that 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. */
int high = inb_p(nic_base + EN0_RSARHI);
int low = inb_p(nic_base + EN0_RSARLO);
addr = (high << 8) + low;
@@ -366,7 +446,6 @@
dev->name, ring_offset + xfer_count, addr);
}
#endif
- ei_status.dmaing &= ~0x01;
return ring_offset + count;
}
@@ -374,29 +453,49 @@
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 flags;
/* 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) {
+
+ check_dma_lock(dev);
+
+ if (set_bit(0,(void*)&ei_status.dmaing)) {
if (ei_debug > 0)
- printk("%s: DMAing conflict in ne_block_output."
+ printk("%s: DMA lock already set in ne_block_output."
"[DMAstat:%d][irqlock:%d][intr:%d]\n",
dev->name, ei_status.dmaing, ei_status.irqlock,
dev->interrupt);
return;
}
- ei_status.dmaing |= 0x02;
+
+#ifdef CONFIG_NE_SANITY
+ if (set_bit(2,(void*)&ei_status.dmaing)) {
+ if (ei_debug > 0)
+ printk("%s: Already Rx DMAing in ne_block_output "
+ "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock,
+ dev->interrupt);
+ return;
+ }
+#else
+ ei_status.dmaing |= 0x04; /* set Rx flag */
+#endif
+
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
- retry:
-#if defined(rw_bugfix)
+#ifdef CONFIG_NE_SANITY
+retry:
+#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
@@ -412,19 +511,8 @@
SLOW_DOWN_IO;
#endif /* rw_bugfix */
- /*
- Now the normal output. I believe that if we don't lock this, a
- race condition will munge the remote byte count values, and then
- the ne2k will hang the machine by holding I/O CH RDY because it
- expects more data. Hopefully fixes the lockups. -- Paul Gortmaker.
-
- Use save_flags/cli/restore_flags rather than cli/sti to avoid risk
- of accidentally enabling interrupts which were disabled when we
- were entered. Dave Platt <dplatt@3do.com>
- */
+ /* Now the normal output. */
- save_flags(flags);
- cli();
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
outb_p(0x00, nic_base + EN0_RSARLO);
@@ -436,7 +524,6 @@
} else {
outsb(NE_BASE + NE_DATAPORT, buf, count);
}
- restore_flags(flags);
#ifdef CONFIG_NE_SANITY
/* This was for the ALPHA version only, but enough people have
@@ -444,8 +531,6 @@
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;
@@ -461,7 +546,6 @@
}
}
#endif
- ei_status.dmaing &= ~0x02;
return;
}