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
- Lines: 293
- Date:
Thu Feb 10 12:26:47 2000
- Orig file:
v2.3.42/linux/drivers/net/sunhme.c
- Orig date:
Tue Feb 1 01:35:44 2000
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)