Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d3dab7d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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: 4990d4fe (PM / Wakeirq: Add automated device wake IRQ handling)
Reported-by: default avatarFelipe Balbi <balbi@ti.com>
Tested-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent db874c7e
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -45,14 +45,12 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq,
		return -EEXIST;
	}

	err = device_wakeup_attach_irq(dev, wirq);
	if (!err)
		dev->power.wakeirq = wirq;
	spin_unlock_irqrestore(&dev->power.lock, flags);

	err = device_wakeup_attach_irq(dev, wirq);
	if (err)
	spin_unlock_irqrestore(&dev->power.lock, flags);
	return err;

	return 0;
}

/**
@@ -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);
+10 −21
Original line number Diff line number Diff line
@@ -247,32 +247,25 @@ EXPORT_SYMBOL_GPL(device_wakeup_enable);
 * Attach a device wakeirq to the wakeup source so the device
 * wake IRQ can be configured automatically for suspend and
 * resume.
 *
 * Call under the device's power.lock lock.
 */
int device_wakeup_attach_irq(struct device *dev,
			     struct wake_irq *wakeirq)
{
	struct wakeup_source *ws;
	int ret = 0;

	spin_lock_irq(&dev->power.lock);
	ws = dev->power.wakeup;
	if (!ws) {
		dev_err(dev, "forgot to call call device_init_wakeup?\n");
		ret = -EINVAL;
		goto unlock;
		return -EINVAL;
	}

	if (ws->wakeirq) {
		ret = -EEXIST;
		goto unlock;
	}
	if (ws->wakeirq)
		return -EEXIST;

	ws->wakeirq = wakeirq;

unlock:
	spin_unlock_irq(&dev->power.lock);

	return ret;
	return 0;
}

/**
@@ -280,20 +273,16 @@ int device_wakeup_attach_irq(struct device *dev,
 * @dev: Device to handle
 *
 * Removes a device wakeirq from the wakeup source.
 *
 * Call under the device's power.lock lock.
 */
void device_wakeup_detach_irq(struct device *dev)
{
	struct wakeup_source *ws;

	spin_lock_irq(&dev->power.lock);
	ws = dev->power.wakeup;
	if (!ws)
		goto unlock;

	if (ws)
		ws->wakeirq = NULL;

unlock:
	spin_unlock_irq(&dev->power.lock);
}

/**