Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Doug Berger and committed by
David S. Miller
eb236c29 df8f348e

+69 -15
+61 -15
drivers/net/ethernet/broadcom/genet/bcmgenet.c
··· 3270 3270 3271 3271 static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) 3272 3272 { 3273 - struct bcmgenet_priv *priv = dev_id; 3274 - 3275 - pm_wakeup_event(&priv->pdev->dev, 0); 3276 - 3273 + /* Acknowledge the interrupt */ 3277 3274 return IRQ_HANDLED; 3278 3275 } 3279 3276 ··· 4171 4174 } 4172 4175 4173 4176 #ifdef CONFIG_PM_SLEEP 4177 + static int bcmgenet_resume_noirq(struct device *d) 4178 + { 4179 + struct net_device *dev = dev_get_drvdata(d); 4180 + struct bcmgenet_priv *priv = netdev_priv(dev); 4181 + int ret; 4182 + u32 reg; 4183 + 4184 + if (!netif_running(dev)) 4185 + return 0; 4186 + 4187 + /* Turn on the clock */ 4188 + ret = clk_prepare_enable(priv->clk); 4189 + if (ret) 4190 + return ret; 4191 + 4192 + if (device_may_wakeup(d) && priv->wolopts) { 4193 + /* Account for Wake-on-LAN events and clear those events 4194 + * (Some devices need more time between enabling the clocks 4195 + * and the interrupt register reflecting the wake event so 4196 + * read the register twice) 4197 + */ 4198 + reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); 4199 + reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); 4200 + if (reg & UMAC_IRQ_WAKE_EVENT) 4201 + pm_wakeup_event(&priv->pdev->dev, 0); 4202 + } 4203 + 4204 + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_WAKE_EVENT, INTRL2_CPU_CLEAR); 4205 + 4206 + return 0; 4207 + } 4208 + 4174 4209 static int bcmgenet_resume(struct device *d) 4175 4210 { 4176 4211 struct net_device *dev = dev_get_drvdata(d); ··· 4213 4184 4214 4185 if (!netif_running(dev)) 4215 4186 return 0; 4216 - 4217 - /* Turn on the clock */ 4218 - ret = clk_prepare_enable(priv->clk); 4219 - if (ret) 4220 - return ret; 4221 4187 4222 4188 /* From WOL-enabled suspend, switch to regular clock */ 4223 4189 if (device_may_wakeup(d) && priv->wolopts) ··· 4286 4262 { 4287 4263 struct net_device *dev = dev_get_drvdata(d); 4288 4264 struct bcmgenet_priv *priv = netdev_priv(dev); 4289 - int ret = 0; 4290 4265 u32 offset; 4291 4266 4292 4267 if (!netif_running(dev)) ··· 4305 4282 priv->hfb_en[2] = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32)); 4306 4283 bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL); 4307 4284 4285 + return 0; 4286 + } 4287 + 4288 + static int bcmgenet_suspend_noirq(struct device *d) 4289 + { 4290 + struct net_device *dev = dev_get_drvdata(d); 4291 + struct bcmgenet_priv *priv = netdev_priv(dev); 4292 + int ret = 0; 4293 + 4294 + if (!netif_running(dev)) 4295 + return 0; 4296 + 4308 4297 /* Prepare the device for Wake-on-LAN and switch to the slow clock */ 4309 4298 if (device_may_wakeup(d) && priv->wolopts) 4310 4299 ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); 4311 4300 else if (priv->internal_phy) 4312 4301 ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); 4313 4302 4303 + /* Let the framework handle resumption and leave the clocks on */ 4304 + if (ret) 4305 + return ret; 4306 + 4314 4307 /* Turn off the clocks */ 4315 4308 clk_disable_unprepare(priv->clk); 4316 4309 4317 - if (ret) 4318 - bcmgenet_resume(d); 4319 - 4320 - return ret; 4310 + return 0; 4321 4311 } 4312 + #else 4313 + #define bcmgenet_suspend NULL 4314 + #define bcmgenet_suspend_noirq NULL 4315 + #define bcmgenet_resume NULL 4316 + #define bcmgenet_resume_noirq NULL 4322 4317 #endif /* CONFIG_PM_SLEEP */ 4323 4318 4324 - static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); 4319 + static const struct dev_pm_ops bcmgenet_pm_ops = { 4320 + .suspend = bcmgenet_suspend, 4321 + .suspend_noirq = bcmgenet_suspend_noirq, 4322 + .resume = bcmgenet_resume, 4323 + .resume_noirq = bcmgenet_resume_noirq, 4324 + }; 4325 4325 4326 4326 static const struct acpi_device_id genet_acpi_match[] = { 4327 4327 { "BCM6E4E", (kernel_ulong_t)&bcm2711_plat_data },
+2
drivers/net/ethernet/broadcom/genet/bcmgenet.h
··· 312 312 #define UMAC_IRQ_HFB_SM (1 << 10) 313 313 #define UMAC_IRQ_HFB_MM (1 << 11) 314 314 #define UMAC_IRQ_MPD_R (1 << 12) 315 + #define UMAC_IRQ_WAKE_EVENT (UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM | \ 316 + UMAC_IRQ_MPD_R) 315 317 #define UMAC_IRQ_RXDMA_MBDONE (1 << 13) 316 318 #define UMAC_IRQ_RXDMA_PDONE (1 << 14) 317 319 #define UMAC_IRQ_RXDMA_BDONE (1 << 15)
+6
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
··· 193 193 bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); 194 194 } 195 195 196 + reg = UMAC_IRQ_MPD_R; 197 + if (hfb_enable) 198 + reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM; 199 + 200 + bcmgenet_intrl2_0_writel(priv, reg, INTRL2_CPU_MASK_CLEAR); 201 + 196 202 return 0; 197 203 } 198 204