diff options
Diffstat (limited to 'drivers/net/sundance.c')
-rw-r--r-- | drivers/net/sundance.c | 62 |
1 files changed, 49 insertions, 13 deletions
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 6b8f4ba..c06ecc8 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -264,8 +264,6 @@ enum alta_offsets { ASICCtrl = 0x30, EEData = 0x34, EECtrl = 0x36, - TxStartThresh = 0x3c, - RxEarlyThresh = 0x3e, FlashAddr = 0x40, FlashData = 0x44, TxStatus = 0x46, @@ -420,7 +418,7 @@ static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static int reset_tx (struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void rx_poll(unsigned long data); static void tx_poll(unsigned long data); static void refill_rx (struct net_device *dev); @@ -790,6 +788,7 @@ static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; + unsigned long flags; int i; /* Do we need to reset the chip??? */ @@ -834,6 +833,10 @@ static int netdev_open(struct net_device *dev) iowrite8(0x01, ioaddr + DebugCtrl1); netif_start_queue(dev); + spin_lock_irqsave(&np->lock, flags); + reset_tx(dev); + spin_unlock_irqrestore(&np->lock, flags); + iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); if (netif_msg_ifup(np)) @@ -1081,6 +1084,8 @@ reset_tx (struct net_device *dev) /* free all tx skbuff */ for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].next_desc = 0; + skb = np->tx_skbuff[i]; if (skb) { pci_unmap_single(np->pci_dev, @@ -1096,13 +1101,17 @@ reset_tx (struct net_device *dev) } np->cur_tx = np->dirty_tx = 0; np->cur_task = 0; + + np->last_tx = NULL; + iowrite8(127, ioaddr + TxDMAPollPeriod); + iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); return 0; } /* The interrupt handler cleans up after the Tx thread, and schedule a Rx thread work */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct netdev_private *np = netdev_priv(dev); @@ -1111,6 +1120,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs int tx_cnt; int tx_status; int handled = 0; + int i; do { @@ -1153,21 +1163,24 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs np->stats.tx_fifo_errors++; if (tx_status & 0x02) np->stats.tx_window_errors++; + /* ** This reset has been verified on ** DFE-580TX boards ! phdm@macqel.be. */ if (tx_status & 0x10) { /* TxUnderrun */ - unsigned short txthreshold; - - txthreshold = ioread16 (ioaddr + TxStartThresh); /* Restart Tx FIFO and transmitter */ sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); - iowrite16 (txthreshold, ioaddr + TxStartThresh); /* No need to reset the Tx pointer here */ } - /* Restart the Tx. */ - iowrite16 (TxEnable, ioaddr + MACCtrl1); + /* Restart the Tx. Need to make sure tx enabled */ + i = 10; + do { + iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1); + if (ioread16(ioaddr + MACCtrl1) & TxEnabled) + break; + mdelay(1); + } while (--i); } /* Yup, this is a documentation bug. It cost me *hours*. */ iowrite16 (0, ioaddr + TxStatus); @@ -1629,6 +1642,14 @@ static int netdev_close(struct net_device *dev) struct sk_buff *skb; int i; + /* Wait and kill tasklet */ + tasklet_kill(&np->rx_tasklet); + tasklet_kill(&np->tx_tasklet); + np->cur_tx = 0; + np->dirty_tx = 0; + np->cur_task = 0; + np->last_tx = NULL; + netif_stop_queue(dev); if (netif_msg_ifdown(np)) { @@ -1643,12 +1664,26 @@ static int netdev_close(struct net_device *dev) /* Disable interrupts by clearing the interrupt mask. */ iowrite16(0x0000, ioaddr + IntrEnable); + /* Disable Rx and Tx DMA for safely release resource */ + iowrite32(0x500, ioaddr + DMACtrl); + /* Stop the chip's Tx and Rx processes. */ iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); - /* Wait and kill tasklet */ - tasklet_kill(&np->rx_tasklet); - tasklet_kill(&np->tx_tasklet); + for (i = 2000; i > 0; i--) { + if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0) + break; + mdelay(1); + } + + iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset, + ioaddr +ASICCtrl + 2); + + for (i = 2000; i > 0; i--) { + if ((ioread16(ioaddr + ASICCtrl +2) & ResetBusy) == 0) + break; + mdelay(1); + } #ifdef __i386__ if (netif_msg_hw(np)) { @@ -1686,6 +1721,7 @@ static int netdev_close(struct net_device *dev) } } for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].next_desc = 0; skb = np->tx_skbuff[i]; if (skb) { pci_unmap_single(np->pci_dev, |