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: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Imre Deak <imre.deak@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
cae3052790
commit
d7a181da2d
|
@ -107,7 +107,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||||
INIT_LIST_HEAD(&bus->hlink_list);
|
INIT_LIST_HEAD(&bus->hlink_list);
|
||||||
bus->idx = idx++;
|
bus->idx = idx++;
|
||||||
|
|
||||||
mutex_init(&bus->lock);
|
|
||||||
bus->cmd_dma_state = true;
|
bus->cmd_dma_state = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -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);
|
INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
|
||||||
spin_lock_init(&bus->reg_lock);
|
spin_lock_init(&bus->reg_lock);
|
||||||
mutex_init(&bus->cmd_mutex);
|
mutex_init(&bus->cmd_mutex);
|
||||||
|
mutex_init(&bus->lock);
|
||||||
bus->irq = -1;
|
bus->irq = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
dev_dbg(bus->dev, "display power %s\n",
|
||||||
enable ? "enable" : "disable");
|
enable ? "enable" : "disable");
|
||||||
|
|
||||||
|
mutex_lock(&bus->lock);
|
||||||
if (enable)
|
if (enable)
|
||||||
set_bit(idx, &bus->display_power_status);
|
set_bit(idx, &bus->display_power_status);
|
||||||
else
|
else
|
||||||
clear_bit(idx, &bus->display_power_status);
|
clear_bit(idx, &bus->display_power_status);
|
||||||
|
|
||||||
if (!acomp || !acomp->ops)
|
if (!acomp || !acomp->ops)
|
||||||
return;
|
goto unlock;
|
||||||
|
|
||||||
if (bus->display_power_status) {
|
if (bus->display_power_status) {
|
||||||
if (!bus->display_power_active) {
|
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;
|
bus->display_power_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&bus->lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
|
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue