summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-04-10 06:49:55 -0400
committerTakashi Iwai <tiwai@suse.de>2019-04-10 09:23:36 -0400
commitd7a181da2dfa3190487c446042ba01e07d851c74 (patch)
treec2c281018d0a0dd56e792e0fca49af8313d5a30b
parentcae30527901d9590db0e12ace994c1d58bea87fd (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.c1
-rw-r--r--sound/hda/hdac_bus.c1
-rw-r--r--sound/hda/hdac_component.c6
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}
96EXPORT_SYMBOL_GPL(snd_hdac_display_power); 100EXPORT_SYMBOL_GPL(snd_hdac_display_power);
97 101