diff options
author | Doug Berger <opendmb@gmail.com> | 2020-04-30 16:26:51 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-05-01 15:54:33 -0700 |
commit | eb236c2994b031f805be691fa9ea39cba4690166 (patch) | |
tree | ccfec9cd9cf2e3835252bc4901c4b02a90faa326 | |
parent | df8f348e76d556cc88445fd78e83235a910cb41e (diff) |
net: bcmgenet: Move wake-up event out of side band ISR
The side band interrupt service routine is not available on chips
like 7211, or rather, it does not permit the signaling of wake-up
events due to the complex interrupt hierarchy.
Move the wake-up event accounting into a .resume_noirq function,
account for possible wake-up events and clear the MPD/HFB interrupts
from there, while leaving the hardware untouched until the resume
function proceeds with doing its usual business.
Because bcmgenet_wol_power_down_cfg() now enables the MPD and HFB
interrupts, it is invoked by a .suspend_noirq function to prevent
the servicing of interrupts after the clocks have been disabled.
Signed-off-by: Doug Berger <opendmb@gmail.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 72 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 6 |
3 files changed, 67 insertions, 13 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index ad614d7201bd..ff31da0ed846 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3270,10 +3270,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) { - struct bcmgenet_priv *priv = dev_id; - - pm_wakeup_event(&priv->pdev->dev, 0); - + /* Acknowledge the interrupt */ return IRQ_HANDLED; } @@ -4174,13 +4171,12 @@ static void bcmgenet_shutdown(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int bcmgenet_resume(struct device *d) +static int bcmgenet_resume_noirq(struct device *d) { struct net_device *dev = dev_get_drvdata(d); struct bcmgenet_priv *priv = netdev_priv(dev); - unsigned long dma_ctrl; - u32 offset, reg; int ret; + u32 reg; if (!netif_running(dev)) return 0; @@ -4190,6 +4186,34 @@ static int bcmgenet_resume(struct device *d) if (ret) return ret; + if (device_may_wakeup(d) && priv->wolopts) { + /* Account for Wake-on-LAN events and clear those events + * (Some devices need more time between enabling the clocks + * and the interrupt register reflecting the wake event so + * read the register twice) + */ + reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); + reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); + if (reg & UMAC_IRQ_WAKE_EVENT) + pm_wakeup_event(&priv->pdev->dev, 0); + } + + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_WAKE_EVENT, INTRL2_CPU_CLEAR); + + return 0; +} + +static int bcmgenet_resume(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned long dma_ctrl; + u32 offset, reg; + int ret; + + if (!netif_running(dev)) + return 0; + /* From WOL-enabled suspend, switch to regular clock */ if (device_may_wakeup(d) && priv->wolopts) bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); @@ -4262,7 +4286,6 @@ static int bcmgenet_suspend(struct device *d) { struct net_device *dev = dev_get_drvdata(d); struct bcmgenet_priv *priv = netdev_priv(dev); - int ret = 0; u32 offset; if (!netif_running(dev)) @@ -4282,23 +4305,46 @@ static int bcmgenet_suspend(struct device *d) priv->hfb_en[2] = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32)); bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL); + return 0; +} + +static int bcmgenet_suspend_noirq(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcmgenet_priv *priv = netdev_priv(dev); + int ret = 0; + + if (!netif_running(dev)) + return 0; + /* Prepare the device for Wake-on-LAN and switch to the slow clock */ if (device_may_wakeup(d) && priv->wolopts) ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); else if (priv->internal_phy) ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); + /* Let the framework handle resumption and leave the clocks on */ + if (ret) + return ret; + /* Turn off the clocks */ clk_disable_unprepare(priv->clk); - if (ret) - bcmgenet_resume(d); - - return ret; + return 0; } +#else +#define bcmgenet_suspend NULL +#define bcmgenet_suspend_noirq NULL +#define bcmgenet_resume NULL +#define bcmgenet_resume_noirq NULL #endif /* CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); +static const struct dev_pm_ops bcmgenet_pm_ops = { + .suspend = bcmgenet_suspend, + .suspend_noirq = bcmgenet_suspend_noirq, + .resume = bcmgenet_resume, + .resume_noirq = bcmgenet_resume_noirq, +}; static const struct acpi_device_id genet_acpi_match[] = { { "BCM6E4E", (kernel_ulong_t)&bcm2711_plat_data }, diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 031d91f45067..a12cb59298f4 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -312,6 +312,8 @@ struct bcmgenet_mib_counters { #define UMAC_IRQ_HFB_SM (1 << 10) #define UMAC_IRQ_HFB_MM (1 << 11) #define UMAC_IRQ_MPD_R (1 << 12) +#define UMAC_IRQ_WAKE_EVENT (UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM | \ + UMAC_IRQ_MPD_R) #define UMAC_IRQ_RXDMA_MBDONE (1 << 13) #define UMAC_IRQ_RXDMA_PDONE (1 << 14) #define UMAC_IRQ_RXDMA_BDONE (1 << 15) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index 4b9d65f392c2..4ea6a26b04f7 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -193,6 +193,12 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); } + reg = UMAC_IRQ_MPD_R; + if (hfb_enable) + reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM; + + bcmgenet_intrl2_0_writel(priv, reg, INTRL2_CPU_MASK_CLEAR); + return 0; } |