summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorMohan Kumar <mkumard@nvidia.com>2022-08-11 10:57:04 +0530
committerTakashi Iwai <tiwai@suse.de>2022-08-11 07:44:59 +0200
commit636aa8807b5780b76609b40cd3d3e1b5a225471c (patch)
tree1d518f4af25362986b7d7f1fd44af2f591760158 /sound
parent74bba640d69914cf832b87f6bbb700e5ba430672 (diff)
ALSA: hda: Fix crash due to jack poll in suspend
With jackpoll_in_suspend flag set, there is a possibility that jack poll worker thread will run even after system suspend was completed. Any register access after system pm callback flow will result in kernel crash as still jack poll worker thread tries to access registers. To fix the crash issue during system flow, cancel the jack poll worker thread during system pm prepare callback and cancel the worker thread at start of runtime suspend callback and re-schedule at last to avoid any unwarranted access of register by worker thread during suspend flow. Signed-off-by: Mohan Kumar <mkumard@nvidia.com> Fixes: b33115bd05af ("ALSA: hda: Jack detection poll in suspend state") Link: https://lore.kernel.org/r/20220811052704.2944-1-mkumard@nvidia.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_codec.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 7b2e62fa82d5..384426d7e9dd 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2940,8 +2940,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
if (!codec->card)
return 0;
- if (!codec->bus->jackpoll_in_suspend)
- cancel_delayed_work_sync(&codec->jackpoll_work);
+ cancel_delayed_work_sync(&codec->jackpoll_work);
state = hda_call_codec_suspend(codec);
if (codec->link_down_at_suspend ||
@@ -2949,6 +2948,11 @@ static int hda_codec_runtime_suspend(struct device *dev)
(state & AC_PWRST_CLK_STOP_OK)))
snd_hdac_codec_link_down(&codec->core);
snd_hda_codec_display_power(codec, false);
+
+ if (codec->bus->jackpoll_in_suspend &&
+ (dev->power.power_state.event != PM_EVENT_SUSPEND))
+ schedule_delayed_work(&codec->jackpoll_work,
+ codec->jackpoll_interval);
return 0;
}
@@ -2972,6 +2976,9 @@ static int hda_codec_runtime_resume(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int hda_codec_pm_prepare(struct device *dev)
{
+ struct hda_codec *codec = dev_to_hda_codec(dev);
+
+ cancel_delayed_work_sync(&codec->jackpoll_work);
dev->power.power_state = PMSG_SUSPEND;
return pm_runtime_suspended(dev);
}
@@ -2991,9 +2998,6 @@ static void hda_codec_pm_complete(struct device *dev)
static int hda_codec_pm_suspend(struct device *dev)
{
- struct hda_codec *codec = dev_to_hda_codec(dev);
-
- cancel_delayed_work_sync(&codec->jackpoll_work);
dev->power.power_state = PMSG_SUSPEND;
return pm_runtime_force_suspend(dev);
}