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

Commit d7a181da authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda: Fix racy display power access



snd_hdac_display_power() doesn't handle the concurrent calls carefully
enough, and it may lead to the doubly get_power or put_power calls,
when a runtime PM and an async work get called in racy way.

This patch addresses it by reusing the bus->lock mutex that has been
used for protecting the link state change in ext bus code, so that it
can protect against racy display state changes.  The initialization of
bus->lock was moved from snd_hdac_ext_bus_init() to
snd_hdac_bus_init() as well accordingly.

Testcase: igt/i915_pm_rpm/module-reload #glk-dsi
Reported-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Imre Deak <imre.deak@intel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent cae30527
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -107,7 +107,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
	INIT_LIST_HEAD(&bus->hlink_list);
	bus->idx = idx++;

	mutex_init(&bus->lock);
	bus->cmd_dma_state = true;

	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
	INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
	spin_lock_init(&bus->reg_lock);
	mutex_init(&bus->cmd_mutex);
	mutex_init(&bus->lock);
	bus->irq = -1;
	return 0;
}
+5 −1
Original line number Diff line number Diff line
@@ -69,13 +69,15 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)

	dev_dbg(bus->dev, "display power %s\n",
		enable ? "enable" : "disable");

	mutex_lock(&bus->lock);
	if (enable)
		set_bit(idx, &bus->display_power_status);
	else
		clear_bit(idx, &bus->display_power_status);

	if (!acomp || !acomp->ops)
		return;
		goto unlock;

	if (bus->display_power_status) {
		if (!bus->display_power_active) {
@@ -92,6 +94,8 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
			bus->display_power_active = false;
		}
	}
 unlock:
	mutex_unlock(&bus->lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);