* [PATCH] usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling
@ 2026-08-27 21:16 Amit Sunil Dhamne via B4 Relay
2026-08-31 11:08 ` Heikki Krogerus
0 siblings, 1 reply; 2+ messages in thread
From: Amit Sunil Dhamne via B4 Relay @ 2026-08-27 21:16 UTC (permalink / raw)
To: Badhri Jagan Sridharan, Heikki Krogerus, Greg Kroah-Hartman
Cc: linux-usb, linux-kernel, RD Babiera, Kyle Tso, stable,
Amit Sunil Dhamne
From: Amit Sunil Dhamne <amitsd@google.com>
When a sink detach occurs while waiting for TX send status, the old
TCPM_SOURCING_VBUS event along with TCPM_VBUS_EVENT and TCPM_CC_EVENT
can be queued in port->pd_events. Because TCPM_SOURCING_VBUS is
evaluated after TCPM_VBUS_EVENT and TCPM_CC_EVENT in
tcpm_pd_event_handler(), a stale TCPM_SOURCING_VBUS event can override
the detach handling and incorrectly set port->vbus_source and
port->vbus_present to true.
Add a state guard to check that the port is either operating as a
Source (tcpm_port_is_source(port)) or in a Fast Role Swap (FRS) state
up to FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED before processing
TCPM_SOURCING_VBUS. Otherwise, discard and log the event.
Log snippet for error condition before fix:
[72792.204955] state change SRC_ATTACHED -> SRC_STARTUP [rev3 NONE_AMS]
[72792.204960] sourcing vbus
[72792.204962] VBUS on
[72792.204970] AMS POWER_NEGOTIATION start
[72792.204974] cc:=4
[72792.205319] state change SRC_STARTUP -> AMS_START [rev3 POWER_NEGOTIATION]
[72792.205325] state change AMS_START -> SRC_SEND_CAPABILITIES [rev3 POWER_NEGOTIATION]
[72792.205332] PD TX, header: 0x11a1
[72792.216911] PD TX complete, status: 2
[72792.216957] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [rev3 POWER_NEGOTIATION]
[72792.218005] VBUS off
[72792.218013] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION]
[72792.218020] VBUS VSAFE0V
[72792.218024] state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED [rev3 POWER_NEGOTIATION]
[72792.218458] CC1: 2 -> 0, CC2: 0 -> 0 [state SNK_UNATTACHED, polarity 0, disconnected]
[72792.218467] VBUS on --> VBUS left on
[72792.218980] disable vbus discharge ret:0
[72792.235193] Start toggling
After fix:
[ 1195.291691] state change SRC_ATTACHED -> SRC_STARTUP [rev3 NONE_AMS]
[ 1195.291698] sourcing vbus
[ 1195.291700] VBUS on
[ 1195.291707] AMS POWER_NEGOTIATION start
[ 1195.291710] cc:=4
[ 1195.291758] state change SRC_STARTUP -> AMS_START [rev3 POWER_NEGOTIATION]
[ 1195.291794] state change AMS_START -> SRC_SEND_CAPABILITIES [rev3 POWER_NEGOTIATION]
[ 1195.291798] PD TX, header: 0x11a1
[ 1195.297056] PD TX complete, status: 2
[ 1195.297092] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [rev3 POWER_NEGOTIATION]
[ 1195.297177] VBUS off
[ 1195.297184] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION]
[ 1195.297227] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_SEND_CAPABILITIES, polarity 0, disconnected]
[ 1195.307469] cc:=2
[ 1195.307544] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION]
[ 1195.307555] Discarding sourcing vbus! Invalid state SRC_SEND_CAPABILITIES
[ 1195.957636] state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED [delayed 650 ms]
[ 1195.957732] disable vbus discharge ret:0
[ 1195.970196] Start toggling
[ 1195.970468] VBUS off
[ 1196.051637] VBUS off
[ 1196.051642] VBUS VSAFE0V
Fixes: 8dc4bd073663 ("usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS)")
Cc: stable@vger.kernel.org
Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
---
drivers/usb/typec/tcpm/tcpm.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a8cd1959c426..2d6b14aa2085 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -7119,16 +7119,32 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
}
}
if (events & TCPM_SOURCING_VBUS) {
- tcpm_log(port, "sourcing vbus");
/*
* In fast role swap case TCPC autonomously sources vbus. Set vbus_source
- * true as TCPM wouldn't have called tcpm_set_vbus.
+ * true conditionally as TCPM wouldn't have called tcpm_set_vbus.
+ * If TCPM calls tcpm_set_vbus to source vbus, vbus_source would already
+ * be true.
*
- * When vbus is sourced on the command on TCPM i.e. TCPM called
- * tcpm_set_vbus to source vbus, vbus_source would already be true.
+ * When TCPM_FRS_EVENT and TCPM_SOURCING_VBUS arrive simultaneously,
+ * handling TCPM_FRS_EVENT above transitions the state to AMS_START
+ * with upcoming_state FR_SWAP_SEND.
*/
- port->vbus_source = true;
- _tcpm_pd_vbus_on(port);
+
+ if (tcpm_port_is_source(port) ||
+ tcpm_port_is_debug_source(port) ||
+ (port->state == AMS_START && port->upcoming_state == FR_SWAP_SEND) ||
+ port->state == FR_SWAP_SEND ||
+ port->state == FR_SWAP_SEND_TIMEOUT ||
+ port->state == FR_SWAP_SNK_SRC_TRANSITION_TO_OFF ||
+ port->state == FR_SWAP_SNK_SRC_NEW_SINK_READY ||
+ port->state == FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED) {
+ tcpm_log(port, "sourcing vbus");
+ port->vbus_source = true;
+ _tcpm_pd_vbus_on(port);
+ } else {
+ tcpm_log(port, "Discarding sourcing vbus! Invalid state %s",
+ tcpm_states[port->state]);
+ }
}
if (events & TCPM_PORT_CLEAN) {
tcpm_log(port, "port clean");
---
base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
change-id: 20260827-sourcing-vbus-9f87cc4b6257
Best regards,
--
Amit Sunil Dhamne <amitsd@google.com>
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling
2026-08-27 21:16 [PATCH] usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling Amit Sunil Dhamne via B4 Relay
@ 2026-08-31 11:08 ` Heikki Krogerus
0 siblings, 0 replies; 2+ messages in thread
From: Heikki Krogerus @ 2026-08-31 11:08 UTC (permalink / raw)
To: amitsd
Cc: Badhri Jagan Sridharan, Greg Kroah-Hartman, linux-usb,
linux-kernel, RD Babiera, Kyle Tso, stable
On Thu, Aug 27, 2026 at 09:16:17PM +0000, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd@google.com>
>
> When a sink detach occurs while waiting for TX send status, the old
> TCPM_SOURCING_VBUS event along with TCPM_VBUS_EVENT and TCPM_CC_EVENT
> can be queued in port->pd_events. Because TCPM_SOURCING_VBUS is
> evaluated after TCPM_VBUS_EVENT and TCPM_CC_EVENT in
> tcpm_pd_event_handler(), a stale TCPM_SOURCING_VBUS event can override
> the detach handling and incorrectly set port->vbus_source and
> port->vbus_present to true.
>
> Add a state guard to check that the port is either operating as a
> Source (tcpm_port_is_source(port)) or in a Fast Role Swap (FRS) state
> up to FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED before processing
> TCPM_SOURCING_VBUS. Otherwise, discard and log the event.
>
> Log snippet for error condition before fix:
> [72792.204955] state change SRC_ATTACHED -> SRC_STARTUP [rev3 NONE_AMS]
> [72792.204960] sourcing vbus
> [72792.204962] VBUS on
> [72792.204970] AMS POWER_NEGOTIATION start
> [72792.204974] cc:=4
> [72792.205319] state change SRC_STARTUP -> AMS_START [rev3 POWER_NEGOTIATION]
> [72792.205325] state change AMS_START -> SRC_SEND_CAPABILITIES [rev3 POWER_NEGOTIATION]
> [72792.205332] PD TX, header: 0x11a1
> [72792.216911] PD TX complete, status: 2
> [72792.216957] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [rev3 POWER_NEGOTIATION]
> [72792.218005] VBUS off
> [72792.218013] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION]
> [72792.218020] VBUS VSAFE0V
> [72792.218024] state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED [rev3 POWER_NEGOTIATION]
> [72792.218458] CC1: 2 -> 0, CC2: 0 -> 0 [state SNK_UNATTACHED, polarity 0, disconnected]
> [72792.218467] VBUS on --> VBUS left on
> [72792.218980] disable vbus discharge ret:0
> [72792.235193] Start toggling
>
> After fix:
> [ 1195.291691] state change SRC_ATTACHED -> SRC_STARTUP [rev3 NONE_AMS]
> [ 1195.291698] sourcing vbus
> [ 1195.291700] VBUS on
> [ 1195.291707] AMS POWER_NEGOTIATION start
> [ 1195.291710] cc:=4
> [ 1195.291758] state change SRC_STARTUP -> AMS_START [rev3 POWER_NEGOTIATION]
> [ 1195.291794] state change AMS_START -> SRC_SEND_CAPABILITIES [rev3 POWER_NEGOTIATION]
> [ 1195.291798] PD TX, header: 0x11a1
> [ 1195.297056] PD TX complete, status: 2
> [ 1195.297092] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [rev3 POWER_NEGOTIATION]
> [ 1195.297177] VBUS off
> [ 1195.297184] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION]
> [ 1195.297227] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_SEND_CAPABILITIES, polarity 0, disconnected]
> [ 1195.307469] cc:=2
> [ 1195.307544] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION]
> [ 1195.307555] Discarding sourcing vbus! Invalid state SRC_SEND_CAPABILITIES
> [ 1195.957636] state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED [delayed 650 ms]
> [ 1195.957732] disable vbus discharge ret:0
> [ 1195.970196] Start toggling
> [ 1195.970468] VBUS off
> [ 1196.051637] VBUS off
> [ 1196.051642] VBUS VSAFE0V
>
> Fixes: 8dc4bd073663 ("usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS)")
> Cc: stable@vger.kernel.org
> Assisted-by: Gemini:gemini-3.1-pro
> Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
> Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> ---
> drivers/usb/typec/tcpm/tcpm.c | 28 ++++++++++++++++++++++------
> 1 file changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index a8cd1959c426..2d6b14aa2085 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -7119,16 +7119,32 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
> }
> }
> if (events & TCPM_SOURCING_VBUS) {
> - tcpm_log(port, "sourcing vbus");
> /*
> * In fast role swap case TCPC autonomously sources vbus. Set vbus_source
> - * true as TCPM wouldn't have called tcpm_set_vbus.
> + * true conditionally as TCPM wouldn't have called tcpm_set_vbus.
> + * If TCPM calls tcpm_set_vbus to source vbus, vbus_source would already
> + * be true.
> *
> - * When vbus is sourced on the command on TCPM i.e. TCPM called
> - * tcpm_set_vbus to source vbus, vbus_source would already be true.
> + * When TCPM_FRS_EVENT and TCPM_SOURCING_VBUS arrive simultaneously,
> + * handling TCPM_FRS_EVENT above transitions the state to AMS_START
> + * with upcoming_state FR_SWAP_SEND.
> */
> - port->vbus_source = true;
> - _tcpm_pd_vbus_on(port);
> +
> + if (tcpm_port_is_source(port) ||
> + tcpm_port_is_debug_source(port) ||
> + (port->state == AMS_START && port->upcoming_state == FR_SWAP_SEND) ||
> + port->state == FR_SWAP_SEND ||
> + port->state == FR_SWAP_SEND_TIMEOUT ||
> + port->state == FR_SWAP_SNK_SRC_TRANSITION_TO_OFF ||
> + port->state == FR_SWAP_SNK_SRC_NEW_SINK_READY ||
> + port->state == FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED) {
> + tcpm_log(port, "sourcing vbus");
> + port->vbus_source = true;
> + _tcpm_pd_vbus_on(port);
> + } else {
> + tcpm_log(port, "Discarding sourcing vbus! Invalid state %s",
> + tcpm_states[port->state]);
> + }
> }
> if (events & TCPM_PORT_CLEAN) {
> tcpm_log(port, "port clean");
>
> ---
> base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
> change-id: 20260827-sourcing-vbus-9f87cc4b6257
>
> Best regards,
> --
> Amit Sunil Dhamne <amitsd@google.com>
>
--
heikki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-31 11:08 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27 21:16 [PATCH] usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling Amit Sunil Dhamne via B4 Relay
2026-08-31 11:08 ` Heikki Krogerus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox