Skip to contentSkip to conversation

drm/bridge: dw-hdmi-qp: Guard clear_audio_infoframe when PHY is down

PATCH Superseded Frank Zhang 2 participants 2 messages Apr 16 – Apr 17

Subsystems (4)

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 drm/bridge: dw-hdmi-qp: Guard clear_audio_infoframe when PHY is down

The following panic was observed during system reboot:

Kernel panic - not syncing: Asynchronous SError Interrupt
CPU: 7 UID: 1000 PID: 2637 Comm: pipewire ... 6.19.10-300.fc44.aarch64
Call trace:
 ...
 regmap_update_bits_base+0x5c/0x90
 dw_hdmi_qp_bridge_clear_infoframe+0xb0/0x120 [dw_hdmi_qp]
 drm_bridge_connector_clear_infoframe+0x28/0x48 [drm_display_helper]
 ...
 dw_hdmi_qp_audio_disable+0x24/0xb8 [dw_hdmi_qp]
 drm_bridge_connector_audio_shutdown+0x30/0x60 [drm_display_helper]
 drm_connector_hdmi_audio_shutdown+0x24/0x38 [drm_display_helper]
 hdmi_codec_shutdown+0x60/0x90 [snd_soc_hdmi_codec]
 ...
 snd_pcm_release_substream.part.0+0x44/0xd8 [snd_pcm]
 snd_pcm_release+0x60/0xe8 [snd_pcm]
 ...

The root cause is pipewire tries to close the HDMI audio device after atomic_disable(), which sets tmds_char_rate to 0 and disable the PHY.

In this case, dw_hdmi_qp_audio_disable() will call clear_audio_infoframe(), accessing registers without checking tmds_char_rate.

Add a tmds_char_rate check in dw_hdmi_qp_bridge_clear_audio_infoframe() to skip the register write when the PHY is inactive.

drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +6 -5
index d649a1cf07f5..f963dff81dc6 100644
@@ -886,11 +886,12 @@ static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	dw_hdmi_qp_mod(hdmi, 0,
-		       PKTSCHED_ACR_TX_EN |
-		       PKTSCHED_AUDS_TX_EN |
-		       PKTSCHED_AUDI_TX_EN,
-		       PKTSCHED_PKT_EN);
+	if (hdmi->tmds_char_rate)
+		dw_hdmi_qp_mod(hdmi, 0,
+			       PKTSCHED_ACR_TX_EN |
+			       PKTSCHED_AUDS_TX_EN |
+			       PKTSCHED_AUDI_TX_EN,
+			       PKTSCHED_PKT_EN);
 
 	return 0;
 }
Signature · 1 line
2.53.0
#1 lore raw

Hi Frank,

Please add me to CC if you send a v2.

Quoted 22 lines · Frank Zhang

The following panic was observed during system reboot:

Kernel panic - not syncing: Asynchronous SError Interrupt
CPU: 7 UID: 1000 PID: 2637 Comm: pipewire ... 6.19.10-300.fc44.aarch64
Call trace:
  ...
  regmap_update_bits_base+0x5c/0x90
  dw_hdmi_qp_bridge_clear_infoframe+0xb0/0x120 [dw_hdmi_qp]
  drm_bridge_connector_clear_infoframe+0x28/0x48 [drm_display_helper]
  ...
  dw_hdmi_qp_audio_disable+0x24/0xb8 [dw_hdmi_qp]
  drm_bridge_connector_audio_shutdown+0x30/0x60 [drm_display_helper]
  drm_connector_hdmi_audio_shutdown+0x24/0x38 [drm_display_helper]
  hdmi_codec_shutdown+0x60/0x90 [snd_soc_hdmi_codec]
  ...
  snd_pcm_release_substream.part.0+0x44/0xd8 [snd_pcm]
  snd_pcm_release+0x60/0xe8 [snd_pcm]
  ...

The root cause is pipewire tries to close the HDMI audio device after atomic_disable(), which sets tmds_char_rate to 0 and disable the PHY.

Quoted 8 lines

In this case, dw_hdmi_qp_audio_disable() will call clear_audio_infoframe(), accessing registers without checking tmds_char_rate.

Add a tmds_char_rate check in dw_hdmi_qp_bridge_clear_audio_infoframe() to skip the register write when the PHY is inactive.

Add a "Fixes:" tag so this gets backported were needed.

Quoted 5 lines
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +0 -0
index d649a1cf07f5..f963dff81dc6 100644

drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge) · line 889

Quoted 9 lines
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +1 -5
@@ -886,11 +886,12 @@ static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
  {
  	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	dw_hdmi_qp_mod(hdmi, 0,
-		       PKTSCHED_ACR_TX_EN |
-		       PKTSCHED_AUDS_TX_EN |
-		       PKTSCHED_AUDI_TX_EN,
-		       PKTSCHED_PKT_EN);
+	if (hdmi->tmds_char_rate)

I'd rather move the call to drm_atomic_helper_connector_hdmi_clear_audio_infoframe() inside the if (hdmi->tmds_char_rate) of dw_hdmi_qp_audio_disable(). There is no need to check for tmds_char_rate in every dw_hdmi_qp_bridge_clear_audio_infoframe() call.

drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge) · line 897

Quoted 8 lines
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +5 -0
+		dw_hdmi_qp_mod(hdmi, 0,
+			       PKTSCHED_ACR_TX_EN |
+			       PKTSCHED_AUDS_TX_EN |
+			       PKTSCHED_AUDI_TX_EN,
+			       PKTSCHED_PKT_EN);
 
  	return 0;
  }

Regards,
Detlev.