patch-pre2.0.5 linux/drivers/net/8390.c
Next file: linux/drivers/net/CONFIG
Previous file: linux/drivers/net/3c509.c
Back to the patch index
Back to the overall index
- Lines: 132
- Date:
Thu May 16 11:18:50 1996
- Orig file:
pre2.0.4/linux/drivers/net/8390.c
- Orig date:
Tue May 7 16:22:26 1996
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/8390.c linux/drivers/net/8390.c
@@ -29,6 +29,7 @@
ei_block_input() for eth_io_copy_and_sum().
Paul Gortmaker : exchange static int ei_pingpong for a #define,
also add better Tx error handling.
+ Paul Gortmaker : rewrite Rx overrun handling as per NS specs.
Sources:
@@ -377,6 +378,7 @@
int e8390_base = dev->base_addr;
unsigned char txsr = inb_p(e8390_base+EN0_TSR);
unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
#ifdef VERBOSE_ERROR_DUMP
printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
@@ -398,6 +400,13 @@
if (tx_was_aborted)
ei_tx_intr(dev);
+ /*
+ * Note: NCR reads zero on 16 collisions so we add them
+ * in by hand. Somebody might care...
+ */
+ if (txsr & ENTSR_ABT)
+ ei_local->stat.collisions += 16;
+
}
/* We have finished a transmit: check for errors and then trigger the next
@@ -580,43 +589,76 @@
return;
}
-/* We have a receiver overrun: we have to kick the 8390 to get it started
- again.*/
+/*
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network." Ugh.
+ */
static void ei_rx_overrun(struct device *dev)
{
int e8390_base = dev->base_addr;
- int reset_start_time = jiffies;
+ unsigned long wait_start_time;
+ unsigned char was_txing, must_resend = 0;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
- /* We should already be stopped and in page0. Remove after testing. */
+ /*
+ * Record whether a Tx was in progress and then issue the
+ * stop command.
+ */
+ was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
if (ei_debug > 1)
- printk("%s: Receiver overrun.\n", dev->name);
+ printk("%s: Receiver overrun.\n", dev->name);
ei_local->stat.rx_over_errors++;
- /* The old Biro driver does dummy = inb_p( RBCR[01] ); at this point.
- It might mean something -- magic to speed up a reset? A 8390 bug?*/
-
- /* Wait for the reset to complete. This should happen almost instantly,
- but could take up to 1.5msec in certain rare instances. There is no
- easy way of timing something in that range, so we use 'jiffies' as
- a sanity check. */
- while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0)
- if (jiffies - reset_start_time > 2*HZ/100) {
- printk("%s: reset did not complete at ei_rx_overrun.\n",
- dev->name);
- NS8390_init(dev, 1);
- return;
- }
-
- /* Remove packets right away. */
+ /*
+ * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+ * Early datasheets said to poll the reset bit, but now they say that
+ * it "is not a reliable indicator and subequently should be ignored."
+ * We wait at least 10ms.
+ */
+ wait_start_time = jiffies;
+ while (jiffies - wait_start_time <= 1*HZ/100)
+ barrier();
+
+ /*
+ * Reset RBCR[01] back to zero as per magic incantation.
+ */
+ outb_p(0x00, e8390_base+EN0_RCNTLO);
+ outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+ /*
+ * See if any Tx was interrupted or not. According to NS, this
+ * step is vital, and skipping it will cause no end of havoc.
+ */
+ if (was_txing) {
+ unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+ if (!tx_completed) must_resend = 1;
+ }
+
+ /*
+ * Have to enter loopback mode and then restart the NIC before
+ * you are allowed to slurp packets up off the ring.
+ */
+ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+ /*
+ * Clear the Rx ring of all the debris, and ack the interrupt.
+ */
ei_receive(dev);
-
outb_p(ENISR_OVER, e8390_base+EN0_ISR);
- /* Generic 8390 insns to start up again, same as in open_8390(). */
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
- outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+
+ /*
+ * Leave loopback mode, and resend any packet that got stopped.
+ */
+ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+ if (must_resend)
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+
}
static struct enet_statistics *get_stats(struct device *dev)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this