Re: 3c59x driver 0.25 falls off network

Linus Torvalds (torvalds@cs.helsinki.fi)
Wed, 17 Jul 1996 08:23:01 +0300 (EET DST)


On Tue, 16 Jul 1996, Ove Ewerlid wrote:
>
> Well, after removing the tbusy-optimization from the 0.25 driver things
> have worked very well for me (all in all 5 different 3c595 on 4
> machines).

Thanks for the hint, Ove. Could you try this alternative patch rather
than the one you did? This still keeps the optimization, but it rewrites
the logic to do it another way without clearing "tbusy" when it does do
the optimization, and that was definitely wrong (it kept tbusy cleared
after the packet, even though it didn't have size for any larger
packets).

Others seeing problems with the 3c59x driver (both the old and the newer
one), could you please test this patch too (it's against 0.25 in 2.0.7,
but it should patch cleanly against any of the newer kernels with the
0.25 driver).

(Umm, I don't even _have_ a 3c59x card, so this patch is obviously untested.
But you all know I write perfect code even when I don't test it, don't you?)

Linus

-----
--- v2.0.7/linux/drivers/net/3c59x.c Mon Jul 8 16:09:54 1996
+++ linux/drivers/net/3c59x.c Wed Jul 17 08:11:44 1996
@@ -750,19 +750,25 @@
we actually have room for this packet.
*/

- if (inw(ioaddr + TxFree) > skb->len) /* We actually have free room. */
- dev->tbusy = 0; /* Fake out the check below. */
- else if (dev->tbusy) {
- /* Transmitter timeout, serious problems. */
- int tickssofar = jiffies - dev->trans_start;
- int i;
+ switch (dev->tbusy) {
+ int i, tickssofar;
+ default:
+ /* even if we're busy, we might have room for a small packet */
+ if (inw(ioaddr + TxFree) > skb->len)
+ break;

- if (tickssofar < 2) /* We probably aren't empty. */
+ /* Check for transmitter timeout, serious problems. */
+ tickssofar = jiffies - dev->trans_start;
+
+ /* We probably aren't empty - don't bother timeouting (20ms) */
+ if (tickssofar < 2*HZ/100)
return 1;
+
/* Wait a while to see if there really is room. */
for (i = WAIT_TX_AVAIL; i >= 0; i--)
if (inw(ioaddr + TxFree) > skb->len)
- break;
+ break;
+
if ( i < 0) {
if (tickssofar < TX_TIMEOUT)
return 1;
@@ -771,7 +777,8 @@
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
for (i = 20; i >= 0 ; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress) break;
+ if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+ break;
outw(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies;
dev->tbusy = 0;
@@ -779,15 +786,8 @@
vp->stats.tx_dropped++;
return 0; /* Yes, silently *drop* the packet! */
}
- dev->tbusy = 0;
- }
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
+ case 0:
+ break;
}

/* Put out the doubleword header... */
-----