Skip to content

Commit

Permalink
net: bcmgenet: Move wake-up event out of side band ISR
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Doug Berger authored and David S. Miller committed May 1, 2020
1 parent df8f348 commit eb236c2
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 13 deletions.
72 changes: 59 additions & 13 deletions drivers/net/ethernet/broadcom/genet/bcmgenet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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))
Expand All @@ -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 },
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/broadcom/genet/bcmgenet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit eb236c2

Please sign in to comment.