* [PATCH 0/2] phy: qcom: qmp-combo: fix forced com_init() error handling
@ 2026-09-09 15:14 Oleg Keri
2026-09-09 15:14 ` [PATCH 1/2] phy: qcom: qmp-combo: do not decrement init_count on a forced init failure Oleg Keri
2026-09-09 15:14 ` [PATCH 2/2] phy: qcom: qmp-combo: check qmp_combo_com_init() in the typec callbacks Oleg Keri
0 siblings, 2 replies; 4+ messages in thread
From: Oleg Keri @ 2026-09-09 15:14 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Bjorn Andersson, Johan Hovold
Cc: linux-arm-msm, linux-phy, linux-kernel, Michael Scott
Two pre-existing problems in the typec_switch and typec_mux callbacks,
both on the force=true path that tears the common block down and brings it
back up. Found while looking at that code for
https://lore.kernel.org/all/20260909140345.4239-1-okerixx@gmail.com/
which is an unrelated fix to the same two functions and does not depend on
these; they can be applied in either order.
Patch 1 stops a forced qmp_combo_com_init() failure from dropping an
init_count reference it never took, which drives the counter negative and
makes qmp_combo_com_exit() return early for the rest of the boot.
Patch 2 stops both callbacks from carrying on to write PHY registers after
the bringup has failed and left the clocks disabled.
Neither is easy to trigger deliberately - both need qmp_combo_com_init() to
fail - so they are found by inspection rather than reproduced. The tree
they were written against is exercised daily on a Lenovo Yoga Slim 7x Gen 11
(Snapdragon X2 Elite), where the typec callbacks run on every USB-C
orientation and altmode change.
Oleg Keri (2):
phy: qcom: qmp-combo: do not decrement init_count on a forced init
failure
phy: qcom: qmp-combo: check qmp_combo_com_init() in the typec
callbacks
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
--
2.55.0
base-commit: df2908090cda368b01ff43709f51890076c56157
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] phy: qcom: qmp-combo: do not decrement init_count on a forced init failure
2026-09-09 15:14 [PATCH 0/2] phy: qcom: qmp-combo: fix forced com_init() error handling Oleg Keri
@ 2026-09-09 15:14 ` Oleg Keri
2026-09-09 15:14 ` [PATCH 2/2] phy: qcom: qmp-combo: check qmp_combo_com_init() in the typec callbacks Oleg Keri
1 sibling, 0 replies; 4+ messages in thread
From: Oleg Keri @ 2026-09-09 15:14 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Bjorn Andersson, Johan Hovold
Cc: linux-arm-msm, linux-phy, linux-kernel, Michael Scott
qmp_combo_com_init() only takes a reference when it is not forced:
if (!force && qmp->init_count++)
return 0;
With force set, && short-circuits on !force and init_count++ is never
evaluated. The error path decrements unconditionally, so a forced init
that fails drops a reference it never took and init_count goes negative.
init_count is a plain int, so the damage persists for the rest of the
boot. qmp_combo_com_exit() then sees a non-zero value in
if (!force && --qmp->init_count)
return 0;
and returns early every time, so the clocks, resets and regulators are
never released; the runtime PM callbacks only bail on exactly zero, so
they keep touching hardware that may already be off.
Both callers that pass force are the typec_switch and typec_mux
callbacks, which tear the common block down and bring it back up on an
orientation or altmode change.
Only decrement the count when it was actually taken.
Fixes: 2851117f8f42 ("phy: qcom-qmp-combo: Introduce orientation switching")
Signed-off-by: Oleg Keri <okerixx@gmail.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index bf4d29fe1719..7d740ed0ce16 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -4253,7 +4253,8 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
err_disable_regulators:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
err_decrement_count:
- qmp->init_count--;
+ if (!force)
+ qmp->init_count--;
return ret;
}
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] phy: qcom: qmp-combo: check qmp_combo_com_init() in the typec callbacks
2026-09-09 15:14 [PATCH 0/2] phy: qcom: qmp-combo: fix forced com_init() error handling Oleg Keri
2026-09-09 15:14 ` [PATCH 1/2] phy: qcom: qmp-combo: do not decrement init_count on a forced init failure Oleg Keri
@ 2026-09-09 15:14 ` Oleg Keri
1 sibling, 0 replies; 4+ messages in thread
From: Oleg Keri @ 2026-09-09 15:14 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Bjorn Andersson, Johan Hovold
Cc: linux-arm-msm, linux-phy, linux-kernel, Michael Scott
qmp_combo_typec_switch_set() and qmp_combo_typec_mux_set() tear the common
block down and bring it straight back up on an orientation or altmode
change, but they discard the result of the bringup:
qmp_combo_com_exit(qmp, true);
qmp_combo_com_init(qmp, true);
if (qmp->usb_init_count)
qmp_combo_usb_power_on(qmp->usb_phy);
If qmp_combo_com_init() fails - a regulator, a reset or
clk_bulk_prepare_enable() - it unwinds what it had brought up and returns
an error, leaving the clocks disabled. Both callbacks then carry on and
qmp_combo_usb_power_on(), and dp_aux_init() after it, write PHY registers
with no clock running.
Propagate the failure instead.
Fixes: 2851117f8f42 ("phy: qcom-qmp-combo: Introduce orientation switching")
Signed-off-by: Oleg Keri <okerixx@gmail.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 7d740ed0ce16..44b6f29926dc 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -4924,6 +4924,7 @@ static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
{
struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
const struct qmp_phy_cfg *cfg = qmp->cfg;
+ int ret = 0;
if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE)
return 0;
@@ -4938,15 +4939,19 @@ static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
qmp_combo_usb_power_off(qmp->usb_phy);
qmp_combo_com_exit(qmp, true);
- qmp_combo_com_init(qmp, true);
+ ret = qmp_combo_com_init(qmp, true);
+ if (ret)
+ goto out;
+
if (qmp->usb_init_count)
qmp_combo_usb_power_on(qmp->usb_phy);
if (qmp->dp_init_count)
cfg->dp_aux_init(qmp);
}
+out:
mutex_unlock(&qmp->phy_mutex);
- return 0;
+ return ret;
}
static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
@@ -4955,6 +4960,7 @@ static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_s
const struct qmp_phy_cfg *cfg = qmp->cfg;
enum qmpphy_mode new_mode;
unsigned int svid;
+ int ret;
guard(mutex)(&qmp->phy_mutex);
@@ -5012,7 +5018,9 @@ static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_s
qmp_combo_com_exit(qmp, true);
/* Now everything's powered down, power up the right PHYs */
- qmp_combo_com_init(qmp, true);
+ ret = qmp_combo_com_init(qmp, true);
+ if (ret)
+ return ret;
if (new_mode == QMPPHY_MODE_DP_ONLY) {
if (qmp->usb_init_count)
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] phy: qcom: qmp-combo: do not decrement init_count on a forced init failure
[not found] <20260909152846.3C3931F00A3A@smtp.kernel.org>
@ 2026-09-09 15:38 ` Oleg Keri
0 siblings, 0 replies; 4+ messages in thread
From: Oleg Keri @ 2026-09-09 15:38 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Johan Hovold,
Bjorn Andersson
Cc: linux-phy, linux-arm-msm, linux-kernel, Michael Scott
You are right, and this patch should be dropped. Please do not apply it.
The diagnosis in the commit message holds - a forced qmp_combo_com_init()
never takes the reference, because && short-circuits on !force, so the
unconditional decrement in the error path drops one that was never taken.
The remedy does not.
Tracing a consumer that holds phy_init(), so init_count is 1 and the block
is up, through a typec callback that does com_exit(force) then a com_init(force)
which fails:
before this patch init_count 0, hardware down.
a later com_exit(false) does --init_count -> -1, which
is non-zero, so it returns early: no double disable,
but the reference is lost and the count stays negative.
with this patch init_count 1, hardware down.
a later com_exit(false) does --init_count -> 0 and
proceeds to the full teardown, so
clk_disable_unprepare(), clk_bulk_disable_unprepare()
and regulator_bulk_disable() all run against resources
the error path already released.
So it swaps a silently negative counter for a real unbalanced disable, which
is worse than what it replaces. Exactly what you asked.
The underlying problem is that init_count is being used for two different
things - how many consumers hold a reference, and whether the common block
is currently powered - and after a failed forced re-init those two diverge.
No adjustment to the single counter can express that, so I would rather send
nothing here than send another half fix. I will come back to it with the
hardware state tracked separately, once I can convince myself the teardown
paths are balanced in every case.
Patch 2/2 does not touch the counter at all - it only stops both callbacks
carrying on to write PHY registers after the bringup has already failed and
left the clocks disabled - so it stands on its own and can still be applied.
The runtime PM patch it was a follow-up to is likewise independent:
https://lore.kernel.org/all/20260909140345.4239-1-okerixx@gmail.com/
pw-bot: changes-requested
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-09 15:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-09 15:14 [PATCH 0/2] phy: qcom: qmp-combo: fix forced com_init() error handling Oleg Keri
2026-09-09 15:14 ` [PATCH 1/2] phy: qcom: qmp-combo: do not decrement init_count on a forced init failure Oleg Keri
2026-09-09 15:14 ` [PATCH 2/2] phy: qcom: qmp-combo: check qmp_combo_com_init() in the typec callbacks Oleg Keri
[not found] <20260909152846.3C3931F00A3A@smtp.kernel.org>
2026-09-09 15:38 ` [PATCH 1/2] phy: qcom: qmp-combo: do not decrement init_count on a forced init failure Oleg Keri
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®