* [PATCH v2] drm/msm/dp: hold one runtime PM reference per plugged state
@ 2026-10-07 15:58 Joonhoe Kim
2026-10-24 2:58 ` [v2] " Val Packett
0 siblings, 1 reply; 3+ messages in thread
From: Joonhoe Kim @ 2026-10-07 15:58 UTC (permalink / raw)
To: robin.clark, lumag
Cc: abhinav.kumar, jesszhan0024, sean, marijn.suijten, airlied,
simona, yongxing.mou, val, linux-arm-msm, dri-devel, freedreno,
linux-kernel
The plug handler takes a runtime PM reference every time it runs and
sets dp->plugged; the unplug handler drops a single reference when
dp->plugged is set. msm_dp_bridge_detect() also takes a reference and
marks the sink plugged, and keeps that reference as well -- on every
detect while the sink stays connected. On top of that, in the current
tree the plug handler runs more than once per plug:
drm_bridge_connector_detect() calls .detect() and then .hpd_notify(),
and pmic_glink altmode reports an IRQ_HPD as "connected" too. Every
extra reference is leaked on unplug.
On a Lenovo TB323FU (SM8850, DP over the USB-C port via pmic_glink
altmode) the DP controller's usage count reached 28-34 after a few
plugs (rpm_usage tracepoint), so the controller never runtime-suspended
after the display was unplugged. It in turn kept the MDSS core GDSC on
while all displays were off.
Make the plugged state own exactly one reference: the plug handler
only takes it when the sink was not plugged yet, and detect() returns
its own reference when the plugged state already holds one, or drops
both when it finds the sink gone.
With this the count stays at 1-3 while a display is connected, the
controller suspends 3-4 s after unplug, MDSS suspends and its GDSC
powers off on DPMS off, and replugging (quickly or after 20 s) still
brings the picture back. Only tested on this device.
Fixes: 3ea2d1c3d154 ("drm/msm/dp: turn link_ready into plugged")
Assisted-by: LLM
Signed-off-by: Joonhoe Kim <26rote@gmail.com>
---
Changes in v2:
- Drop the plugged state's reference once, after the if/else, instead
of in both branches [Val]
- Drop the comments
- Link to v1: https://lore.kernel.org/all/20260929130627.959-1-26rote@gmail.com/
drivers/gpu/drm/msm/dp/dp_display.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 6abe30bdff12..4059cb9dba64 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -412,10 +412,12 @@ static int msm_dp_hpd_plug_handle(struct msm_dp_display_private *dp)
guard(mutex)(&dp->plugged_lock);
- ret = pm_runtime_resume_and_get(&pdev->dev);
- if (ret) {
- DRM_ERROR("failed to pm_runtime_resume\n");
- return ret;
+ if (!dp->plugged) {
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret) {
+ DRM_ERROR("failed to pm_runtime_resume\n");
+ return ret;
+ }
}
msm_dp_aux_enable_xfers(dp->aux, true);
@@ -897,6 +899,7 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
u8 dpcd[DP_RECEIVER_CAP_SIZE];
struct drm_dp_desc desc;
bool phy_deinit;
+ bool was_plugged;
int ret;
dp = to_dp_bridge(bridge)->msm_dp_display;
@@ -910,6 +913,7 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
return status;
}
+ was_plugged = priv->plugged;
phy_deinit = msm_dp_display_host_phy_init(priv);
msm_dp_aux_enable_xfers(priv->aux, true);
@@ -962,6 +966,9 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
pm_runtime_put_sync(&dp->pdev->dev);
}
+ if (was_plugged)
+ pm_runtime_put_sync(&dp->pdev->dev);
+
return status;
}
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [v2] drm/msm/dp: hold one runtime PM reference per plugged state
2026-10-07 15:58 [PATCH v2] drm/msm/dp: hold one runtime PM reference per plugged state Joonhoe Kim
@ 2026-10-24 2:58 ` Val Packett
2026-10-24 5:20 ` [PATCH v2] " Joonhoe Kim
0 siblings, 1 reply; 3+ messages in thread
From: Val Packett @ 2026-10-24 2:58 UTC (permalink / raw)
To: Joonhoe Kim, robin.clark, Dmitry Baryshkov
Cc: abhinav.kumar, jesszhan0024, sean, marijn.suijten, airlied,
simona, yongxing.mou, linux-arm-msm, dri-devel, freedreno,
linux-kernel
On 10/7/26 12:58 PM, Joonhoe Kim wrote:
> The plug handler takes a runtime PM reference every time it runs and
> sets dp->plugged; the unplug handler drops a single reference when
> dp->plugged is set. msm_dp_bridge_detect() also takes a reference and
> marks the sink plugged, and keeps that reference as well -- on every
> detect while the sink stays connected. On top of that, in the current
> tree the plug handler runs more than once per plug:
> drm_bridge_connector_detect() calls .detect() and then .hpd_notify(),
> and pmic_glink altmode reports an IRQ_HPD as "connected" too. Every
> extra reference is leaked on unplug.
>
> On a Lenovo TB323FU (SM8850, DP over the USB-C port via pmic_glink
> altmode) the DP controller's usage count reached 28-34 after a few
> plugs (rpm_usage tracepoint), so the controller never runtime-suspended
> after the display was unplugged. It in turn kept the MDSS core GDSC on
> while all displays were off.
>
> Make the plugged state own exactly one reference: the plug handler
> only takes it when the sink was not plugged yet, and detect() returns
> its own reference when the plugged state already holds one, or drops
> both when it finds the sink gone.
>
> With this the count stays at 1-3 while a display is connected, the
> controller suspends 3-4 s after unplug, MDSS suspends and its GDSC
> powers off on DPMS off, and replugging (quickly or after 20 s) still
> brings the picture back. Only tested on this device.
>
> Fixes: 3ea2d1c3d154 ("drm/msm/dp: turn link_ready into plugged")
> Assisted-by: LLM
> Signed-off-by: Joonhoe Kim <26rote@gmail.com>
> ---
> Changes in v2:
> - Drop the plugged state's reference once, after the if/else, instead
> of in both branches [Val]
> - Drop the comments
> - Link to v1: https://lore.kernel.org/all/20260929130627.959-1-26rote@gmail.com/
>
> drivers/gpu/drm/msm/dp/dp_display.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index 6abe30bdff12..4059cb9dba64 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -412,10 +412,12 @@ static int msm_dp_hpd_plug_handle(struct msm_dp_display_private *dp)
>
> guard(mutex)(&dp->plugged_lock);
>
> - ret = pm_runtime_resume_and_get(&pdev->dev);
> - if (ret) {
> - DRM_ERROR("failed to pm_runtime_resume\n");
> - return ret;
> + if (!dp->plugged) {
> + ret = pm_runtime_resume_and_get(&pdev->dev);
> + if (ret) {
> + DRM_ERROR("failed to pm_runtime_resume\n");
> + return ret;
> + }
> }
>
> msm_dp_aux_enable_xfers(dp->aux, true);
This part (msm_dp_hpd_plug_handle) is now also handled by the IRQ_HPD
series:
https://lore.kernel.org/all/20261024-hpd-irq-events-v8-6-6ee949e7a384@oss.qualcomm.com/
> @@ -897,6 +899,7 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
> u8 dpcd[DP_RECEIVER_CAP_SIZE];
> struct drm_dp_desc desc;
> bool phy_deinit;
> + bool was_plugged;
> int ret;
>
> dp = to_dp_bridge(bridge)->msm_dp_display;
> @@ -910,6 +913,7 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
> return status;
> }
>
> + was_plugged = priv->plugged;
> phy_deinit = msm_dp_display_host_phy_init(priv);
>
> msm_dp_aux_enable_xfers(priv->aux, true);
> @@ -962,6 +966,9 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
> pm_runtime_put_sync(&dp->pdev->dev);
> }
>
> + if (was_plugged)
> + pm_runtime_put_sync(&dp->pdev->dev);
Thinking about this again, this flow of the reference(s) seems confusing.
If I understand it correctly now,
* there's a long-term reference associated with priv->plugged;
* and this function needs the device to not be suspended because it's
doing transfers to check if there's something plugged into the port.
With the current flow (fixed by this v2 patch to not leak, or at least
leak less):
* we always take +1 reference;
* if we "find a plug" (!was_plugged && priv->plugged): no drop, our
reference "becomes" the long-term one;
* if we "find an unplug" (was_plugged && !priv->plugged): we drop our
own reference, as well as the long-term one;
* if we "find no change while plugged" (was_plugged && priv->plugged):
we only drop our own reference;
* if we "find no change while unplugged" (!was_plugged &&
!priv->plugged): no drop, is this intended or a leak still? Not clear
who needs the reference to persist in this case?
**If** that last case is actually **not** intended to keep the
reference, I think it would be clearer to, instead:
* use a guard (probably PM_RUNTIME_ACQUIRE_IF_ENABLED to keep the error
check) for this function's own reference;
* and use a plain get an extra time when setting priv->plugged = true..?
> +
> return status;
> }
>
Thanks,
~val
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v2] drm/msm/dp: hold one runtime PM reference per plugged state
2026-10-24 2:58 ` [v2] " Val Packett
@ 2026-10-24 5:20 ` Joonhoe Kim
0 siblings, 0 replies; 3+ messages in thread
From: Joonhoe Kim @ 2026-10-24 5:20 UTC (permalink / raw)
To: Val Packett
Cc: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Yongxing Mou, linux-arm-msm, dri-devel, freedreno,
linux-kernel
On Sat, Oct 24, 2026 at 02:58:25AM +0000, Val Packett wrote:
> This part (msm_dp_hpd_plug_handle) is now also handled by the IRQ_HPD
> series:
Yes. v3 is on top of that series and keeps only the detect() part.
> * if we "find no change while unplugged" (!was_plugged &&
> !priv->plugged): no drop, is this intended or a leak still?
It does not leak: the existing put in the "if (!priv->plugged)" block
drops the function's own reference in that case, and only the second
put depends on was_plugged. Agreed that this is hard to see from the
code, though.
> * use a guard (probably PM_RUNTIME_ACQUIRE_IF_ENABLED to keep the error
> check) for this function's own reference;
> * and use a plain get an extra time when setting priv->plugged = true..?
Done in v3: the plugged state takes its reference with
pm_runtime_get_noresume() when detect() sets priv->plugged and drops
it when detect() clears it:
https://lore.kernel.org/all/20261024051952.2006-1-26rote@gmail.com/
Thanks,
Joonhoe Kim
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-24 5:20 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-07 15:58 [PATCH v2] drm/msm/dp: hold one runtime PM reference per plugged state Joonhoe Kim
2026-10-24 2:58 ` [v2] " Val Packett
2026-10-24 5:20 ` [PATCH v2] " Joonhoe Kim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®