patch-2.3.45 linux/drivers/net/pcmcia/fmvj18x_cs.c

Next file: linux/drivers/net/pcmcia/netwave_cs.c
Previous file: linux/drivers/net/pcmcia/aironet4500_cs.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
@@ -115,6 +115,7 @@
 static void fjn_reset(struct net_device *dev);
 static struct net_device_stats *fjn_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
+static void fjn_tx_timeout (struct net_device *dev);
 
 static dev_info_t dev_info = "fmvj18x_cs";
 static dev_link_t *dev_list = NULL;
@@ -139,6 +140,7 @@
     cardtype_t cardtype;
     u_short sent;
     u_char mc_filter[8];
+    spinlock_t lock;
 } local_info_t;
 
 #define MC_FILTERBREAK 64
@@ -235,6 +237,8 @@
 #define INTR_OFF             0x0d /* LAN controler ignores interrupts */
 #define INTR_ON              0x1d /* LAN controler will catch interrupts */
 
+#define TX_TIMEOUT	     10
+
 /*======================================================================
 
     This bit of code is used to avoid unregistering network devices
@@ -278,6 +282,8 @@
     lp = kmalloc(sizeof(*lp), GFP_KERNEL);
     if (!lp) return NULL;
     memset(lp, 0, sizeof(*lp));
+    
+    lp->lock = SPIN_LOCK_UNLOCKED;
     link = &lp->link; dev = &lp->dev;
     link->priv = dev->priv = link->irq.Instance = lp;
 
@@ -314,7 +320,9 @@
     dev->init = &fmvj18x_init;
     dev->open = &fjn_open;
     dev->stop = &fjn_close;
-    dev->tbusy = 0xFF;
+    dev->tx_timeout = fjn_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+    netif_start_queue (dev);
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -462,7 +470,7 @@
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
 	goto failed;
@@ -585,8 +593,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    dev->tbusy = 0xFF; 
-	    dev->start = 0;
+	    netif_stop_queue (dev);
 	    link->release.expires = jiffies + HZ/20;
 	    add_timer(&link->release);
 	}
@@ -601,8 +608,7 @@
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
 	    if (link->open) {
-		dev->tbusy = 0xFF; 
-		dev->start = 0;
+	    	netif_stop_queue (dev);
 	    }
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
@@ -614,9 +620,8 @@
 	if (link->state & DEV_CONFIG) {
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
-		dev->tbusy = 0;
-		dev->start = 1;
 		fjn_reset(dev);
+		netif_start_queue (dev);
 	    }
 	}
 	break;
@@ -670,12 +675,9 @@
 	       "unknown device.\n", irq);
         return;
     }
-    if (dev->interrupt) {
-        printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
-	       dev->name);
-        return;
-    }
-    dev->interrupt = 1;
+    
+    spin_lock (&lp->lock);
+    
     ioaddr = dev->base_addr;
 
     /* avoid multiple interrupts */
@@ -708,71 +710,65 @@
 	    lp->tx_queue = 0;
 	    lp->tx_queue_len = 0;
 	    dev->trans_start = jiffies;
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);	/* Inform upper layers. */
+	    netif_wake_queue (dev);
 	} else {
 	    lp->tx_started = 0;
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);	/* Inform upper layers. */
+	    netif_stop_queue (dev);
 	}
     }
     DEBUG(4, "%s: exiting interrupt,\n", dev->name);
     DEBUG(4, "    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
 
-    dev->interrupt = 0;
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
-    return;
+    spin_unlock (&lp->lock);
+    
 } /* fjn_interrupt */
 
 /*====================================================================*/
-
-static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void fjn_tx_timeout (struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
-    ioaddr_t ioaddr = dev->base_addr;
-
-    if (dev->tbusy) {
-	/* If we get here, some higher level has decided we are broken.
-	   There should really be a "kick me" function call instead. */
-	int tickssofar = jiffies - dev->trans_start;
-	if (tickssofar < 10)
-	    return 1;
-	printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
-	       dev->name, htons(inw(ioaddr + TX_STATUS)),
-	       inb(ioaddr + TX_STATUS) & F_TMT_RDY
-	       ? "IRQ conflict" : "network cable problem");
-	printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
-	       "%04x %04x %04x %04x %04x.\n",
-	       dev->name, htons(inw(ioaddr + 0)),
-	       htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
-	       htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
-	       htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
-	       htons(inw(ioaddr +14)));
+	struct local_info_t *lp = (struct local_info_t *) dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	printk (KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+		dev->name, htons (inw (ioaddr + TX_STATUS)),
+		inb (ioaddr + TX_STATUS) & F_TMT_RDY
+		? "IRQ conflict" : "network cable problem");
+	printk (KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+		"%04x %04x %04x %04x %04x.\n",
+		dev->name, htons (inw (ioaddr + 0)),
+		htons (inw (ioaddr + 2)), htons (inw (ioaddr + 4)),
+		htons (inw (ioaddr + 6)), htons (inw (ioaddr + 8)),
+		htons (inw (ioaddr + 10)), htons (inw (ioaddr + 12)),
+		htons (inw (ioaddr + 14)));
 	lp->stats.tx_errors++;
+
 	/* ToDo: We should try to restart the adaptor... */
-	cli();
+	spin_lock_irqsave (&lp->lock, flags);
 
-	fjn_reset(dev);
+	fjn_reset (dev);
 
 	lp->tx_started = 0;
 	lp->tx_queue = 0;
 	lp->tx_queue_len = 0;
 	lp->sent = 0;
 	lp->open_time = jiffies;
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
-    
-	sti();
-    }
+	netif_start_queue (dev);
+
+	spin_unlock_irqrestore (&lp->lock, flags);
+}
+
+
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
 
-    /* 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 (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-	printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name);
-    else {
+    netif_stop_queue (dev);
+    if (1) {
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char *buf = skb->data;
 
@@ -806,17 +802,17 @@
 	    lp->tx_queue_len = 0;
 	    dev->trans_start = jiffies;
 	    lp->tx_started = 1;
-	    dev->tbusy = 0;
+	    netif_start_queue (dev);
 	} else {
 	    if( sram_config == 0 ) {
 		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
 		    /* Yes, there is room for one more packet. */
-		    dev->tbusy = 0;
+		    netif_start_queue (dev);
 	    } else {
 		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
 						lp->tx_queue < 127 )
 		    /* Yes, there is room for one more packet. */
-		    dev->tbusy = 0;
+		    netif_start_queue (dev);
 	    }
 	}
 
@@ -1025,9 +1021,7 @@
     lp->tx_queue = 0;
     lp->tx_queue_len = 0;
     lp->open_time = jiffies;
-    dev->interrupt = 0;
-    dev->tbusy = 0;
-    dev->start = 1;
+    netif_start_queue (dev);    
     
     MOD_INC_USE_COUNT;
 
@@ -1045,8 +1039,7 @@
     DEBUG(4, "fjn_close('%s').\n", dev->name);
 
     lp->open_time = 0;
-    dev->tbusy = 1;
-    dev->start = 0;
+    netif_stop_queue (dev);
 
     /* Set configuration register 0 to disable Tx and Rx. */
     if( sram_config == 0 ) 
@@ -1064,7 +1057,6 @@
 	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     link->open--;
-    dev->start = 0;
     if (link->state & DEV_STALE_CONFIG) {
 	link->release.expires = jiffies + HZ/20;
 	link->state |= DEV_RELEASE_PENDING;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)