Skip to content

Commit 9ec9b2a

Browse files
kcxtkuba-moo
authored andcommitted
net: ipa: disable ipa interrupt during suspend
The IPA interrupt can fire when pm_runtime is disabled due to it racing with the PM suspend/resume code. This causes a splat in the interrupt handler when it tries to call pm_runtime_get(). Explicitly disable the interrupt in our ->suspend callback, and re-enable it in ->resume to avoid this. If there is an interrupt pending it will be handled after resuming. The interrupt is a wake_irq, as a result even when disabled if it fires it will cause the system to wake from suspend as well as cancel any suspend transition that may be in progress. If there is an interrupt pending, the ipa_isr_thread handler will be called after resuming. Fixes: 1aac309 ("net: ipa: use autosuspend") Signed-off-by: Caleb Connolly <[email protected]> Reviewed-by: Alex Elder <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 1f3bd64 commit 9ec9b2a

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

drivers/net/ipa/ipa_interrupt.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)
127127
return IRQ_HANDLED;
128128
}
129129

130+
void ipa_interrupt_irq_disable(struct ipa *ipa)
131+
{
132+
disable_irq(ipa->interrupt->irq);
133+
}
134+
135+
void ipa_interrupt_irq_enable(struct ipa *ipa)
136+
{
137+
enable_irq(ipa->interrupt->irq);
138+
}
139+
130140
/* Common function used to enable/disable TX_SUSPEND for an endpoint */
131141
static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
132142
u32 endpoint_id, bool enable)

drivers/net/ipa/ipa_interrupt.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt);
8585
*/
8686
void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt);
8787

88+
/**
89+
* ipa_interrupt_irq_enable() - Enable IPA interrupts
90+
* @ipa: IPA pointer
91+
*
92+
* This enables the IPA interrupt line
93+
*/
94+
void ipa_interrupt_irq_enable(struct ipa *ipa);
95+
96+
/**
97+
* ipa_interrupt_irq_disable() - Disable IPA interrupts
98+
* @ipa: IPA pointer
99+
*
100+
* This disables the IPA interrupt line
101+
*/
102+
void ipa_interrupt_irq_disable(struct ipa *ipa);
103+
88104
/**
89105
* ipa_interrupt_config() - Configure the IPA interrupt framework
90106
* @ipa: IPA pointer

drivers/net/ipa/ipa_power.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ static int ipa_suspend(struct device *dev)
181181

182182
__set_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags);
183183

184+
/* Increment the disable depth to ensure that the IRQ won't
185+
* be re-enabled until the matching _enable call in
186+
* ipa_resume(). We do this to ensure that the interrupt
187+
* handler won't run whilst PM runtime is disabled.
188+
*
189+
* Note that disabling the IRQ is NOT the same as disabling
190+
* irq wake. If wakeup is enabled for the IPA then the IRQ
191+
* will still cause the system to wake up, see irq_set_irq_wake().
192+
*/
193+
ipa_interrupt_irq_disable(ipa);
194+
184195
return pm_runtime_force_suspend(dev);
185196
}
186197

@@ -193,6 +204,12 @@ static int ipa_resume(struct device *dev)
193204

194205
__clear_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags);
195206

207+
/* Now that PM runtime is enabled again it's safe
208+
* to turn the IRQ back on and process any data
209+
* that was received during suspend.
210+
*/
211+
ipa_interrupt_irq_enable(ipa);
212+
196213
return ret;
197214
}
198215

0 commit comments

Comments
 (0)