patch-2.3.43 linux/drivers/net/sunhme.c

Next file: linux/drivers/net/sunhme.h
Previous file: linux/drivers/net/sunbmac.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.85 2000/01/28 13:42:27 jj Exp $
+/* $Id: sunhme.c,v 1.86 2000/02/09 11:15:36 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -1194,7 +1194,10 @@
 			rxd = &hp->happy_block->happy_meal_rxd[i];
 			dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
 			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE);
-			dev_kfree_skb(skb);
+			if (in_irq())
+				dev_kfree_skb_irq(skb);
+			else
+				dev_kfree_skb(skb);
 			hp->rx_skbs[i] = NULL;
 		}
 	}
@@ -1208,7 +1211,10 @@
 			txd = &hp->happy_block->happy_meal_txd[i];
 			dma_addr = hme_read_desc32(hp, &txd->tx_addr);
 			hme_dma_unmap(hp, dma_addr, skb->len);
-			dev_kfree_skb(skb);
+			if (in_irq())
+				dev_kfree_skb_irq(skb);
+			else
+				dev_kfree_skb(skb);
 			hp->tx_skbs[i] = NULL;
 		}
 	}
@@ -1871,8 +1877,12 @@
 {
 	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
 	struct happy_meal_txd *this;
-	int elem = hp->tx_old;
+	struct net_device *dev = hp->dev;
+	int elem;
 
+	spin_lock(&hp->happy_lock);
+
+	elem = hp->tx_old;
 	TXD(("TX<"));
 	while (elem != hp->tx_new) {
 		struct sk_buff *skb;
@@ -1889,13 +1899,19 @@
 		hp->tx_skbs[elem] = NULL;
 		hp->net_stats.tx_bytes += skb->len;
 
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 
 		hp->net_stats.tx_packets++;
 		elem = NEXT_TX(elem);
 	}
 	hp->tx_old = elem;
 	TXD((">"));
+
+	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+	    TX_BUFFS_AVAIL(hp) > 0)
+		netif_wake_queue(dev);
+
+	spin_unlock(&hp->happy_lock);
 }
 
 #ifdef RXDEBUG
@@ -2020,14 +2036,10 @@
 
 	HMD(("happy_meal_interrupt: status=%08x ", happy_status));
 
-	dev->interrupt = 1;
-
 	if (happy_status & GREG_STAT_ERRORS) {
 		HMD(("ERRORS "));
-		if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) {
-			dev->interrupt = 0;
+		if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))
 			return;
-		}
 	}
 
 	if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2045,12 +2057,6 @@
 		happy_meal_rx(hp, dev);
 	}
 
-	if (dev->tbusy && (TX_BUFFS_AVAIL(hp) > 0)) {
-		hp->dev->tbusy = 0;
-		mark_bh(NET_BH);
-	}
-
-	dev->interrupt = 0;
 	HMD(("done\n"));
 }
 
@@ -2072,14 +2078,10 @@
 				      GREG_STAT_RXTOHOST)))
 			continue;
 
-		dev->interrupt = 1;
-
 		if (happy_status & GREG_STAT_ERRORS) {
 			HMD(("ERRORS "));
-			if (happy_meal_is_not_so_happy(hp, happy_status)) {
-				dev->interrupt=0;
+			if (happy_meal_is_not_so_happy(hp, happy_status))
 				break;
-			}
 		}
 
 		if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2096,12 +2098,6 @@
 			HMD(("RXTOHOST "));
 			happy_meal_rx(hp, dev);
 		}
-
-		if (dev->tbusy && (TX_BUFFS_AVAIL(hp) > 0)) {
-			hp->dev->tbusy = 0;
-			mark_bh(NET_BH);
-		}
-		dev->interrupt = 0;
 	}
 	HMD(("done\n"));
 }
@@ -2161,50 +2157,46 @@
 #define SXD(x)
 #endif
 
+static void happy_meal_tx_timeout(struct net_device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+
+	printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+	tx_dump_log();
+	printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+		hme_read32(hp, hp->gregs + GREG_STAT),
+		hme_read32(hp, hp->etxregs + ETX_CFG),
+		hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
+	happy_meal_init(hp, 0);
+	netif_wake_queue(dev);
+}
+
 static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
 	int len, entry;
+	u32 mapping;
 
-	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		int tickssofar = jiffies - dev->trans_start;
-	    
-		if (tickssofar >= 40) {
-			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
-			hp->net_stats.tx_errors++;
-			tx_dump_log();
-			printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
-				hme_read32(hp, hp->gregs + GREG_STAT),
-				hme_read32(hp, hp->etxregs + ETX_CFG),
-				hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
-			happy_meal_init(hp, 0);
-			dev->tbusy = 0;
-			dev->trans_start = jiffies;
-		} else
-			tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0);
-		return 1;
-	}
-
-	if (!TX_BUFFS_AVAIL(hp)) {
-		tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0);
-		return 1;
-	}
 	len = skb->len;
-	entry = hp->tx_new;
+	mapping = hme_dma_map(hp, skb->data, len);
+
+	spin_lock_irq(&hp->happy_lock);
 
+	entry = hp->tx_new;
 	SXD(("SX<l[%d]e[%d]>", len, entry));
 	hp->tx_skbs[entry] = skb;
 	hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
 		      (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)),
-		      hme_dma_map(hp, skb->data, len));
+		      mapping);
 	hp->tx_new = NEXT_TX(entry);
+	if (TX_BUFFS_AVAIL(hp) <= 0)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&hp->happy_lock);
 
 	/* Get it going. */
