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 | ||