mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-16 02:44:26 +08:00
usb: chipidea: core: fix possible concurrent when switch role
commit451b15ed13
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:a932a8041f
("usb: chipidea: core: add sysfs group") cc: <stable@vger.kernel.org> Acked-by: Peter Chen <peter.chen@kernel.org> Signed-off-by: Xu Yang <xu.yang_2@nxp.com> Link: https://lore.kernel.org/r/20230317061516.2451728-2-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ef74a7ffe7
commit
27c40c3aa4
@ -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)
|
||||
|
@ -977,8 +977,12 @@ static ssize_t role_store(struct device *dev,
|
||||
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 *dev,
|
||||
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_device *pdev)
|
||||
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 &
|
||||
|
@ -167,8 +167,10 @@ static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
|
||||
|
||||
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 ci_hdrc *ci)
|
||||
if (role == CI_ROLE_GADGET)
|
||||
ci_handle_vbus_change(ci);
|
||||
}
|
||||
mutex_unlock(&ci->mutex);
|
||||
}
|
||||
/**
|
||||
* ci_otg_work - perform otg (vbus/id) event handle
|
||||
|
Loading…
Reference in New Issue
Block a user