tulip bug, alternative fix, #3 (tested)

Wolfgang Walter wolfgang.walter@stusta.mhn.de
Sat Nov 27 23:48:04 1999


Hi,

this patch works for me. Would be nice if you could confirm it :-). Change
compared with my previous one I sent you: TimerInt handling changed.

Thanks,

Wolfgang Walter


--- 2.2.14pre4/drivers/net/tulip.c	Fri Nov  5 18:02:35 1999
+++ 2.2.14pre4-m/drivers/net/tulip.c	Sun Nov 28 05:59:44 1999
@@ -530,6 +530,9 @@
 	int cur_index;						/* Current media index. */
 	int saved_if_port;
 	unsigned char pci_bus, pci_devfn;
+	int ttimer;
+	int susp_rx;
+	unsigned long nir;
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
@@ -2484,6 +2487,9 @@
 	tp->tx_full = 0;
 	tp->cur_rx = tp->cur_tx = 0;
 	tp->dirty_rx = tp->dirty_tx = 0;
+	tp->susp_rx = 0;
+	tp->ttimer = 0;
+	tp->nir = 0;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		tp->rx_ring[i].status = 0x00000000;
@@ -2578,6 +2584,8 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int csr5, work_budget = max_interrupt_work;
+	int entry;
+	int missed;
 
 #if defined(__i386__) && defined(SMP_CHECK)
 	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
@@ -2595,6 +2603,8 @@
 	dev->interrupt = 1;
 #endif
 
+	tp->nir++;
+
 	do {
 		csr5 = inl(ioaddr + CSR5);
 		/* Acknowledge all of the current interrupt sources ASAP. */
@@ -2703,12 +2713,6 @@
 				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
 			}
-			if (csr5 & TimerInt) {
-				if (tulip_debug > 2)
-					printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
-						   dev->name, csr5);
-				outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-			}
 			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
 				if (tp->link_change)
 					(tp->link_change)(dev, csr5);
@@ -2716,6 +2720,13 @@
 			/* Clear all error sources, included undocumented ones! */
 			outl(0x0800f7ba, ioaddr + CSR5);
 		}
+		if (csr5 & TimerInt) {
+			if (tulip_debug > 2)
+				printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+					   dev->name, csr5);
+			outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+			tp->ttimer = 0;
+		}
 		if (--work_budget < 0) {
 			if (tulip_debug > 1)
 				printk(KERN_WARNING "%s: Too much work during an interrupt, "
@@ -2723,12 +2734,43 @@
 			/* Acknowledge all interrupt sources. */
 			outl(0x8001ffff, ioaddr + CSR5);
 			/* Clear all interrupting sources, set timer to re-enable. */
-			outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt,
+			outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
 				 ioaddr + CSR7);
 			outl(12, ioaddr + CSR11);
+			tp->ttimer = 1;
 			break;
 		}
 	} while (1);
+
+
+	/* if in suspend mode: try to get an skb */
+	entry = tp->cur_rx % RX_RING_SIZE;
+	/* if in suspend mode: try to get an skb; if received packets pending: receive  */
+	if (tp->susp_rx || (tp->rx_skbuff[entry] != NULL && ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned)))) {
+		if (tp->susp_rx)
+			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (cur_rx = %u, ttimer = %d) try to get some skbs\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer);
+		tulip_rx(dev);
+		tp->susp_rx = 0;
+		entry = tp->cur_rx % RX_RING_SIZE;
+	}
+
+	/* check if we card is in suspend mode */
+	if (tp->rx_skbuff[entry] == NULL) {
+		printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer);
+		tp->susp_rx = 1;
+		if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
+			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+			outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
+				ioaddr + CSR7);
+			outl(TimerInt, ioaddr + CSR5);
+			outl(12, ioaddr + CSR11);
+			tp->ttimer = 1;
+		}
+	}
+
+	if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+		tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+	}
 
 	if (tulip_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",