diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index 3a4b6cb7b7b9..7a41cad5788f 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -42,6 +42,12 @@ void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct bcmgenet_priv *priv = netdev_priv(dev); struct device *kdev = &priv->pdev->dev; + if (dev->phydev) { + phy_ethtool_get_wol(dev->phydev, wol); + if (wol->supported) + return; + } + if (!device_can_wakeup(kdev)) { wol->supported = 0; wol->wolopts = 0; @@ -63,6 +69,14 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct bcmgenet_priv *priv = netdev_priv(dev); struct device *kdev = &priv->pdev->dev; + int ret; + + /* Try Wake-on-LAN from the PHY first */ + if (dev->phydev) { + ret = phy_ethtool_set_wol(dev->phydev, wol); + if (ret != -EOPNOTSUPP) + return ret; + } if (!device_can_wakeup(kdev)) return -ENOTSUPP; diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index b2c0baa51f39..27c57f6ab211 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -6,12 +6,14 @@ #include "bcm-phy-lib.h" #include #include +#include #include #include #include #include #include #include +#include #define MII_BCM_CHANNEL_WIDTH 0x2000 #define BCM_CL45VEN_EEE_ADV 0x3c @@ -816,6 +818,216 @@ int bcm_phy_cable_test_get_status_rdb(struct phy_device *phydev, } EXPORT_SYMBOL_GPL(bcm_phy_cable_test_get_status_rdb); +#define BCM54XX_WOL_SUPPORTED_MASK (WAKE_UCAST | \ + WAKE_MCAST | \ + WAKE_BCAST | \ + WAKE_MAGIC | \ + WAKE_MAGICSECURE) + +int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + u8 da[ETH_ALEN], mask[ETH_ALEN]; + unsigned int i; + u16 ctl; + int ret; + + /* Allow a MAC driver to play through its own Wake-on-LAN + * implementation + */ + if (wol->wolopts & ~BCM54XX_WOL_SUPPORTED_MASK) + return -EOPNOTSUPP; + + /* The PHY supports passwords of 4, 6 and 8 bytes in size, but Linux's + * ethtool only supports 6, for now. + */ + BUILD_BUG_ON(sizeof(wol->sopass) != ETH_ALEN); + + /* Clear previous interrupts */ + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); + if (ret < 0) + return ret; + + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); + if (ret < 0) + return ret; + + ctl = ret; + + if (!wol->wolopts) { + if (phy_interrupt_is_valid(phydev)) + disable_irq_wake(phydev->irq); + + /* Leave all interrupts disabled */ + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK, + BCM54XX_WOL_ALL_INTRS); + if (ret < 0) + return ret; + + /* Disable the global Wake-on-LAN enable bit */ + ctl &= ~BCM54XX_WOL_EN; + + return bcm_phy_write_exp(phydev, BCM54XX_WOL_MAIN_CTL, ctl); + } + + /* Clear the previously configured mode and mask mode for Wake-on-LAN */ + ctl &= ~(BCM54XX_WOL_MODE_MASK << BCM54XX_WOL_MODE_SHIFT); + ctl &= ~(BCM54XX_WOL_MASK_MODE_MASK << BCM54XX_WOL_MASK_MODE_SHIFT); + ctl &= ~BCM54XX_WOL_DIR_PKT_EN; + ctl &= ~(BCM54XX_WOL_SECKEY_OPT_MASK << BCM54XX_WOL_SECKEY_OPT_SHIFT); + + /* When using WAKE_MAGIC, we program the magic pattern filter to match + * the device's MAC address and we accept any MAC DA in the Ethernet + * frame. + * + * When using WAKE_UCAST, WAKE_BCAST or WAKE_MCAST, we program the + * following: + * - WAKE_UCAST -> MAC DA is the device's MAC with a perfect match + * - WAKE_MCAST -> MAC DA is X1:XX:XX:XX:XX:XX where XX is don't care + * - WAKE_BCAST -> MAC DA is FF:FF:FF:FF:FF:FF with a perfect match + * + * Note that the Broadcast MAC DA is inherently going to match the + * multicast pattern being matched. + */ + memset(mask, 0, sizeof(mask)); + + if (wol->wolopts & WAKE_MCAST) { + memset(da, 0, sizeof(da)); + memset(mask, 0xff, sizeof(mask)); + da[0] = 0x01; + mask[0] = ~da[0]; + } else { + if (wol->wolopts & WAKE_UCAST) { + ether_addr_copy(da, ndev->dev_addr); + } else if (wol->wolopts & WAKE_BCAST) { + eth_broadcast_addr(da); + } else if (wol->wolopts & WAKE_MAGICSECURE) { + ether_addr_copy(da, wol->sopass); + } else if (wol->wolopts & WAKE_MAGIC) { + memset(da, 0, sizeof(da)); + memset(mask, 0xff, sizeof(mask)); + } + } + + for (i = 0; i < ETH_ALEN / 2; i++) { + if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { + ret = bcm_phy_write_exp(phydev, + BCM54XX_WOL_MPD_DATA1(2 - i), + ndev->dev_addr[i * 2] << 8 | + ndev->dev_addr[i * 2 + 1]); + if (ret < 0) + return ret; + } + + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MPD_DATA2(2 - i), + da[i * 2] << 8 | da[i * 2 + 1]); + if (ret < 0) + return ret; + + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MASK(2 - i), + mask[i * 2] << 8 | mask[i * 2 + 1]); + if (ret) + return ret; + } + + if (wol->wolopts & WAKE_MAGICSECURE) { + ctl |= BCM54XX_WOL_SECKEY_OPT_6B << + BCM54XX_WOL_SECKEY_OPT_SHIFT; + ctl |= BCM54XX_WOL_MODE_SINGLE_MPDSEC << BCM54XX_WOL_MODE_SHIFT; + ctl |= BCM54XX_WOL_MASK_MODE_DA_FF << + BCM54XX_WOL_MASK_MODE_SHIFT; + } else { + if (wol->wolopts & WAKE_MAGIC) + ctl |= BCM54XX_WOL_MODE_SINGLE_MPD; + else + ctl |= BCM54XX_WOL_DIR_PKT_EN; + ctl |= BCM54XX_WOL_MASK_MODE_DA_ONLY << + BCM54XX_WOL_MASK_MODE_SHIFT; + } + + /* Globally enable Wake-on-LAN */ + ctl |= BCM54XX_WOL_EN | BCM54XX_WOL_CRC_CHK; + + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MAIN_CTL, ctl); + if (ret < 0) + return ret; + + /* Enable WOL interrupt on LED4 */ + ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_LED_CTL); + if (ret < 0) + return ret; + + ret |= BCM54XX_LED4_SEL_INTR; + ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_LED_CTL, ret); + if (ret < 0) + return ret; + + /* Enable all Wake-on-LAN interrupt sources */ + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK, 0); + if (ret < 0) + return ret; + + if (phy_interrupt_is_valid(phydev)) + enable_irq_wake(phydev->irq); + + return 0; +} +EXPORT_SYMBOL_GPL(bcm_phy_set_wol); + +void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + u8 da[ETH_ALEN]; + unsigned int i; + int ret; + u16 ctl; + + wol->supported = BCM54XX_WOL_SUPPORTED_MASK; + wol->wolopts = 0; + + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); + if (ret < 0) + return; + + ctl = ret; + + if (!(ctl & BCM54XX_WOL_EN)) + return; + + for (i = 0; i < sizeof(da) / 2; i++) { + ret = bcm_phy_read_exp(phydev, + BCM54XX_WOL_MPD_DATA2(2 - i)); + if (ret < 0) + return; + + da[i * 2] = ret >> 8; + da[i * 2 + 1] = ret & 0xff; + } + + if (ctl & BCM54XX_WOL_DIR_PKT_EN) { + if (is_broadcast_ether_addr(da)) + wol->wolopts |= WAKE_BCAST; + else if (is_multicast_ether_addr(da)) + wol->wolopts |= WAKE_MCAST; + else if (ether_addr_equal(da, ndev->dev_addr)) + wol->wolopts |= WAKE_UCAST; + } else { + ctl = (ctl >> BCM54XX_WOL_MODE_SHIFT) & BCM54XX_WOL_MODE_MASK; + switch (ctl) { + case BCM54XX_WOL_MODE_SINGLE_MPD: + wol->wolopts |= WAKE_MAGIC; + break; + case BCM54XX_WOL_MODE_SINGLE_MPDSEC: + wol->wolopts |= WAKE_MAGICSECURE; + memcpy(wol->sopass, da, sizeof(da)); + break; + default: + break; + } + } +} +EXPORT_SYMBOL_GPL(bcm_phy_get_wol); + MODULE_DESCRIPTION("Broadcom PHY Library"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 729db441797a..c6fed43ec913 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -9,6 +9,8 @@ #include #include +struct ethtool_wolinfo; + /* 28nm only register definitions */ #define MISC_ADDR(base, channel) base, channel @@ -111,4 +113,7 @@ static inline void bcm_ptp_stop(struct bcm_ptp_private *priv) } #endif +int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); +void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); + #endif /* _LINUX_BCM_PHY_LIB_H */ diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index ad71c88c87e7..418e6bc0e998 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -14,8 +14,12 @@ #include #include #include +#include #include #include +#include +#include +#include #define BRCM_PHY_MODEL(phydev) \ ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) @@ -30,8 +34,17 @@ MODULE_LICENSE("GPL"); struct bcm54xx_phy_priv { u64 *stats; struct bcm_ptp_private *ptp; + int wake_irq; + bool wake_irq_enabled; }; +static bool bcm54xx_phy_can_wakeup(struct phy_device *phydev) +{ + struct bcm54xx_phy_priv *priv = phydev->priv; + + return phy_interrupt_is_valid(phydev) || priv->wake_irq >= 0; +} + static int bcm54xx_config_clock_delay(struct phy_device *phydev) { int rc, val; @@ -413,6 +426,16 @@ static int bcm54xx_config_init(struct phy_device *phydev) bcm54xx_ptp_config_init(phydev); + /* Acknowledge any left over interrupt and charge the device for + * wake-up. + */ + err = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); + if (err < 0) + return err; + + if (err) + pm_wakeup_event(&phydev->mdio.dev, 0); + return 0; } @@ -437,12 +460,39 @@ static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable) return ret; } +static int bcm54xx_set_wakeup_irq(struct phy_device *phydev, bool state) +{ + struct bcm54xx_phy_priv *priv = phydev->priv; + int ret = 0; + + if (!bcm54xx_phy_can_wakeup(phydev)) + return ret; + + if (priv->wake_irq_enabled != state) { + if (state) + ret = enable_irq_wake(priv->wake_irq); + else + ret = disable_irq_wake(priv->wake_irq); + priv->wake_irq_enabled = state; + } + + return ret; +} + static int bcm54xx_suspend(struct phy_device *phydev) { - int ret; + int ret = 0; bcm54xx_ptp_stop(phydev); + /* Acknowledge any Wake-on-LAN interrupt prior to suspend */ + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); + if (ret < 0) + return ret; + + if (phydev->wol_enabled) + return bcm54xx_set_wakeup_irq(phydev, true); + /* We cannot use a read/modify/write here otherwise the PHY gets into * a bad state where its LEDs keep flashing, thus defeating the purpose * of low power mode. @@ -456,7 +506,13 @@ static int bcm54xx_suspend(struct phy_device *phydev) static int bcm54xx_resume(struct phy_device *phydev) { - int ret; + int ret = 0; + + if (phydev->wol_enabled) { + ret = bcm54xx_set_wakeup_irq(phydev, false); + if (ret) + return ret; + } ret = bcm54xx_iddq_set(phydev, false); if (ret < 0) @@ -801,14 +857,54 @@ static int brcm_fet_suspend(struct phy_device *phydev) return err; } +static void bcm54xx_phy_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + /* We cannot wake-up if we do not have a dedicated PHY interrupt line + * or an out of band GPIO descriptor for wake-up. Zeroing + * wol->supported allows the caller (MAC driver) to play through and + * offer its own Wake-on-LAN scheme if available. + */ + if (!bcm54xx_phy_can_wakeup(phydev)) { + wol->supported = 0; + return; + } + + bcm_phy_get_wol(phydev, wol); +} + +static int bcm54xx_phy_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret; + + /* We cannot wake-up if we do not have a dedicated PHY interrupt line + * or an out of band GPIO descriptor for wake-up. Returning -EOPNOTSUPP + * allows the caller (MAC driver) to play through and offer its own + * Wake-on-LAN scheme if available. + */ + if (!bcm54xx_phy_can_wakeup(phydev)) + return -EOPNOTSUPP; + + ret = bcm_phy_set_wol(phydev, wol); + if (ret < 0) + return ret; + + return 0; +} + static int bcm54xx_phy_probe(struct phy_device *phydev) { struct bcm54xx_phy_priv *priv; + struct gpio_desc *wakeup_gpio; + int ret = 0; priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->wake_irq = -ENXIO; + phydev->priv = priv; priv->stats = devm_kcalloc(&phydev->mdio.dev, @@ -821,7 +917,28 @@ static int bcm54xx_phy_probe(struct phy_device *phydev) if (IS_ERR(priv->ptp)) return PTR_ERR(priv->ptp); - return 0; + /* We cannot utilize the _optional variant here since we want to know + * whether the GPIO descriptor exists or not to advertise Wake-on-LAN + * support or not. + */ + wakeup_gpio = devm_gpiod_get(&phydev->mdio.dev, "wakeup", GPIOD_IN); + if (PTR_ERR(wakeup_gpio) == -EPROBE_DEFER) + return PTR_ERR(wakeup_gpio); + + if (!IS_ERR(wakeup_gpio)) { + priv->wake_irq = gpiod_to_irq(wakeup_gpio); + ret = irq_set_irq_type(priv->wake_irq, IRQ_TYPE_LEVEL_LOW); + if (ret) + return ret; + } + + /* If we do not have a main interrupt or a side-band wake-up interrupt, + * then the device cannot be marked as wake-up capable. + */ + if (!bcm54xx_phy_can_wakeup(phydev)) + return 0; + + return device_init_wakeup(&phydev->mdio.dev, true); } static void bcm54xx_get_stats(struct phy_device *phydev, @@ -894,6 +1011,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54210E", /* PHY_GBIT_FEATURES */ + .flags = PHY_ALWAYS_CALL_SUSPEND, .get_sset_count = bcm_phy_get_sset_count, .get_strings = bcm_phy_get_strings, .get_stats = bcm54xx_get_stats, @@ -904,6 +1022,8 @@ static struct phy_driver broadcom_drivers[] = { .link_change_notify = bcm54xx_link_change_notify, .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, + .get_wol = bcm54xx_phy_get_wol, + .set_wol = bcm54xx_phy_set_wol, }, { .phy_id = PHY_ID_BCM5461, .phy_id_mask = 0xfffffff0, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 17d0d0555a79..8852b0c53114 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1860,9 +1860,10 @@ int phy_suspend(struct phy_device *phydev) if (phydev->suspended) return 0; - /* If the device has WOL enabled, we cannot suspend the PHY */ phy_ethtool_get_wol(phydev, &wol); - if (wol.wolopts || (netdev && netdev->wol_enabled)) + phydev->wol_enabled = wol.wolopts || (netdev && netdev->wol_enabled); + /* If the device has WOL enabled, we cannot suspend the PHY */ + if (phydev->wol_enabled && !(phydrv->flags & PHY_ALWAYS_CALL_SUSPEND)) return -EBUSY; if (!phydrv || !phydrv->suspend) diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 9e77165f3ef6..e9afbfb6d7a5 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -89,6 +89,7 @@ #define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ #define MII_BCM54XX_EXP_SEL_TOP 0x0d00 /* TOP_MISC expansion register select */ #define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MII_BCM54XX_EXP_SEL_WOL 0x0e00 /* Wake-on-LAN expansion select register */ #define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ #define MII_BCM54XX_EXP_SEL_ETC 0x0d00 /* Expansion register spare + 2k mem */ @@ -253,6 +254,9 @@ #define BCM54XX_TOP_MISC_IDDQ_SD (1 << 2) #define BCM54XX_TOP_MISC_IDDQ_SR (1 << 3) +#define BCM54XX_TOP_MISC_LED_CTL (MII_BCM54XX_EXP_SEL_TOP + 0x0C) +#define BCM54XX_LED4_SEL_INTR BIT(1) + /* * BCM5482: Secondary SerDes registers */ @@ -272,6 +276,57 @@ #define BCM54612E_EXP_SPARE0 (MII_BCM54XX_EXP_SEL_ETC + 0x34) #define BCM54612E_LED4_CLK125OUT_EN (1 << 1) + +/* Wake-on-LAN registers */ +#define BCM54XX_WOL_MAIN_CTL (MII_BCM54XX_EXP_SEL_WOL + 0x80) +#define BCM54XX_WOL_EN BIT(0) +#define BCM54XX_WOL_MODE_SINGLE_MPD 0 +#define BCM54XX_WOL_MODE_SINGLE_MPDSEC 1 +#define BCM54XX_WOL_MODE_DUAL 2 +#define BCM54XX_WOL_MODE_SHIFT 1 +#define BCM54XX_WOL_MODE_MASK 0x3 +#define BCM54XX_WOL_MP_MSB_FF_EN BIT(3) +#define BCM54XX_WOL_SECKEY_OPT_4B 0 +#define BCM54XX_WOL_SECKEY_OPT_6B 1 +#define BCM54XX_WOL_SECKEY_OPT_8B 2 +#define BCM54XX_WOL_SECKEY_OPT_SHIFT 4 +#define BCM54XX_WOL_SECKEY_OPT_MASK 0x3 +#define BCM54XX_WOL_L2_TYPE_CHK BIT(6) +#define BCM54XX_WOL_L4IPV4UDP_CHK BIT(7) +#define BCM54XX_WOL_L4IPV6UDP_CHK BIT(8) +#define BCM54XX_WOL_UDPPORT_CHK BIT(9) +#define BCM54XX_WOL_CRC_CHK BIT(10) +#define BCM54XX_WOL_SECKEY_MODE BIT(11) +#define BCM54XX_WOL_RST BIT(12) +#define BCM54XX_WOL_DIR_PKT_EN BIT(13) +#define BCM54XX_WOL_MASK_MODE_DA_FF 0 +#define BCM54XX_WOL_MASK_MODE_DA_MPD 1 +#define BCM54XX_WOL_MASK_MODE_DA_ONLY 2 +#define BCM54XX_WOL_MASK_MODE_MPD 3 +#define BCM54XX_WOL_MASK_MODE_SHIFT 14 +#define BCM54XX_WOL_MASK_MODE_MASK 0x3 + +#define BCM54XX_WOL_INNER_PROTO (MII_BCM54XX_EXP_SEL_WOL + 0x81) +#define BCM54XX_WOL_OUTER_PROTO (MII_BCM54XX_EXP_SEL_WOL + 0x82) +#define BCM54XX_WOL_OUTER_PROTO2 (MII_BCM54XX_EXP_SEL_WOL + 0x83) + +#define BCM54XX_WOL_MPD_DATA1(x) (MII_BCM54XX_EXP_SEL_WOL + 0x84 + (x)) +#define BCM54XX_WOL_MPD_DATA2(x) (MII_BCM54XX_EXP_SEL_WOL + 0x87 + (x)) +#define BCM54XX_WOL_SEC_KEY_8B (MII_BCM54XX_EXP_SEL_WOL + 0x8A) +#define BCM54XX_WOL_MASK(x) (MII_BCM54XX_EXP_SEL_WOL + 0x8B + (x)) +#define BCM54XX_SEC_KEY_STORE(x) (MII_BCM54XX_EXP_SEL_WOL + 0x8E) +#define BCM54XX_WOL_SHARED_CNT (MII_BCM54XX_EXP_SEL_WOL + 0x92) + +#define BCM54XX_WOL_INT_MASK (MII_BCM54XX_EXP_SEL_WOL + 0x93) +#define BCM54XX_WOL_PKT1 BIT(0) +#define BCM54XX_WOL_PKT2 BIT(1) +#define BCM54XX_WOL_DIR BIT(2) +#define BCM54XX_WOL_ALL_INTRS (BCM54XX_WOL_PKT1 | \ + BCM54XX_WOL_PKT2 | \ + BCM54XX_WOL_DIR) + +#define BCM54XX_WOL_INT_STATUS (MII_BCM54XX_EXP_SEL_WOL + 0x94) + /*****************************************************************************/ /* Fast Ethernet Transceiver definitions. */ /*****************************************************************************/ diff --git a/include/linux/phy.h b/include/linux/phy.h index c5a0dc829714..e0df8b3c2bdb 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -86,6 +86,7 @@ extern const int phy_10gbit_features_array[1]; #define PHY_IS_INTERNAL 0x00000001 #define PHY_RST_AFTER_CLK_EN 0x00000002 #define PHY_POLL_CABLE_TEST 0x00000004 +#define PHY_ALWAYS_CALL_SUSPEND 0x00000008 #define MDIO_DEVICE_IS_PHY 0x80000000 /** @@ -548,6 +549,8 @@ struct macsec_ops; * @downshifted_rate: Set true if link speed has been downshifted. * @is_on_sfp_module: Set true if PHY is located on an SFP module. * @mac_managed_pm: Set true if MAC driver takes of suspending/resuming PHY + * @wol_enabled: Set to true if the PHY or the attached MAC have Wake-on-LAN + * enabled. * @state: State of the PHY for management purposes * @dev_flags: Device-specific flags used by the PHY driver. * @@ -644,6 +647,7 @@ struct phy_device { unsigned downshifted_rate:1; unsigned is_on_sfp_module:1; unsigned mac_managed_pm:1; + unsigned wol_enabled:1; unsigned autoneg:1; /* The most recently read link state */