This is a note to let you know that I've just added the patch titled usb: chipidea: core: fix possible concurrent when switch role to the 5.15-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: usb-chipidea-core-fix-possible-concurrent-when-switch-role.patch and it can be found in the queue-5.15 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 451b15ed138ec15bffbebb58a00ebdd884c3e659 Mon Sep 17 00:00:00 2001 From: Xu Yang <xu.yang_2@xxxxxxx> Date: Fri, 17 Mar 2023 14:15:16 +0800 Subject: usb: chipidea: core: fix possible concurrent when switch role From: Xu Yang <xu.yang_2@xxxxxxx> commit 451b15ed138ec15bffbebb58a00ebdd884c3e659 upstream. The user may call role_store() when driver is handling ci_handle_id_switch() which is triggerred by otg event or power lost event. Unfortunately, the controller may go into chaos in this case. Fix this by protecting it with mutex lock. Fixes: a932a8041ff9 ("usb: chipidea: core: add sysfs group") cc: <stable@xxxxxxxxxxxxxxx> Acked-by: Peter Chen <peter.chen@xxxxxxxxxx> Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx> Link: https://lore.kernel.org/r/20230317061516.2451728-2-xu.yang_2@xxxxxxx Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/usb/chipidea/ci.h | 2 ++ drivers/usb/chipidea/core.c | 8 +++++++- drivers/usb/chipidea/otg.c | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -203,6 +203,7 @@ struct hw_bank { * @in_lpm: if the core in low power mode * @wakeup_int: if wakeup interrupt occur * @rev: The revision number for controller + * @mutex: protect code from concorrent running when doing role switch */ struct ci_hdrc { struct device *dev; @@ -255,6 +256,7 @@ struct ci_hdrc { bool in_lpm; bool wakeup_int; enum ci_revision rev; + struct mutex mutex; }; static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -977,8 +977,12 @@ static ssize_t role_store(struct device if (role == CI_ROLE_END) return -EINVAL; - if (role == ci->role) + mutex_lock(&ci->mutex); + + if (role == ci->role) { + mutex_unlock(&ci->mutex); return n; + } pm_runtime_get_sync(dev); disable_irq(ci->irq); @@ -988,6 +992,7 @@ static ssize_t role_store(struct device ci_handle_vbus_change(ci); enable_irq(ci->irq); pm_runtime_put_sync(dev); + mutex_unlock(&ci->mutex); return (ret == 0) ? n : ret; } @@ -1023,6 +1028,7 @@ static int ci_hdrc_probe(struct platform return -ENOMEM; spin_lock_init(&ci->lock); + mutex_init(&ci->mutex); ci->dev = dev; ci->platdata = dev_get_platdata(dev); ci->imx28_write_fix = !!(ci->platdata->flags & --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -167,8 +167,10 @@ static int hw_wait_vbus_lower_bsv(struct static void ci_handle_id_switch(struct ci_hdrc *ci) { - enum ci_role role = ci_otg_role(ci); + enum ci_role role; + mutex_lock(&ci->mutex); + role = ci_otg_role(ci); if (role != ci->role) { dev_dbg(ci->dev, "switching from %s to %s\n", ci_role(ci)->name, ci->roles[role]->name); @@ -198,6 +200,7 @@ static void ci_handle_id_switch(struct c if (role == CI_ROLE_GADGET) ci_handle_vbus_change(ci); } + mutex_unlock(&ci->mutex); } /** * ci_otg_work - perform otg (vbus/id) event handle Patches currently in stable-queue which might be from xu.yang_2@xxxxxxx are queue-5.15/usb-typec-tcpm-fix-warning-when-handle-discover_identity-message.patch queue-5.15/usb-chipidea-core-fix-possible-concurrent-when-switch-role.patch queue-5.15/usb-chipdea-core-fix-return-einval-if-request-role-is-the-same-with-current-role.patch