Skip to content

Commit 5f7e54b

Browse files
committed
ALSA: hda: Handle the jack polling always via a work
We used to call directly hda_jackpoll_work() from a couple of places for updating the jack and notify to user-space, but this makes rather the code flow fragile. Namely, because of those direct calls, hda_jackpoll_work() uses snd_hda_power_up_pm() and *_down_pm() calls instead of the standard snd_hda_power_up() and *_down() calls. The latter pair assures the runtime PM resume sync, so it can avoid the race against the PM callbacks gracefully, while the former pair may continue if called concurrently, hence it may race (by design). In this patch, we change the call pattern of hda_jackpoll_work(); now all callers are replaced with the standard snd_hda_jack_report_sync() and the additional schedule_delayed_work(). Since hda_jackpoll_work() is called only from the associated work, it's always outside the PM code path, and we can safely use snd_hda_power_up() and *_down() there instead. This allows us to remove the racy check of power-state in hda_jackpoll_work(), as well as the tricky cancel_delayed_work() and rescheduling at hda_codec_runtime_suspend(). Reported-by: Joakim Zhang <joakim.zhang@cixtech.com> Closes: https://lore.kernel.org/20250619020844.2974160-1-joakim.zhang@cixtech.com Tested-by: Joakim Zhang <joakim.zhang@cixtech.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20250623131437.10670-4-tiwai@suse.de
1 parent 507cd12 commit 5f7e54b

1 file changed

Lines changed: 14 additions & 27 deletions

File tree

sound/pci/hda/hda_codec.c

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -639,24 +639,16 @@ static void hda_jackpoll_work(struct work_struct *work)
639639
struct hda_codec *codec =
640640
container_of(work, struct hda_codec, jackpoll_work.work);
641641

642-
/* for non-polling trigger: we need nothing if already powered on */
643-
if (!codec->jackpoll_interval && snd_hdac_is_power_on(&codec->core))
642+
if (!codec->jackpoll_interval)
644643
return;
645644

646645
/* the power-up/down sequence triggers the runtime resume */
647-
snd_hda_power_up_pm(codec);
646+
snd_hda_power_up(codec);
648647
/* update jacks manually if polling is required, too */
649-
if (codec->jackpoll_interval) {
650-
snd_hda_jack_set_dirty_all(codec);
651-
snd_hda_jack_poll_all(codec);
652-
}
653-
snd_hda_power_down_pm(codec);
654-
655-
if (!codec->jackpoll_interval)
656-
return;
657-
658-
schedule_delayed_work(&codec->jackpoll_work,
659-
codec->jackpoll_interval);
648+
snd_hda_jack_set_dirty_all(codec);
649+
snd_hda_jack_poll_all(codec);
650+
schedule_delayed_work(&codec->jackpoll_work, codec->jackpoll_interval);
651+
snd_hda_power_down(codec);
660652
}
661653

662654
/* release all pincfg lists */
@@ -2895,12 +2887,12 @@ static void hda_call_codec_resume(struct hda_codec *codec)
28952887
snd_hda_regmap_sync(codec);
28962888
}
28972889

2898-
if (codec->jackpoll_interval)
2899-
hda_jackpoll_work(&codec->jackpoll_work.work);
2900-
else
2901-
snd_hda_jack_report_sync(codec);
2890+
snd_hda_jack_report_sync(codec);
29022891
codec->core.dev.power.power_state = PMSG_ON;
29032892
snd_hdac_leave_pm(&codec->core);
2893+
if (codec->jackpoll_interval)
2894+
schedule_delayed_work(&codec->jackpoll_work,
2895+
codec->jackpoll_interval);
29042896
}
29052897

29062898
static int hda_codec_runtime_suspend(struct device *dev)
@@ -2912,19 +2904,13 @@ static int hda_codec_runtime_suspend(struct device *dev)
29122904
if (!codec->card)
29132905
return 0;
29142906

2915-
cancel_delayed_work_sync(&codec->jackpoll_work);
2916-
29172907
state = hda_call_codec_suspend(codec);
29182908
if (codec->link_down_at_suspend ||
29192909
(codec_has_clkstop(codec) && codec_has_epss(codec) &&
29202910
(state & AC_PWRST_CLK_STOP_OK)))
29212911
snd_hdac_codec_link_down(&codec->core);
29222912
snd_hda_codec_display_power(codec, false);
29232913

2924-
if (codec->bus->jackpoll_in_suspend &&
2925-
(dev->power.power_state.event != PM_EVENT_SUSPEND))
2926-
schedule_delayed_work(&codec->jackpoll_work,
2927-
codec->jackpoll_interval);
29282914
return 0;
29292915
}
29302916

@@ -3097,10 +3083,11 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
30973083
if (err < 0)
30983084
return err;
30993085

3086+
snd_hda_jack_report_sync(codec); /* call at the last init point */
31003087
if (codec->jackpoll_interval)
3101-
hda_jackpoll_work(&codec->jackpoll_work.work);
3102-
else
3103-
snd_hda_jack_report_sync(codec); /* call at the last init point */
3088+
schedule_delayed_work(&codec->jackpoll_work,
3089+
codec->jackpoll_interval);
3090+
31043091
sync_power_up_states(codec);
31053092
return 0;
31063093
}

0 commit comments

Comments
 (0)