From 4bdc42094d9c4af75f90ee49b9009ea8dfe41444 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 10 Apr 2019 13:03:22 +0200
Subject: [PATCH] ALSA: hda: Fix racy display power access
Git-commit: 4bdc42094d9c4af75f90ee49b9009ea8dfe41444
Patch-mainline: v5.2-rc1
References: bsc#1156928
[ backport note: SLE15-SP1 & co still don't have bus->lock, and we can't
add this new field due to kABI compatibility.
In this patch, a global lock is used instead, which should be good enough
-- tiwai ]
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>
Cc: Imre Deak <imre.deak@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/s5h8swiunph.wl-tiwai@suse.de
---
sound/hda/hdac_component.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
--- a/sound/hda/hdac_component.c
+++ b/sound/hda/hdac_component.c
@@ -10,6 +10,8 @@
#include <sound/hda_component.h>
#include <sound/hda_register.h>
+static DEFINE_MUTEX(hdac_bus_lock);
+
static void hdac_acomp_release(struct device *dev, void *res)
{
}
@@ -71,13 +73,15 @@ int snd_hdac_display_power(struct hdac_b
dev_dbg(bus->dev, "display power %s\n",
enable ? "enable" : "disable");
+
+ mutex_lock(&hdac_bus_lock);
if (enable)
set_bit(idx, &bus->display_power_status);
else
clear_bit(idx, &bus->display_power_status);
if (!acomp || !acomp->ops)
- return 0;
+ goto unlock;
if (bus->display_power_status) {
if (!bus->display_power_active) {
@@ -95,6 +99,8 @@ int snd_hdac_display_power(struct hdac_b
}
}
+ unlock:
+ mutex_unlock(&hdac_bus_lock);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);