diff options
-rw-r--r-- | drivers/net/pcnet32.c | 236 |
1 files changed, 212 insertions, 24 deletions
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 7e900572eaf8..1bc3f5bffb95 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c | |||
@@ -22,8 +22,8 @@ | |||
22 | *************************************************************************/ | 22 | *************************************************************************/ |
23 | 23 | ||
24 | #define DRV_NAME "pcnet32" | 24 | #define DRV_NAME "pcnet32" |
25 | #define DRV_VERSION "1.31c" | 25 | #define DRV_VERSION "1.32" |
26 | #define DRV_RELDATE "01.Nov.2005" | 26 | #define DRV_RELDATE "18.Mar.2006" |
27 | #define PFX DRV_NAME ": " | 27 | #define PFX DRV_NAME ": " |
28 | 28 | ||
29 | static const char * const version = | 29 | static const char * const version = |
@@ -133,7 +133,7 @@ static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { | |||
133 | }; | 133 | }; |
134 | #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) | 134 | #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) |
135 | 135 | ||
136 | #define PCNET32_NUM_REGS 168 | 136 | #define PCNET32_NUM_REGS 136 |
137 | 137 | ||
138 | #define MAX_UNITS 8 /* More are supported, limit only on options */ | 138 | #define MAX_UNITS 8 /* More are supported, limit only on options */ |
139 | static int options[MAX_UNITS]; | 139 | static int options[MAX_UNITS]; |
@@ -265,6 +265,9 @@ static int homepna[MAX_UNITS]; | |||
265 | * v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only. | 265 | * v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only. |
266 | * Force 100Mbit FD if Auto (ASEL) is selected. | 266 | * Force 100Mbit FD if Auto (ASEL) is selected. |
267 | * See Bugzilla 2669 and 4551. | 267 | * See Bugzilla 2669 and 4551. |
268 | * v1.32 18 Mar2006 Thomas Bogendoerfer and Don Fry added Multi-Phy | ||
269 | * handling for supporting AT-270x FTX cards with FX and Tx PHYs. | ||
270 | * Philippe Seewer assisted with auto negotiation and testing. | ||
268 | */ | 271 | */ |
269 | 272 | ||
270 | 273 | ||
@@ -375,6 +378,7 @@ struct pcnet32_private { | |||
375 | unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ | 378 | unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ |
376 | struct net_device_stats stats; | 379 | struct net_device_stats stats; |
377 | char tx_full; | 380 | char tx_full; |
381 | char phycount; /* number of phys found */ | ||
378 | int options; | 382 | int options; |
379 | unsigned int shared_irq:1, /* shared irq possible */ | 383 | unsigned int shared_irq:1, /* shared irq possible */ |
380 | dxsuflo:1, /* disable transmit stop on uflo */ | 384 | dxsuflo:1, /* disable transmit stop on uflo */ |
@@ -384,6 +388,9 @@ struct pcnet32_private { | |||
384 | struct timer_list watchdog_timer; | 388 | struct timer_list watchdog_timer; |
385 | struct timer_list blink_timer; | 389 | struct timer_list blink_timer; |
386 | u32 msg_enable; /* debug message level */ | 390 | u32 msg_enable; /* debug message level */ |
391 | |||
392 | /* each bit indicates an available PHY */ | ||
393 | u32 phymask; | ||
387 | }; | 394 | }; |
388 | 395 | ||
389 | static void pcnet32_probe_vlbus(void); | 396 | static void pcnet32_probe_vlbus(void); |
@@ -415,6 +422,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
415 | static void pcnet32_purge_tx_ring(struct net_device *dev); | 422 | static void pcnet32_purge_tx_ring(struct net_device *dev); |
416 | static int pcnet32_alloc_ring(struct net_device *dev, char *name); | 423 | static int pcnet32_alloc_ring(struct net_device *dev, char *name); |
417 | static void pcnet32_free_ring(struct net_device *dev); | 424 | static void pcnet32_free_ring(struct net_device *dev); |
425 | static void pcnet32_check_media(struct net_device *dev, int verbose); | ||
418 | 426 | ||
419 | 427 | ||
420 | enum pci_flags_bit { | 428 | enum pci_flags_bit { |
@@ -936,9 +944,14 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data) | |||
936 | return 0; | 944 | return 0; |
937 | } | 945 | } |
938 | 946 | ||
947 | #define PCNET32_REGS_PER_PHY 32 | ||
948 | #define PCNET32_MAX_PHYS 32 | ||
939 | static int pcnet32_get_regs_len(struct net_device *dev) | 949 | static int pcnet32_get_regs_len(struct net_device *dev) |
940 | { | 950 | { |
941 | return(PCNET32_NUM_REGS * sizeof(u16)); | 951 | struct pcnet32_private *lp = dev->priv; |
952 | int j = lp->phycount * PCNET32_REGS_PER_PHY; | ||
953 | |||
954 | return((PCNET32_NUM_REGS + j) * sizeof(u16)); | ||
942 | } | 955 | } |
943 | 956 | ||
944 | static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, | 957 | static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, |
@@ -998,9 +1011,14 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
998 | 1011 | ||
999 | /* read mii phy registers */ | 1012 | /* read mii phy registers */ |
1000 | if (lp->mii) { | 1013 | if (lp->mii) { |
1001 | for (i=0; i<32; i++) { | 1014 | int j; |
1002 | lp->a.write_bcr(ioaddr, 33, ((lp->mii_if.phy_id) << 5) | i); | 1015 | for (j=0; j<PCNET32_MAX_PHYS; j++) { |
1003 | *buff++ = lp->a.read_bcr(ioaddr, 34); | 1016 | if (lp->phymask & (1 << j)) { |
1017 | for (i=0; i<PCNET32_REGS_PER_PHY; i++) { | ||
1018 | lp->a.write_bcr(ioaddr, 33, (j << 5) | i); | ||
1019 | *buff++ = lp->a.read_bcr(ioaddr, 34); | ||
1020 | } | ||
1021 | } | ||
1004 | } | 1022 | } |
1005 | } | 1023 | } |
1006 | 1024 | ||
@@ -1009,10 +1027,6 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
1009 | a->write_csr(ioaddr, 5, 0x0000); | 1027 | a->write_csr(ioaddr, 5, 0x0000); |
1010 | } | 1028 | } |
1011 | 1029 | ||
1012 | i = buff - (u16 *)ptr; | ||
1013 | for (; i < PCNET32_NUM_REGS; i++) | ||
1014 | *buff++ = 0; | ||
1015 | |||
1016 | spin_unlock_irqrestore(&lp->lock, flags); | 1030 | spin_unlock_irqrestore(&lp->lock, flags); |
1017 | } | 1031 | } |
1018 | 1032 | ||
@@ -1185,7 +1199,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
1185 | if (cards_found < MAX_UNITS && homepna[cards_found]) | 1199 | if (cards_found < MAX_UNITS && homepna[cards_found]) |
1186 | media |= 1; /* switch to home wiring mode */ | 1200 | media |= 1; /* switch to home wiring mode */ |
1187 | if (pcnet32_debug & NETIF_MSG_PROBE) | 1201 | if (pcnet32_debug & NETIF_MSG_PROBE) |
1188 | printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", | 1202 | printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", |
1189 | (media & 1) ? "1" : "10"); | 1203 | (media & 1) ? "1" : "10"); |
1190 | a->write_bcr(ioaddr, 49, media); | 1204 | a->write_bcr(ioaddr, 49, media); |
1191 | break; | 1205 | break; |
@@ -1401,8 +1415,34 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
1401 | } | 1415 | } |
1402 | 1416 | ||
1403 | /* Set the mii phy_id so that we can query the link state */ | 1417 | /* Set the mii phy_id so that we can query the link state */ |
1404 | if (lp->mii) | 1418 | if (lp->mii) { |
1419 | /* lp->phycount and lp->phymask are set to 0 by memset above */ | ||
1420 | |||
1405 | lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f; | 1421 | lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f; |
1422 | /* scan for PHYs */ | ||
1423 | for (i=0; i<PCNET32_MAX_PHYS; i++) { | ||
1424 | unsigned short id1, id2; | ||
1425 | |||
1426 | id1 = mdio_read(dev, i, MII_PHYSID1); | ||
1427 | if (id1 == 0xffff) | ||
1428 | continue; | ||
1429 | id2 = mdio_read(dev, i, MII_PHYSID2); | ||
1430 | if (id2 == 0xffff) | ||
1431 | continue; | ||
1432 | if (i == 31 && ((chip_version + 1) & 0xfffe) == 0x2624) | ||
1433 | continue; /* 79C971 & 79C972 have phantom phy at id 31 */ | ||
1434 | lp->phycount++; | ||
1435 | lp->phymask |= (1 << i); | ||
1436 | lp->mii_if.phy_id = i; | ||
1437 | if (pcnet32_debug & NETIF_MSG_PROBE) | ||
1438 | printk(KERN_INFO PFX "Found PHY %04x:%04x at address %d.\n", | ||
1439 | id1, id2, i); | ||
1440 | } | ||
1441 | lp->a.write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5); | ||
1442 | if (lp->phycount > 1) { | ||
1443 | lp->options |= PCNET32_PORT_MII; | ||
1444 | } | ||
1445 | } | ||
1406 | 1446 | ||
1407 | init_timer (&lp->watchdog_timer); | 1447 | init_timer (&lp->watchdog_timer); |
1408 | lp->watchdog_timer.data = (unsigned long) dev; | 1448 | lp->watchdog_timer.data = (unsigned long) dev; |
@@ -1625,7 +1665,7 @@ pcnet32_open(struct net_device *dev) | |||
1625 | dev->name); | 1665 | dev->name); |
1626 | } | 1666 | } |
1627 | } | 1667 | } |
1628 | { | 1668 | if (lp->phycount < 2) { |
1629 | /* | 1669 | /* |
1630 | * 24 Jun 2004 according AMD, in order to change the PHY, | 1670 | * 24 Jun 2004 according AMD, in order to change the PHY, |
1631 | * DANAS (or DISPM for 79C976) must be set; then select the speed, | 1671 | * DANAS (or DISPM for 79C976) must be set; then select the speed, |
@@ -1651,6 +1691,62 @@ pcnet32_open(struct net_device *dev) | |||
1651 | lp->a.write_bcr(ioaddr, 32, val); | 1691 | lp->a.write_bcr(ioaddr, 32, val); |
1652 | } | 1692 | } |
1653 | } | 1693 | } |
1694 | } else { | ||
1695 | int first_phy = -1; | ||
1696 | u16 bmcr; | ||
1697 | u32 bcr9; | ||
1698 | struct ethtool_cmd ecmd; | ||
1699 | |||
1700 | /* | ||
1701 | * There is really no good other way to handle multiple PHYs | ||
1702 | * other than turning off all automatics | ||
1703 | */ | ||
1704 | val = lp->a.read_bcr(ioaddr, 2); | ||
1705 | lp->a.write_bcr(ioaddr, 2, val & ~2); | ||
1706 | val = lp->a.read_bcr(ioaddr, 32); | ||
1707 | lp->a.write_bcr(ioaddr, 32, val & ~(1 << 7)); /* stop MII manager */ | ||
1708 | |||
1709 | if (!(lp->options & PCNET32_PORT_ASEL)) { | ||
1710 | /* setup ecmd */ | ||
1711 | ecmd.port = PORT_MII; | ||
1712 | ecmd.transceiver = XCVR_INTERNAL; | ||
1713 | ecmd.autoneg = AUTONEG_DISABLE; | ||
1714 | ecmd.speed = lp->options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; | ||
1715 | bcr9 = lp->a.read_bcr(ioaddr, 9); | ||
1716 | |||
1717 | if (lp->options & PCNET32_PORT_FD) { | ||
1718 | ecmd.duplex = DUPLEX_FULL; | ||
1719 | bcr9 |= (1 << 0); | ||
1720 | } else { | ||
1721 | ecmd.duplex = DUPLEX_HALF; | ||
1722 | bcr9 |= ~(1 << 0); | ||
1723 | } | ||
1724 | lp->a.write_bcr(ioaddr, 9, bcr9); | ||
1725 | } | ||
1726 | |||
1727 | for (i=0; i<PCNET32_MAX_PHYS; i++) { | ||
1728 | if (lp->phymask & (1 << i)) { | ||
1729 | /* isolate all but the first PHY */ | ||
1730 | bmcr = mdio_read(dev, i, MII_BMCR); | ||
1731 | if (first_phy == -1) { | ||
1732 | first_phy = i; | ||
1733 | mdio_write(dev, i, MII_BMCR, bmcr & ~BMCR_ISOLATE); | ||
1734 | } else { | ||
1735 | mdio_write(dev, i, MII_BMCR, bmcr | BMCR_ISOLATE); | ||
1736 | } | ||
1737 | /* use mii_ethtool_sset to setup PHY */ | ||
1738 | lp->mii_if.phy_id = i; | ||
1739 | ecmd.phy_address = i; | ||
1740 | if (lp->options & PCNET32_PORT_ASEL) { | ||
1741 | mii_ethtool_gset(&lp->mii_if, &ecmd); | ||
1742 | ecmd.autoneg = AUTONEG_ENABLE; | ||
1743 | } | ||
1744 | mii_ethtool_sset(&lp->mii_if, &ecmd); | ||
1745 | } | ||
1746 | } | ||
1747 | lp->mii_if.phy_id = first_phy; | ||
1748 | if (netif_msg_link(lp)) | ||
1749 | printk(KERN_INFO "%s: Using PHY number %d.\n", dev->name, first_phy); | ||
1654 | } | 1750 | } |
1655 | 1751 | ||
1656 | #ifdef DO_DXSUFLO | 1752 | #ifdef DO_DXSUFLO |
@@ -1680,11 +1776,9 @@ pcnet32_open(struct net_device *dev) | |||
1680 | 1776 | ||
1681 | netif_start_queue(dev); | 1777 | netif_start_queue(dev); |
1682 | 1778 | ||
1683 | /* If we have mii, print the link status and start the watchdog */ | 1779 | /* Print the link status and start the watchdog */ |
1684 | if (lp->mii) { | 1780 | pcnet32_check_media (dev, 1); |
1685 | mii_check_media (&lp->mii_if, netif_msg_link(lp), 1); | 1781 | mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); |
1686 | mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); | ||
1687 | } | ||
1688 | 1782 | ||
1689 | i = 0; | 1783 | i = 0; |
1690 | while (i++ < 100) | 1784 | while (i++ < 100) |
@@ -2430,17 +2524,111 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
2430 | return rc; | 2524 | return rc; |
2431 | } | 2525 | } |
2432 | 2526 | ||
2527 | static int pcnet32_check_otherphy(struct net_device *dev) | ||
2528 | { | ||
2529 | struct pcnet32_private *lp = dev->priv; | ||
2530 | struct mii_if_info mii = lp->mii_if; | ||
2531 | u16 bmcr; | ||
2532 | int i; | ||
2533 | |||
2534 | for (i = 0; i < PCNET32_MAX_PHYS; i++) { | ||
2535 | if (i == lp->mii_if.phy_id) | ||
2536 | continue; /* skip active phy */ | ||
2537 | if (lp->phymask & (1 << i)) { | ||
2538 | mii.phy_id = i; | ||
2539 | if (mii_link_ok(&mii)) { | ||
2540 | /* found PHY with active link */ | ||
2541 | if (netif_msg_link(lp)) | ||
2542 | printk(KERN_INFO "%s: Using PHY number %d.\n", dev->name, i); | ||
2543 | |||
2544 | /* isolate inactive phy */ | ||
2545 | bmcr = mdio_read(dev, lp->mii_if.phy_id, MII_BMCR); | ||
2546 | mdio_write(dev, lp->mii_if.phy_id, MII_BMCR, bmcr | BMCR_ISOLATE); | ||
2547 | |||
2548 | /* de-isolate new phy */ | ||
2549 | bmcr = mdio_read(dev, i, MII_BMCR); | ||
2550 | mdio_write(dev, i, MII_BMCR, bmcr & ~BMCR_ISOLATE); | ||
2551 | |||
2552 | /* set new phy address */ | ||
2553 | lp->mii_if.phy_id = i; | ||
2554 | return 1; | ||
2555 | } | ||
2556 | } | ||
2557 | } | ||
2558 | return 0; | ||
2559 | } | ||
2560 | |||
2561 | /* | ||
2562 | * Show the status of the media. Similar to mii_check_media however it | ||
2563 | * correctly shows the link speed for all (tested) pcnet32 variants. | ||
2564 | * Devices with no mii just report link state without speed. | ||
2565 | * | ||
2566 | * Caller is assumed to hold and release the lp->lock. | ||
2567 | */ | ||
2568 | |||
2569 | static void pcnet32_check_media(struct net_device *dev, int verbose) | ||
2570 | { | ||
2571 | struct pcnet32_private *lp = dev->priv; | ||
2572 | int curr_link; | ||
2573 | int prev_link = netif_carrier_ok(dev) ? 1 : 0; | ||
2574 | u32 bcr9; | ||
2575 | |||
2576 | if (lp->mii) { | ||
2577 | curr_link = mii_link_ok(&lp->mii_if); | ||
2578 | } else { | ||
2579 | ulong ioaddr = dev->base_addr; /* card base I/O address */ | ||
2580 | curr_link = (lp->a.read_bcr(ioaddr, 4) != 0xc0); | ||
2581 | } | ||
2582 | if (!curr_link) { | ||
2583 | if (prev_link || verbose) { | ||
2584 | netif_carrier_off(dev); | ||
2585 | if (netif_msg_link(lp)) | ||
2586 | printk(KERN_INFO "%s: link down\n", dev->name); | ||
2587 | } | ||
2588 | if (lp->phycount > 1) { | ||
2589 | curr_link = pcnet32_check_otherphy(dev); | ||
2590 | prev_link = 0; | ||
2591 | } | ||
2592 | } else if (verbose || !prev_link) { | ||
2593 | netif_carrier_on(dev); | ||
2594 | if (lp->mii) { | ||
2595 | if (netif_msg_link(lp)) { | ||
2596 | struct ethtool_cmd ecmd; | ||
2597 | mii_ethtool_gset(&lp->mii_if, &ecmd); | ||
2598 | printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", | ||
2599 | dev->name, | ||
2600 | (ecmd.speed == SPEED_100) ? "100" : "10", | ||
2601 | (ecmd.duplex == DUPLEX_FULL) ? "full" : "half"); | ||
2602 | } | ||
2603 | bcr9 = lp->a.read_bcr(dev->base_addr, 9); | ||
2604 | if ((bcr9 & (1 << 0)) != lp->mii_if.full_duplex) { | ||
2605 | if (lp->mii_if.full_duplex) | ||
2606 | bcr9 |= (1 << 0); | ||
2607 | else | ||
2608 | bcr9 &= ~(1 << 0); | ||
2609 | lp->a.write_bcr(dev->base_addr, 9, bcr9); | ||
2610 | } | ||
2611 | } else { | ||
2612 | if (netif_msg_link(lp)) | ||
2613 | printk(KERN_INFO "%s: link up\n", dev->name); | ||
2614 | } | ||
2615 | } | ||
2616 | } | ||
2617 | |||
2618 | /* | ||
2619 | * Check for loss of link and link establishment. | ||
2620 | * Can not use mii_check_media because it does nothing if mode is forced. | ||
2621 | */ | ||
2622 | |||
2433 | static void pcnet32_watchdog(struct net_device *dev) | 2623 | static void pcnet32_watchdog(struct net_device *dev) |
2434 | { | 2624 | { |
2435 | struct pcnet32_private *lp = dev->priv; | 2625 | struct pcnet32_private *lp = dev->priv; |
2436 | unsigned long flags; | 2626 | unsigned long flags; |
2437 | 2627 | ||
2438 | /* Print the link status if it has changed */ | 2628 | /* Print the link status if it has changed */ |
2439 | if (lp->mii) { | 2629 | spin_lock_irqsave(&lp->lock, flags); |
2440 | spin_lock_irqsave(&lp->lock, flags); | 2630 | pcnet32_check_media(dev, 0); |
2441 | mii_check_media (&lp->mii_if, netif_msg_link(lp), 0); | 2631 | spin_unlock_irqrestore(&lp->lock, flags); |
2442 | spin_unlock_irqrestore(&lp->lock, flags); | ||
2443 | } | ||
2444 | 2632 | ||
2445 | mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); | 2633 | mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); |
2446 | } | 2634 | } |