From e6cde88eb8ec848ccc134857857750eb2b2358eb Mon Sep 17 00:00:00 2001 From: Narayan Reddy Date: Fri, 8 Oct 2021 00:20:47 +0530 Subject: [PATCH] nvethernet: move mdio_register to open Issue: mdio bus is registered in probe and before exiting probe ethernet clocks are disabled to save power. When SC7 is initiated then PHY framework invokes a PHY suspend which triggers the PHY register write. Since clocks are not enabled PHY register write is ignored and returned failure which inturn prevented the entire system to enter into SC7 Fix: Move mdio bus registration to open so that PHY reads/writes will not be invoked before bringing up the ethernet interface. Bug 3368603 Change-Id: Idc74be76f47ca1cb607502a4572cb2001d42903a Signed-off-by: Narayan Reddy Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2607300 Tested-by: mobile promotions Reviewed-by: svc_kernel_abi Reviewed-by: Bhadram Varka Reviewed-by: Rakesh Goyal Reviewed-by: Bibek Basu Reviewed-by: mobile promotions --- .../ethernet/nvidia/nvethernet/ether_linux.c | 250 +++++++++--------- 1 file changed, 126 insertions(+), 124 deletions(-) diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index 14866d94..fffd6fa0 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -2256,6 +2256,117 @@ static int ether_update_mac_addr_filter(struct ether_priv_data *pdata, return osi_handle_ioctl(osi_core, ioctl_data); } +/** + * @brief MII call back for MDIO register write. + * + * Algorithm: Invoke OSI layer for PHY register write. + * phy_write() API from Linux PHY subsystem will call this. + * + * @param[in] bus: MDIO bus instances. + * @param[in] phyaddr: PHY address (ID). + * @param[in] phyreg: PHY register to write. + * @param[in] phydata: Data to be written in register. + * + * @note MAC has to be out of reset. + * + * @retval 0 on success + * @retval "negative value" on failure. + */ +static int ether_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, + u16 phydata) +{ + struct net_device *ndev = bus->priv; + struct ether_priv_data *pdata = netdev_priv(ndev); + + if (!pdata->clks_enable) { + dev_err(pdata->dev, + "%s:No clks available, skipping PHY write\n", __func__); + return -ENODEV; + } + + return osi_write_phy_reg(pdata->osi_core, (unsigned int)phyaddr, + (unsigned int)phyreg, phydata); +} + +/** + * @brief MII call back for MDIO register read. + * + * Algorithm: Invoke OSI layer for PHY register read. + * phy_read() API from Linux subsystem will call this. + * + * @param[in] bus: MDIO bus instances. + * @param[in] phyaddr: PHY address (ID). + * @param[in] phyreg: PHY register to read. + * + * @note MAC has to be out of reset. + * + * @retval data from PHY register on success + * @retval "nagative value" on failure. + */ +static int ether_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) +{ + struct net_device *ndev = bus->priv; + struct ether_priv_data *pdata = netdev_priv(ndev); + + if (!pdata->clks_enable) { + dev_err(pdata->dev, + "%s:No clks available, skipping PHY read\n", __func__); + return -ENODEV; + } + + return osi_read_phy_reg(pdata->osi_core, (unsigned int)phyaddr, + (unsigned int)phyreg); +} + +/** + * @brief MDIO bus registration. + * + * Algorithm: Registers MDIO bus if there is mdio sub DT node + * as part of MAC DT node. + * + * @param[in] pdata: OSD private data. + * + * @retval 0 on success + * @retval "negative value" on failure. + */ +static int ether_mdio_register(struct ether_priv_data *pdata) +{ + struct device *dev = pdata->dev; + struct mii_bus *new_bus = NULL; + int ret = 0; + + if (pdata->mdio_node == NULL) { + pdata->mii = NULL; + return 0; + } + + new_bus = devm_mdiobus_alloc(dev); + if (new_bus == NULL) { + ret = -ENOMEM; + dev_err(dev, "failed to allocate MDIO bus\n"); + goto exit; + } + + new_bus->name = "nvethernet_mdio_bus"; + new_bus->read = ether_mdio_read; + new_bus->write = ether_mdio_write; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + new_bus->priv = pdata->ndev; + new_bus->parent = dev; + + ret = of_mdiobus_register(new_bus, pdata->mdio_node); + if (ret) { + dev_err(dev, "failed to register MDIO bus (%s)\n", + new_bus->name); + goto exit; + } + + pdata->mii = new_bus; + +exit: + return ret; +} + /** * @brief Call back to handle bring up of Ethernet interface * @@ -2330,6 +2441,12 @@ static int ether_open(struct net_device *dev) goto err_poll_swr; } + ret = ether_mdio_register(pdata); + if (ret < 0) { + dev_err(&dev->dev, "failed to register MDIO bus\n"); + goto err_mdio_reg; + } + atomic_set(&pdata->padcal_in_progress, OSI_DISABLE); /* PHY reset and initialization */ ret = ether_phy_init(dev); @@ -2470,7 +2587,11 @@ err_alloc: phy_disconnect(pdata->phydev); } err_phy_init: + if (pdata->mii != NULL) { + mdiobus_unregister(pdata->mii); + } err_poll_swr: +err_mdio_reg: if (pdata->xpcs_rst) { reset_control_assert(pdata->xpcs_rst); } @@ -2719,6 +2840,10 @@ static int ether_close(struct net_device *ndev) reset_control_assert(pdata->mac_rst); } + if (pdata->mii != NULL) { + mdiobus_unregister(pdata->mii); + } + /* Disable clock */ ether_disable_clks(pdata); @@ -4058,117 +4183,6 @@ static int ether_alloc_napi(struct ether_priv_data *pdata) return 0; } -/** - * @brief MII call back for MDIO register write. - * - * Algorithm: Invoke OSI layer for PHY register write. - * phy_write() API from Linux PHY subsystem will call this. - * - * @param[in] bus: MDIO bus instances. - * @param[in] phyaddr: PHY address (ID). - * @param[in] phyreg: PHY register to write. - * @param[in] phydata: Data to be written in register. - * - * @note MAC has to be out of reset. - * - * @retval 0 on success - * @retval "negative value" on failure. - */ -static int ether_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, - u16 phydata) -{ - struct net_device *ndev = bus->priv; - struct ether_priv_data *pdata = netdev_priv(ndev); - - if (!pdata->clks_enable) { - dev_err(pdata->dev, - "%s:No clks available, skipping PHY write\n", __func__); - return -ENODEV; - } - - return osi_write_phy_reg(pdata->osi_core, (unsigned int)phyaddr, - (unsigned int)phyreg, phydata); -} - -/** - * @brief MII call back for MDIO register read. - * - * Algorithm: Invoke OSI layer for PHY register read. - * phy_read() API from Linux subsystem will call this. - * - * @param[in] bus: MDIO bus instances. - * @param[in] phyaddr: PHY address (ID). - * @param[in] phyreg: PHY register to read. - * - * @note MAC has to be out of reset. - * - * @retval data from PHY register on success - * @retval "nagative value" on failure. - */ -static int ether_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) -{ - struct net_device *ndev = bus->priv; - struct ether_priv_data *pdata = netdev_priv(ndev); - - if (!pdata->clks_enable) { - dev_err(pdata->dev, - "%s:No clks available, skipping PHY read\n", __func__); - return -ENODEV; - } - - return osi_read_phy_reg(pdata->osi_core, (unsigned int)phyaddr, - (unsigned int)phyreg); -} - -/** - * @brief MDIO bus registration. - * - * Algorithm: Registers MDIO bus if there is mdio sub DT node - * as part of MAC DT node. - * - * @param[in] pdata: OSD private data. - * - * @retval 0 on success - * @retval "negative value" on failure. - */ -static int ether_mdio_register(struct ether_priv_data *pdata) -{ - struct device *dev = pdata->dev; - struct mii_bus *new_bus = NULL; - int ret = 0; - - if (pdata->mdio_node == NULL) { - pdata->mii = NULL; - return 0; - } - - new_bus = devm_mdiobus_alloc(dev); - if (new_bus == NULL) { - ret = -ENOMEM; - dev_err(dev, "failed to allocate MDIO bus\n"); - goto exit; - } - - new_bus->name = "nvethernet_mdio_bus"; - new_bus->read = ether_mdio_read; - new_bus->write = ether_mdio_write; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); - new_bus->priv = pdata->ndev; - new_bus->parent = dev; - - ret = of_mdiobus_register(new_bus, pdata->mdio_node); - if (ret) { - dev_err(dev, "failed to register MDIO bus (%s)\n", - new_bus->name); - goto exit; - } - - pdata->mii = new_bus; - -exit: - return ret; -} - /** * @brief ether_set_vm_irq_chan_mask - Set VM DMA channel mask. * @@ -6165,19 +6179,13 @@ static int ether_probe(struct platform_device *pdev) goto err_dma_mask; } - ret = ether_mdio_register(pdata); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register MDIO bus\n"); - goto err_dma_mask; - } - ndev->netdev_ops = ðer_netdev_ops; ether_set_ethtool_ops(ndev); ret = ether_alloc_napi(pdata); if (ret < 0) { dev_err(&pdev->dev, "failed to allocate NAPI\n"); - goto err_napi; + goto err_dma_mask; } /* Setup the tx_usecs timer */ @@ -6267,8 +6275,6 @@ err_netdev: #ifdef MACSEC_SUPPORT err_macsec: #endif /* MACSEC_SUPPORT */ -err_napi: - mdiobus_unregister(pdata->mii); err_dma_mask: ether_disable_clks(pdata); ether_put_clks(pdata); @@ -6308,10 +6314,6 @@ static int ether_remove(struct platform_device *pdev) /* remove nvethernet sysfs group under /sys/devices// */ ether_sysfs_unregister(pdata); - if (pdata->mii != NULL) { - mdiobus_unregister(pdata->mii); - } - ether_put_clks(pdata); /* Assert MAC RST gpio */