summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMike Shaver <shaver@ingenia.com>1997-08-20 18:18:52 +0000
committerMike Shaver <shaver@ingenia.com>1997-08-20 18:18:52 +0000
commit8e3dfa33f12d5c4195a985ea6b49f41b1ae7d5a5 (patch)
tree15a94aea4d1baf10185e478e80b7d39f85038742 /drivers
parentfc3482fb16dbbcdfdf55b552f1eec635e93fa0d0 (diff)
Mark Salter's patch to fix the excessive eth0 timeout bug.
Mark's description of the problem: This patch seems to have fixed the excessive ethernet timeouts I've been seeing. The problem was a race condition when queueing another packet for transmisson. The code in sgiseeq_start_xmit() would try to start another transmission from the head of the transmit queue if the HPC was inactive. Because interrupts are off at this time, it was possible that that packet had been transmitted but the queue head had not been advanced by an interrupt service. This resulted in a duplicate packet being sent over the wire and when interrupts were reenabled, the normal ack'ing of the original transmission of that packet would put the HPC into a wedged state which eventually led to a timeout and reset.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sgiseeq.c48
1 files changed, 26 insertions, 22 deletions
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index bf85e014a..fe8153561 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.c,v 1.17 1996/08/16 04:43:32 dm Exp $
+/* $Id: sgiseeq.c,v 1.1.1.1 1997/06/01 03:17:20 ralf Exp $
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -351,6 +351,25 @@ static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp,
}
}
+static inline void kick_tx(struct sgiseeq_tx_desc *td,
+ volatile struct hpc3_ethregs *hregs)
+{
+ /* If the HPC aint doin nothin, and there are more packets
+ * with ETXD cleared and XIU set we must make very certain
+ * that we restart the HPC else we risk locking up the
+ * adapter. The following code is only safe iff the HPCDMA
+ * is not active!
+ */
+ while((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
+ (HPCDMA_XIU | HPCDMA_ETXD))
+ td = (struct sgiseeq_tx_desc *)
+ KSEG1ADDR(td->tdma.pnext);
+ if(td->tdma.cntinfo & HPCDMA_XIU) {
+ hregs->tx_ndptr = PHYSADDR(td);
+ hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
+ }
+}
+
static inline void sgiseeq_tx(struct device *dev, struct sgiseeq_private *sp,
volatile struct hpc3_ethregs *hregs,
volatile struct sgiseeq_regs *sregs)
@@ -371,22 +390,8 @@ static inline void sgiseeq_tx(struct device *dev, struct sgiseeq_private *sp,
if(status & SEEQ_TSTAT_LCLS)
sp->stats.collisions++;
}
- /* If the HPC aint doin nothin, and there are more packets
- * with ETXD cleared and XIU set we must make very certain
- * that we restart the HPC else we risk locking up the
- * adapter. The following read of tx_ndptr is only safe
- * iff the HPCDMA is not active!
- */
- td = (struct sgiseeq_tx_desc *)
- KSEG1ADDR(((hregs->tx_ndptr) & ~0xf));
- while((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
- (HPCDMA_XIU | HPCDMA_ETXD))
- td = (struct sgiseeq_tx_desc *)
- KSEG1ADDR(td->tdma.pnext);
- if(td->tdma.cntinfo & HPCDMA_XIU) {
- hregs->tx_ndptr = PHYSADDR(td);
- hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
- }
+ kick_tx((struct sgiseeq_tx_desc *)KSEG1ADDR((hregs->tx_ndptr & ~0xf)),
+ hregs);
}
/* Ack 'em... */
@@ -515,7 +520,7 @@ static inline int verify_tx(struct sgiseeq_private *sp,
}
if(skb->len <= 0) {
- printk("%s: skb len is %ld\n", dev->name, skb->len);
+ printk("%s: skb len is %d\n", dev->name, skb->len);
return -1;
}
/* Are we getting in someone else's way? */
@@ -575,10 +580,9 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct device *dev)
sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */
/* Maybe kick the HPC back into motion. */
- if(!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE)) {
- hregs->tx_ndptr = PHYSADDR(&sp->srings.tx_desc[sp->tx_old]);
- hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
- }
+ if(!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE))
+ kick_tx(&sp->srings.tx_desc[sp->tx_old], hregs);
+
dev->trans_start = jiffies;
dev_kfree_skb(skb, FREE_WRITE);