Skip to content

Commit b604650

Browse files
committed
usb: dwc2: reinit for host mode during resume if lost power
If the dwc2 controller lost power in suspend, we need to reinit the core when the dwc2 in host mode. There are two methods to set the dwc2 in host mode, and we need to reinit the dwc2 to host mode separately during resume. 1. Set the dr_mode to otg, and plug in OTG cable with the ID pin conneted to GND. In this case, we can reinit the core to device mode firstly, and later after do dwc2_hsotg_resume, it can trigger the ID status change interrupt if the OTG cable is still connected, then we can init for Host mode in the ID status change interrupt handler. 2. Set the dr_mode to host, and force the dwc2 to Host mode irrespective of ID input pin. In this case, we can't depend on the ID status change, so we do force host mode and init the core during resume. With this patch, it can fix the kernel panic if the dr_mode is set to host mode during resume. [ 134.975352] Unable to handle kernel write to read-only memory at virtual address 0000000000000068 ... [ 134.981681] CPU: 0 PID: 1646 Comm: Binder:157_3 Not tainted 4.19.193 #37 [ 134.982290] Hardware name: Rockchip rk3326 S1002 avb board (DT) [ 134.982836] pstate: 60400085 (nZCv daIf +PAN -UAO) [ 134.983286] pc : kill_all_requests+0x20/0xe8 [ 134.983685] lr : dwc2_hsotg_core_init_disconnected+0x24/0x770 ... [ 135.098090] [ 135.098248] Call trace: [ 135.098503] kill_all_requests+0x20/0xe8 [ 135.098876] dwc2_hsotg_core_init_disconnected+0x24/0x770 [ 135.099377] dwc2_resume+0x108/0x110 [ 135.099722] dpm_run_callback+0x48/0x230 [ 135.100099] device_resume+0xb4/0x250 [ 135.100448] dpm_resume+0x104/0x398 [ 135.100784] dpm_resume_end+0x14/0x28 [ 135.101142] suspend_devices_and_enter+0x15c/0xa68 [ 135.101586] pm_suspend+0x458/0x6d8 [ 135.101927] state_store+0x84/0x108 [ 135.102271] kobj_attr_store+0x14/0x28 [ 135.102637] sysfs_kf_write+0x48/0x58 [ 135.102988] kernfs_fop_write+0xf4/0x220 [ 135.103367] __vfs_write+0x34/0x158 [ 135.103708] vfs_write+0xb0/0x1d0 [ 135.104027] ksys_write+0x64/0xe0 [ 135.104346] __arm64_sys_write+0x14/0x20 [ 135.104726] el0_svc_common.constprop.0+0x64/0x178 [ 135.105172] el0_svc_compat_handler+0x18/0x20 [ 135.105580] el0_svc_compat+0x8/0x34 [ 135.105929] Code: a90153f3 aa0003f6 f9001bf7 2a0203f7 (f900343f) [ 135.106485] ---[ end trace ddc1f4a0765afacd ]--- [ 135.253494] Kernel panic - not syncing: Fatal exception Change-Id: Ibfcd1c9176d8b4abb2fc8b3b5c8b0b6a866db4e7 Signed-off-by: William Wu <[email protected]>
1 parent f4d9021 commit b604650

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

drivers/usb/dwc2/platform.c

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -628,19 +628,45 @@ static int __maybe_unused dwc2_resume(struct device *dev)
628628
return ret;
629629
}
630630

631-
/* Stop hcd if dr_mode is host and PD is power off when suspend */
632-
if (dwc2->op_state == OTG_STATE_A_HOST && dwc2_is_device_mode(dwc2)) {
633-
spin_lock_irqsave(&dwc2->lock, flags);
634-
dwc2_hcd_disconnect(dwc2, true);
635-
dwc2->op_state = OTG_STATE_B_PERIPHERAL;
636-
dwc2->lx_state = DWC2_L3;
637-
if (!dwc2->driver)
638-
dwc2_hsotg_core_init_disconnected(dwc2, false);
639-
spin_unlock_irqrestore(&dwc2->lock, flags);
640-
}
631+
if (dwc2_is_device_mode(dwc2)) {
632+
if (dwc2->dr_mode == USB_DR_MODE_HOST) {
633+
/* Reinit for Host mode if lost power */
634+
dwc2_force_mode(dwc2, true);
635+
636+
spin_lock_irqsave(&dwc2->lock, flags);
637+
dwc2_hsotg_disconnect(dwc2);
638+
spin_unlock_irqrestore(&dwc2->lock, flags);
639+
640+
dwc2->op_state = OTG_STATE_A_HOST;
641+
/* Initialize the Core for Host mode */
642+
dwc2_core_init(dwc2, false);
643+
dwc2_enable_global_interrupts(dwc2);
644+
dwc2_hcd_start(dwc2);
645+
} else {
646+
/* Reinit for OTG in Host mode if lost power */
647+
if (dwc2->dr_mode == USB_DR_MODE_OTG &&
648+
dwc2->op_state == OTG_STATE_A_HOST) {
649+
/*
650+
* Reinit the core to device mode, and later
651+
* after do dwc2_hsotg_resume, it can trigger
652+
* the ID status change interrupt if the OTG
653+
* cable is still connected, then we can init
654+
* for Host mode in the ID status change
655+
* interrupt handler.
656+
*/
657+
spin_lock_irqsave(&dwc2->lock, flags);
658+
dwc2_hcd_disconnect(dwc2, true);
659+
dwc2->op_state = OTG_STATE_B_PERIPHERAL;
660+
dwc2->lx_state = DWC2_L3;
661+
if (!dwc2->driver)
662+
dwc2_hsotg_core_init_disconnected(dwc2, false);
663+
spin_unlock_irqrestore(&dwc2->lock, flags);
641664

642-
if (dwc2_is_device_mode(dwc2))
643-
ret = dwc2_hsotg_resume(dwc2);
665+
}
666+
667+
ret = dwc2_hsotg_resume(dwc2);
668+
}
669+
}
644670

645671
return ret;
646672
}

0 commit comments

Comments
 (0)