patch-2.1.78 linux/drivers/net/plip.c
Next file: linux/drivers/net/smc-ultra.c
Previous file: linux/drivers/net/hp.c
Back to the patch index
Back to the overall index
- Lines: 335
- Date:
Sun Jan 4 10:24:27 1998
- Orig file:
v2.1.77/linux/drivers/net/plip.c
- Orig date:
Mon Dec 1 12:04:13 1997
diff -u --recursive --new-file v2.1.77/linux/drivers/net/plip.c linux/drivers/net/plip.c
@@ -12,11 +12,11 @@
* Modularization and ifreq/ifmap support by Alan Cox.
* Rewritten by Niibe Yutaka.
* parport-sharing awareness code by Philip Blundell.
+ * SMP locking by Niibe Yutaka.
*
* Fixes:
* Niibe Yutaka
- * - Module initialization. You can specify I/O addr and IRQ:
- * # insmod plip.o io=0x3bc irq=7
+ * - Module initialization.
* - MTU fix.
* - Make sure other end is OK, before sending a packet.
* - Fix immediate timer problem.
@@ -45,7 +45,7 @@
* To use with DOS box, please do (Turn on ARP switch):
* # ifconfig plip[0-2] arp
*/
-static const char *version = "NET3 PLIP version 2.2-parport gniibe@mri.co.jp\n";
+static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n";
/*
Sources:
@@ -108,6 +108,7 @@
#include <asm/bitops.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
+#include <asm/spinlock.h>
#include <linux/parport.h>
@@ -214,6 +215,7 @@
int port_owner;
int should_relinquish;
int (*orig_rebuild_header)(struct sk_buff *skb);
+ spinlock_t lock;
};
/* Entry point of PLIP driver.
@@ -238,7 +240,7 @@
printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name);
return -ENODEV;
}
-
+
pardev = parport_register_device(pb, dev->name, plip_preempt,
plip_wakeup, plip_interrupt,
PARPORT_DEV_LURK, dev);
@@ -291,6 +293,7 @@
nl->deferred.sync = 0;
nl->deferred.routine = (void *)(void *)plip_kick_bh;
nl->deferred.data = dev;
+ spin_lock_init(&nl->lock);
return 0;
}
@@ -367,7 +370,7 @@
{
unsigned char c0;
- cli();
+ spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_SEND) {
if (error != ERROR) { /* Timeout */
@@ -375,7 +378,7 @@
if ((snd->state == PLIP_PK_TRIGGER
&& nl->timeout_count <= 10)
|| nl->timeout_count <= 3) {
- sti();
+ spin_unlock_irq(&nl->lock);
/* Try again later */
return TIMEOUT;
}
@@ -388,12 +391,12 @@
} else if (nl->connection == PLIP_CN_RECEIVE) {
if (rcv->state == PLIP_PK_TRIGGER) {
/* Transmission was interrupted. */
- sti();
+ spin_unlock_irq(&nl->lock);
return OK;
}
if (error != ERROR) { /* Timeout */
if (++nl->timeout_count <= 3) {
- sti();
+ spin_unlock_irq(&nl->lock);
/* Try again later */
return TIMEOUT;
}
@@ -413,12 +416,13 @@
dev_kfree_skb(snd->skb, FREE_WRITE);
snd->skb = NULL;
}
+ spin_unlock_irq(&nl->lock);
disable_irq(dev->irq);
+ synchronize_irq();
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->tbusy = 1;
nl->connection = PLIP_CN_ERROR;
outb(0x00, PAR_DATA(dev));
- sti();
return TIMEOUT;
}
@@ -493,6 +497,7 @@
switch (rcv->state) {
case PLIP_PK_TRIGGER:
disable_irq(dev->irq);
+ /* Don't need to synchronize irq, as we can safely ignore it */
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->interrupt = 0;
outb(0x01, PAR_DATA(dev)); /* send ACK */
@@ -577,10 +582,10 @@
/* Close the connection. */
outb (0x00, PAR_DATA(dev));
- cli();
+ spin_lock_irq(&nl->lock);
if (snd->state != PLIP_PK_DONE) {
nl->connection = PLIP_CN_SEND;
- sti();
+ spin_unlock_irq(&nl->lock);
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
@@ -588,7 +593,7 @@
return OK;
} else {
nl->connection = PLIP_CN_NONE;
- sti();
+ spin_unlock_irq(&nl->lock);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
enable_irq(dev->irq);
return OK;
@@ -673,28 +678,34 @@
cx = nl->trigger;
while (1) {
udelay(PLIP_DELAY_UNIT);
- cli();
+ spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_RECEIVE) {
- sti();
- /* interrupted */
+ spin_unlock_irq(&nl->lock);
+ /* Interrupted. */
nl->enet_stats.collisions++;
- if (net_debug > 1)
- printk("%s: collision.\n", dev->name);
return OK;
}
c0 = inb(PAR_STATUS(dev));
if (c0 & 0x08) {
+ spin_unlock_irq(&nl->lock);
disable_irq(dev->irq);
+ synchronize_irq();
+ if (nl->connection == PLIP_CN_RECEIVE) {
+ /* Interrupted.
+ We don't need to enable irq,
+ as it is soon disabled. */
+ nl->enet_stats.collisions++;
+ return OK;
+ }
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
if (net_debug > 2)
printk("%s: send start\n", dev->name);
snd->state = PLIP_PK_LENGTH_LSB;
snd->nibble = PLIP_NB_BEGIN;
nl->timeout_count = 0;
- sti();
break;
}
- sti();
+ spin_unlock_irq(&nl->lock);
if (--cx == 0) {
outb(0x00, data_addr);
return TIMEOUT;
@@ -755,13 +766,13 @@
plip_connection_close(struct device *dev, struct net_local *nl,
struct plip_local *snd, struct plip_local *rcv)
{
- cli();
+ spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_CLOSING) {
nl->connection = PLIP_CN_NONE;
dev->tbusy = 0;
mark_bh(NET_BH);
}
- sti();
+ spin_unlock_irq(&nl->lock);
if (nl->should_relinquish) {
nl->should_relinquish = nl->port_owner = 0;
parport_release(nl->pardev);
@@ -805,7 +816,7 @@
unsigned char c0;
if (dev == NULL) {
- printk ("plip_interrupt: irq %d for unknown device.\n", irq);
+ printk("plip_interrupt: irq %d for unknown device.\n", irq);
return;
}
@@ -825,7 +836,7 @@
if (net_debug > 3)
printk("%s: interrupt.\n", dev->name);
- cli();
+ spin_lock_irq(&nl->lock);
switch (nl->connection) {
case PLIP_CN_CLOSING:
dev->tbusy = 0;
@@ -837,16 +848,18 @@
nl->timeout_count = 0;
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- sti();
+ spin_unlock_irq(&nl->lock);
break;
case PLIP_CN_RECEIVE:
- sti();
- printk("%s: receive interrupt when receiving packet\n", dev->name);
+ /* May occur because there is race condition
+ around test and set of dev->interrupt.
+ Ignore this interrupt. */
+ spin_unlock_irq(&nl->lock);
break;
case PLIP_CN_ERROR:
- sti();
+ spin_unlock_irq(&nl->lock);
printk("%s: receive interrupt in error state\n", dev->name);
break;
}
@@ -898,7 +911,7 @@
if (net_debug > 2)
printk("%s: send request\n", dev->name);
- cli();
+ spin_lock_irq(&nl->lock);
dev->trans_start = jiffies;
snd->skb = skb;
snd->length.h = skb->len;
@@ -909,7 +922,7 @@
}
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- sti();
+ spin_unlock_irq(&nl->lock);
return 0;
}
@@ -946,24 +959,25 @@
nl->connection = PLIP_CN_NONE;
nl->is_deferred = 0;
- /* Fill in the MAC-level header. */
+ /* Fill in the MAC-level header.
+ (ab)Use "dev->broadcast" to store point-to-point MAC address.
+ PLIP doesn't have a real mac address, but we need to create one
+ to be DOS compatible. */
memset(dev->dev_addr, 0xfc, ETH_ALEN);
+ memset(dev->broadcast, 0xfc, ETH_ALEN);
- /* Now PLIP doesnt have a real mac addr which is a pain..
- we need to create one, and to be DOS compatible its a good
- idea to use the same rules. Layering purists please look away */
-
- if((in_dev=dev->ip_ptr)!=NULL)
- {
+ if ((in_dev=dev->ip_ptr) != NULL) {
/*
- * Any address wil do - we take the first
+ * Any address will do - we take the first
*/
struct in_ifaddr *ifa=in_dev->ifa_list;
- if(ifa!=NULL)
- memcpy(dev->dev_addr+2,&ifa->ifa_local,4);
+ if (ifa != NULL) {
+ memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+ memcpy(dev->broadcast+2, &ifa->ifa_address, 4);
+ }
}
-
+
dev->interrupt = 0;
dev->start = 1;
dev->tbusy = 0;
@@ -982,8 +996,9 @@
dev->tbusy = 1;
dev->start = 0;
- cli();
- sti();
+ disable_irq(dev->irq);
+ synchronize_irq();
+
#ifdef NOTDEF
outb(0x00, PAR_DATA(dev));
#endif
@@ -1070,15 +1085,21 @@
static int
plip_config(struct device *dev, struct ifmap *map)
{
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct pardevice *pardev = nl->pardev;
+
if (dev->flags & IFF_UP)
return -EBUSY;
- if (map->base_addr != (unsigned long)-1
- && map->base_addr != dev->base_addr)
- printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
+ printk(KERN_WARNING "plip: Warning, changing irq with ifconfig will be obsoleted.\n");
+ printk("plip: Next time, please set with /proc/parport/*/irq instead.\n");
- if (map->irq != (unsigned char)-1)
- dev->irq = map->irq;
+ if (map->irq != (unsigned char)-1) {
+ pardev->port->irq = dev->irq = map->irq;
+ /* Dummy request */
+ request_irq(dev->irq, plip_interrupt, SA_INTERRUPT,
+ pardev->name, NULL);
+ }
return 0;
}
@@ -1233,6 +1254,6 @@
/*
* Local variables:
- * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
+ * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c"
* End:
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov