summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2015-06-03 19:36:29 +0800
committerPeter Chen <peter.chen@freescale.com>2015-06-05 10:34:19 +0800
commitc8095116b717d37a1525ba133918fe5e58a6912f (patch)
treeab6e9ff520cc23051209054664c47e3f7e6d2747
parent2d02af0e2e23fe37ef19ceb9d5c3448d35d48c9b (diff)
MLK-10994-5 usb: chipidea: otg: fix NULL pointer dereference when unload module
With commit "95b62fe MLK-10750 usb: chipidea: otg: remove otg fsm before destory gdaget and host", the otg fsm will be removed first, but when the host is removing, it will trigger pcd interrupt, and otg work is still queued to ci_otg workqueue(otg state is OTG_STATE_A_HOST), but at that time, ci_otg workqueue has been destroyed. In this commit, we make sure the otg work is not queued if ci->wq is NULL, and keep otg state is OTG_STATE_UNDEFINED after otg fsm has been removed. The NULL pointer deference error like belows: Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = a873c000 [00000000] *pgd=a90f9831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: usb_f_ecm u_ether libcomposite configfs ci_hdrc_imx(-) ci_hdrc udc_core ehci_hcd mxc_vadc mx6s_capture mxc_dcic ov5640_camera usbmisc_imx phy_mxs_usb evbug [last unloaded: usb_f_rndis] CPU: 0 PID: 162 Comm: udevd Not tainted 3.14.38-02187-g5639985-dirty #160 task: a863e880 ti: a872e000 task.ti: a872e000 PC is at __queue_work+0x68/0x268 LR is at __queue_work+0x68/0x268 pc : [<80045060>] lr : [<80045060>] psr: 600e0193 sp : a872fed0 ip : 00000000 fp : 00000000 r10: 00000004 r9 : a872e000 r8 : 0000004b r7 : 80e4c804 r6 : a9295000 r5 : a87f8294 r4 : 00000000 r3 : a80690e0 r2 : 00000000 r1 : a8069108 r0 : a8003400 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: a873c04a DAC: 00000015 Process udevd (pid: 162, stack limit = 0xa872e238) Stack: (0xa872fed0 to 0xa8730000) fec0: 00ff3d34 80743750 00000000 600e0193 fee0: a87f8294 a9295000 00000004 0000004b a8008900 80eb51ff 00ff3d34 800452a8 ff00: 00000000 a87f8010 00000000 00000000 00000000 7f060ac0 a8dfced0 a87f8010 ff20: 00002e20 7f059730 a8e7e2c0 a800895c 00000000 8006c1b4 80e46080 80e40458 ff40: a8008900 a800895c a8e7e2c0 c0802100 00fc40e8 00000000 00000048 8006c320 ff60: a8008900 a800895c 00000000 8006f1c4 8006f140 0000004b 0000004b 8006b92c ff80: 80e40e54 8000f9cc c080210c 80e4c970 a872ffb0 8000856c 00fc4308 76d9c890 ffa0: 600e0010 ffffffff 7edef480 800130bc 00fc4308 00ff3d70 00000000 000000ff ffc0: 00000671 00000000 00ff3b90 7edef480 00fc40e8 00000000 00000048 00ff3d34 ffe0: 000321b8 7edef140 000240a0 76d9c890 600e0010 ffffffff abf5e821 abf5ec21 [<80045060>] (__queue_work) from [<800452a8>] (queue_work_on+0x48/0x54) [<800452a8>] (queue_work_on) from [<7f060ac0>] (ci_otg_fsm_irq+0x108/0x310 [ci_hdrc]) [<7f060ac0>] (ci_otg_fsm_irq [ci_hdrc]) from [<7f059730>] (ci_irq+0x94/0x158 [ci_hdrc]) [<7f059730>] (ci_irq [ci_hdrc]) from [<8006c1b4>] (handle_irq_event_percpu+0x50/0x180) [<8006c1b4>] (handle_irq_event_percpu) from [<8006c320>] (handle_irq_event+0x3c/0x5c) [<8006c320>] (handle_irq_event) from [<8006f1c4>] (handle_fasteoi_irq+0x84/0x14c) [<8006f1c4>] (handle_fasteoi_irq) from [<8006b92c>] (generic_handle_irq+0x2c/0x3c) [<8006b92c>] (generic_handle_irq) from [<8000f9cc>] (handle_IRQ+0x40/0x90) [<8000f9cc>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<800130bc>] (__irq_usr+0x3c/0x60) Exception stack(0xa872ffb0 to 0xa872fff8) ffa0: 00fc4308 00ff3d70 00000000 000000ff ffc0: 00000671 00000000 00ff3b90 7edef480 00fc40e8 00000000 00000048 00ff3d34 ffe0: 000321b8 7edef140 000240a0 76d9c890 600e0010 ffffffff Code: e5964084 e0844003 e1a00005 ebfffa14 (e5943000) ---[ end trace 53dc25e918ff7216 ]--- Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Peter Chen <peter.chen@freescale.com> (cherry picked from commit c5b8111e4178387e1a6e9c700fdf887a944a5129)
-rw-r--r--drivers/usb/chipidea/otg.c1
-rw-r--r--drivers/usb/chipidea/otg.h5
-rw-r--r--drivers/usb/chipidea/otg_fsm.c1
3 files changed, 6 insertions, 1 deletions
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 1850b034a4e5..9f9cd6a75d70 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -220,6 +220,7 @@ void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
if (ci->wq) {
flush_workqueue(ci->wq);
destroy_workqueue(ci->wq);
+ ci->wq = NULL;
}
/* Disable all OTG irq and clear status */
hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index b8b4bbd53474..43296cde913d 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -21,8 +21,11 @@ void ci_handle_id_switch(struct ci_hdrc *ci);
void ci_handle_vbus_connected(struct ci_hdrc *ci);
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
{
+ WARN_ON(!ci->wq);
+
disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ if (ci->wq)
+ queue_work(ci->wq, &ci->work);
}
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index ec8f75f6a977..98443c8ceecf 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -947,6 +947,7 @@ void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci)
sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group);
del_timer_sync(&ci->hnp_polling_timer);
+ ci->fsm.otg->state = OTG_STATE_UNDEFINED;
}
/* Restart OTG fsm if resume from power lost */