aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSanjay Hortikar <horti@google.com>2011-11-11 11:11:21 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-14 00:22:46 -0500
commite19df76a1113dc57cda696cd78d06f2834f6d6bb (patch)
treeba19253264cdffd4b9ed2fa76252a1cd0ccfd6aa /drivers
parent63ce40e4fd7d68373127a51dd1facef07c93cf4a (diff)
net-forcedeth: Add internal loopback support for forcedeth NICs.
Support enabling/disabling/querying internal loopback mode for forcedeth NICs using ethtool. Signed-off-by: Sanjay Hortikar <horti@google.com> Signed-off-by: Mahesh Bandewar <maheshb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c156
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
3006static 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
4539static 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
4458static u32 nv_fix_features(struct net_device *dev, u32 features) 4594static 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;
5128out_drain: 5277out_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 " : "",