Skip to content

Commit 2597141

Browse files
Chunfeng Yunrafaeljw
authored andcommitted
PM / wakeirq: support enabling wake-up irq after runtime_suspend called
When the dedicated wake IRQ is level trigger, and it uses the device's low-power status as the wakeup source, that means if the device is not in low-power state, the wake IRQ will be triggered if enabled; For this case, need enable the wake IRQ after running the device's ->runtime_suspend() which make it enter low-power state. e.g. Assume the wake IRQ is a low level trigger type, and the wakeup signal comes from the low-power status of the device. The wakeup signal is low level at running time (0), and becomes high level when the device enters low-power state (runtime_suspend (1) is called), a wakeup event at (2) make the device exit low-power state, then the wakeup signal also becomes low level. ------------------ | ^ ^| ---------------- | | -------------- |<---(0)--->|<--(1)--| (3) (2) (4) if enable the wake IRQ before running runtime_suspend during (0), a wake IRQ will arise, it causes resume immediately; it works if enable wake IRQ ( e.g. at (3) or (4)) after running ->runtime_suspend(). This patch introduces a new status WAKE_IRQ_DEDICATED_REVERSE to optionally support enabling wake IRQ after running ->runtime_suspend(). Suggested-by: Rafael J. Wysocki <[email protected]> Signed-off-by: Chunfeng Yun <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 9f6abfc commit 2597141

File tree

4 files changed

+96
-27
lines changed

4 files changed

+96
-27
lines changed

drivers/base/power/power.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ extern u64 pm_runtime_active_time(struct device *dev);
2525

2626
#define WAKE_IRQ_DEDICATED_ALLOCATED BIT(0)
2727
#define WAKE_IRQ_DEDICATED_MANAGED BIT(1)
28+
#define WAKE_IRQ_DEDICATED_REVERSE BIT(2)
2829
#define WAKE_IRQ_DEDICATED_MASK (WAKE_IRQ_DEDICATED_ALLOCATED | \
29-
WAKE_IRQ_DEDICATED_MANAGED)
30+
WAKE_IRQ_DEDICATED_MANAGED | \
31+
WAKE_IRQ_DEDICATED_REVERSE)
3032

3133
struct wake_irq {
3234
struct device *dev;
@@ -39,7 +41,8 @@ extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
3941
extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq);
4042
extern void dev_pm_enable_wake_irq_check(struct device *dev,
4143
bool can_change_status);
42-
extern void dev_pm_disable_wake_irq_check(struct device *dev);
44+
extern void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable);
45+
extern void dev_pm_enable_wake_irq_complete(struct device *dev);
4346

4447
#ifdef CONFIG_PM_SLEEP
4548

drivers/base/power/runtime.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,8 @@ static int rpm_suspend(struct device *dev, int rpmflags)
645645
if (retval)
646646
goto fail;
647647

648+
dev_pm_enable_wake_irq_complete(dev);
649+
648650
no_callback:
649651
__update_runtime_status(dev, RPM_SUSPENDED);
650652
pm_runtime_deactivate_timer(dev);
@@ -690,7 +692,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
690692
return retval;
691693

692694
fail:
693-
dev_pm_disable_wake_irq_check(dev);
695+
dev_pm_disable_wake_irq_check(dev, true);
694696
__update_runtime_status(dev, RPM_ACTIVE);
695697
dev->power.deferred_resume = false;
696698
wake_up_all(&dev->power.wait_queue);
@@ -873,7 +875,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
873875

874876
callback = RPM_GET_CALLBACK(dev, runtime_resume);
875877

876-
dev_pm_disable_wake_irq_check(dev);
878+
dev_pm_disable_wake_irq_check(dev, false);
877879
retval = rpm_callback(callback, dev);
878880
if (retval) {
879881
__update_runtime_status(dev, RPM_SUSPENDED);

drivers/base/power/wakeirq.c

Lines changed: 80 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -142,24 +142,7 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
142142
return IRQ_HANDLED;
143143
}
144144

145-
/**
146-
* dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
147-
* @dev: Device entry
148-
* @irq: Device wake-up interrupt
149-
*
150-
* Unless your hardware has separate wake-up interrupts in addition
151-
* to the device IO interrupts, you don't need this.
152-
*
153-
* Sets up a threaded interrupt handler for a device that has
154-
* a dedicated wake-up interrupt in addition to the device IO
155-
* interrupt.
156-
*
157-
* The interrupt starts disabled, and needs to be managed for
158-
* the device by the bus code or the device driver using
159-
* dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
160-
* functions.
161-
*/
162-
int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
145+
static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned int flag)
163146
{
164147
struct wake_irq *wirq;
165148
int err;
@@ -197,7 +180,7 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
197180
if (err)
198181
goto err_free_irq;
199182

200-
wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED;
183+
wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED | flag;
201184

202185
return err;
203186

@@ -210,8 +193,57 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
210193

211194
return err;
212195
}
196+
197+
198+
/**
199+
* dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
200+
* @dev: Device entry
201+
* @irq: Device wake-up interrupt
202+
*
203+
* Unless your hardware has separate wake-up interrupts in addition
204+
* to the device IO interrupts, you don't need this.
205+
*
206+
* Sets up a threaded interrupt handler for a device that has
207+
* a dedicated wake-up interrupt in addition to the device IO
208+
* interrupt.
209+
*
210+
* The interrupt starts disabled, and needs to be managed for
211+
* the device by the bus code or the device driver using
212+
* dev_pm_enable_wake_irq*() and dev_pm_disable_wake_irq*()
213+
* functions.
214+
*/
215+
int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
216+
{
217+
return __dev_pm_set_dedicated_wake_irq(dev, irq, 0);
218+
}
213219
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
214220

