Skip to content

Commit

Permalink
ALSA: hda: Fix racy display power access
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Chris Wilson <[email protected]>
Cc: Imre Deak <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
tiwai committed Apr 10, 2019
1 parent cae3052 commit d7a181d
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 2 deletions.
1 change: 0 additions & 1 deletion sound/hda/ext/hdac_ext_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions sound/hda/hdac_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
6 changes: 5 additions & 1 deletion sound/hda/hdac_component.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);

Expand Down

0 comments on commit d7a181d

Please sign in to comment.