aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-01-04 20:18:42 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-01-09 07:09:16 -0500
commit7bf4e594c28afc67bc120a380ca774e43ca496d8 (patch)
tree8f8620cca96c6a29eb8c3a1f7c31e350f8e96ae8
parent32bfa56ac158c1ebcc82df2518860f824be5e5be (diff)
PM / wakeup: Do not fail dev_pm_attach_wake_irq() unnecessarily
Returning an error code from dev_pm_attach_wake_irq() if device_wakeup_attach_irq() called by it returns an error is pointless, because the wakeup source used by it may be deleted by user space via sysfs at any time and in particular right after dev_pm_attach_wake_irq() has returned. Moreover, it requires the callers of dev_pm_attach_wake_irq() to create that wakeup source via device_wakeup_enable() upfront, but that obviously is racy with respect to the sysfs-based manipulations of it. To avoid the race, modify device_wakeup_attach_irq() to check that the wakeup source it is going to use is there (and return early otherwise), make it void (as it cannot fail after that change) and make dev_pm_attach_wake_irq() simply call it for the device unconditionally. Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/power.h11
-rw-r--r--drivers/base/power/wakeirq.c8
-rw-r--r--drivers/base/power/wakeup.c11
3 files changed, 10 insertions, 20 deletions
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 7beee75399d4..21244c53e377 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -41,20 +41,15 @@ extern void dev_pm_disable_wake_irq_check(struct device *dev);
41 41
42#ifdef CONFIG_PM_SLEEP 42#ifdef CONFIG_PM_SLEEP
43 43
44extern int device_wakeup_attach_irq(struct device *dev, 44extern void device_wakeup_attach_irq(struct device *dev, struct wake_irq *wakeirq);
45 struct wake_irq *wakeirq);
46extern void device_wakeup_detach_irq(struct device *dev); 45extern void device_wakeup_detach_irq(struct device *dev);
47extern void device_wakeup_arm_wake_irqs(void); 46extern void device_wakeup_arm_wake_irqs(void);
48extern void device_wakeup_disarm_wake_irqs(void); 47extern void device_wakeup_disarm_wake_irqs(void);
49 48
50#else 49#else
51 50
52static inline int 51static inline void device_wakeup_attach_irq(struct device *dev,
53device_wakeup_attach_irq(struct device *dev, 52 struct wake_irq *wakeirq) {}
54 struct wake_irq *wakeirq)
55{
56 return 0;
57}
58 53
59static inline void device_wakeup_detach_irq(struct device *dev) 54static inline void device_wakeup_detach_irq(struct device *dev)
60{ 55{
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index ae0429827f31..a8ac86e4d79e 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -33,7 +33,6 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq,
33 struct wake_irq *wirq) 33 struct wake_irq *wirq)
34{ 34{
35 unsigned long flags; 35 unsigned long flags;
36 int err;
37 36
38 if (!dev || !wirq) 37 if (!dev || !wirq)
39 return -EINVAL; 38 return -EINVAL;
@@ -45,12 +44,11 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq,
45 return -EEXIST; 44 return -EEXIST;
46 } 45 }
47 46
48 err = device_wakeup_attach_irq(dev, wirq); 47 dev->power.wakeirq = wirq;
49 if (!err) 48 device_wakeup_attach_irq(dev, wirq);
50 dev->power.wakeirq = wirq;
51 49
52 spin_unlock_irqrestore(&dev->power.lock, flags); 50 spin_unlock_irqrestore(&dev->power.lock, flags);
53 return err; 51 return 0;
54} 52}
55 53
56/** 54/**
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index b7b8b2fe89c6..e73a081c6397 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -291,22 +291,19 @@ EXPORT_SYMBOL_GPL(device_wakeup_enable);
291 * 291 *
292 * Call under the device's power.lock lock. 292 * Call under the device's power.lock lock.
293 */ 293 */
294int device_wakeup_attach_irq(struct device *dev, 294void device_wakeup_attach_irq(struct device *dev,
295 struct wake_irq *wakeirq) 295 struct wake_irq *wakeirq)
296{ 296{
297 struct wakeup_source *ws; 297 struct wakeup_source *ws;
298 298
299 ws = dev->power.wakeup; 299 ws = dev->power.wakeup;
300 if (!ws) { 300 if (!ws)
301 dev_err(dev, "forgot to call device_init_wakeup?\n"); 301 return;
302 return -EINVAL;
303 }
304 302
305 if (ws->wakeirq) 303 if (ws->wakeirq)
306 return -EEXIST; 304 dev_err(dev, "Leftover wakeup IRQ found, overriding\n");
307 305
308 ws->wakeirq = wakeirq; 306 ws->wakeirq = wakeirq;
309 return 0;
310} 307}
311 308
312/** 309/**