aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/pcnet32.c236
1 files changed, 212 insertions, 24 deletions
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 7e900572eaf..1bc3f5bffb9 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
29static const char * const version = 29static 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 */
139static int options[MAX_UNITS]; 139static 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
389static void pcnet32_probe_vlbus(void); 396static void pcnet32_probe_vlbus(void);
@@ -415,6 +422,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
415static void pcnet32_purge_tx_ring(struct net_device *dev); 422static void pcnet32_purge_tx_ring(struct net_device *dev);
416static int pcnet32_alloc_ring(struct net_device *dev, char *name); 423static int pcnet32_alloc_ring(struct net_device *dev, char *name);
417static void pcnet32_free_ring(struct net_device *dev); 424static void pcnet32_free_ring(struct net_device *dev);
425static void pcnet32_check_media(struct net_device *dev, int verbose);
418 426
419 427
420enum pci_flags_bit { 428enum 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
939static int pcnet32_get_regs_len(struct net_device *dev) 949static 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
944static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, 957static 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
2527static 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
2569static 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
2433static void pcnet32_watchdog(struct net_device *dev) 2623static 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}