patch-2.3.43 linux/drivers/net/sunbmac.c
Next file: linux/drivers/net/sunbmac.h
Previous file: linux/drivers/net/starfire.c
Back to the patch index
Back to the overall index
- Lines: 231
- Date:
Thu Feb 10 12:26:47 2000
- Orig file:
v2.3.42/linux/drivers/net/sunbmac.c
- Orig date:
Tue Feb 1 01:35:44 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.13 2000/01/28 13:42:29 jj Exp $
+/* $Id: sunbmac.c,v 1.14 2000/02/09 11:15:35 davem Exp $
* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -190,14 +190,20 @@
for (i = 0; i < RX_RING_SIZE; i++) {
if (bp->rx_skbs[i] != NULL) {
- dev_kfree_skb(bp->rx_skbs[i]);
+ if (in_irq())
+ dev_kfree_skb_irq(bp->rx_skbs[i]);
+ else
+ dev_kfree_skb(bp->rx_skbs[i]);
bp->rx_skbs[i] = NULL;
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (bp->tx_skbs[i] != NULL) {
- dev_kfree_skb(bp->tx_skbs[i]);
+ if (in_irq())
+ dev_kfree_skb_irq(bp->tx_skbs[i]);
+ else
+ dev_kfree_skb(bp->tx_skbs[i]);
bp->tx_skbs[i] = NULL;
}
}
@@ -750,8 +756,12 @@
static void bigmac_tx(struct bigmac *bp)
{
struct be_txd *txbase = &bp->bmac_block->be_txd[0];
- int elem = bp->tx_old;
+ struct net_device *dev = bp->dev;
+ int elem;
+
+ spin_lock(&bp->lock);
+ elem = bp->tx_old;
DTX(("bigmac_tx: tx_old[%d] ", elem));
while (elem != bp->tx_new) {
struct sk_buff *skb;
@@ -770,12 +780,18 @@
DTX(("skb(%p) ", skb));
bp->tx_skbs[elem] = NULL;
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
elem = NEXT_TX(elem);
}
DTX((" DONE, tx_old=%d\n", elem));
bp->tx_old = elem;
+
+ if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+ TX_BUFFS_AVAIL(bp) > 0)
+ netif_wake_queue(bp->dev);
+
+ spin_unlock(&bp->lock);
}
/* BigMAC receive complete service routines. */
@@ -874,8 +890,6 @@
bmac_status = sbus_readl(bp->creg + CREG_STAT);
qec_status = sbus_readl(bp->gregs + GLOB_STAT);
- bp->dev->interrupt = 1;
-
DIRQ(("qec_status=%08x bmac_status=%08x\n", qec_status, bmac_status));
if ((qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) ||
(bmac_status & CREG_STAT_ERRORS))
@@ -886,13 +900,6 @@
if (bmac_status & CREG_STAT_RXIRQ)
bigmac_rx(bp);
-
- if (bp->dev->tbusy && (TX_BUFFS_AVAIL(bp) > 0)) {
- bp->dev->tbusy = 0;
- mark_bh(NET_BH);
- }
-
- bp->dev->interrupt = 0;
}
static int bigmac_open(struct net_device *dev)
@@ -928,55 +935,43 @@
return 0;
}
+static void bigmac_tx_timeout(struct net_device *dev)
+{
+ struct bigmac *bp = (struct bigmac *) dev->priv;
+
+ bigmac_init(bp, 0);
+ netif_wake_queue(dev);
+}
+
/* Put a packet on the wire. */
static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
int len, entry;
-
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
-
- if (tickssofar < 40) {
- return 1;
- } else {
- printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
- bp->enet_stats.tx_errors++;
- bigmac_init(bp, 0);
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- dev_kfree_skb(skb);
- return 0;
- }
- }
-
- if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
- printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
-
- if (!TX_BUFFS_AVAIL(bp))
- return 1;
+ u32 mapping;
len = skb->len;
- entry = bp->tx_new;
- DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry));
+ mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len);
/* Avoid a race... */
+ spin_lock_irq(&bp->lock);
+ entry = bp->tx_new;
+ DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry));
bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE;
bp->tx_skbs[entry] = skb;
- bp->bmac_block->be_txd[entry].tx_addr =
- sbus_map_single(bp->bigmac_sdev, skb->data, len);
+ bp->bmac_block->be_txd[entry].tx_addr = mapping;
bp->bmac_block->be_txd[entry].tx_flags =
(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));
- dev->trans_start = jiffies;
bp->tx_new = NEXT_TX(entry);
+ if (TX_BUFFS_AVAIL(bp) <= 0)
+ netif_stop_queue(dev);
+ spin_unlock_irq(&bp->lock);
/* Get it going. */
sbus_writel(CREG_CTRL_TWAKEUP, bp->creg + CREG_CTRL);
- if (TX_BUFFS_AVAIL(bp))
- dev->tbusy = 0;
+
+ dev->trans_start = jiffies;
return 0;
}
@@ -1084,6 +1079,8 @@
bp->qec_sdev = qec_sdev;
bp->bigmac_sdev = qec_sdev->child;
+ spin_lock_init(&bp->lock);
+
/* All further failures we find return this. */
res = ENODEV;
@@ -1194,6 +1191,9 @@
dev->get_stats = &bigmac_get_stats;
dev->set_multicast_list = &bigmac_set_multicast;
+ dev->tx_timeout = &bigmac_tx_timeout;
+ dev->watchdog_timeo = 5*HZ;
+
/* Finish net device registration. */
dev->irq = bp->bigmac_sdev->irqs[0];
dev->dma = 0;
@@ -1251,7 +1251,7 @@
return 1;
}
-int __init bigmac_probe(void)
+static int __init bigmac_probe(void)
{
struct net_device *dev = NULL;
struct sbus_bus *sbus;
@@ -1259,6 +1259,10 @@
static int called = 0;
int cards = 0, v;
+#ifdef MODULE
+ root_bigmac_dev = NULL;
+#endif
+
if (called)
return ENODEV;
called++;
@@ -1280,18 +1284,9 @@
return 0;
}
-#ifdef MODULE
-
-int
-init_module(void)
-{
- root_bigmac_dev = NULL;
- return bigmac_probe();
-}
-
-void
-cleanup_module(void)
+static void __exit bigmac_cleanup(void)
{
+#ifdef MODULE
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
while (root_bigmac_dev) {
struct bigmac *bp = root_bigmac_dev;
@@ -1310,6 +1305,8 @@
kfree(bp->dev);
root_bigmac_dev = bp_nxt;
}
+#endif /* MODULE */
}
-#endif /* MODULE */
+module_init(bigmac_probe);
+module_exit(bigmac_cleanup);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)