Skip to content

Commit 451b15e

Browse files
Xu Yanggregkh
authored andcommitted
usb: chipidea: core: fix possible concurrent when switch role
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: a932a80 ("usb: chipidea: core: add sysfs group") cc: <[email protected]> Acked-by: Peter Chen <[email protected]> Signed-off-by: Xu Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3670de8 commit 451b15e

File tree

3 files changed

+13
-2
lines changed

3 files changed

+13
-2
lines changed

drivers/usb/chipidea/ci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ struct hw_bank {
208208
* @in_lpm: if the core in low power mode
209209
* @wakeup_int: if wakeup interrupt occur
210210
* @rev: The revision number for controller
211+
* @mutex: protect code from concorrent running when doing role switch
211212
*/
212213
struct ci_hdrc {
213214
struct device *dev;
@@ -260,6 +261,7 @@ struct ci_hdrc {
260261
bool in_lpm;
261262
bool wakeup_int;
262263
enum ci_revision rev;
264+
struct mutex mutex;
263265
};
264266

265267
static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)

drivers/usb/chipidea/core.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,8 +987,12 @@ static ssize_t role_store(struct device *dev,
987987
if (role == CI_ROLE_END)
988988
return -EINVAL;
989989

990-
if (role == ci->role)
990+
mutex_lock(&ci->mutex);
991+
992+
if (role == ci->role) {
993+
mutex_unlock(&ci->mutex);
991994
return n;
995+
}
992996

993997
pm_runtime_get_sync(dev);
994998
disable_irq(ci->irq);
@@ -998,6 +1002,7 @@ static ssize_t role_store(struct device *dev,
9981002
ci_handle_vbus_change(ci);
9991003
enable_irq(ci->irq);
10001004
pm_runtime_put_sync(dev);
1005+
mutex_unlock(&ci->mutex);
10011006

10021007
return (ret == 0) ? n : ret;
10031008
}
@@ -1033,6 +1038,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
10331038
return -ENOMEM;
10341039

10351040
spin_lock_init(&ci->lock);
1041+
mutex_init(&ci->mutex);
10361042
ci->dev = dev;
10371043
ci->platdata = dev_get_platdata(dev);
10381044
ci->imx28_write_fix = !!(ci->platdata->flags &

drivers/usb/chipidea/otg.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,10 @@ static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
167167

168168
void ci_handle_id_switch(struct ci_hdrc *ci)
169169
{
170-
enum ci_role role = ci_otg_role(ci);
170+
enum ci_role role;
171171

172+
mutex_lock(&ci->mutex);
173+
role = ci_otg_role(ci);
172174
if (role != ci->role) {
173175
dev_dbg(ci->dev, "switching from %s to %s\n",
174176
ci_role(ci)->name, ci->roles[role]->name);
@@ -198,6 +200,7 @@ void ci_handle_id_switch(struct ci_hdrc *ci)
198200
if (role == CI_ROLE_GADGET)
199201
ci_handle_vbus_change(ci);
200202
}
203+
mutex_unlock(&ci->mutex);
201204
}
202205
/**
203206
* ci_otg_work - perform otg (vbus/id) event handle

0 commit comments

Comments
 (0)