[PATCH 5.15 019/177] usb: typec: ucsi: Fix role swapping

From: Greg Kroah-Hartman
Date: Wed May 04 2022 - 13:18:06 EST


From: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>

commit eb5d7ff3cf0d55093c619b5ad107cd5c05ce8134 upstream.

All attempts to swap the roles timed out because the
completion was done without releasing the port lock. Fixing
that by releasing the lock before starting to wait for the
completion.

Link: https://lore.kernel.org/linux-usb/037de7ac-e210-bdf5-ec7a-8c0c88a0be20@xxxxxxxxx/
Fixes: ad74b8649bea ("usb: typec: ucsi: Preliminary support for alternate modes")
Cc: stable@xxxxxxxxxxxxxxx
Reported-and-tested-by: Jia-Ju Bai <baijiaju1990@xxxxxxxxx>
Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20220405134824.68067-3-heikki.krogerus@xxxxxxxxxxxxxxx
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/usb/typec/ucsi/ucsi.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)

--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -964,14 +964,18 @@ static int ucsi_dr_swap(struct typec_por
if (ret < 0)
goto out_unlock;

+ mutex_unlock(&con->lock);
+
if (!wait_for_completion_timeout(&con->complete,
- msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS)))
- ret = -ETIMEDOUT;
+ msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS)))
+ return -ETIMEDOUT;
+
+ return 0;

out_unlock:
mutex_unlock(&con->lock);

- return ret < 0 ? ret : 0;
+ return ret;
}

static int ucsi_pr_swap(struct typec_port *port, enum typec_role role)
@@ -1002,11 +1006,13 @@ static int ucsi_pr_swap(struct typec_por
if (ret < 0)
goto out_unlock;

+ mutex_unlock(&con->lock);
+
if (!wait_for_completion_timeout(&con->complete,
- msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) {
- ret = -ETIMEDOUT;
- goto out_unlock;
- }
+ msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS)))
+ return -ETIMEDOUT;
+
+ mutex_lock(&con->lock);

/* Something has gone wrong while swapping the role */
if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) !=