ALSA: hda: Modify stream stripe mask only when needed

The recent commit in HD-audio stream management for changing the
stripe control seems causing a regression on some platforms.  The
stripe control is currently used only by HDMI codec, and applying the
stripe mask unconditionally may lead to scratchy and static noises as
seen on some MacBooks.

For addressing the regression, this patch changes the stream
management code to apply the stripe mask conditionally only when the
codec driver requested.

Fixes: 9b6f7e7a29 ("ALSA: hda: program stripe bits for controller")
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204477
Tested-by: Michael Pobega <mpobega@neverware.com>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20191202074947.1617-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2019-12-02 08:49:47 +01:00
parent d2cd795c4e
commit e38e486d66
3 changed files with 18 additions and 7 deletions

View File

@ -493,6 +493,7 @@ struct hdac_stream {
bool prepared:1; bool prepared:1;
bool no_period_wakeup:1; bool no_period_wakeup:1;
bool locked:1; bool locked:1;
bool stripe:1; /* apply stripe control */
/* timestamp */ /* timestamp */
unsigned long start_wallclk; /* start + minimum wallclk */ unsigned long start_wallclk; /* start + minimum wallclk */

View File

@ -96,12 +96,14 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start)
1 << azx_dev->index, 1 << azx_dev->index,
1 << azx_dev->index); 1 << azx_dev->index);
/* set stripe control */ /* set stripe control */
if (azx_dev->substream) if (azx_dev->stripe) {
stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); if (azx_dev->substream)
else stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream);
stripe_ctl = 0; else
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, stripe_ctl = 0;
stripe_ctl); snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
stripe_ctl);
}
/* set DMA start and interrupt mask */ /* set DMA start and interrupt mask */
snd_hdac_stream_updateb(azx_dev, SD_CTL, snd_hdac_stream_updateb(azx_dev, SD_CTL,
0, SD_CTL_DMA_START | SD_INT_MASK); 0, SD_CTL_DMA_START | SD_INT_MASK);
@ -118,7 +120,10 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
snd_hdac_stream_updateb(azx_dev, SD_CTL, snd_hdac_stream_updateb(azx_dev, SD_CTL,
SD_CTL_DMA_START | SD_INT_MASK, 0); SD_CTL_DMA_START | SD_INT_MASK, 0);
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); if (azx_dev->stripe) {
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
azx_dev->stripe = 0;
}
azx_dev->running = false; azx_dev->running = false;
} }
EXPORT_SYMBOL_GPL(snd_hdac_stream_clear); EXPORT_SYMBOL_GPL(snd_hdac_stream_clear);

View File

@ -32,6 +32,7 @@
#include <sound/hda_codec.h> #include <sound/hda_codec.h>
#include "hda_local.h" #include "hda_local.h"
#include "hda_jack.h" #include "hda_jack.h"
#include "hda_controller.h"
static bool static_hdmi_pcm; static bool static_hdmi_pcm;
module_param(static_hdmi_pcm, bool, 0644); module_param(static_hdmi_pcm, bool, 0644);
@ -1249,6 +1250,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
per_pin->cvt_nid = per_cvt->cvt_nid; per_pin->cvt_nid = per_cvt->cvt_nid;
hinfo->nid = per_cvt->cvt_nid; hinfo->nid = per_cvt->cvt_nid;
/* flip stripe flag for the assigned stream if supported */
if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
azx_stream(get_azx_dev(substream))->stripe = 1;
snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id); snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,