diff mbox series

drm/display: bridge_connector: Do atomic check when necessary

Message ID 20250108101351.2599140-1-victor.liu@nxp.com (mailing list archive)
State New
Headers show
Series drm/display: bridge_connector: Do atomic check when necessary | expand

Commit Message

Liu Ying Jan. 8, 2025, 10:13 a.m. UTC
It's ok to pass atomic check successfully if an atomic commit tries to
disable the display pipeline which the connector belongs to. That is,
when the crtc or the best_encoder pointers in struct drm_connector_state
are NULL, drm_bridge_connector_atomic_check() should return 0 directly.
Without the check against the NULL pointers, drm_default_rgb_quant_range()
called by drm_atomic_helper_connector_hdmi_check() would dereference
the NULL pointer to_match in drm_match_cea_mode().

[   46.189903] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[   46.189906] Mem abort info:
[   46.189908]   ESR = 0x0000000096000004
[   46.189910]   EC = 0x25: DABT (current EL), IL = 32 bits
[   46.189914]   SET = 0, FnV = 0
[   46.189917]   EA = 0, S1PTW = 0
[   46.189919]   FSC = 0x04: level 0 translation fault
[   46.189922] Data abort info:
[   46.189923]   ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
[   46.189926]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[   46.189929]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[   46.189932] user pgtable: 4k pages, 48-bit VAs, pgdp=000000010b6b4000
[   46.189936] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000
[   46.189945] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP
[   46.719532] Modules linked in: caam_jr caamhash_desc caamalg_desc dw_hdmi_cec crypto_engine snd_soc_hdmi_codec authenc libdes hantro_vpu mwifiex_pcie mwifiex v4l2_vp9 v4l2_h264 imx8
mp_hdmi_tx v4l2_jpeg v4l2_mem2mem dw_hdmi videobuf2_dma_contig videobuf2_memops ite_it6263 videobuf2_v4l2 snd_soc_simple_card drm_display_helper videodev snd_soc_wm8960 snd_soc_simple_
card_utils fsl_ldb samsung_dsim videobuf2_common etnaviv mc fsl_imx8_ddr_perf gpu_sched imx_lcdif adv7511 phy_fsl_samsung_hdmi drm_client_lib snd_soc_fsl_micfil drm_dma_helper cec imx8
mp_hdmi_pvi snd_soc_fsl_sai imx_pcm_dma snd_soc_fsl_utils rtc_snvs pwm_imx27 snvs_pwrkey flexcan caam can_dev error imx8mm_thermal imx_sdma coresight_tmc display_connector drm_kms_help
er snd_soc_bt_sco imx_cpufreq_dt coresight_funnel coresight overlay bluetooth ecdh_generic ecc cfg80211 rfkill drm fuse backlight ipv6
[   46.795415] CPU: 3 UID: 0 PID: 64 Comm: kworker/3:1 Not tainted 6.13.0-rc6-next-20250107-00009-g045f95f0de2e #1637
[   46.805767] Hardware name: NXP i.MX8MPlus EVK board (DT)
[   46.811078] Workqueue: events drm_mode_rmfb_work_fn [drm]
[   46.816619] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[   46.823581] pc : drm_default_rgb_quant_range+0x0/0x4c [drm]
[   46.829244] lr : drm_atomic_helper_connector_hdmi_check+0xb0/0x6b0 [drm_display_helper]
[   46.837293] sp : ffff80008364ba00
[   46.840605] x29: ffff80008364ba10 x28: ffff0000c8955080 x27: ffff0000c2e1c700
[   46.847743] x26: ffff0000d3887200 x25: ffff0000c2e1c700 x24: ffff0000d3887400
[   46.854881] x23: 0000000000000001 x22: 0000000000000000 x21: ffff0000c8955080
[   46.862019] x20: 0000000000000001 x19: ffff0000d3887c00 x18: 00000000ffffffff
[   46.869157] x17: 0000000000000000 x16: 0000000000000000 x15: ffff800082ce6911
[   46.876293] x14: 0000000000000001 x13: ffff8000827e4a88 x12: 00000000000015f0
[   46.883435] x11: 0000000000000750 x10: ffff80008283ca88 x9 : ffff8000827e4a88
[   46.890573] x8 : 00000000ffffefff x7 : 0000000000000038 x6 : ffff0000db2c3440
[   46.897711] x5 : 0000000000000001 x4 : 0000000000000038 x3 : ffff0000db2c3440
[   46.904847] x2 : 0000000000000000 x1 : 0000000000000001 x0 : 0000000000000000
[   46.911984] Call trace:
[   46.914429]  drm_default_rgb_quant_range+0x0/0x4c [drm] (P)
[   46.920106]  drm_bridge_connector_atomic_check+0x20/0x2c [drm_display_helper]
[   46.927275]  drm_atomic_helper_check_modeset+0x488/0xc78 [drm_kms_helper]
[   46.934111]  drm_atomic_helper_check+0x20/0xa4 [drm_kms_helper]
[   46.940063]  drm_atomic_check_only+0x4b8/0x984 [drm]
[   46.945136]  drm_atomic_commit+0x48/0xc4 [drm]
[   46.949674]  drm_framebuffer_remove+0x44c/0x530 [drm]
[   46.954809]  drm_mode_rmfb_work_fn+0x7c/0xa0 [drm]
[   46.959687]  process_one_work+0x150/0x294
[   46.963700]  worker_thread+0x2dc/0x3dc
[   46.967450]  kthread+0x130/0x204
[   46.970679]  ret_from_fork+0x10/0x20
[   46.974258] Code: d50323bf d65f03c0 52800041 17ffffe6 (b9400001)
[   46.980350] ---[ end trace 0000000000000000 ]---

