summaryrefslogtreecommitdiffstats
path: root/drivers/net/sundance.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sundance.c')
-rw-r--r--drivers/net/sundance.c58
1 files changed, 47 insertions, 11 deletions
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 41c503d..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,
@@ -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,6 +1101,10 @@ 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;
}
@@ -1111,6 +1120,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
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)
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,
OpenPOWER on IntegriCloud