diff options
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r-- | drivers/net/forcedeth.c | 108 |
1 files changed, 78 insertions, 30 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 14e6da2c1bf4..a7e7be7ed705 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -2516,9 +2516,17 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2516 | if (!netif_running(dev)) { | 2516 | if (!netif_running(dev)) { |
2517 | /* We do not track link speed / duplex setting if the | 2517 | /* We do not track link speed / duplex setting if the |
2518 | * interface is disabled. Force a link check */ | 2518 | * interface is disabled. Force a link check */ |
2519 | nv_update_linkspeed(dev); | 2519 | if (nv_update_linkspeed(dev)) { |
2520 | if (!netif_carrier_ok(dev)) | ||
2521 | netif_carrier_on(dev); | ||
2522 | } else { | ||
2523 | if (netif_carrier_ok(dev)) | ||
2524 | netif_carrier_off(dev); | ||
2525 | } | ||
2520 | } | 2526 | } |
2521 | switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) { | 2527 | |
2528 | if (netif_carrier_ok(dev)) { | ||
2529 | switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) { | ||
2522 | case NVREG_LINKSPEED_10: | 2530 | case NVREG_LINKSPEED_10: |
2523 | ecmd->speed = SPEED_10; | 2531 | ecmd->speed = SPEED_10; |
2524 | break; | 2532 | break; |
@@ -2528,10 +2536,14 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2528 | case NVREG_LINKSPEED_1000: | 2536 | case NVREG_LINKSPEED_1000: |
2529 | ecmd->speed = SPEED_1000; | 2537 | ecmd->speed = SPEED_1000; |
2530 | break; | 2538 | break; |
2539 | } | ||
2540 | ecmd->duplex = DUPLEX_HALF; | ||
2541 | if (np->duplex) | ||
2542 | ecmd->duplex = DUPLEX_FULL; | ||
2543 | } else { | ||
2544 | ecmd->speed = -1; | ||
2545 | ecmd->duplex = -1; | ||
2531 | } | 2546 | } |
2532 | ecmd->duplex = DUPLEX_HALF; | ||
2533 | if (np->duplex) | ||
2534 | ecmd->duplex = DUPLEX_FULL; | ||
2535 | 2547 | ||
2536 | ecmd->autoneg = np->autoneg; | 2548 | ecmd->autoneg = np->autoneg; |
2537 | 2549 | ||
@@ -2539,23 +2551,20 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2539 | if (np->autoneg) { | 2551 | if (np->autoneg) { |
2540 | ecmd->advertising |= ADVERTISED_Autoneg; | 2552 | ecmd->advertising |= ADVERTISED_Autoneg; |
2541 | adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); | 2553 | adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); |
2542 | } else { | 2554 | if (adv & ADVERTISE_10HALF) |
2543 | adv = np->fixed_mode; | 2555 | ecmd->advertising |= ADVERTISED_10baseT_Half; |
2544 | } | 2556 | if (adv & ADVERTISE_10FULL) |
2545 | if (adv & ADVERTISE_10HALF) | 2557 | ecmd->advertising |= ADVERTISED_10baseT_Full; |
2546 | ecmd->advertising |= ADVERTISED_10baseT_Half; | 2558 | if (adv & ADVERTISE_100HALF) |
2547 | if (adv & ADVERTISE_10FULL) | 2559 | ecmd->advertising |= ADVERTISED_100baseT_Half; |
2548 | ecmd->advertising |= ADVERTISED_10baseT_Full; | 2560 | if (adv & ADVERTISE_100FULL) |
2549 | if (adv & ADVERTISE_100HALF) | 2561 | ecmd->advertising |= ADVERTISED_100baseT_Full; |
2550 | ecmd->advertising |= ADVERTISED_100baseT_Half; | 2562 | if (np->gigabit == PHY_GIGABIT) { |
2551 | if (adv & ADVERTISE_100FULL) | 2563 | adv = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); |
2552 | ecmd->advertising |= ADVERTISED_100baseT_Full; | 2564 | if (adv & ADVERTISE_1000FULL) |
2553 | if (np->autoneg && np->gigabit == PHY_GIGABIT) { | 2565 | ecmd->advertising |= ADVERTISED_1000baseT_Full; |
2554 | adv = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); | 2566 | } |
2555 | if (adv & ADVERTISE_1000FULL) | ||
2556 | ecmd->advertising |= ADVERTISED_1000baseT_Full; | ||
2557 | } | 2567 | } |
2558 | |||
2559 | ecmd->supported = (SUPPORTED_Autoneg | | 2568 | ecmd->supported = (SUPPORTED_Autoneg | |
2560 | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | | 2569 | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | |
2561 | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | | 2570 | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | |
@@ -2607,7 +2616,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2607 | return -EINVAL; | 2616 | return -EINVAL; |
2608 | } | 2617 | } |
2609 | 2618 | ||
2610 | spin_lock_irq(&np->lock); | 2619 | netif_carrier_off(dev); |
2620 | if (netif_running(dev)) { | ||
2621 | nv_disable_irq(dev); | ||
2622 | spin_lock_bh(&dev->xmit_lock); | ||
2623 | spin_lock(&np->lock); | ||
2624 | /* stop engines */ | ||
2625 | nv_stop_rx(dev); | ||
2626 | nv_stop_tx(dev); | ||
2627 | spin_unlock(&np->lock); | ||
2628 | spin_unlock_bh(&dev->xmit_lock); | ||
2629 | } | ||
2630 | |||
2611 | if (ecmd->autoneg == AUTONEG_ENABLE) { | 2631 | if (ecmd->autoneg == AUTONEG_ENABLE) { |
2612 | int adv, bmcr; | 2632 | int adv, bmcr; |
2613 | 2633 | ||
@@ -2638,6 +2658,8 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2638 | mii_rw(dev, np->phyaddr, MII_CTRL1000, adv); | 2658 | mii_rw(dev, np->phyaddr, MII_CTRL1000, adv); |
2639 | } | 2659 | } |
2640 | 2660 | ||
2661 | if (netif_running(dev)) | ||
2662 | printk(KERN_INFO "%s: link down.\n", dev->name); | ||
2641 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 2663 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
2642 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | 2664 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); |
2643 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | 2665 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); |
@@ -2676,20 +2698,30 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2676 | } | 2698 | } |
2677 | 2699 | ||
2678 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 2700 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
2679 | bmcr |= ~(BMCR_ANENABLE|BMCR_SPEED100|BMCR_FULLDPLX); | 2701 | bmcr &= ~(BMCR_ANENABLE|BMCR_SPEED100|BMCR_SPEED1000|BMCR_FULLDPLX); |
2680 | if (adv & (ADVERTISE_10FULL|ADVERTISE_100FULL)) | 2702 | if (np->fixed_mode & (ADVERTISE_10FULL|ADVERTISE_100FULL)) |
2681 | bmcr |= BMCR_FULLDPLX; | 2703 | bmcr |= BMCR_FULLDPLX; |
2682 | if (adv & (ADVERTISE_100HALF|ADVERTISE_100FULL)) | 2704 | if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL)) |
2683 | bmcr |= BMCR_SPEED100; | 2705 | bmcr |= BMCR_SPEED100; |
2684 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | 2706 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); |
2685 | 2707 | if (np->phy_oui == PHY_OUI_MARVELL) { | |
2686 | if (netif_running(dev)) { | 2708 | /* reset the phy */ |
2709 | if (phy_reset(dev)) { | ||
2710 | printk(KERN_INFO "%s: phy reset failed\n", dev->name); | ||
2711 | return -EINVAL; | ||
2712 | } | ||
2713 | } else if (netif_running(dev)) { | ||
2687 | /* Wait a bit and then reconfigure the nic. */ | 2714 | /* Wait a bit and then reconfigure the nic. */ |
2688 | udelay(10); | 2715 | udelay(10); |
2689 | nv_linkchange(dev); | 2716 | nv_linkchange(dev); |
2690 | } | 2717 | } |
2691 | } | 2718 | } |
2692 | spin_unlock_irq(&np->lock); | 2719 | |
2720 | if (netif_running(dev)) { | ||
2721 | nv_start_rx(dev); | ||
2722 | nv_start_tx(dev); | ||
2723 | nv_enable_irq(dev); | ||
2724 | } | ||
2693 | 2725 | ||
2694 | return 0; | 2726 | return 0; |
2695 | } | 2727 | } |
@@ -2721,19 +2753,35 @@ static int nv_nway_reset(struct net_device *dev) | |||
2721 | struct fe_priv *np = netdev_priv(dev); | 2753 | struct fe_priv *np = netdev_priv(dev); |
2722 | int ret; | 2754 | int ret; |
2723 | 2755 | ||
2724 | spin_lock_irq(&np->lock); | ||
2725 | if (np->autoneg) { | 2756 | if (np->autoneg) { |
2726 | int bmcr; | 2757 | int bmcr; |
2727 | 2758 | ||
2759 | netif_carrier_off(dev); | ||
2760 | if (netif_running(dev)) { | ||
2761 | nv_disable_irq(dev); | ||
2762 | spin_lock_bh(&dev->xmit_lock); | ||
2763 | spin_lock(&np->lock); | ||
2764 | /* stop engines */ | ||
2765 | nv_stop_rx(dev); | ||
2766 | nv_stop_tx(dev); | ||
2767 | spin_unlock(&np->lock); | ||
2768 | spin_unlock_bh(&dev->xmit_lock); | ||
2769 | printk(KERN_INFO "%s: link down.\n", dev->name); | ||
2770 | } | ||
2771 | |||
2728 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 2772 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
2729 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | 2773 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); |
2730 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | 2774 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); |
2731 | 2775 | ||
2776 | if (netif_running(dev)) { | ||
2777 | nv_start_rx(dev); | ||
2778 | nv_start_tx(dev); | ||
2779 | nv_enable_irq(dev); | ||
2780 | } | ||
2732 | ret = 0; | 2781 | ret = 0; |
2733 | } else { | 2782 | } else { |
2734 | ret = -EINVAL; | 2783 | ret = -EINVAL; |
2735 | } | 2784 | } |
2736 | spin_unlock_irq(&np->lock); | ||
2737 | 2785 | ||
2738 | return ret; | 2786 | return ret; |
2739 | } | 2787 | } |