| From 4879efb34f7d49235fac334d76d9c6a77a021413 Mon Sep 17 00:00:00 2001 |
| From: "Steinar H. Gunderson" <sesse@google.com> |
| Date: Tue, 24 May 2016 20:13:15 +0200 |
| Subject: usb: dwc3: exynos: Fix deferred probing storm. |
| |
| From: Steinar H. Gunderson <sesse@google.com> |
| |
| commit 4879efb34f7d49235fac334d76d9c6a77a021413 upstream. |
| |
| dwc3-exynos has two problems during init if the regulators are slow |
| to come up (for instance if the I2C bus driver is not on the initramfs) |
| and return probe deferral. First, every time this happens, the driver |
| leaks the USB phys created; they need to be deallocated on error. |
| |
| Second, since the phy devices are created before the regulators fail, |
| this means that there's a new device to re-trigger deferred probing, |
| which causes it to essentially go into a busy loop of re-probing the |
| device until the regulators come up. |
| |
| Move the phy creation to after the regulators have succeeded, and also |
| fix cleanup on failure. On my ODROID XU4 system (with Debian's initramfs |
| which doesn't contain the I2C driver), this reduces the number of probe |
| attempts (for each of the two controllers) from more than 2000 to eight. |
| |
| Signed-off-by: Steinar H. Gunderson <sesse@google.com> |
| Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> |
| Reviewed-by: Vivek Gautam <gautam.vivek@samsung.com> |
| Fixes: d720f057fda4 ("usb: dwc3: exynos: add nop transceiver support") |
| Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/dwc3/dwc3-exynos.c | 19 +++++++++++-------- |
| 1 file changed, 11 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/usb/dwc3/dwc3-exynos.c |
| +++ b/drivers/usb/dwc3/dwc3-exynos.c |
| @@ -128,12 +128,6 @@ static int dwc3_exynos_probe(struct plat |
| |
| platform_set_drvdata(pdev, exynos); |
| |
| - ret = dwc3_exynos_register_phys(exynos); |
| - if (ret) { |
| - dev_err(dev, "couldn't register PHYs\n"); |
| - return ret; |
| - } |
| - |
| exynos->dev = dev; |
| |
| exynos->clk = devm_clk_get(dev, "usbdrd30"); |
| @@ -183,20 +177,29 @@ static int dwc3_exynos_probe(struct plat |
| goto err3; |
| } |
| |
| + ret = dwc3_exynos_register_phys(exynos); |
| + if (ret) { |
| + dev_err(dev, "couldn't register PHYs\n"); |
| + goto err4; |
| + } |
| + |
| if (node) { |
| ret = of_platform_populate(node, NULL, NULL, dev); |
| if (ret) { |
| dev_err(dev, "failed to add dwc3 core\n"); |
| - goto err4; |
| + goto err5; |
| } |
| } else { |
| dev_err(dev, "no device node, failed to add dwc3 core\n"); |
| ret = -ENODEV; |
| - goto err4; |
| + goto err5; |
| } |
| |
| return 0; |
| |
| +err5: |
| + platform_device_unregister(exynos->usb2_phy); |
| + platform_device_unregister(exynos->usb3_phy); |
| err4: |
| regulator_disable(exynos->vdd10); |
| err3: |