Skip to content

Commit f5dac54

Browse files
Kai-Heng Fengtiwai
authored andcommitted
ALSA: hda: Separate runtime and system suspend
Both pm_runtime_force_suspend() and pm_runtime_force_resume() have some implicit checks, so it can make code flow more straightforward if we separate runtime and system suspend callbacks. High Definition Audio Specification, 4.5.9.3 Codec Wake From System S3 states that codec can wake the system up from S3 if WAKEEN is toggled. Since HDA controller has different wakeup settings for runtime and system susend, we also need to explicitly disable direct-complete which can be enabled automatically by PCI core. In addition to that, avoid waking up codec if runtime resume is for system suspend, to not break direct-complete for codecs. While at it, also remove AZX_DCAPS_SUSPEND_SPURIOUS_WAKEUP, as the original bug commit a663052 ("ALSA: hda: Workaround for spurious wakeups on some Intel platforms") solves doesn't happen with this patch. Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Link: https://lore.kernel.org/r/20201027130038.16463-3-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 215a22e commit f5dac54

2 files changed

Lines changed: 36 additions & 29 deletions

File tree

sound/pci/hda/hda_controller.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
/* 24 unused */
4242
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
4343
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
44-
#define AZX_DCAPS_SUSPEND_SPURIOUS_WAKEUP (1 << 27) /* Workaround for spurious wakeups after suspend */
44+
/* 27 unused */
4545
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
4646
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
4747
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
@@ -143,6 +143,7 @@ struct azx {
143143
unsigned int align_buffer_size:1;
144144
unsigned int region_requested:1;
145145
unsigned int disabled:1; /* disabled by vga_switcheroo */
146+
unsigned int pm_prepared:1;
146147

147148
/* GTS present */
148149
unsigned int gts_present:1;

sound/pci/hda/hda_intel.c

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,7 @@ enum {
297297
/* PCH for HSW/BDW; with runtime PM */
298298
/* no i915 binding for this as HSW/BDW has another controller for HDMI */
299299
#define AZX_DCAPS_INTEL_PCH \
300-
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
301-
AZX_DCAPS_SUSPEND_SPURIOUS_WAKEUP)
300+
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME)
302301

303302
/* HSW HDMI */
304303
#define AZX_DCAPS_INTEL_HASWELL \
@@ -985,7 +984,7 @@ static void __azx_runtime_suspend(struct azx *chip)
985984
display_power(chip, false);
986985
}
987986

988-
static void __azx_runtime_resume(struct azx *chip, bool from_rt)
987+
static void __azx_runtime_resume(struct azx *chip)
989988
{
990989
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
991990
struct hdac_bus *bus = azx_bus(chip);
@@ -1002,7 +1001,8 @@ static void __azx_runtime_resume(struct azx *chip, bool from_rt)
10021001
azx_init_pci(chip);
10031002
hda_intel_init_chip(chip, true);
10041003

1005-
if (from_rt) {
1004+
/* Avoid codec resume if runtime resume is for system suspend */
1005+
if (!chip->pm_prepared) {
10061006
list_for_each_codec(codec, &chip->bus) {
10071007
if (codec->relaxed_resume)
10081008
continue;
@@ -1018,6 +1018,29 @@ static void __azx_runtime_resume(struct azx *chip, bool from_rt)
10181018
}
10191019

10201020
#ifdef CONFIG_PM_SLEEP
1021+
static int azx_prepare(struct device *dev)
1022+
{
1023+
struct snd_card *card = dev_get_drvdata(dev);
1024+
struct azx *chip;
1025+
1026+
chip = card->private_data;
1027+
chip->pm_prepared = 1;
1028+
1029+
/* HDA controller always requires different WAKEEN for runtime suspend
1030+
* and system suspend, so don't use direct-complete here.
1031+
*/
1032+
return 0;
1033+
}
1034+
1035+
static void azx_complete(struct device *dev)
1036+
{
1037+
struct snd_card *card = dev_get_drvdata(dev);
1038+
struct azx *chip;
1039+
1040+
chip = card->private_data;
1041+
chip->pm_prepared = 0;
1042+
}
1043+
10211044
static int azx_suspend(struct device *dev)
10221045
{
10231046
struct snd_card *card = dev_get_drvdata(dev);
@@ -1029,15 +1052,7 @@ static int azx_suspend(struct device *dev)
10291052

10301053
chip = card->private_data;
10311054
bus = azx_bus(chip);
1032-
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
1033-
/* An ugly workaround: direct call of __azx_runtime_suspend() and
1034-
* __azx_runtime_resume() for old Intel platforms that suffer from
1035-
* spurious wakeups after S3 suspend
1036-
*/
1037-
if (chip->driver_caps & AZX_DCAPS_SUSPEND_SPURIOUS_WAKEUP)
1038-
__azx_runtime_suspend(chip);
1039-
else
1040-
pm_runtime_force_suspend(dev);
1055+
__azx_runtime_suspend(chip);
10411056
if (bus->irq >= 0) {
10421057
free_irq(bus->irq, chip);
10431058
bus->irq = -1;
@@ -1066,11 +1081,7 @@ static int azx_resume(struct device *dev)
10661081
if (azx_acquire_irq(chip, 1) < 0)
10671082
return -EIO;
10681083

1069-
if (chip->driver_caps & AZX_DCAPS_SUSPEND_SPURIOUS_WAKEUP)
1070-
__azx_runtime_resume(chip, false);
1071-
else
1072-
pm_runtime_force_resume(dev);
1073-
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
1084+
__azx_runtime_resume(chip);
10741085

10751086
trace_azx_resume(chip);
10761087
return 0;
@@ -1118,10 +1129,7 @@ static int azx_runtime_suspend(struct device *dev)
11181129
chip = card->private_data;
11191130

11201131
/* enable controller wake up event */
1121-
if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) {
1122-
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
1123-
STATESTS_INT_MASK);
1124-
}
1132+
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK);
11251133

11261134
__azx_runtime_suspend(chip);
11271135
trace_azx_runtime_suspend(chip);
@@ -1132,18 +1140,14 @@ static int azx_runtime_resume(struct device *dev)
11321140
{
11331141
struct snd_card *card = dev_get_drvdata(dev);
11341142
struct azx *chip;
1135-
bool from_rt = snd_power_get_state(card) == SNDRV_CTL_POWER_D0;
11361143

11371144
if (!azx_is_pm_ready(card))
11381145
return 0;
11391146
chip = card->private_data;
1140-
__azx_runtime_resume(chip, from_rt);
1147+
__azx_runtime_resume(chip);
11411148

11421149
/* disable controller Wake Up event*/
1143-
if (from_rt) {
1144-
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
1145-
~STATESTS_INT_MASK);
1146-
}
1150+
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK);
11471151

11481152
trace_azx_runtime_resume(chip);
11491153
return 0;
@@ -1177,6 +1181,8 @@ static int azx_runtime_idle(struct device *dev)
11771181
static const struct dev_pm_ops azx_pm = {
11781182
SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
11791183
#ifdef CONFIG_PM_SLEEP
1184+
.prepare = azx_prepare,
1185+
.complete = azx_complete,
11801186
.freeze_noirq = azx_freeze_noirq,
11811187
.thaw_noirq = azx_thaw_noirq,
11821188
#endif

0 commit comments

Comments
 (0)