Fixes: 8ec116ff21a9 ("drm/display: bridge_connector: provide atomic_check for HDMI bridges")
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 5 +++++
 1 file changed, 5 insertions(+)

Comments

Dmitry Baryshkov Jan. 8, 2025, 10:28 a.m. UTC | #1
On Wed, Jan 08, 2025 at 06:13:51PM +0800, Liu Ying wrote:
> It's ok to pass atomic check successfully if an atomic commit tries to
> disable the display pipeline which the connector belongs to. That is,
> when the crtc or the best_encoder pointers in struct drm_connector_state
> are NULL, drm_bridge_connector_atomic_check() should return 0 directly.
> Without the check against the NULL pointers, drm_default_rgb_quant_range()
> called by drm_atomic_helper_connector_hdmi_check() would dereference
> the NULL pointer to_match in drm_match_cea_mode().
> 

[..]

> [   46.823581] pc : drm_default_rgb_quant_range+0x0/0x4c [drm]
> [   46.829244] lr : drm_atomic_helper_connector_hdmi_check+0xb0/0x6b0 [drm_display_helper]
> [   46.837293] sp : ffff80008364ba00

[..]

> [   46.911984] Call trace:
> [   46.914429]  drm_default_rgb_quant_range+0x0/0x4c [drm] (P)
> [   46.920106]  drm_bridge_connector_atomic_check+0x20/0x2c [drm_display_helper]
> [   46.927275]  drm_atomic_helper_check_modeset+0x488/0xc78 [drm_kms_helper]
> [   46.934111]  drm_atomic_helper_check+0x20/0xa4 [drm_kms_helper]
> [   46.940063]  drm_atomic_check_only+0x4b8/0x984 [drm]
> [   46.945136]  drm_atomic_commit+0x48/0xc4 [drm]
> [   46.949674]  drm_framebuffer_remove+0x44c/0x530 [drm]
> [   46.954809]  drm_mode_rmfb_work_fn+0x7c/0xa0 [drm]
> [   46.959687]  process_one_work+0x150/0x294
> [   46.963700]  worker_thread+0x2dc/0x3dc
> [   46.967450]  kthread+0x130/0x204
> [   46.970679]  ret_from_fork+0x10/0x20
> [   46.974258] Code: d50323bf d65f03c0 52800041 17ffffe6 (b9400001)
> [   46.980350] ---[ end trace 0000000000000000 ]---

Please trim the backtrace in a way I trimmed it. Also you can drop the
timestamps, they don't have useful information.

> 
> Fixes: 8ec116ff21a9 ("drm/display: bridge_connector: provide atomic_check for HDMI bridges")
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  drivers/gpu/drm/display/drm_bridge_connector.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
> index 32108307de66..587020a3f3e8 100644
> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> @@ -343,6 +343,11 @@ static int drm_bridge_connector_atomic_check(struct drm_connector *connector,
>  {
>  	struct drm_bridge_connector *bridge_connector =
>  		to_drm_bridge_connector(connector);
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, connector);
> +
> +	if (!new_conn_state->crtc || !new_conn_state->best_encoder)
> +		return 0;

Unfortunately, this is not enough. Other drivers (e.g. sun4i) use
drm_atomic_helper_connector_hdmi_check() at connector's atomic_check()
function. Please move necessary checks to the helper itself. Also please
add corresponding KUnit test: attempt to atomic_check() the unconnected
HDMI connector, there is a test suite for the HDMI connector functions,
but the atomic_check() for the disconnected connecor seems to be missing.

>  
>  	if (bridge_connector->bridge_hdmi)
>  		return drm_atomic_helper_connector_hdmi_check(connector, state);
> -- 
> 2.34.1
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 32108307de66..587020a3f3e8 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -343,6 +343,11 @@  static int drm_bridge_connector_atomic_check(struct drm_connector *connector,
 {
 	struct drm_bridge_connector *bridge_connector =
 		to_drm_bridge_connector(connector);
+	struct drm_connector_state *new_conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
+
+	if (!new_conn_state->crtc || !new_conn_state->best_encoder)
+		return 0;
 
 	if (bridge_connector->bridge_hdmi)
 		return drm_atomic_helper_connector_hdmi_check(connector, state);