]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
net: eqos: fix timeout error
authorBhadram Varka <vbhadram@nvidia.com>
Wed, 22 Mar 2017 11:24:42 +0000 (16:54 +0530)
committermobile promotions <svcmobile_promotions@nvidia.com>
Mon, 29 May 2017 10:01:09 +0000 (03:01 -0700)
Issue: EQOS trying to access the PHY registers through
mdiobus_write/read from the phy_change IRQ handler.
At this stage PHY is not in proper state to respond
to the register read/write which leads to below timeout -

[   18.116266] Decoded FIFO Entry: 0
[   18.116267]  Direction: READ
[   18.116268]  Bridge ID: 0x9
[   18.116270]  Error Type: 0x12 -- Timeout error
[   18.116271]  Length: 0
[   18.116274]  Protection: 0x2 -- Unprivileged, Non-Secure, Data Access
[   18.116276]  Source ID: 0x1 -- CCPLEX
[   18.116277]  AXI_ID: 0x4 -- A57 Core 0
[   18.116279]  Cache: 0x1 -- Device
[   18.116280]  Burst: 0x1
[   18.116310]  Address: 0x2490200 (Unknown Device)

Fix: Start the PHY while bringup the interface and
stop the PHY while the interface is going down.

Bug 200284385

Change-Id: Ib557f49b11f857f214b245e0284e045c8b4981d9
Signed-off-by: Bhadram Varka <vbhadram@nvidia.com>
Reviewed-on: http://git-master/r/1488009
Reviewed-by: Narayan Reddy <narayanr@nvidia.com>
Tested-by: Narayan Reddy <narayanr@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
drivers/net/ethernet/nvidia/eqos/drv.c
drivers/net/ethernet/nvidia/eqos/drv.h
drivers/net/ethernet/nvidia/eqos/init.c
drivers/net/ethernet/nvidia/eqos/mdio.c

index ceb9afeae8f2a9f76268277b9baf721e51127796..9b1dd776f12483ca8da8b7ba4eb91d339d13d1e1 100644 (file)
@@ -1246,6 +1246,18 @@ static int eqos_open(struct net_device *dev)
        if (!is_valid_ether_addr(dev->dev_addr))
                return -EADDRNOTAVAIL;
 
+       /* Reset the PHY */
+       gpio_set_value(pdata->phy_reset_gpio, 0);
+       usleep_range(10, 11);
+       gpio_set_value(pdata->phy_reset_gpio, 1);
+
+       /* PHY initialisation */
+       ret = eqos_init_phy(dev);
+       if (ret) {
+               dev_err(&dev->dev, "%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
+               return ret;
+       }
+
        ret = request_txrx_irqs(pdata);
        if (ret != Y_SUCCESS)
                goto err_irq_0;
@@ -1295,6 +1307,19 @@ static int eqos_close(struct net_device *dev)
 
        pr_debug("-->%s\n", __func__);
 
+       /* Put PHY in low power mode */
+       if (pdata->phydev && pdata->phydev->drv &&
+           pdata->phydev->drv->low_power_mode)
+               pdata->phydev->drv->low_power_mode(pdata->phydev, true);
+
+       /* Stop and disconnect the PHY */
+       if (pdata->phydev) {
+               phy_stop(pdata->phydev);
+               phy_disconnect(pdata->phydev);
+               gpio_set_value(pdata->phy_reset_gpio, 0);
+               pdata->phydev = NULL;
+       }
+
        mutex_lock(&pdata->hw_change_lock);
        eqos_stop_dev(pdata);
 
@@ -5727,18 +5752,6 @@ void eqos_stop_dev(struct eqos_prv_data *pdata)
        /* Unregister broadcasting MAC timestamp to clients */
        tegra_unregister_hwtime_source();
 #endif
-
-       if (pdata->phydev && pdata->phydev->drv &&
-           pdata->phydev->drv->low_power_mode) {
-               pdata->phydev->drv->low_power_mode(pdata->phydev, true);
-               if (!pdata->suspended)
-                       phy_stop_interrupts(pdata->phydev);
-       } else if (pdata->phydev) {
-               /* stop the PHY */
-               phy_stop(pdata->phydev);
-               gpio_set_value(pdata->phy_reset_gpio, 0);
-       }
-
        /* Stop the PHY state machine */
        if (pdata->phydev)
                phy_stop_machine(pdata->phydev);
@@ -5786,21 +5799,6 @@ void eqos_start_dev(struct eqos_prv_data *pdata)
 
        pr_debug("-->%s()\n", __func__);
 
-       if (pdata->phydev->drv->low_power_mode) {
-               /* reset the PHY Broadcom PHY needs minimum of 2us delay */
-               pr_debug("%s(): exit from iddq-lp mode\n", __func__);
-               gpio_set_value(pdata->phy_reset_gpio, 0);
-               usleep_range(10, 11);
-               gpio_set_value(pdata->phy_reset_gpio, 1);
-               pdata->phydev->drv->low_power_mode(pdata->phydev, false);
-               if (pdata->suspended == 0 && netif_running(pdata->dev))
-                       phy_start_interrupts(pdata->phydev);
-       } else if (!gpio_get_value(pdata->phy_reset_gpio))
-       {
-               /* deassert phy reset */
-               gpio_set_value(pdata->phy_reset_gpio, 1);
-       }
-
        /* issue CAR reset to device */
        hw_if->car_reset(pdata);
        hw_if->pad_calibrate(pdata);
index 945336509d1b2cb25aff1c90fe17e70de1a764b9..56ec45e4994840640242836b480e89dea023fe7a 100644 (file)
@@ -117,4 +117,5 @@ static int eqos_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid);
 void eqos_stop_dev(struct eqos_prv_data *pdata);
 void eqos_start_dev(struct eqos_prv_data *pdata);
 int eqos_config_mac_loopback_mode(struct net_device *dev, unsigned int flags);
