mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
nvethernet: defer WOL enablement.
This change defers WOL enablement to the moment before suspending so the network retains connected after enabling WOL. ethtool -s eth0 wol g Bug 4450559 Change-Id: Ib5e59052fb72a9c4f88667ab6182633af545b99d Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3271298 Tested-by: Revanth Kumar Uppala <ruppala@nvidia.com> Reviewed-by: Revanth Kumar Uppala <ruppala@nvidia.com> GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com> Reviewed-by: Bhadram Varka <vbhadram@nvidia.com> Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
e2b9c86688
commit
0652332c19
@@ -6831,6 +6831,107 @@ static void ether_shutdown(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
#ifndef OSI_STRIPPED_LIB
|
||||||
|
/**
|
||||||
|
* @brief Revert the WOL settings
|
||||||
|
*
|
||||||
|
* Alogorithm: Create a struct ethtool_wolinfo to disable WOL settings
|
||||||
|
*
|
||||||
|
* @param[in] dev: Platform device associated with platform driver.
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval "negative value" on failure.
|
||||||
|
*/
|
||||||
|
static inline int ether_revert_wol(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u32 wolopts = 0;
|
||||||
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
|
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||||
|
|
||||||
|
swap(pdata->wol.wolopts, wolopts);
|
||||||
|
ret = ether_set_wol_impl(ndev, &pdata->wol);
|
||||||
|
pdata->wol.wolopts = wolopts;
|
||||||
|
if (ret)
|
||||||
|
dev_err(pdata->dev, "Fail to enable PHY network functionality %d\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ethernet platform driver prepare callback.
|
||||||
|
*
|
||||||
|
* Alogorithm: Configure the defer WOL settings if enabled by user
|
||||||
|
*
|
||||||
|
* @param[in] dev: Platform device associated with platform driver.
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval "negative value" on failure.
|
||||||
|
*/
|
||||||
|
static int ether_prepare(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
|
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||||
|
struct phy_device *phydev = pdata->phydev;
|
||||||
|
|
||||||
|
if (pdata->wol.wolopts) {
|
||||||
|
ret = ether_set_wol_impl(ndev, &pdata->wol);
|
||||||
|
if (ret)
|
||||||
|
goto ether_prepare_fail;
|
||||||
|
|
||||||
|
ret = enable_irq_wake(phydev->irq);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(pdata->dev, "PHY enable irq wake failed, %d\n",
|
||||||
|
ret);
|
||||||
|
goto ether_prepare_fail;
|
||||||
|
}
|
||||||
|
/* enable device wake on WoL set */
|
||||||
|
device_init_wakeup(&ndev->dev, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ether_prepare_fail:
|
||||||
|
if (unlikely(ret))
|
||||||
|
ether_revert_wol(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ethernet platform driver complete callback.
|
||||||
|
*
|
||||||
|
* Alogorithm: Revert the defer WOL settings if enabled by user
|
||||||
|
*
|
||||||
|
* @param[in] dev: Platform device associated with platform driver.
|
||||||
|
*/
|
||||||
|
static void ether_complete(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
|
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||||
|
struct phy_device *phydev = pdata->phydev;
|
||||||
|
|
||||||
|
if (pdata->wol.wolopts) {
|
||||||
|
ret = ether_revert_wol(dev);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(pdata->dev, "Fail to enable PHY network functionality %d\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = disable_irq_wake(phydev->irq);
|
||||||
|
if (ret) {
|
||||||
|
dev_info(pdata->dev,
|
||||||
|
"PHY disable irq wake failed, %d\n",
|
||||||
|
ret);
|
||||||
|
}
|
||||||
|
/* disable device wake on WoL reset */
|
||||||
|
device_init_wakeup(&ndev->dev, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* !(OSI_STRIPPED_LIB) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Ethernet platform driver resume call.
|
* @brief Ethernet platform driver resume call.
|
||||||
*
|
*
|
||||||
@@ -7035,10 +7136,14 @@ static int ether_resume_noirq(struct device *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops ether_pm_ops = {
|
static const struct dev_pm_ops ether_pm_ops = {
|
||||||
|
#ifndef OSI_STRIPPED_LIB
|
||||||
|
.prepare = ether_prepare,
|
||||||
|
.complete = ether_complete,
|
||||||
|
#endif /* !OSI_STRIPPED_LIB */
|
||||||
.suspend = ether_suspend_noirq,
|
.suspend = ether_suspend_noirq,
|
||||||
.resume = ether_resume_noirq,
|
.resume = ether_resume_noirq,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -668,6 +668,8 @@ struct ether_priv_data {
|
|||||||
struct tasklet_struct lane_restart_task;
|
struct tasklet_struct lane_restart_task;
|
||||||
/** xtra sw error counters */
|
/** xtra sw error counters */
|
||||||
struct ether_xtra_stat_counters xstats;
|
struct ether_xtra_stat_counters xstats;
|
||||||
|
/** wol configs */
|
||||||
|
struct ethtool_wolinfo wol;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -678,6 +680,21 @@ struct ether_priv_data {
|
|||||||
* @note Network device needs to created.
|
* @note Network device needs to created.
|
||||||
*/
|
*/
|
||||||
void ether_set_ethtool_ops(struct net_device *ndev);
|
void ether_set_ethtool_ops(struct net_device *ndev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure WOL settings in PHY subsystem
|
||||||
|
*
|
||||||
|
* @param[in] ndev – pointer to net device structure.
|
||||||
|
* @param[in] wol – pointer to ethtool_wolinfo structure.
|
||||||
|
*
|
||||||
|
* @note MAC and PHY need to be initialized.
|
||||||
|
*
|
||||||
|
* @retval zero on success and -ve number on failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ether_set_wol_impl(struct net_device *ndev, struct ethtool_wolinfo *wol);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates Ethernet sysfs group
|
* @brief Creates Ethernet sysfs group
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1336,6 +1336,38 @@ static int ether_set_eee(struct net_device *ndev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure WOL settings in PHY subsystem
|
||||||
|
*
|
||||||
|
* Algorithm: Call phy subsystem to enable or disable
|
||||||
|
* Wake On Lan settings based on wol param
|
||||||
|
*
|
||||||
|
* @param[in] ndev – pointer to net device structure.
|
||||||
|
* @param[in] wol – pointer to ethtool_wolinfo structure.
|
||||||
|
*
|
||||||
|
* @note MAC and PHY need to be initialized.
|
||||||
|
*
|
||||||
|
* @retval zero on success and -ve number on failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ether_set_wol_impl(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||||
|
{
|
||||||
|
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||||
|
struct phy_device *phydev = pdata->phydev;
|
||||||
|
|
||||||
|
if (!phydev) {
|
||||||
|
netdev_err(pdata->ndev,
|
||||||
|
"%s: phydev is null check iface up status\n",
|
||||||
|
__func__);
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!phy_interrupt_is_valid(phydev))
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
return phy_ethtool_set_wol(pdata->phydev, wol);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function is invoked by kernel when user request to set
|
* @brief This function is invoked by kernel when user request to set
|
||||||
* pmt parameters for remote wakeup or magic wakeup
|
* pmt parameters for remote wakeup or magic wakeup
|
||||||
@@ -1351,46 +1383,24 @@ static int ether_set_eee(struct net_device *ndev,
|
|||||||
*/
|
*/
|
||||||
static int ether_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
static int ether_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
struct ether_priv_data *pdata = netdev_priv(ndev);
|
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!wol)
|
if (!wol)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!pdata->phydev) {
|
/* Disable WOL on demand.
|
||||||
netdev_err(pdata->ndev,
|
* Enabling WOL will to deferred to before system suspend.
|
||||||
"%s: phydev is null check iface up status\n",
|
*/
|
||||||
__func__);
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!phy_interrupt_is_valid(pdata->phydev))
|
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
ret = phy_ethtool_set_wol(pdata->phydev, wol);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (wol->wolopts) {
|
if (wol->wolopts) {
|
||||||
ret = enable_irq_wake(pdata->phydev->irq);
|
/* The WOL request to the PHY layer is defered, and will apply on
|
||||||
if (ret) {
|
* it only when the system is going to suspend. */
|
||||||
dev_err(pdata->dev, "PHY enable irq wake failed, %d\n",
|
memcpy(&pdata->wol, wol, sizeof(struct ethtool_wolinfo));
|
||||||
ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
/* enable device wake on WoL set */
|
|
||||||
device_init_wakeup(&ndev->dev, true);
|
|
||||||
} else {
|
|
||||||
ret = disable_irq_wake(pdata->phydev->irq);
|
|
||||||
if (ret) {
|
|
||||||
dev_info(pdata->dev,
|
|
||||||
"PHY disable irq wake failed, %d\n",
|
|
||||||
ret);
|
|
||||||
}
|
|
||||||
/* disable device wake on WoL reset */
|
|
||||||
device_init_wakeup(&ndev->dev, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Set wolopts to 0 to implicitly say that WOL is disabled */
|
||||||
|
pdata->wol.wolopts = 0;
|
||||||
|
ret = ether_set_wol_impl(ndev, wol);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1411,6 +1421,7 @@ static int ether_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
|||||||
static void ether_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
static void ether_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
struct ether_priv_data *pdata = netdev_priv(ndev);
|
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||||
|
u32 wolopts;
|
||||||
|
|
||||||
if (!wol)
|
if (!wol)
|
||||||
return;
|
return;
|
||||||
@@ -1422,13 +1433,20 @@ static void ether_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wol->supported = 0;
|
|
||||||
wol->wolopts = 0;
|
|
||||||
|
|
||||||
if (!phy_interrupt_is_valid(pdata->phydev))
|
if (!phy_interrupt_is_valid(pdata->phydev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
phy_ethtool_get_wol(pdata->phydev, wol);
|
wolopts = pdata->wol.wolopts;
|
||||||
|
|
||||||
|
pdata->wol.supported = 0;
|
||||||
|
pdata->wol.wolopts = 0;
|
||||||
|
|
||||||
|
phy_ethtool_get_wol(pdata->phydev, &pdata->wol);
|
||||||
|
|
||||||
|
if (wolopts & WAKE_MAGIC) {
|
||||||
|
pdata->wol.wolopts |= WAKE_MAGIC;
|
||||||
|
}
|
||||||
|
memcpy(wol, &pdata->wol, sizeof(struct ethtool_wolinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user