diff options
Diffstat (limited to 'drivers/net/sundance.c')
-rw-r--r-- | drivers/net/sundance.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 41c503d8bac..c06ecc8002b 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c | |||
@@ -264,8 +264,6 @@ enum alta_offsets { | |||
264 | ASICCtrl = 0x30, | 264 | ASICCtrl = 0x30, |
265 | EEData = 0x34, | 265 | EEData = 0x34, |
266 | EECtrl = 0x36, | 266 | EECtrl = 0x36, |
267 | TxStartThresh = 0x3c, | ||
268 | RxEarlyThresh = 0x3e, | ||
269 | FlashAddr = 0x40, | 267 | FlashAddr = 0x40, |
270 | FlashData = 0x44, | 268 | FlashData = 0x44, |
271 | TxStatus = 0x46, | 269 | TxStatus = 0x46, |
@@ -790,6 +788,7 @@ static int netdev_open(struct net_device *dev) | |||
790 | { | 788 | { |
791 | struct netdev_private *np = netdev_priv(dev); | 789 | struct netdev_private *np = netdev_priv(dev); |
792 | void __iomem *ioaddr = np->base; | 790 | void __iomem *ioaddr = np->base; |
791 | unsigned long flags; | ||
793 | int i; | 792 | int i; |
794 | 793 | ||
795 | /* Do we need to reset the chip??? */ | 794 | /* Do we need to reset the chip??? */ |
@@ -834,6 +833,10 @@ static int netdev_open(struct net_device *dev) | |||
834 | iowrite8(0x01, ioaddr + DebugCtrl1); | 833 | iowrite8(0x01, ioaddr + DebugCtrl1); |
835 | netif_start_queue(dev); | 834 | netif_start_queue(dev); |
836 | 835 | ||
836 | spin_lock_irqsave(&np->lock, flags); | ||
837 | reset_tx(dev); | ||
838 | spin_unlock_irqrestore(&np->lock, flags); | ||
839 | |||
837 | iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); | 840 | iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); |
838 | 841 | ||
839 | if (netif_msg_ifup(np)) | 842 | if (netif_msg_ifup(np)) |
@@ -1081,6 +1084,8 @@ reset_tx (struct net_device *dev) | |||
1081 | 1084 | ||
1082 | /* free all tx skbuff */ | 1085 | /* free all tx skbuff */ |
1083 | for (i = 0; i < TX_RING_SIZE; i++) { | 1086 | for (i = 0; i < TX_RING_SIZE; i++) { |
1087 | np->tx_ring[i].next_desc = 0; | ||
1088 | |||
1084 | skb = np->tx_skbuff[i]; | 1089 | skb = np->tx_skbuff[i]; |
1085 | if (skb) { | 1090 | if (skb) { |
1086 | pci_unmap_single(np->pci_dev, | 1091 | pci_unmap_single(np->pci_dev, |
@@ -1096,6 +1101,10 @@ reset_tx (struct net_device *dev) | |||
1096 | } | 1101 | } |
1097 | np->cur_tx = np->dirty_tx = 0; | 1102 | np->cur_tx = np->dirty_tx = 0; |
1098 | np->cur_task = 0; | 1103 | np->cur_task = 0; |
1104 | |||
1105 | np->last_tx = NULL; | ||
1106 | iowrite8(127, ioaddr + TxDMAPollPeriod); | ||
1107 | |||
1099 | iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); | 1108 | iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); |
1100 | return 0; | 1109 | return 0; |
1101 | } | 1110 | } |
@@ -1111,6 +1120,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) | |||
1111 | int tx_cnt; | 1120 | int tx_cnt; |
1112 | int tx_status; | 1121 | int tx_status; |
1113 | int handled = 0; | 1122 | int handled = 0; |
1123 | int i; | ||
1114 | 1124 | ||
1115 | 1125 | ||
1116 | do { | 1126 | do { |
@@ -1153,21 +1163,24 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) | |||
1153 | np->stats.tx_fifo_errors++; | 1163 | np->stats.tx_fifo_errors++; |
1154 | if (tx_status & 0x02) | 1164 | if (tx_status & 0x02) |
1155 | np->stats.tx_window_errors++; | 1165 | np->stats.tx_window_errors++; |
1166 | |||
1156 | /* | 1167 | /* |
1157 | ** This reset has been verified on | 1168 | ** This reset has been verified on |
1158 | ** DFE-580TX boards ! phdm@macqel.be. | 1169 | ** DFE-580TX boards ! phdm@macqel.be. |
1159 | */ | 1170 | */ |
1160 | if (tx_status & 0x10) { /* TxUnderrun */ | 1171 | if (tx_status & 0x10) { /* TxUnderrun */ |
1161 | unsigned short txthreshold; | ||
1162 | |||
1163 | txthreshold = ioread16 (ioaddr + TxStartThresh); | ||
1164 | /* Restart Tx FIFO and transmitter */ | 1172 | /* Restart Tx FIFO and transmitter */ |
1165 | sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); | 1173 | sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); |
1166 | iowrite16 (txthreshold, ioaddr + TxStartThresh); | ||
1167 | /* No need to reset the Tx pointer here */ | 1174 | /* No need to reset the Tx pointer here */ |
1168 | } | 1175 | } |
1169 | /* Restart the Tx. */ | 1176 | /* Restart the Tx. Need to make sure tx enabled */ |
1170 | iowrite16 (TxEnable, ioaddr + MACCtrl1); | 1177 | i = 10; |
1178 | do { | ||
1179 | iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1); | ||
1180 | if (ioread16(ioaddr + MACCtrl1) & TxEnabled) | ||
1181 | break; | ||
1182 | mdelay(1); | ||
1183 | } while (--i); | ||
1171 | } | 1184 | } |
1172 | /* Yup, this is a documentation bug. It cost me *hours*. */ | 1185 | /* Yup, this is a documentation bug. It cost me *hours*. */ |
1173 | iowrite16 (0, ioaddr + TxStatus); | 1186 | iowrite16 (0, ioaddr + TxStatus); |
@@ -1629,6 +1642,14 @@ static int netdev_close(struct net_device *dev) | |||
1629 | struct sk_buff *skb; | 1642 | struct sk_buff *skb; |
1630 | int i; | 1643 | int i; |
1631 | 1644 | ||
1645 | /* Wait and kill tasklet */ | ||
1646 | tasklet_kill(&np->rx_tasklet); | ||
1647 | tasklet_kill(&np->tx_tasklet); | ||
1648 | np->cur_tx = 0; | ||
1649 | np->dirty_tx = 0; | ||
1650 | np->cur_task = 0; | ||
1651 | np->last_tx = NULL; | ||
1652 | |||
1632 | netif_stop_queue(dev); | 1653 | netif_stop_queue(dev); |
1633 | 1654 | ||
1634 | if (netif_msg_ifdown(np)) { | 1655 | if (netif_msg_ifdown(np)) { |
@@ -1643,12 +1664,26 @@ static int netdev_close(struct net_device *dev) | |||
1643 | /* Disable interrupts by clearing the interrupt mask. */ | 1664 | /* Disable interrupts by clearing the interrupt mask. */ |
1644 | iowrite16(0x0000, ioaddr + IntrEnable); | 1665 | iowrite16(0x0000, ioaddr + IntrEnable); |
1645 | 1666 | ||
1667 | /* Disable Rx and Tx DMA for safely release resource */ | ||
1668 | iowrite32(0x500, ioaddr + DMACtrl); | ||
1669 | |||
1646 | /* Stop the chip's Tx and Rx processes. */ | 1670 | /* Stop the chip's Tx and Rx processes. */ |
1647 | iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); | 1671 | iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); |
1648 | 1672 | ||
1649 | /* Wait and kill tasklet */ | 1673 | for (i = 2000; i > 0; i--) { |
1650 | tasklet_kill(&np->rx_tasklet); | 1674 | if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0) |
1651 | tasklet_kill(&np->tx_tasklet); | 1675 | break; |
1676 | mdelay(1); | ||
1677 | } | ||
1678 | |||
1679 | iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset, | ||
1680 | ioaddr +ASICCtrl + 2); | ||
1681 | |||
1682 | for (i = 2000; i > 0; i--) { | ||
1683 | if ((ioread16(ioaddr + ASICCtrl +2) & ResetBusy) == 0) | ||
1684 | break; | ||
1685 | mdelay(1); | ||
1686 | } | ||
1652 | 1687 | ||
1653 | #ifdef __i386__ | 1688 | #ifdef __i386__ |
1654 | if (netif_msg_hw(np)) { | 1689 | if (netif_msg_hw(np)) { |
@@ -1686,6 +1721,7 @@ static int netdev_close(struct net_device *dev) | |||
1686 | } | 1721 | } |
1687 | } | 1722 | } |
1688 | for (i = 0; i < TX_RING_SIZE; i++) { | 1723 | for (i = 0; i < TX_RING_SIZE; i++) { |
1724 | np->tx_ring[i].next_desc = 0; | ||
1689 | skb = np->tx_skbuff[i]; | 1725 | skb = np->tx_skbuff[i]; |
1690 | if (skb) { | 1726 | if (skb) { |
1691 | pci_unmap_single(np->pci_dev, | 1727 | pci_unmap_single(np->pci_dev, |