aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/wakeirq.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-07-07 13:08:39 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-07-07 13:08:39 +0200
commit6d3dab7d84177f836b14961b4d252d0959d66768 (patch)
treec6f73c97ea97931bbb8cf4d36e8c2e7b0d321268 /drivers/base/power/wakeirq.c
parentPM / wakeirq: Fix typo in prototype for dev_pm_set_dedicated_wake_irq (diff)
downloadlinux-dev-6d3dab7d84177f836b14961b4d252d0959d66768.tar.xz
linux-dev-6d3dab7d84177f836b14961b4d252d0959d66768.zip
PM / wakeirq: Avoid setting power.wakeirq too hastily
If dev_pm_attach_wake_irq() fails, the device's power.wakeirq field should not be set to point to the struct wake_irq passed to that function, as that object will be freed going forward. For this reason, make dev_pm_attach_wake_irq() first call device_wakeup_attach_irq() and only set the device's power.wakeirq field if that's successful. That requires device_wakeup_attach_irq() to be called under the device's power.lock lock, but since dev_pm_attach_wake_irq() is the only caller of it, the requisite changes are easy to make. Fixes: 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling) Reported-by: Felipe Balbi <balbi@ti.com> Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base/power/wakeirq.c')
-rw-r--r--drivers/base/power/wakeirq.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index 7470004ca810..eb6e67451dec 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -45,14 +45,12 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq,
return -EEXIST;
}
- dev->power.wakeirq = wirq;
- spin_unlock_irqrestore(&dev->power.lock, flags);
-
err = device_wakeup_attach_irq(dev, wirq);
- if (err)
- return err;
+ if (!err)
+ dev->power.wakeirq = wirq;
- return 0;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+ return err;
}
/**
@@ -105,10 +103,10 @@ void dev_pm_clear_wake_irq(struct device *dev)
return;
spin_lock_irqsave(&dev->power.lock, flags);
+ device_wakeup_detach_irq(dev);
dev->power.wakeirq = NULL;
spin_unlock_irqrestore(&dev->power.lock, flags);
- device_wakeup_detach_irq(dev);
if (wirq->dedicated_irq)
free_irq(wirq->irq, wirq);
kfree(wirq);