Commit b71b95efa5abca33e1bfb85d55162c7f99f54c23
Committed by
Jeff Garzik
1 parent
89358f90ab
Exists in
master
and in
7 other branches
[PATCH] sundance: fix DFE-580TX Tx Underrun
Under heavy PCI bus load, ports of the DFE-580TX 4-ethernet port board stop working, with currently no other cure than a powercycle. Here is a tested fix. By the way, I also fixed some references and attribution. Signed-off-by: Philippe De Muyter <phdm@macqel.be> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Showing 1 changed file with 48 additions and 14 deletions Side-by-side Diff
drivers/net/sundance.c
... | ... | @@ -80,7 +80,7 @@ |
80 | 80 | I/O access could affect performance in ARM-based system |
81 | 81 | - Add Linux software VLAN support |
82 | 82 | |
83 | - Version LK1.08 (D-Link): | |
83 | + Version LK1.08 (Philippe De Muyter phdm@macqel.be): | |
84 | 84 | - Fix bug of custom mac address |
85 | 85 | (StationAddr register only accept word write) |
86 | 86 | |
87 | 87 | |
... | ... | @@ -91,11 +91,14 @@ |
91 | 91 | Version LK1.09a (ICPlus): |
92 | 92 | - Add the delay time in reading the contents of EEPROM |
93 | 93 | |
94 | + Version LK1.10 (Philippe De Muyter phdm@macqel.be): | |
95 | + - Make 'unblock interface after Tx underrun' work | |
96 | + | |
94 | 97 | */ |
95 | 98 | |
96 | 99 | #define DRV_NAME "sundance" |
97 | -#define DRV_VERSION "1.01+LK1.09a" | |
98 | -#define DRV_RELDATE "10-Jul-2003" | |
100 | +#define DRV_VERSION "1.01+LK1.10" | |
101 | +#define DRV_RELDATE "28-Oct-2005" | |
99 | 102 | |
100 | 103 | |
101 | 104 | /* The user-configurable values. |
... | ... | @@ -263,8 +266,10 @@ |
263 | 266 | IVb. References |
264 | 267 | |
265 | 268 | The Sundance ST201 datasheet, preliminary version. |
266 | -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html | |
267 | -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html | |
269 | +The Kendin KS8723 datasheet, preliminary version. | |
270 | +The ICplus IP100 datasheet, preliminary version. | |
271 | +http://www.scyld.com/expert/100mbps.html | |
272 | +http://www.scyld.com/expert/NWay.html | |
268 | 273 | |
269 | 274 | IVc. Errata |
270 | 275 | |
... | ... | @@ -500,6 +505,25 @@ |
500 | 505 | static int netdev_close(struct net_device *dev); |
501 | 506 | static struct ethtool_ops ethtool_ops; |
502 | 507 | |
508 | +static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) | |
509 | +{ | |
510 | + struct netdev_private *np = netdev_priv(dev); | |
511 | + void __iomem *ioaddr = np->base + ASICCtrl; | |
512 | + int countdown; | |
513 | + | |
514 | + /* ST201 documentation states ASICCtrl is a 32bit register */ | |
515 | + iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); | |
516 | + /* ST201 documentation states reset can take up to 1 ms */ | |
517 | + countdown = 10 + 1; | |
518 | + while (ioread32 (ioaddr) & (ResetBusy << 16)) { | |
519 | + if (--countdown == 0) { | |
520 | + printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); | |
521 | + break; | |
522 | + } | |
523 | + udelay(100); | |
524 | + } | |
525 | +} | |
526 | + | |
503 | 527 | static int __devinit sundance_probe1 (struct pci_dev *pdev, |
504 | 528 | const struct pci_device_id *ent) |
505 | 529 | { |
506 | 530 | |
507 | 531 | |
508 | 532 | |
... | ... | @@ -1190,23 +1214,33 @@ |
1190 | 1214 | ("%s: Transmit status is %2.2x.\n", |
1191 | 1215 | dev->name, tx_status); |
1192 | 1216 | if (tx_status & 0x1e) { |
1217 | + if (netif_msg_tx_err(np)) | |
1218 | + printk("%s: Transmit error status %4.4x.\n", | |
1219 | + dev->name, tx_status); | |
1193 | 1220 | np->stats.tx_errors++; |
1194 | 1221 | if (tx_status & 0x10) |
1195 | 1222 | np->stats.tx_fifo_errors++; |
1196 | 1223 | if (tx_status & 0x08) |
1197 | 1224 | np->stats.collisions++; |
1225 | + if (tx_status & 0x04) | |
1226 | + np->stats.tx_fifo_errors++; | |
1198 | 1227 | if (tx_status & 0x02) |
1199 | 1228 | np->stats.tx_window_errors++; |
1200 | - /* This reset has not been verified!. */ | |
1201 | - if (tx_status & 0x10) { /* Reset the Tx. */ | |
1202 | - np->stats.tx_fifo_errors++; | |
1203 | - spin_lock(&np->lock); | |
1204 | - reset_tx(dev); | |
1205 | - spin_unlock(&np->lock); | |
1229 | + /* | |
1230 | + ** This reset has been verified on | |
1231 | + ** DFE-580TX boards ! phdm@macqel.be. | |
1232 | + */ | |
1233 | + if (tx_status & 0x10) { /* TxUnderrun */ | |
1234 | + unsigned short txthreshold; | |
1235 | + | |
1236 | + txthreshold = ioread16 (ioaddr + TxStartThresh); | |
1237 | + /* Restart Tx FIFO and transmitter */ | |
1238 | + sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); | |
1239 | + iowrite16 (txthreshold, ioaddr + TxStartThresh); | |
1240 | + /* No need to reset the Tx pointer here */ | |
1206 | 1241 | } |
1207 | - if (tx_status & 0x1e) /* Restart the Tx. */ | |
1208 | - iowrite16 (TxEnable, | |
1209 | - ioaddr + MACCtrl1); | |
1242 | + /* Restart the Tx. */ | |
1243 | + iowrite16 (TxEnable, ioaddr + MACCtrl1); | |
1210 | 1244 | } |
1211 | 1245 | /* Yup, this is a documentation bug. It cost me *hours*. */ |
1212 | 1246 | iowrite16 (0, ioaddr + TxStatus); |