+int eqos_init_phy(struct net_device *ndev);
 #endif
index 110e1de1510498f2a06ccbdabd030013d6a41c97..187c30173f986fb151286cbbf99e98c14a7ddd5c 100644 (file)
@@ -1078,11 +1078,6 @@ int eqos_probe(struct platform_device *pdev)
                pr_err("%s: MDIO is not present\n\n", DEV_NAME);
        }
 
-       if (pdata->phydev->drv->low_power_mode) {
-               pdata->phydev->drv->low_power_mode(pdata->phydev, true);
-               phy_stop_interrupts(pdata->phydev);
-       }
-
        /* enabling and registration of irq with magic wakeup */
        if (1 == pdata->hw_feat.mgk_sel) {
                device_set_wakeup_capable(&pdev->dev, 1);
@@ -1426,8 +1421,17 @@ static INT eqos_suspend(struct platform_device *pdev, pm_message_t state)
        pdata->suspended = 1;
 
        if (netif_running(dev)) {
-               /* Disable PHY interrupts */
-               phy_stop_interrupts(pdata->phydev);
+               if (pdata->phydev && pdata->phydev->drv &&
+                   pdata->phydev->drv->low_power_mode)
+                       pdata->phydev->drv->low_power_mode(pdata->phydev, true);
+
+               /* Stop and disconnect the PHY */
+               if (pdata->phydev) {
+                       phy_stop_interrupts(pdata->phydev);
+                       phy_stop(pdata->phydev);
+                       gpio_set_value(pdata->phy_reset_gpio, 0);
+               }
+
                eqos_stop_dev(pdata);
                pdata->hw_stopped = true;
        }
@@ -1475,6 +1479,17 @@ static INT eqos_resume(struct platform_device *pdev)
        eqos_clock_init(pdata);
 
        if (netif_running(dev)) {
+               if (pdata->phydev->drv->low_power_mode) {
+                       /* reset the PHY Broadcom PHY needs minimum of 2us delay */
+                       pr_err("%s(): exit from iddq-lp mode\n", __func__);
+                       gpio_set_value(pdata->phy_reset_gpio, 0);
+                       usleep_range(10, 11);
+                       gpio_set_value(pdata->phy_reset_gpio, 1);
+                       pdata->phydev->drv->low_power_mode(pdata->phydev, false);
+               } else if (!gpio_get_value(pdata->phy_reset_gpio)) {
+                       /* deassert phy reset */
+                       gpio_set_value(pdata->phy_reset_gpio, 1);
+               }
                /* first start eqos  */
                eqos_start_dev(pdata);
 
index b68c9ecb46026ebcd23e568a2ec61a10cc064b34..0f4d834f0f060f854162560c9658e7d61e6c77cd 100644 (file)
@@ -462,7 +462,7 @@ static void eqos_adjust_link(struct net_device *dev)
 * \retval 0 on success & negative number on failure.
 */
 
-static int eqos_init_phy(struct net_device *dev)
+int eqos_init_phy(struct net_device *dev)
 {
        struct eqos_prv_data *pdata = netdev_priv(dev);
        struct phy_device *phydev = NULL;
@@ -616,19 +616,9 @@ int eqos_mdio_register(struct net_device *dev)
        }
        pdata->mii = new_bus;
 
-       ret = eqos_init_phy(dev);
-       if (unlikely(ret)) {
-               pr_err("Cannot attach to PHY (error: %d)\n", ret);
-               goto err_out_phy_connect;
-       }
-
        DBGPR_MDIO("<--eqos_mdio_register\n");
 
        return ret;
-
- err_out_phy_connect:
-       eqos_mdio_unregister(dev);
-       return ret;
 }
 
 /*!