221+
/**
222+
* dev_pm_set_dedicated_wake_irq_reverse - Request a dedicated wake-up interrupt
223+
* with reverse enable ordering
224+
* @dev: Device entry
225+
* @irq: Device wake-up interrupt
226+
*
227+
* Unless your hardware has separate wake-up interrupts in addition
228+
* to the device IO interrupts, you don't need this.
229+
*
230+
* Sets up a threaded interrupt handler for a device that has a dedicated
231+
* wake-up interrupt in addition to the device IO interrupt. It sets
232+
* the status of WAKE_IRQ_DEDICATED_REVERSE to tell rpm_suspend()
233+
* to enable dedicated wake-up interrupt after running the runtime suspend
234+
* callback for @dev.
235+
*
236+
* The interrupt starts disabled, and needs to be managed for
237+
* the device by the bus code or the device driver using
238+
* dev_pm_enable_wake_irq*() and dev_pm_disable_wake_irq*()
239+
* functions.
240+
*/
241+
int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq)
242+
{
243+
return __dev_pm_set_dedicated_wake_irq(dev, irq, WAKE_IRQ_DEDICATED_REVERSE);
244+
}
245+
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq_reverse);
246+
215247
/**
216248
* dev_pm_enable_wake_irq - Enable device wake-up interrupt
217249
* @dev: Device
@@ -282,27 +314,54 @@ void dev_pm_enable_wake_irq_check(struct device *dev,
282314
return;
283315

284316
enable:
285-
enable_irq(wirq->irq);
317+
if (!can_change_status || !(wirq->status & WAKE_IRQ_DEDICATED_REVERSE))
318+
enable_irq(wirq->irq);
286319
}
287320

288321
/**
289322
* dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt
290323
* @dev: Device
324+
* @cond_disable: if set, also check WAKE_IRQ_DEDICATED_REVERSE
291325
*
292326
* Disables wake-up interrupt conditionally based on status.
293327
* Should be only called from rpm_suspend() and rpm_resume() path.
294328
*/
295-
void dev_pm_disable_wake_irq_check(struct device *dev)
329+
void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable)
296330
{
297331
struct wake_irq *wirq = dev->power.wakeirq;
298332

299333
if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK))
300334
return;
301335

336+
if (cond_disable && (wirq->status & WAKE_IRQ_DEDICATED_REVERSE))
337+
return;
338+
302339
if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED)
303340
disable_irq_nosync(wirq->irq);
304341
}
305342

343+
/**
344+
* dev_pm_enable_wake_irq_complete - enable wake IRQ not enabled before
345+
* @dev: Device using the wake IRQ
346+
*
347+
* Enable wake IRQ conditionally based on status, mainly used if want to
348+
* enable wake IRQ after running ->runtime_suspend() which depends on
349+
* WAKE_IRQ_DEDICATED_REVERSE.
350+
*
351+
* Should be only called from rpm_suspend() path.
352+
*/
353+
void dev_pm_enable_wake_irq_complete(struct device *dev)
354+
{
355+
struct wake_irq *wirq = dev->power.wakeirq;
356+
357+
if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK))
358+
return;
359+
360+
if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED &&
361+
wirq->status & WAKE_IRQ_DEDICATED_REVERSE)
362+
enable_irq(wirq->irq);
363+
}
364+
306365
/**
307366
* dev_pm_arm_wake_irq - Arm device wake-up
308367
* @wirq: Device wake-up interrupt

include/linux/pm_wakeirq.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
#ifdef CONFIG_PM
1818

1919
extern int dev_pm_set_wake_irq(struct device *dev, int irq);
20-
extern int dev_pm_set_dedicated_wake_irq(struct device *dev,
21-
int irq);
20+
extern int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq);
21+
extern int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq);
2222
extern void dev_pm_clear_wake_irq(struct device *dev);
2323
extern void dev_pm_enable_wake_irq(struct device *dev);
2424
extern void dev_pm_disable_wake_irq(struct device *dev);
@@ -35,6 +35,11 @@ static inline int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
3535
return 0;
3636
}
3737

38+
static inline int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq)
39+
{
40+
return 0;
41+
}
42+
3843
static inline void dev_pm_clear_wake_irq(struct device *dev)
3944
{
4045
}

0 commit comments

Comments
 (0)