Commit 7dd822b2 authored by Jeff Garzik's avatar Jeff Garzik

sundance net drvr: fix reset_tx logic

(contributed by Edward Peng @ D-Link, cleaned up by me)
parent bb09051b
...@@ -322,6 +322,8 @@ enum alta_offsets { ...@@ -322,6 +322,8 @@ enum alta_offsets {
TxDMAPollPeriod = 0x0a, TxDMAPollPeriod = 0x0a,
RxDMAStatus = 0x0c, RxDMAStatus = 0x0c,
RxListPtr = 0x10, RxListPtr = 0x10,
DebugCtrl0 = 0x1a,
DebugCtrl1 = 0x1c,
RxDMABurstThresh = 0x14, RxDMABurstThresh = 0x14,
RxDMAUrgentThresh = 0x15, RxDMAUrgentThresh = 0x15,
RxDMAPollPeriod = 0x16, RxDMAPollPeriod = 0x16,
...@@ -480,7 +482,7 @@ static void netdev_timer(unsigned long data); ...@@ -480,7 +482,7 @@ static void netdev_timer(unsigned long data);
static void tx_timeout(struct net_device *dev); static void tx_timeout(struct net_device *dev);
static void init_ring(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 start_tx(struct sk_buff *skb, struct net_device *dev);
static int reset_tx (struct net_device *dev, int irq); static int reset_tx (struct net_device *dev);
static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static void rx_poll(unsigned long data); static void rx_poll(unsigned long data);
static void refill_rx (struct net_device *dev); static void refill_rx (struct net_device *dev);
...@@ -934,6 +936,7 @@ static void tx_timeout(struct net_device *dev) ...@@ -934,6 +936,7 @@ static void tx_timeout(struct net_device *dev)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
long flag; long flag;
writew(0, ioaddr + IntrEnable);
printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x " printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
"TxFrameId %2.2x," "TxFrameId %2.2x,"
" resetting...\n", dev->name, readb(ioaddr + TxStatus), " resetting...\n", dev->name, readb(ioaddr + TxStatus),
...@@ -948,9 +951,11 @@ static void tx_timeout(struct net_device *dev) ...@@ -948,9 +951,11 @@ static void tx_timeout(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) for (i = 0; i < TX_RING_SIZE; i++)
printk(" %8.8x", np->tx_ring[i].status); printk(" %8.8x", np->tx_ring[i].status);
printk("\n"); printk("\n");
printk(KERN_DEBUG "cur_tx=%d dirty_tx=%d\n", np->cur_tx, np->dirty_tx);
printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
} }
spin_lock_irqsave(&np->lock, flag); spin_lock_irqsave(&np->lock, flag);
reset_tx(dev, 0); reset_tx(dev);
spin_unlock_irqrestore(&np->lock, flag); spin_unlock_irqrestore(&np->lock, flag);
/* Perhaps we should reinitialize the hardware here. */ /* Perhaps we should reinitialize the hardware here. */
...@@ -962,9 +967,7 @@ static void tx_timeout(struct net_device *dev) ...@@ -962,9 +967,7 @@ static void tx_timeout(struct net_device *dev)
dev->trans_start = jiffies; dev->trans_start = jiffies;
np->stats.tx_errors++; np->stats.tx_errors++;
netif_wake_queue(dev);
if (!netif_queue_stopped(dev))
netif_wake_queue(dev);
} }
...@@ -1067,15 +1070,18 @@ start_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1067,15 +1070,18 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
writel (1000, ioaddr + DownCounter); writel (1000, ioaddr + DownCounter);
return 0; return 0;
} }
/* Reset hardware tx and reset TxListPtr to TxFrameId */
static int static int
reset_tx (struct net_device *dev, int irq) reset_tx (struct net_device *dev)
{ {
struct netdev_private *np = (struct netdev_private*) dev->priv; struct netdev_private *np = (struct netdev_private*) dev->priv;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
struct sk_buff *skb;
int i; int i;
int frame_id; int irq = in_interrupt();
frame_id = readb(ioaddr + TxFrameId); /* reset tx logic */
writel (0, dev->base_addr + TxListPtr);
writew (TxReset | DMAReset | FIFOReset | NetworkReset, writew (TxReset | DMAReset | FIFOReset | NetworkReset,
ioaddr + ASICCtrl + 2); ioaddr + ASICCtrl + 2);
for (i=50; i > 0; i--) { for (i=50; i > 0; i--) {
...@@ -1083,25 +1089,22 @@ reset_tx (struct net_device *dev, int irq) ...@@ -1083,25 +1089,22 @@ reset_tx (struct net_device *dev, int irq)
break; break;
mdelay(1); mdelay(1);
} }
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { /* free all tx skbuff */
int entry = np->dirty_tx % TX_RING_SIZE; for (i = 0; i < TX_RING_SIZE; i++) {
struct sk_buff *skb; skb = np->tx_skbuff[i];
if (!(np->tx_ring[entry].status & 0x00010000)) if (skb) {
break; pci_unmap_single(np->pci_dev,
skb = np->tx_skbuff[entry]; np->tx_ring[i].frag[0].addr, skb->len,
/* Free the original skb. */ PCI_DMA_TODEVICE);
pci_unmap_single(np->pci_dev, if (irq)
np->tx_ring[entry].frag[0].addr, dev_kfree_skb_irq (skb);
skb->len, PCI_DMA_TODEVICE); else
if (irq) dev_kfree_skb (skb);
dev_kfree_skb_irq (np->tx_skbuff[entry]); np->tx_skbuff[i] = 0;
else np->stats.tx_dropped++;
dev_kfree_skb (np->tx_skbuff[entry]); }
np->tx_skbuff[entry] = 0;
} }
writel (np->tx_ring_dma + frame_id * sizeof(*np->tx_ring), np->cur_tx = np->dirty_tx = 0;
dev->base_addr + TxListPtr);
return 0; return 0;
} }
...@@ -1156,7 +1159,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1156,7 +1159,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
if (tx_status & 0x10) { /* Reset the Tx. */ if (tx_status & 0x10) { /* Reset the Tx. */
np->stats.tx_fifo_errors++; np->stats.tx_fifo_errors++;
spin_lock(&np->lock); spin_lock(&np->lock);
reset_tx(dev, 1); reset_tx(dev);
spin_unlock(&np->lock); spin_unlock(&np->lock);
} }
if (tx_status & 0x1e) /* Restart the Tx. */ if (tx_status & 0x1e) /* Restart the Tx. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment