usb: dwc2: Defer forcing peripheral mode
authorDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 26 Feb 2020 10:39:04 +0000 (19:39 +0900)
committerHoegeun Kwon <hoegeun.kwon@samsung.com>
Tue, 30 Mar 2021 01:39:32 +0000 (10:39 +0900)
dwc2 forces the mode as following dr_mode when it is finally
determined. In the case of peripheral mode, however, this causes the
notification to host without any preparation about gadget driver.
In host, hcd requests device descriptor for enumeration, but it does
never get response. See log below:

 usb 2-2: new high-speed USB device number 6 using xhci_hcd
 usb 2-2: device descriptor read/64, error -110
 usb 2-2: device descriptor read/64, error -110
 usb 2-2: new high-speed USB device number 7 using xhci_hcd
 usb 2-2: device descriptor read/64, error -110
 usb 2-2: device descriptor read/64, error -110
 usb usb2-port2: attempt power cycle
 usb 2-2: new high-speed USB device number 8 using xhci_hcd
 xhci_hcd 0000:00:14.0: Timeout while waiting for setup device command
 xhci_hcd 0000:00:14.0: Timeout while waiting for setup device command
 usb 2-2: device not accepting address 8, error -62
 usb 2-2: new high-speed USB device number 9 using xhci_hcd
 xhci_hcd 0000:00:14.0: Timeout while waiting for setup device command
 xhci_hcd 0000:00:14.0: Timeout while waiting for setup device command
 usb 2-2: device not accepting address 9, error -62
 usb usb2-port2: unable to enumerate USB device

Even worse, all ports on host can get disabled at least xhci case in
this situation. To prevent this, forcing peripheral mode will be
defered until the gadget driver is prepared.

Change-Id: Ifa0ffe7f28f32fd595c6c2ca54918667b34b95fb
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/params.c

index fec17a2..92b9ca4 100644 (file)
@@ -667,7 +667,12 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
 
                break;
        case USB_DR_MODE_PERIPHERAL:
-               dwc2_force_mode(hsotg, false);
+               /*
+                * To prevent early notification to host without any
+                * preparation about device descriptor, forcing mode
+                * is defered until gadget driver is ready.
+                */
+               /* dwc2_force_mode(hsotg, false); */
                break;
        case USB_DR_MODE_OTG:
                dwc2_clear_force_mode(hsotg);
index 09c2a07..5d30ee8 100644 (file)
@@ -4469,6 +4469,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
        hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 
        if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
+               dwc2_force_mode(hsotg, false);
                ret = dwc2_lowlevel_hw_enable(hsotg);
                if (ret)
                        goto err;
index afb0dc8..262d5a1 100644 (file)
@@ -758,7 +758,8 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
        if (hsotg->dr_mode == USB_DR_MODE_HOST)
                return;
 
-       dwc2_force_mode(hsotg, false);
+       if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL)
+               dwc2_force_mode(hsotg, false);
 
        gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);