diff options
| author | Takashi Iwai <tiwai@suse.de> | 2019-04-10 06:49:55 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2019-04-10 09:23:36 -0400 |
| commit | d7a181da2dfa3190487c446042ba01e07d851c74 (patch) | |
| tree | c2c281018d0a0dd56e792e0fca49af8313d5a30b | |
| parent | cae30527901d9590db0e12ace994c1d58bea87fd (diff) | |
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>
| -rw-r--r-- | sound/hda/ext/hdac_ext_bus.c | 1 | ||||
| -rw-r--r-- | sound/hda/hdac_bus.c | 1 | ||||
| -rw-r--r-- | sound/hda/hdac_component.c | 6 |
3 files changed, 6 insertions, 2 deletions
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 9c37d9af3023..ec7715c6b0c0 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c | |||
| @@ -107,7 +107,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, | |||
| 107 | INIT_LIST_HEAD(&bus->hlink_list); | 107 | INIT_LIST_HEAD(&bus->hlink_list); |
| 108 | bus->idx = idx++; | 108 | bus->idx = idx++; |
| 109 | 109 | ||
| 110 | mutex_init(&bus->lock); | ||
| 111 | bus->cmd_dma_state = true; | 110 | bus->cmd_dma_state = true; |
| 112 | 111 | ||
| 113 | return 0; | 112 | return 0; |
diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 012305177f68..ad8eee08013f 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c | |||
| @@ -38,6 +38,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, | |||
| 38 | INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); | 38 | INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); |
| 39 | spin_lock_init(&bus->reg_lock); | 39 | spin_lock_init(&bus->reg_lock); |
| 40 | mutex_init(&bus->cmd_mutex); | 40 | mutex_init(&bus->cmd_mutex); |
| 41 | mutex_init(&bus->lock); | ||
| 41 | bus->irq = -1; | 42 | bus->irq = -1; |
| 42 | return 0; | 43 | return 0; |
| 43 | } | 44 | } |
diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index a6d37b9d6413..6b5caee61c6e 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c | |||
| @@ -69,13 +69,15 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) | |||
| 69 | 69 | ||
| 70 | dev_dbg(bus->dev, "display power %s\n", | 70 | dev_dbg(bus->dev, "display power %s\n", |
| 71 | enable ? "enable" : "disable"); | 71 | enable ? "enable" : "disable"); |
| 72 | |||
| 73 | mutex_lock(&bus->lock); | ||
| 72 | if (enable) | 74 | if (enable) |
| 73 | set_bit(idx, &bus->display_power_status); | 75 | set_bit(idx, &bus->display_power_status); |
| 74 | else | 76 | else |
| 75 | clear_bit(idx, &bus->display_power_status); | 77 | clear_bit(idx, &bus->display_power_status); |
| 76 | 78 | ||
| 77 | if (!acomp || !acomp->ops) | 79 | if (!acomp || !acomp->ops) |
| 78 | return; | 80 | goto unlock; |
| 79 | 81 | ||
| 80 | if (bus->display_power_status) { | 82 | if (bus->display_power_status) { |
| 81 | if (!bus->display_power_active) { | 83 | if (!bus->display_power_active) { |
| @@ -92,6 +94,8 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) | |||
| 92 | bus->display_power_active = false; | 94 | bus->display_power_active = false; |
| 93 | } | 95 | } |
| 94 | } | 96 | } |
| 97 | unlock: | ||
| 98 | mutex_unlock(&bus->lock); | ||
| 95 | } | 99 | } |
| 96 | EXPORT_SYMBOL_GPL(snd_hdac_display_power); | 100 | EXPORT_SYMBOL_GPL(snd_hdac_display_power); |
| 97 | 101 | ||
