diff options
Diffstat (limited to 'drivers/net/sundance.c')
-rw-r--r-- | drivers/net/sundance.c | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d500a5771dbc..0ab9c38b4a34 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c | |||
@@ -80,7 +80,7 @@ | |||
80 | I/O access could affect performance in ARM-based system | 80 | I/O access could affect performance in ARM-based system |
81 | - Add Linux software VLAN support | 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 | - Fix bug of custom mac address | 84 | - Fix bug of custom mac address |
85 | (StationAddr register only accept word write) | 85 | (StationAddr register only accept word write) |
86 | 86 | ||
@@ -91,11 +91,14 @@ | |||
91 | Version LK1.09a (ICPlus): | 91 | Version LK1.09a (ICPlus): |
92 | - Add the delay time in reading the contents of EEPROM | 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 | #define DRV_NAME "sundance" | 99 | #define DRV_NAME "sundance" |
97 | #define DRV_VERSION "1.01+LK1.09a" | 100 | #define DRV_VERSION "1.01+LK1.10" |
98 | #define DRV_RELDATE "10-Jul-2003" | 101 | #define DRV_RELDATE "28-Oct-2005" |
99 | 102 | ||
100 | 103 | ||
101 | /* The user-configurable values. | 104 | /* The user-configurable values. |
@@ -263,8 +266,10 @@ IV. Notes | |||
263 | IVb. References | 266 | IVb. References |
264 | 267 | ||
265 | The Sundance ST201 datasheet, preliminary version. | 268 | The Sundance ST201 datasheet, preliminary version. |
266 | http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html | 269 | The Kendin KS8723 datasheet, preliminary version. |
267 | http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html | 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 | IVc. Errata | 274 | IVc. Errata |
270 | 275 | ||
@@ -500,6 +505,25 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | |||
500 | static int netdev_close(struct net_device *dev); | 505 | static int netdev_close(struct net_device *dev); |
501 | static struct ethtool_ops ethtool_ops; | 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 | static int __devinit sundance_probe1 (struct pci_dev *pdev, | 527 | static int __devinit sundance_probe1 (struct pci_dev *pdev, |
504 | const struct pci_device_id *ent) | 528 | const struct pci_device_id *ent) |
505 | { | 529 | { |
@@ -518,6 +542,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, | |||
518 | #else | 542 | #else |
519 | int bar = 1; | 543 | int bar = 1; |
520 | #endif | 544 | #endif |
545 | int phy, phy_idx = 0; | ||
521 | 546 | ||
522 | 547 | ||
523 | /* when built into the kernel, we only print version if device is found */ | 548 | /* when built into the kernel, we only print version if device is found */ |
@@ -549,6 +574,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, | |||
549 | for (i = 0; i < 3; i++) | 574 | for (i = 0; i < 3; i++) |
550 | ((u16 *)dev->dev_addr)[i] = | 575 | ((u16 *)dev->dev_addr)[i] = |
551 | le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); | 576 | le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); |
577 | memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); | ||
552 | 578 | ||
553 | dev->base_addr = (unsigned long)ioaddr; | 579 | dev->base_addr = (unsigned long)ioaddr; |
554 | dev->irq = irq; | 580 | dev->irq = irq; |
@@ -605,33 +631,31 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, | |||
605 | printk("%2.2x:", dev->dev_addr[i]); | 631 | printk("%2.2x:", dev->dev_addr[i]); |
606 | printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); | 632 | printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); |
607 | 633 | ||
608 | if (1) { | 634 | np->phys[0] = 1; /* Default setting */ |
609 | int phy, phy_idx = 0; | 635 | np->mii_preamble_required++; |
610 | np->phys[0] = 1; /* Default setting */ | 636 | for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { |
611 | np->mii_preamble_required++; | 637 | int mii_status = mdio_read(dev, phy, MII_BMSR); |
612 | for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { | 638 | int phyx = phy & 0x1f; |
613 | int mii_status = mdio_read(dev, phy, MII_BMSR); | 639 | if (mii_status != 0xffff && mii_status != 0x0000) { |
614 | if (mii_status != 0xffff && mii_status != 0x0000) { | 640 | np->phys[phy_idx++] = phyx; |
615 | np->phys[phy_idx++] = phy; | 641 | np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); |
616 | np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); | 642 | if ((mii_status & 0x0040) == 0) |
617 | if ((mii_status & 0x0040) == 0) | 643 | np->mii_preamble_required++; |
618 | np->mii_preamble_required++; | 644 | printk(KERN_INFO "%s: MII PHY found at address %d, status " |
619 | printk(KERN_INFO "%s: MII PHY found at address %d, status " | 645 | "0x%4.4x advertising %4.4x.\n", |
620 | "0x%4.4x advertising %4.4x.\n", | 646 | dev->name, phyx, mii_status, np->mii_if.advertising); |
621 | dev->name, phy, mii_status, np->mii_if.advertising); | ||
622 | } | ||
623 | } | ||
624 | np->mii_preamble_required--; | ||
625 | |||
626 | if (phy_idx == 0) { | ||
627 | printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", | ||
628 | dev->name, ioread32(ioaddr + ASICCtrl)); | ||
629 | goto err_out_unregister; | ||
630 | } | 647 | } |
648 | } | ||
649 | np->mii_preamble_required--; | ||
631 | 650 | ||
632 | np->mii_if.phy_id = np->phys[0]; | 651 | if (phy_idx == 0) { |
652 | printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", | ||
653 | dev->name, ioread32(ioaddr + ASICCtrl)); | ||
654 | goto err_out_unregister; | ||
633 | } | 655 | } |
634 | 656 | ||
657 | np->mii_if.phy_id = np->phys[0]; | ||
658 | |||
635 | /* Parse override configuration */ | 659 | /* Parse override configuration */ |
636 | np->an_enable = 1; | 660 | np->an_enable = 1; |
637 | if (card_idx < MAX_UNITS) { | 661 | if (card_idx < MAX_UNITS) { |
@@ -692,7 +716,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, | |||
692 | /* Reset the chip to erase previous misconfiguration. */ | 716 | /* Reset the chip to erase previous misconfiguration. */ |
693 | if (netif_msg_hw(np)) | 717 | if (netif_msg_hw(np)) |
694 | printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); | 718 | printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); |
695 | iowrite16(0x007f, ioaddr + ASICCtrl + 2); | 719 | iowrite16(0x00ff, ioaddr + ASICCtrl + 2); |
696 | if (netif_msg_hw(np)) | 720 | if (netif_msg_hw(np)) |
697 | printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); | 721 | printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); |
698 | 722 | ||
@@ -1190,23 +1214,33 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs | |||
1190 | ("%s: Transmit status is %2.2x.\n", | 1214 | ("%s: Transmit status is %2.2x.\n", |
1191 | dev->name, tx_status); | 1215 | dev->name, tx_status); |
1192 | if (tx_status & 0x1e) { | 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 | np->stats.tx_errors++; | 1220 | np->stats.tx_errors++; |
1194 | if (tx_status & 0x10) | 1221 | if (tx_status & 0x10) |
1195 | np->stats.tx_fifo_errors++; | 1222 | np->stats.tx_fifo_errors++; |
1196 | if (tx_status & 0x08) | 1223 | if (tx_status & 0x08) |
1197 | np->stats.collisions++; | 1224 | np->stats.collisions++; |
1225 | if (tx_status & 0x04) | ||
1226 | np->stats.tx_fifo_errors++; | ||
1198 | if (tx_status & 0x02) | 1227 | if (tx_status & 0x02) |
1199 | np->stats.tx_window_errors++; | 1228 | np->stats.tx_window_errors++; |
1200 | /* This reset has not been verified!. */ | 1229 | /* |
1201 | if (tx_status & 0x10) { /* Reset the Tx. */ | 1230 | ** This reset has been verified on |
1202 | np->stats.tx_fifo_errors++; | 1231 | ** DFE-580TX boards ! phdm@macqel.be. |
1203 | spin_lock(&np->lock); | 1232 | */ |
1204 | reset_tx(dev); | 1233 | if (tx_status & 0x10) { /* TxUnderrun */ |
1205 | spin_unlock(&np->lock); | 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. */ | 1242 | /* Restart the Tx. */ |
1208 | iowrite16 (TxEnable, | 1243 | iowrite16 (TxEnable, ioaddr + MACCtrl1); |
1209 | ioaddr + MACCtrl1); | ||
1210 | } | 1244 | } |
1211 | /* Yup, this is a documentation bug. It cost me *hours*. */ | 1245 | /* Yup, this is a documentation bug. It cost me *hours*. */ |
1212 | iowrite16 (0, ioaddr + TxStatus); | 1246 | iowrite16 (0, ioaddr + TxStatus); |
@@ -1619,6 +1653,7 @@ static struct ethtool_ops ethtool_ops = { | |||
1619 | .get_link = get_link, | 1653 | .get_link = get_link, |
1620 | .get_msglevel = get_msglevel, | 1654 | .get_msglevel = get_msglevel, |
1621 | .set_msglevel = set_msglevel, | 1655 | .set_msglevel = set_msglevel, |
1656 | .get_perm_addr = ethtool_op_get_perm_addr, | ||
1622 | }; | 1657 | }; |
1623 | 1658 | ||
1624 | static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 1659 | static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |