| Message ID | 20260731-dw-hdmi-qp-scramb-v10-29-294364b2cf15@collabora.com (mailing list archive) |
|---|---|
| State | New |
| Headers |
Return-Path: <linux-sunxi+bounces-24860-sunxi=pue.re@lists.linux.dev> X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sin.lore.kernel.org (sin.lore.kernel.org [104.64.211.4]) by mxe881.netcup.net (Postfix) with ESMTPS id EF9071C0256 for <noreply@patchwork.local>; Fri, 31 Jul 2026 19:06:32 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=collabora.com; spf=pass (sender IP is 104.64.211.4) smtp.mailfrom=linux-sunxi+bounces-24860-noreply=patchwork.local@lists.linux.dev smtp.helo=sin.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 104.64.211.4 as permitted sender) client-ip=104.64.211.4; envelope-from=linux-sunxi+bounces-24860-noreply=patchwork.local@lists.linux.dev; helo=sin.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sin.lore.kernel.org (Postfix) with ESMTP id BC05B3040F51 for <noreply@patchwork.local>; Fri, 31 Jul 2026 16:25:43 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 775E246C85C; Fri, 31 Jul 2026 16:20:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="Qpc0N2qY" X-Original-To: linux-sunxi@lists.linux.dev Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF4AE44E64E for <linux-sunxi@lists.linux.dev>; Fri, 31 Jul 2026 16:20:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785514809; cv=none; b=VAL2ZHzVsGmeWlLXL0eBGcZGgsWx3E2VOT/rmNZO/+anx200rrWdWZeLH5ifvq8+1OCBG6ReNfD3s5LaV1827DOXI1Dyrb1Gsr7ltMXPAyovnNuGcw3V1Xx+U/emjxc0hUatFsmOVAo2sQMcb9i6RdueWA+2DLDRaQPw0udVqdI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785514809; c=relaxed/simple; bh=8nvSV+nWPFUZXqT08BM59NFazu9V0O6/Yz51yOFt+3A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EiNUW0HhKfHX/cT670Iy6OyHVTjYJHkHDwG2jkh5kLaI/ednszZCUuR7DGEpTChL6Lk/l/eM0e7Rwz8GsZf9Gz/p/QjBF758zmW5XU9nv8966VzTAI7Bp3g1LkaZqnyLYaa5cLwr6xuuhcX8uTb+Q51gQECcGs5CuirDVCixhKQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=Qpc0N2qY; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785514775; bh=8nvSV+nWPFUZXqT08BM59NFazu9V0O6/Yz51yOFt+3A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Qpc0N2qY9F96XlP1jiuBu23w9d7ybxKu1jufE0iVbV4zbVzIY2sN4E2fkMZ1E7Jvj +Cd4fHq/Sh2k7ZM3aD3QF3dgNNnMesOrVP2DItVCEPHUsEmS9ZaDfFF/1Rklm7JzLp ajrm1Dbcoh8fabQEyoISX0GNotZqhPQ6SrIPDWzsKeJ78QuPgOi7A/Txl9h+RIGczh 3YnaxaroHLPuXq9ELek0WqPJ2SrYK8AKJmXYKiqALJ2c65bjupWIkJOZ6lUWhSVxBI +RqkAKltUhj0I8Dk5mp9eC349bG69lpkUZb/6MBNPMYfxmaA2b/d0RclpEdimrAfbX +1a2BF+psXVSw== Received: from localhost (unknown [100.64.0.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange secp256r1 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: cristicc) by bali.collaboradmins.com (Postfix) with ESMTPSA id A3C1817E095F; Fri, 31 Jul 2026 18:19:35 +0200 (CEST) From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> Date: Fri, 31 Jul 2026 19:19:36 +0300 Subject: [PATCH v10 29/69] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: <linux-sunxi.lists.linux.dev> List-Subscribe: <mailto:linux-sunxi+subscribe@lists.linux.dev> List-Unsubscribe: <mailto:linux-sunxi+unsubscribe@lists.linux.dev> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260731-dw-hdmi-qp-scramb-v10-29-294364b2cf15@collabora.com> References: <20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com> In-Reply-To: <20260731-dw-hdmi-qp-scramb-v10-0-294364b2cf15@collabora.com> To: Andrzej Hajda <andrzej.hajda@intel.com>, Neil Armstrong <neil.armstrong@linaro.org>, Robert Foss <rfoss@kernel.org>, Laurent Pinchart <Laurent.pinchart@ideasonboard.com>, Jonas Karlman <jonas@kwiboo.se>, Jernej Skrabec <jernej.skrabec@gmail.com>, Luca Ceresoli <luca.ceresoli@bootlin.com>, Maarten Lankhorst <maarten.lankhorst@linux.intel.com>, Maxime Ripard <mripard@kernel.org>, Thomas Zimmermann <tzimmermann@suse.de>, David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>, Chen-Yu Tsai <wens@kernel.org>, Samuel Holland <samuel@sholland.org>, Dave Stevenson <dave.stevenson@raspberrypi.com>, =?utf-8?q?Ma=C3=ADra_Canal?= <mcanal@igalia.com>, Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>, Sandy Huang <hjc@rock-chips.com>, =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>, Andy Yan <andy.yan@rock-chips.com>, Algea Cao <algea.cao@rock-chips.com>, Daniel Stone <daniels@collabora.com>, Liu Ying <victor.liu@nxp.com>, Phong LE <ple@baylibre.com> Cc: kernel@collabora.com, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-rockchip@lists.infradead.org, Sashiko <sashiko-bot@kernel.org> X-Mailer: b4 0.15.2 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= |
| Series |
Add HDMI 2.0 support to DW HDMI QP TX
|
|
Commit Message
Cristian Ciocaltea
July 31, 2026, 4:19 p.m. UTC
The system-sleep PM callbacks fetch the driver state via
dev_get_drvdata() and dereference it unconditionally. However, the
platform device is bound by ->probe(), which merely registers a
component, hence the callbacks may well run when no valid state is
available:
- Before the aggregate driver calls ->bind(), e.g. when the system
suspends while probing is still deferred waiting for the VOP,
dev_get_drvdata() returns NULL.
- After ->unbind(), or when ->bind() fails past platform_set_drvdata(),
drvdata is left pointing to memory obtained via drmm_kzalloc(), which
is released together with the DRM device, while this platform device
remains bound and PM-capable.
Publish the driver data only after ->bind() completes successfully, and
clear it in ->unbind(). This ensures that a non-NULL drvdata always
represents live state, allowing each PM callback to rely on a single
NULL check.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151550.8E14D1F000E9@smtp.kernel.org/
Closes: https://lore.kernel.org/all/20260723014811.1F9F01F000E9@smtp.kernel.org/
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
Comments
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] Use-After-Free of `hdmi` struct due to `devm_request_threaded_irq` being used in component bind, leaking the IRQ on unbind. - [High] The HPD hardirq handler checks the raw SOC status register instead of the interrupt pending status, breaking unplug detection and stealing shared IRQs. -- --- Patch [29]: [PATCH v10 29/69] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops --- commit fc12a8c8d5e7177cf76cf4554fb62df0ebde5bbd Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops The system-sleep PM callbacks fetch the driver state via dev_get_drvdata() and dereference it unconditionally. This patch ensures non-NULL drvdata always represents live state, allowing each PM callback to rely on a single NULL check. Closes: https://lore.kernel.org/all/20260702151550.8E14D1F000E9@smtp.kernel.org/ Closes: https://lore.kernel.org/all/20260723014811.1F9F01F000E9@smtp.kernel.org/ > diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c > index 9c4cf68d79d50..646a4cb968309 100644 > --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c > +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c [ ... ] > @@ -704,6 +704,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev, > { > struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); > > + dev_set_drvdata(dev, NULL); > + > cancel_delayed_work_sync(&hdmi->hpd_work); [Severity: High] This isn't a bug introduced by this patch, but is it safe to rely on devm_request_threaded_irq() for the HPD interrupt when lifecycle is managed via component bind and unbind? Looking at dw_hdmi_qp_rockchip_bind(), the IRQ is requested with devm on the component device: ret = devm_request_threaded_irq(dev, hdmi->hpd_irq, ...); Because devm resources are tied to the device's probe and remove lifecycle, the IRQ is not freed when the component is unbound. When the aggregate DRM device is torn down, hdmi (allocated via drmm_kzalloc) is freed. If the HPD interrupt fires afterwards, the still-active IRQ handler will dereference the freed hdmi pointer. Also, calling cancel_delayed_work_sync() here doesn't prevent the active IRQ handler from immediately re-arming the workqueue. Should this use a non-devm request_threaded_irq() in dw_hdmi_qp_rockchip_bind() and call free_irq() here in dw_hdmi_qp_rockchip_unbind()? [Severity: High] This is also a pre-existing issue, but does the hardirq handler properly handle interrupts on unplug events? Looking at dw_hdmi_qp_rk3588_hardirq() and dw_hdmi_qp_rk3576_hardirq(), they read the raw level register without masking: regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); if (intr_stat) { ... When the HDMI cable is unplugged, the HPD level goes to 0, which triggers the interrupt. If no other unrelated bits in this 32-bit register are set, intr_stat evaluates to 0 and the handler returns IRQ_NONE without clearing the interrupt. Could this cause the kernel to see an unhandled interrupt and disable it permanently? Conversely, if any unrelated bit is 1, it will always return IRQ_WAKE_THREAD, falsely claiming interrupts for other devices on this shared IRQ line. Should this check the interrupt pending status instead of the raw SOC status register? > }
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index 9c4cf68d79d5..646a4cb96830 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -683,8 +683,6 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, if (ret) return dev_err_probe(hdmi->dev, ret, "Failed to init encoder"); - platform_set_drvdata(pdev, hdmi); - hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); if (IS_ERR(hdmi->hdmi)) return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi), @@ -695,6 +693,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, return dev_err_probe(hdmi->dev, PTR_ERR(connector), "Failed to init bridge connector\n"); + platform_set_drvdata(pdev, hdmi); + return 0; } @@ -704,6 +704,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev, { struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); + dev_set_drvdata(dev, NULL); + cancel_delayed_work_sync(&hdmi->hpd_work); } @@ -726,7 +728,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev) { struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); - dw_hdmi_qp_suspend(dev, hdmi->hdmi); + if (hdmi) + dw_hdmi_qp_suspend(dev, hdmi->hdmi); return 0; } @@ -735,6 +738,9 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) { struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); + if (!hdmi) + return 0; + hdmi->ctrl_ops->io_init(hdmi); dw_hdmi_qp_resume(dev, hdmi->hdmi);