diff options
author | Maxime Chevallier <maxime.chevallier@bootlin.com> | 2024-12-03 13:43:15 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2024-12-06 13:41:52 +0000 |
commit | d2adc441a19a592ce104e2b257ad9d002eaec53f (patch) | |
tree | bea94641117c64a394f205939fcc8192f861e6aa /drivers/net/ethernet/freescale | |
parent | 43068024cc2a2abdf39c73d3c1ed63a77207ae31 (diff) |
net: freescale: ucc_geth: Fix WOL configuration
The get/set_wol ethtool ops rely on querying the PHY for its WoL
capabilities, checking for the presence of a PHY and a PHY interrupts
isn't enough. Address that by cleaning up the WoL configuration
sequence.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r-- | drivers/net/ethernet/freescale/ucc_geth.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/ucc_geth.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/ucc_geth_ethtool.c | 36 |
3 files changed, 32 insertions, 9 deletions
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index cc5f9ca42a78..587bcbc079da 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -3413,11 +3413,11 @@ static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state) */ ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); - if (ugeth->wol_en & WAKE_MAGIC) { + if (ugeth->wol_en & WAKE_MAGIC && !ugeth->phy_wol_en) { setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX); - } else if (!(ugeth->wol_en & WAKE_PHY)) { + } else if (!ugeth->phy_wol_en) { phy_stop(ndev->phydev); } diff --git a/drivers/net/ethernet/freescale/ucc_geth.h b/drivers/net/ethernet/freescale/ucc_geth.h index c08a56b7c9fe..e08cfc8d8904 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.h +++ b/drivers/net/ethernet/freescale/ucc_geth.h @@ -1217,6 +1217,7 @@ struct ucc_geth_private { int oldduplex; int oldlink; int wol_en; + u32 phy_wol_en; struct device_node *node; }; diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index fb5254d7d1ba..89b323ef8145 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -346,26 +346,48 @@ static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct ucc_geth_private *ugeth = netdev_priv(netdev); struct phy_device *phydev = netdev->phydev; - if (phydev && phydev->irq) - wol->supported |= WAKE_PHY; + wol->supported = 0; + wol->wolopts = 0; + + if (phydev) + phy_ethtool_get_wol(phydev, wol); + if (qe_alive_during_sleep()) wol->supported |= WAKE_MAGIC; - wol->wolopts = ugeth->wol_en; + wol->wolopts |= ugeth->wol_en; } static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct ucc_geth_private *ugeth = netdev_priv(netdev); struct phy_device *phydev = netdev->phydev; + int ret = 0; - if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC)) - return -EINVAL; - else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq)) + if (phydev) { + ret = phy_ethtool_set_wol(phydev, wol); + if (ret == -EOPNOTSUPP) { + ugeth->phy_wol_en = 0; + } else if (ret) { + return ret; + } else { + ugeth->phy_wol_en = wol->wolopts; + goto out; + } + } + + /* If the PHY isn't handling the WoL and the MAC is asked to more than + * WAKE_MAGIC, error-out + */ + if (!ugeth->phy_wol_en && + wol->wolopts & ~WAKE_MAGIC) return -EINVAL; - else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep()) + + if (wol->wolopts & WAKE_MAGIC && + !qe_alive_during_sleep()) return -EINVAL; +out: ugeth->wol_en = wol->wolopts; device_set_wakeup_enable(&netdev->dev, ugeth->wol_en); |