From: ChiYuan Huang cy_huang@richtek.com
commit 36f78477ac2c89e9a2eed4a31404a291a3450b5d upstream.
There's the altmode re-registeration issue after data role swap (DR_SWAP).
Comparing to USBPD 2.0, in USBPD 3.0, it loose the limit that only DFP can initiate the VDM command to get partner identity information.
For a USBPD 3.0 UFP device, it may already get the identity information from its port partner before DR_SWAP. If DR_SWAP send or receive at the mean time, 'send_discover' flag will be raised again. It causes discover identify action restart while entering ready state. And after all discover actions are done, the 'tcpm_register_altmodes' will be called. If old altmode is not unregistered, this sysfs create fail can be found.
In 'DR_SWAP_CHANGE_DR' state case, only DFP will unregister altmodes. For UFP, the original altmodes keep registered.
This patch fix the logic that after DR_SWAP, 'tcpm_unregister_altmodes' must be called whatever the current data role is.
Reviewed-by: Macpaul Lin macpaul.lin@mediatek.com Fixes: ae8a2ca8a221 ("usb: typec: Group all TCPCI/TCPM code together") Reported-by: TommyYl Chen tommyyl.chen@mediatek.com Cc: stable@vger.kernel.org Signed-off-by: ChiYuan Huang cy_huang@richtek.com Acked-by: Heikki Krogerus heikki.krogerus@linux.intel.com Link: https://lore.kernel.org/r/1673248790-15794-1-git-send-email-cy_huang@richtek... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/usb/typec/tcpm/tcpm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
--- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -4527,14 +4527,13 @@ static void run_state_machine(struct tcp tcpm_set_state(port, ready_state(port), 0); break; case DR_SWAP_CHANGE_DR: - if (port->data_role == TYPEC_HOST) { - tcpm_unregister_altmodes(port); + tcpm_unregister_altmodes(port); + if (port->data_role == TYPEC_HOST) tcpm_set_roles(port, true, port->pwr_role, TYPEC_DEVICE); - } else { + else tcpm_set_roles(port, true, port->pwr_role, TYPEC_HOST); - } tcpm_ams_finish(port); tcpm_set_state(port, ready_state(port), 0); break;