-	dev->trans_start = jiffies;
 	hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP);
-
-	if (TX_BUFFS_AVAIL(hp))
-		dev->tbusy = 0;
+	dev->trans_start = jiffies;
 
 	tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
 	return 0;
@@ -2228,7 +2220,7 @@
 	u32 crc, poly = CRC_POLYNOMIAL_LE;
 
 	/* Lock out others. */
-	set_bit(0, (void *) &dev->tbusy);
+	netif_stop_queue(dev);
 
 	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
 		hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff);
@@ -2272,7 +2264,7 @@
 	}
 
 	/* Let us get going again. */
-	dev->tbusy = 0;
+	netif_wake_queue(dev);
 }
 
 /* Ethtool support... */
@@ -2552,6 +2544,8 @@
 
 	hp->happy_dev = sdev;
 
+	spin_lock_init(&hp->happy_lock);
+
 	if (sdev->num_registers != 5) {
 		printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
 		       sdev->num_registers);
@@ -2637,6 +2631,8 @@
 	dev->hard_start_xmit = &happy_meal_start_xmit;
 	dev->get_stats = &happy_meal_get_stats;
 	dev->set_multicast_list = &happy_meal_set_multicast;
+	dev->tx_timeout = &happy_meal_tx_timeout;
+	dev->watchdog_timeo = 5*HZ;
 	dev->do_ioctl = &happy_meal_ioctl;
 
 	dev->irq = sdev->irqs[0];
@@ -2741,6 +2737,8 @@
 
 	hp->happy_dev = pdev;
 
+	spin_lock_init(&hp->happy_lock);
+
 	if (qp != NULL) {
 		hp->qfe_parent = qp;
 		hp->qfe_ent = qfe_slot;
@@ -2912,12 +2910,16 @@
 }
 #endif
 
-int __init happy_meal_probe(void)
+static int __init happy_meal_probe(void)
 {
 	struct net_device *dev = NULL;
 	static int called = 0;
 	int cards;
 
+#ifdef MODULE
+	root_happy_dev = NULL;
+#endif
+
 	if (called)
 		return ENODEV;
 	called++;
@@ -2936,18 +2938,10 @@
 	return 0;
 }
 
-#ifdef MODULE
 
-int
-init_module(void)
-{
-	root_happy_dev = NULL;
-	return happy_meal_probe();
-}
-
-void
-cleanup_module(void)
+static void __exit cleanup_module(void)
 {
+#ifdef MODULE
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_happy_dev) {
 		struct happy_meal *hp = root_happy_dev;
@@ -2978,6 +2972,8 @@
 		kfree(hp->dev);
 		root_happy_dev = next;
 	}
+#endif /* MODULE */
 }
 
-#endif /* MODULE */
+module_init(happy_meal_probe);
+module_exit(happy_meal_cleanup_module);

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