2020-04-30 23:30:18

by Doug Berger

[permalink] [raw]
Subject: [PATCH net-next] 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 <[email protected]>
---
drivers/net/ethernet/broadcom/genet/bcmgenet.c | 72 ++++++++++++++++++----
drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +
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;
}

--
2.7.4


2020-05-01 01:23:02

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH net-next] net: bcmgenet: Move wake-up event out of side band ISR



On 4/30/2020 4:26 PM, Doug Berger wrote:
> 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 <[email protected]>

Signed-off-by: Florian Fainelli <[email protected]>
--
Florian

2020-05-01 22:56:28

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next] net: bcmgenet: Move wake-up event out of side band ISR

From: Doug Berger <[email protected]>
Date: Thu, 30 Apr 2020 16:26:51 -0700

> 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 <[email protected]>

Applied, thank you.