* [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; 3+ 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] 3+ 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; 3+ 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] 3+ 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; 3+ 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] 3+ messages in thread
end of thread, other threads:[~2026-09-09 15:15 UTC | newest]
Thread overview: 3+ 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
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®