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 /drivers/net/ethernet/broadcom/genet/bcmgenet.c | |
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>
Diffstat (limited to 'drivers/net/ethernet/broadcom/genet/bcmgenet.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 72 |
1 files changed, 59 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 }, |