From: Heikki Krogerus heikki.krogerus@linux.intel.com
stable inclusion from stable-v5.10.114 commit fb1fe1a4557a5cdfc339d37adb6105b1edc27120 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5IY1V
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
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@gmail... Fixes: ad74b8649bea ("usb: typec: ucsi: Preliminary support for alternate modes") Cc: stable@vger.kernel.org Reported-and-tested-by: Jia-Ju Bai baijiaju1990@gmail.com Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Link: https://lore.kernel.org/r/20220405134824.68067-3-heikki.krogerus@linux.intel... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Acked-by: Xie XiuQi xiexiuqi@huawei.com --- drivers/usb/typec/ucsi/ucsi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 167209752cba..dfda8f5487c0 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -937,14 +937,18 @@ static int ucsi_dr_swap(struct typec_port *port, enum typec_data_role role) 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) @@ -975,11 +979,13 @@ static int ucsi_pr_swap(struct typec_port *port, enum typec_role role) 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) !=