diff mbox series

[1/3] ALSA: hda/hdmi: fix i915 silent stream programming flow

Message ID 20221208154358.3848764-2-kai.vehmanen@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series ALSA: hda/hdmi: i915 keepalive fixes | expand

Commit Message

Kai Vehmanen Dec. 8, 2022, 3:43 p.m. UTC
The i915 display codec may not successfully transition to
normal audio streaming mode, if the stream id is programmed
while codec is actively transmitting data. This can happen
when silent stream is enabled in KAE mode.

Fix the issue by implementing a i915 specific programming
flow, where the silent streaming is temporarily stopped,
a small delay is applied to ensure display codec becomes
idle, and then proceed with reprogramming the stream ID.

Fixes: 15175a4f2bbb ("ALSA: hda/hdmi: add keep-alive support for ADL-P and DG2")
Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7353
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Tested-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
---
 sound/pci/hda/patch_hdmi.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

Comments

Amadeusz Sławiński Dec. 8, 2022, 4:25 p.m. UTC | #1
On 12/8/2022 4:43 PM, Kai Vehmanen wrote:
> The i915 display codec may not successfully transition to
> normal audio streaming mode, if the stream id is programmed
> while codec is actively transmitting data. This can happen
> when silent stream is enabled in KAE mode.
> 
> Fix the issue by implementing a i915 specific programming
> flow, where the silent streaming is temporarily stopped,
> a small delay is applied to ensure display codec becomes
> idle, and then proceed with reprogramming the stream ID.
> 
> Fixes: 15175a4f2bbb ("ALSA: hda/hdmi: add keep-alive support for ADL-P and DG2")
> Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7353
> Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Tested-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> ---
>   sound/pci/hda/patch_hdmi.c | 23 +++++++++++++++++++++--
>   1 file changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index 7a40ddfd695a..a0ba24165ae2 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -2879,9 +2879,28 @@ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
>   				 hda_nid_t pin_nid, int dev_id, u32 stream_tag,
>   				 int format)
>   {
> +	struct hdmi_spec *spec = codec->spec;
> +	int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);

Shouldn't return value from pin_id_to_pin_index() be checked? It seems 
that it can return -EINVAL.

> +	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
> +	int res;
> +
>   	haswell_verify_D0(codec, cvt_nid, pin_nid);
> -	return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
> -				 stream_tag, format);
> +
> +	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
> +		silent_stream_set_kae(codec, per_pin, false);
> +		/* wait for pending transfers in codec to clear */
> +		usleep_range(100, 200);
> +	}
> +
> +	res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
> +				stream_tag, format);
> +
> +	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
> +		usleep_range(100, 200);
> +		silent_stream_set_kae(codec, per_pin, true);
> +	}
> +
> +	return res;
>   }
>   
>   /* pin_cvt_fixup ops override for HSW+ and VLV+ */
Kai Vehmanen Dec. 9, 2022, 8:42 a.m. UTC | #2
Hi,

On Thu, 8 Dec 2022, Amadeusz Sławiński wrote:

> On 12/8/2022 4:43 PM, Kai Vehmanen wrote:
> > @@ -2879,9 +2879,28 @@ static int i915_hsw_setup_stream(struct hda_codec
> > *codec, hda_nid_t cvt_nid,
> >   				 hda_nid_t pin_nid, int dev_id, u32
> > stream_tag,
> >   				 int format)
> >   {
> > +	struct hdmi_spec *spec = codec->spec;
> > +	int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
> 
> Shouldn't return value from pin_id_to_pin_index() be checked? It seems that it
> can return -EINVAL.

that's a good point. I think we are safe with current code as setup_stream 
ops is only called from generic_hdmi_playback_pcm_prepare() and 
spec->ops.setup_stream() there is only called with a valid pin. But this 
leaves room for future errors, and passing negative index to get_pin() is 
pretty bad. Let me send a V2 later today.

Thanks for the review!

Br, Kai
diff mbox series

Patch

diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 7a40ddfd695a..a0ba24165ae2 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -2879,9 +2879,28 @@  static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
 				 hda_nid_t pin_nid, int dev_id, u32 stream_tag,
 				 int format)
 {
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+	int res;
+
 	haswell_verify_D0(codec, cvt_nid, pin_nid);
-	return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
-				 stream_tag, format);
+
+	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+		silent_stream_set_kae(codec, per_pin, false);
+		/* wait for pending transfers in codec to clear */
+		usleep_range(100, 200);
+	}
+
+	res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+				stream_tag, format);
+
+	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+		usleep_range(100, 200);
+		silent_stream_set_kae(codec, per_pin, true);
+	}
+
+	return res;
 }
 
 /* pin_cvt_fixup ops override for HSW+ and VLV+ */