patch-2.2.0-pre2 linux/drivers/net/plip.c
Next file: linux/drivers/net/sdla.c
Previous file: linux/drivers/net/hp100.c
Back to the patch index
Back to the overall index
- Lines: 173
- Date:
Tue Dec 29 11:51:50 1998
- Orig file:
v2.2.0-pre1/linux/drivers/net/plip.c
- Orig date:
Fri Oct 23 22:01:21 1998
diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/plip.c linux/drivers/net/plip.c
@@ -21,6 +21,10 @@
* - Make sure other end is OK, before sending a packet.
* - Fix immediate timer problem.
*
+ * Al Viro
+ * - Changed {enable,disable}_irq handling to make it work
+ * with new ("stack") semantics.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -120,6 +124,9 @@
#endif
static unsigned int net_debug = NET_DEBUG;
+#define ENABLE(irq) enable_irq(irq)
+#define DISABLE(irq) disable_irq(irq)
+
/* In micro second */
#define PLIP_DELAY_UNIT 1
@@ -333,6 +340,7 @@
#define OK 0
#define TIMEOUT 1
#define ERROR 2
+#define HS_TIMEOUT 3
typedef int (*plip_func)(struct device *dev, struct net_local *nl,
struct plip_local *snd, struct plip_local *rcv);
@@ -371,13 +379,22 @@
int error)
{
unsigned char c0;
+ /*
+ * This is tricky. If we got here from the beginning of send (either
+ * with ERROR or HS_TIMEOUT) we have IRQ enabled. Otherwise it's
+ * already disabled. With the old variant of {enable,disable}_irq()
+ * extra disable_irq() was a no-op. Now it became mortal - it's
+ * unbalanced and thus we'll never re-enable IRQ (until rmmod plip,
+ * that is). So we have to treat HS_TIMEOUT and ERROR from send
+ * in a special way.
+ */
spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_SEND) {
if (error != ERROR) { /* Timeout */
nl->timeout_count++;
- if ((snd->state == PLIP_PK_TRIGGER
+ if ((error == HS_TIMEOUT
&& nl->timeout_count <= 10)
|| nl->timeout_count <= 3) {
spin_unlock_irq(&nl->lock);
@@ -387,7 +404,8 @@
c0 = inb(PAR_STATUS(dev));
printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",
dev->name, snd->state, c0);
- }
+ } else
+ error = HS_TIMEOUT;
nl->enet_stats.tx_errors++;
nl->enet_stats.tx_aborted_errors++;
} else if (nl->connection == PLIP_CN_RECEIVE) {
@@ -419,8 +437,10 @@
snd->skb = NULL;
}
spin_unlock_irq(&nl->lock);
- disable_irq(dev->irq);
- synchronize_irq();
+ if (error == HS_TIMEOUT) {
+ DISABLE(dev->irq);
+ synchronize_irq();
+ }
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->tbusy = 1;
nl->connection = PLIP_CN_ERROR;
@@ -498,7 +518,7 @@
switch (rcv->state) {
case PLIP_PK_TRIGGER:
- disable_irq(dev->irq);
+ DISABLE(dev->irq);
/* Don't need to synchronize irq, as we can safely ignore it */
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->interrupt = 0;
@@ -518,7 +538,7 @@
nl->connection = PLIP_CN_SEND;
queue_task(&nl->deferred, &tq_timer);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
- enable_irq(dev->irq);
+ ENABLE(dev->irq);
return OK;
}
} else {
@@ -592,13 +612,13 @@
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
- enable_irq(dev->irq);
+ ENABLE(dev->irq);
return OK;
} else {
nl->connection = PLIP_CN_NONE;
spin_unlock_irq(&nl->lock);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
- enable_irq(dev->irq);
+ ENABLE(dev->irq);
return OK;
}
}
@@ -674,7 +694,7 @@
switch (snd->state) {
case PLIP_PK_TRIGGER:
if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80)
- return TIMEOUT;
+ return HS_TIMEOUT;
/* Trigger remote rx interrupt. */
outb(0x08, data_addr);
@@ -691,12 +711,16 @@
c0 = inb(PAR_STATUS(dev));
if (c0 & 0x08) {
spin_unlock_irq(&nl->lock);
- disable_irq(dev->irq);
+ DISABLE(dev->irq);
synchronize_irq();
if (nl->connection == PLIP_CN_RECEIVE) {
/* Interrupted.
We don't need to enable irq,
as it is soon disabled. */
+ /* Yes, we do. New variant of
+ {enable,disable}_irq *counts*
+ them. -- AV */
+ ENABLE(dev->irq);
nl->enet_stats.collisions++;
return OK;
}
@@ -711,7 +735,7 @@
spin_unlock_irq(&nl->lock);
if (--cx == 0) {
outb(0x00, data_addr);
- return TIMEOUT;
+ return HS_TIMEOUT;
}
}
@@ -760,7 +784,7 @@
nl->is_deferred = 1;
queue_task(&nl->deferred, &tq_timer);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
- enable_irq(dev->irq);
+ ENABLE(dev->irq);
return OK;
}
return OK;
@@ -800,7 +824,7 @@
dev->tbusy = 0;
dev->interrupt = 0;
outb(PAR_INTR_ON, PAR_CONTROL(dev));
- enable_irq(dev->irq);
+ ENABLE(dev->irq);
mark_bh(NET_BH);
} else {
nl->is_deferred = 1;
@@ -1000,7 +1024,7 @@
dev->tbusy = 1;
dev->start = 0;
- disable_irq(dev->irq);
+ DISABLE(dev->irq);
synchronize_irq();
#ifdef NOTDEF
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov