diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/nvidia/forcedeth.c | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index d24c45bec508..e8a5ae356407 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c | |||
@@ -3003,6 +3003,73 @@ static void nv_update_pause(struct net_device *dev, u32 pause_flags) | |||
3003 | } | 3003 | } |
3004 | } | 3004 | } |
3005 | 3005 | ||
3006 | static void nv_force_linkspeed(struct net_device *dev, int speed, int duplex) | ||
3007 | { | ||
3008 | struct fe_priv *np = netdev_priv(dev); | ||
3009 | u8 __iomem *base = get_hwbase(dev); | ||
3010 | u32 phyreg, txreg; | ||
3011 | int mii_status; | ||
3012 | |||
3013 | np->linkspeed = NVREG_LINKSPEED_FORCE|speed; | ||
3014 | np->duplex = duplex; | ||
3015 | |||
3016 | /* see if gigabit phy */ | ||
3017 | mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); | ||
3018 | if (mii_status & PHY_GIGABIT) { | ||
3019 | np->gigabit = PHY_GIGABIT; | ||
3020 | phyreg = readl(base + NvRegSlotTime); | ||
3021 | phyreg &= ~(0x3FF00); | ||
3022 | if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) | ||
3023 | phyreg |= NVREG_SLOTTIME_10_100_FULL; | ||
3024 | else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) | ||
3025 | phyreg |= NVREG_SLOTTIME_10_100_FULL; | ||
3026 | else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) | ||
3027 | phyreg |= NVREG_SLOTTIME_1000_FULL; | ||
3028 | writel(phyreg, base + NvRegSlotTime); | ||
3029 | } | ||
3030 | |||
3031 | phyreg = readl(base + NvRegPhyInterface); | ||
3032 | phyreg &= ~(PHY_HALF|PHY_100|PHY_1000); | ||
3033 | if (np->duplex == 0) | ||
3034 | phyreg |= PHY_HALF; | ||
3035 | if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100) | ||
3036 | phyreg |= PHY_100; | ||
3037 | else if ((np->linkspeed & NVREG_LINKSPEED_MASK) == | ||
3038 | NVREG_LINKSPEED_1000) | ||
3039 | phyreg |= PHY_1000; | ||
3040 | writel(phyreg, base + NvRegPhyInterface); | ||
3041 | |||
3042 | if (phyreg & PHY_RGMII) { | ||
3043 | if ((np->linkspeed & NVREG_LINKSPEED_MASK) == | ||
3044 | NVREG_LINKSPEED_1000) | ||
3045 | txreg = NVREG_TX_DEFERRAL_RGMII_1000; | ||
3046 | else | ||
3047 | txreg = NVREG_TX_DEFERRAL_RGMII_10_100; | ||
3048 | } else { | ||
3049 | txreg = NVREG_TX_DEFERRAL_DEFAULT; | ||
3050 | } | ||
3051 | writel(txreg, base + NvRegTxDeferral); | ||
3052 | |||
3053 | if (np->desc_ver == DESC_VER_1) { | ||
3054 | txreg = NVREG_TX_WM_DESC1_DEFAULT; | ||
3055 | } else { | ||
3056 | if ((np->linkspeed & NVREG_LINKSPEED_MASK) == | ||
3057 | NVREG_LINKSPEED_1000) | ||
3058 | txreg = NVREG_TX_WM_DESC2_3_1000; | ||
3059 | else | ||
3060 | txreg = NVREG_TX_WM_DESC2_3_DEFAULT; | ||
3061 | } | ||
3062 | writel(txreg, base + NvRegTxWatermark); | ||
3063 | |||
3064 | writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD), | ||
3065 | base + NvRegMisc1); | ||
3066 | pci_push(base); | ||
3067 | writel(np->linkspeed, base + NvRegLinkSpeed); | ||
3068 | pci_push(base); | ||
3069 | |||
3070 | return; | ||
3071 | } | ||
3072 | |||
3006 | /** | 3073 | /** |
3007 | * nv_update_linkspeed: Setup the MAC according to the link partner | 3074 | * nv_update_linkspeed: Setup the MAC according to the link partner |
3008 | * @dev: Network device to be configured | 3075 | * @dev: Network device to be configured |
@@ -3024,11 +3091,25 @@ static int nv_update_linkspeed(struct net_device *dev) | |||
3024 | int newls = np->linkspeed; | 3091 | int newls = np->linkspeed; |
3025 | int newdup = np->duplex; | 3092 | int newdup = np->duplex; |
3026 | int mii_status; | 3093 | int mii_status; |
3094 | u32 bmcr; | ||
3027 | int retval = 0; | 3095 | int retval = 0; |
3028 | u32 control_1000, status_1000, phyreg, pause_flags, txreg; | 3096 | u32 control_1000, status_1000, phyreg, pause_flags, txreg; |
3029 | u32 txrxFlags = 0; | 3097 | u32 txrxFlags = 0; |
3030 | u32 phy_exp; | 3098 | u32 phy_exp; |
3031 | 3099 | ||
3100 | /* If device loopback is enabled, set carrier on and enable max link | ||
3101 | * speed. | ||
3102 | */ | ||
3103 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | ||
3104 | if (bmcr & BMCR_LOOPBACK) { | ||
3105 | if (netif_running(dev)) { | ||
3106 | nv_force_linkspeed(dev, NVREG_LINKSPEED_1000, 1); | ||
3107 | if (!netif_carrier_ok(dev)) | ||
3108 | netif_carrier_on(dev); | ||
3109 | } | ||
3110 | return 1; | ||
3111 | } | ||
3112 | |||
3032 | /* BMSR_LSTATUS is latched, read it twice: | 3113 | /* BMSR_LSTATUS is latched, read it twice: |
3033 | * we want the current value. | 3114 | * we want the current value. |
3034 | */ | 3115 | */ |
@@ -4455,6 +4536,61 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* | |||
4455 | return 0; | 4536 | return 0; |
4456 | } | 4537 | } |
4457 | 4538 | ||
4539 | static int nv_set_loopback(struct net_device *dev, u32 features) | ||
4540 | { | ||
4541 | struct fe_priv *np = netdev_priv(dev); | ||
4542 | unsigned long flags; | ||
4543 | u32 miicontrol; | ||
4544 | int err, retval = 0; | ||
4545 | |||
4546 | spin_lock_irqsave(&np->lock, flags); | ||
4547 | miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | ||
4548 | if (features & NETIF_F_LOOPBACK) { | ||
4549 | if (miicontrol & BMCR_LOOPBACK) { | ||
4550 | spin_unlock_irqrestore(&np->lock, flags); | ||
4551 | netdev_info(dev, "Loopback already enabled\n"); | ||
4552 | return 0; | ||
4553 | } | ||
4554 | nv_disable_irq(dev); | ||
4555 | /* Turn on loopback mode */ | ||
4556 | miicontrol |= BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000; | ||
4557 | err = mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol); | ||
4558 | if (err) { | ||
4559 | retval = PHY_ERROR; | ||
4560 | spin_unlock_irqrestore(&np->lock, flags); | ||
4561 | phy_init(dev); | ||
4562 | } else { | ||
4563 | if (netif_running(dev)) { | ||
4564 | /* Force 1000 Mbps full-duplex */ | ||
4565 | nv_force_linkspeed(dev, NVREG_LINKSPEED_1000, | ||
4566 | 1); | ||
4567 | /* Force link up */ | ||
4568 | netif_carrier_on(dev); | ||
4569 | } | ||
4570 | spin_unlock_irqrestore(&np->lock, flags); | ||
4571 | netdev_info(dev, | ||
4572 | "Internal PHY loopback mode enabled.\n"); | ||
4573 | } | ||
4574 | } else { | ||
4575 | if (!(miicontrol & BMCR_LOOPBACK)) { | ||
4576 | spin_unlock_irqrestore(&np->lock, flags); | ||
4577 | netdev_info(dev, "Loopback already disabled\n"); | ||
4578 | return 0; | ||
4579 | } | ||
4580 | nv_disable_irq(dev); | ||
4581 | /* Turn off loopback */ | ||
4582 | spin_unlock_irqrestore(&np->lock, flags); | ||
4583 | netdev_info(dev, "Internal PHY loopback mode disabled.\n"); | ||
4584 | phy_init(dev); | ||
4585 | } | ||
4586 | msleep(500); | ||
4587 | spin_lock_irqsave(&np->lock, flags); | ||
4588 | nv_enable_irq(dev); | ||
4589 | spin_unlock_irqrestore(&np->lock, flags); | ||
4590 | |||
4591 | return retval; | ||
4592 | } | ||
4593 | |||
4458 | static u32 nv_fix_features(struct net_device *dev, u32 features) | 4594 | static u32 nv_fix_features(struct net_device *dev, u32 features) |
4459 | { | 4595 | { |
4460 | /* vlan is dependent on rx checksum offload */ | 4596 | /* vlan is dependent on rx checksum offload */ |
@@ -4490,6 +4626,13 @@ static int nv_set_features(struct net_device *dev, u32 features) | |||
4490 | struct fe_priv *np = netdev_priv(dev); | 4626 | struct fe_priv *np = netdev_priv(dev); |
4491 | u8 __iomem *base = get_hwbase(dev); | 4627 | u8 __iomem *base = get_hwbase(dev); |
4492 | u32 changed = dev->features ^ features; | 4628 | u32 changed = dev->features ^ features; |
4629 | int retval; | ||
4630 | |||
4631 | if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) { | ||
4632 | retval = nv_set_loopback(dev, features); | ||
4633 | if (retval != 0) | ||
4634 | return retval; | ||
4635 | } | ||
4493 | 4636 | ||
4494 | if (changed & NETIF_F_RXCSUM) { | 4637 | if (changed & NETIF_F_RXCSUM) { |
4495 | spin_lock_irq(&np->lock); | 4638 | spin_lock_irq(&np->lock); |
@@ -5124,6 +5267,12 @@ static int nv_open(struct net_device *dev) | |||
5124 | 5267 | ||
5125 | spin_unlock_irq(&np->lock); | 5268 | spin_unlock_irq(&np->lock); |
5126 | 5269 | ||
5270 | /* If the loopback feature was set while the device was down, make sure | ||
5271 | * that it's set correctly now. | ||
5272 | */ | ||
5273 | if (dev->features & NETIF_F_LOOPBACK) | ||
5274 | nv_set_loopback(dev, dev->features); | ||
5275 | |||
5127 | return 0; | 5276 | return 0; |
5128 | out_drain: | 5277 | out_drain: |
5129 | nv_drain_rxtx(dev); | 5278 | nv_drain_rxtx(dev); |
@@ -5328,6 +5477,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5328 | 5477 | ||
5329 | dev->features |= dev->hw_features; | 5478 | dev->features |= dev->hw_features; |
5330 | 5479 | ||
5480 | /* Add loopback capability to the device. */ | ||
5481 | dev->hw_features |= NETIF_F_LOOPBACK; | ||
5482 | |||
5331 | np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; | 5483 | np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; |
5332 | if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) || | 5484 | if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) || |
5333 | (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) || | 5485 | (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) || |
@@ -5603,12 +5755,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5603 | dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n", | 5755 | dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n", |
5604 | dev->name, np->phy_oui, np->phyaddr, dev->dev_addr); | 5756 | dev->name, np->phy_oui, np->phyaddr, dev->dev_addr); |
5605 | 5757 | ||
5606 | dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%sdesc-v%u\n", | 5758 | dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%s%sdesc-v%u\n", |
5607 | dev->features & NETIF_F_HIGHDMA ? "highdma " : "", | 5759 | dev->features & NETIF_F_HIGHDMA ? "highdma " : "", |
5608 | dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ? | 5760 | dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ? |
5609 | "csum " : "", | 5761 | "csum " : "", |
5610 | dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ? | 5762 | dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ? |
5611 | "vlan " : "", | 5763 | "vlan " : "", |
5764 | dev->features & (NETIF_F_LOOPBACK) ? | ||
5765 | "loopback " : "", | ||
5612 | id->driver_data & DEV_HAS_POWER_CNTRL ? "pwrctl " : "", | 5766 | id->driver_data & DEV_HAS_POWER_CNTRL ? "pwrctl " : "", |
5613 | id->driver_data & DEV_HAS_MGMT_UNIT ? "mgmt " : "", | 5767 | id->driver_data & DEV_HAS_MGMT_UNIT ? "mgmt " : "", |
5614 | id->driver_data & DEV_NEED_TIMERIRQ ? "timirq " : "", | 5768 | id->driver_data & DEV_NEED_TIMERIRQ ? "timirq " : "", |