diff mbox

[v4,4/4] usb: dwc2: refactor common low-level hw code to platform.c

Message ID 1443771918-19075-1-git-send-email-m.szyprowski@samsung.com
State Superseded
Headers show

Commit Message

Marek Szyprowski Oct. 2, 2015, 7:45 a.m. UTC
DWC2 module on some platforms needs three additional hardware
resources: phy controller, clock and power supply. All of them must be
enabled/activated to properly initialize and operate. This was initially
handled in s3c-hsotg driver, which has been converted to 'gadget' part
of dwc2 driver. Unfortunately, not all of this code got moved to common
platform code, what resulted in accessing DWC2 registers without
enabling low-level hardware resources. This fails for example on Exynos
SoCs. This patch moves all the code for managing those resources to
common platform.c file and provides convenient wrappers for controlling
them.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
Changelog:
v4:
- fixed broken conditional compilation and adjusted comments in dwc2_hsotg
  structure documentation

v3:
- rebased onto latest 'testing/next' from Felipe Balbi (includes
  s3c_hsotg -> dwc2 rename)

v2:
- moved setting of ll_hw_enabled flag to enable/disable functions,
  as suggested by John Youn
- moved setting of phy width to dwc2_lowlevel_init function
---
 drivers/usb/dwc2/core.h     |  24 +++--
 drivers/usb/dwc2/gadget.c   | 193 ++++--------------------------------
 drivers/usb/dwc2/platform.c | 234 +++++++++++++++++++++++++++++++++++++-------
 3 files changed, 228 insertions(+), 223 deletions(-)

Comments

John Youn Oct. 5, 2015, 10:26 p.m. UTC | #1
On 10/2/2015 12:45 AM, Marek Szyprowski wrote:
> DWC2 module on some platforms needs three additional hardware
> resources: phy controller, clock and power supply. All of them must be
> enabled/activated to properly initialize and operate. This was initially
> handled in s3c-hsotg driver, which has been converted to 'gadget' part
> of dwc2 driver. Unfortunately, not all of this code got moved to common
> platform code, what resulted in accessing DWC2 registers without
> enabling low-level hardware resources. This fails for example on Exynos
> SoCs. This patch moves all the code for managing those resources to
> common platform.c file and provides convenient wrappers for controlling
> them.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> Changelog:
> v4:
> - fixed broken conditional compilation and adjusted comments in dwc2_hsotg
>   structure documentation
> 
> v3:
> - rebased onto latest 'testing/next' from Felipe Balbi (includes
>   s3c_hsotg -> dwc2 rename)
> 
> v2:
> - moved setting of ll_hw_enabled flag to enable/disable functions,
>   as suggested by John Youn
> - moved setting of phy width to dwc2_lowlevel_init function
> ---
>  drivers/usb/dwc2/core.h     |  24 +++--
>  drivers/usb/dwc2/gadget.c   | 193 ++++--------------------------------
>  drivers/usb/dwc2/platform.c | 234 +++++++++++++++++++++++++++++++++++++-------
>  3 files changed, 228 insertions(+), 223 deletions(-)
> 

Hi Marek,

I still see lockdep warnings.

Any ideas about these?


[ 1618.179611] ======================================================
[ 1618.179612] [ INFO: possible circular locking dependency detected ]
[ 1618.179613] 4.3.0-rc3-snps-00125-g744fd93 #28 Not tainted
[ 1618.179614] -------------------------------------------------------
[ 1618.179615] modprobe/2658 is trying to acquire lock:
[ 1618.179616]  (&hsotg->init_mutex){+.+.+.}, at: [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
[ 1618.179622] 
[ 1618.179622] but task is already holding lock:
[ 1618.179623]  (udc_lock){+.+.+.}, at: [<ffffffffc0374b8a>] usb_gadget_probe_driver+0x3a/0xd0 [udc_core]
[ 1618.179627] 
[ 1618.179627] which lock already depends on the new lock.
[ 1618.179627] 
[ 1618.179628] 
[ 1618.179628] the existing dependency chain (in reverse order) is:
[ 1618.179629] 
[ 1618.179629] -> #1 (udc_lock){+.+.+.}:
[ 1618.179631]        [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
[ 1618.179635]        [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
[ 1618.179638]        [<ffffffffc0374da7>] usb_add_gadget_udc_release+0x187/0x240 [udc_core]
[ 1618.179640]        [<ffffffffc0374e70>] usb_add_gadget_udc+0x10/0x20 [udc_core]
[ 1618.179642]        [<ffffffffc043b30c>] dwc2_gadget_init+0x47c/0x580 [dwc2]
[ 1618.179645]        [<ffffffffc042d2f2>] dwc2_driver_probe+0x422/0x4b0 [dwc2]
[ 1618.179648]        [<ffffffff8153fe94>] platform_drv_probe+0x34/0x90
[ 1618.179650]        [<ffffffff8153db54>] driver_probe_device+0x224/0x480
[ 1618.179652]        [<ffffffff8153deb1>] __device_attach_driver+0x71/0xa0
[ 1618.179654]        [<ffffffff8153b78d>] bus_for_each_drv+0x5d/0x90
[ 1618.179655]        [<ffffffff8153d83f>] __device_attach+0xbf/0x140
[ 1618.179657]        [<ffffffff8153df23>] device_initial_probe+0x13/0x20
[ 1618.179658]        [<ffffffff8153cb03>] bus_probe_device+0xa3/0xb0
[ 1618.179660]        [<ffffffff8153a76d>] device_add+0x40d/0x690
[ 1618.179661]        [<ffffffff8153fb81>] platform_device_add+0x111/0x270
[ 1618.179663]        [<ffffffffc0394128>] dwc2_pci_probe+0xe8/0x1d2 [dwc2_pci]
[ 1618.179665]        [<ffffffff81446085>] local_pci_probe+0x45/0xa0
[ 1618.179668]        [<ffffffff81447451>] pci_device_probe+0xe1/0x130
[ 1618.179669]        [<ffffffff8153db54>] driver_probe_device+0x224/0x480
[ 1618.179671]        [<ffffffff8153de38>] __driver_attach+0x88/0x90
[ 1618.179672]        [<ffffffff8153b6d6>] bus_for_each_dev+0x66/0xa0
[ 1618.179674]        [<ffffffff8153d31e>] driver_attach+0x1e/0x20
[ 1618.179675]        [<ffffffff8153ce8e>] bus_add_driver+0x1ee/0x280
[ 1618.179677]        [<ffffffff8153e930>] driver_register+0x60/0xe0
[ 1618.179678]        [<ffffffff81445a60>] __pci_register_driver+0x60/0x70
[ 1618.179680]        [<ffffffffc000601e>] 0xffffffffc000601e
[ 1618.179681]        [<ffffffff81002123>] do_one_initcall+0xb3/0x200
[ 1618.179684]        [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
[ 1618.179687]        [<ffffffff81120e48>] load_module+0x21a8/0x2840
[ 1618.179689]        [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
[ 1618.179691]        [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
[ 1618.179693] 
[ 1618.179693] -> #0 (&hsotg->init_mutex){+.+.+.}:
[ 1618.179695]        [<ffffffff810d97f5>] __lock_acquire+0x1d35/0x1db0
[ 1618.179697]        [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
[ 1618.179698]        [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
[ 1618.179700]        [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
[ 1618.179703]        [<ffffffffc0374a34>] udc_bind_to_driver+0xa4/0x100 [udc_core]
[ 1618.179705]        [<ffffffffc0374bca>] usb_gadget_probe_driver+0x7a/0xd0 [udc_core]
[ 1618.179707]        [<ffffffffc059a674>] usb_composite_probe+0xa4/0xc0 [libcomposite]
[ 1618.179709]        [<ffffffffc0474010>] msg_init+0x10/0x1000 [g_mass_storage]
[ 1618.179711]        [<ffffffff81002123>] do_one_initcall+0xb3/0x200
[ 1618.179713]        [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
[ 1618.179714]        [<ffffffff81120e48>] load_module+0x21a8/0x2840
[ 1618.179716]        [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
[ 1618.179717]        [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
[ 1618.179719] 
[ 1618.179719] other info that might help us debug this:
[ 1618.179719] 
[ 1618.179720]  Possible unsafe locking scenario:
[ 1618.179720] 
[ 1618.179721]        CPU0                    CPU1
[ 1618.179722]        ----                    ----
[ 1618.179722]   lock(udc_lock);
[ 1618.179723]                                lock(&hsotg->init_mutex);
[ 1618.179725]                                lock(udc_lock);
[ 1618.179726]   lock(&hsotg->init_mutex);
[ 1618.179727] 
[ 1618.179727]  *** DEADLOCK ***
[ 1618.179727] 
[ 1618.179728] 1 lock held by modprobe/2658:
[ 1618.179729]  #0:  (udc_lock){+.+.+.}, at: [<ffffffffc0374b8a>] usb_gadget_probe_driver+0x3a/0xd0 [udc_core]
[ 1618.179732] 
[ 1618.179732] stack backtrace:
[ 1618.179734] CPU: 3 PID: 2658 Comm: modprobe Not tainted 4.3.0-rc3-snps-00125-g744fd93 #28
[ 1618.179735] Hardware name: ASUS All Series/H97M-PLUS, BIOS 2305 10/09/2014
[ 1618.179736]  ffffffff82aa4b20 ffff880215a57a20 ffffffff813f3289 ffffffff82aa4b20
[ 1618.179738]  ffff880215a57a60 ffffffff810d609c ffff880215a57ac0 ffff880213560808
[ 1618.179740]  0000000000000001 0000000000000000 ffff880213560840 ffff880213560000
[ 1618.179742] Call Trace:
[ 1618.179744]  [<ffffffff813f3289>] dump_stack+0x4b/0x72
[ 1618.179746]  [<ffffffff810d609c>] print_circular_bug+0x1ec/0x260
[ 1618.179748]  [<ffffffff810d97f5>] __lock_acquire+0x1d35/0x1db0
[ 1618.179749]  [<ffffffff81539400>] ? dev_vprintk_emit+0x90/0x240
[ 1618.179752]  [<ffffffffc0000100>] ? pps_cdev_release+0x10/0x30 [pps_core]
[ 1618.179754]  [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
[ 1618.179756]  [<ffffffffc043aa3c>] ? dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
[ 1618.179758]  [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
[ 1618.179760]  [<ffffffffc043aa3c>] ? dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
[ 1618.179762]  [<ffffffff8153984c>] ? __dev_printk+0x3c/0x80
[ 1618.179764]  [<ffffffffc043aa3c>] ? dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
[ 1618.179767]  [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
[ 1618.179768]  [<ffffffffc0474000>] ? 0xffffffffc0474000
[ 1618.179770]  [<ffffffffc0374a34>] udc_bind_to_driver+0xa4/0x100 [udc_core]
[ 1618.179772]  [<ffffffffc0374bca>] usb_gadget_probe_driver+0x7a/0xd0 [udc_core]
[ 1618.179774]  [<ffffffffc059a674>] usb_composite_probe+0xa4/0xc0 [libcomposite]
[ 1618.179776]  [<ffffffffc0474010>] msg_init+0x10/0x1000 [g_mass_storage]
[ 1618.179777]  [<ffffffff81002123>] do_one_initcall+0xb3/0x200
[ 1618.179779]  [<ffffffff810f881d>] ? rcu_read_lock_sched_held+0x6d/0x80
[ 1618.179782]  [<ffffffff8120c064>] ? kmem_cache_alloc_trace+0x1f4/0x2d0
[ 1618.179783]  [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
[ 1618.179785]  [<ffffffff81120e48>] load_module+0x21a8/0x2840
[ 1618.179786]  [<ffffffff8111d0e0>] ? __symbol_put+0x40/0x40
[ 1618.179788]  [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
[ 1618.179790]  [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a

Regards,
John




--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Felipe Balbi Oct. 5, 2015, 11:27 p.m. UTC | #2
John Youn <John.Youn@synopsys.com> writes:

Hi,

> On 10/2/2015 12:45 AM, Marek Szyprowski wrote:
>> DWC2 module on some platforms needs three additional hardware
>> resources: phy controller, clock and power supply. All of them must be
>> enabled/activated to properly initialize and operate. This was initially
>> handled in s3c-hsotg driver, which has been converted to 'gadget' part
>> of dwc2 driver. Unfortunately, not all of this code got moved to common
>> platform code, what resulted in accessing DWC2 registers without
>> enabling low-level hardware resources. This fails for example on Exynos
>> SoCs. This patch moves all the code for managing those resources to
>> common platform.c file and provides convenient wrappers for controlling
>> them.
>> 
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>> Changelog:
>> v4:
>> - fixed broken conditional compilation and adjusted comments in dwc2_hsotg
>>   structure documentation
>> 
>> v3:
>> - rebased onto latest 'testing/next' from Felipe Balbi (includes
>>   s3c_hsotg -> dwc2 rename)
>> 
>> v2:
>> - moved setting of ll_hw_enabled flag to enable/disable functions,
>>   as suggested by John Youn
>> - moved setting of phy width to dwc2_lowlevel_init function
>> ---
>>  drivers/usb/dwc2/core.h     |  24 +++--
>>  drivers/usb/dwc2/gadget.c   | 193 ++++--------------------------------
>>  drivers/usb/dwc2/platform.c | 234 +++++++++++++++++++++++++++++++++++++-------
>>  3 files changed, 228 insertions(+), 223 deletions(-)
>> 
>
> Hi Marek,
>
> I still see lockdep warnings.
>
> Any ideas about these?
>
>
> [ 1618.179611] ======================================================
> [ 1618.179612] [ INFO: possible circular locking dependency detected ]
> [ 1618.179613] 4.3.0-rc3-snps-00125-g744fd93 #28 Not tainted
> [ 1618.179614] -------------------------------------------------------
> [ 1618.179615] modprobe/2658 is trying to acquire lock:
> [ 1618.179616]  (&hsotg->init_mutex){+.+.+.}, at: [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
> [ 1618.179622] 
> [ 1618.179622] but task is already holding lock:
> [ 1618.179623]  (udc_lock){+.+.+.}, at: [<ffffffffc0374b8a>] usb_gadget_probe_driver+0x3a/0xd0 [udc_core]
> [ 1618.179627] 
> [ 1618.179627] which lock already depends on the new lock.
> [ 1618.179627] 
> [ 1618.179628] 
> [ 1618.179628] the existing dependency chain (in reverse order) is:
> [ 1618.179629] 
> [ 1618.179629] -> #1 (udc_lock){+.+.+.}:
> [ 1618.179631]        [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
> [ 1618.179635]        [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
> [ 1618.179638]        [<ffffffffc0374da7>] usb_add_gadget_udc_release+0x187/0x240 [udc_core]
> [ 1618.179640]        [<ffffffffc0374e70>] usb_add_gadget_udc+0x10/0x20 [udc_core]
> [ 1618.179642]        [<ffffffffc043b30c>] dwc2_gadget_init+0x47c/0x580 [dwc2]
> [ 1618.179645]        [<ffffffffc042d2f2>] dwc2_driver_probe+0x422/0x4b0 [dwc2]
> [ 1618.179648]        [<ffffffff8153fe94>] platform_drv_probe+0x34/0x90
> [ 1618.179650]        [<ffffffff8153db54>] driver_probe_device+0x224/0x480
> [ 1618.179652]        [<ffffffff8153deb1>] __device_attach_driver+0x71/0xa0
> [ 1618.179654]        [<ffffffff8153b78d>] bus_for_each_drv+0x5d/0x90
> [ 1618.179655]        [<ffffffff8153d83f>] __device_attach+0xbf/0x140
> [ 1618.179657]        [<ffffffff8153df23>] device_initial_probe+0x13/0x20
> [ 1618.179658]        [<ffffffff8153cb03>] bus_probe_device+0xa3/0xb0
> [ 1618.179660]        [<ffffffff8153a76d>] device_add+0x40d/0x690
> [ 1618.179661]        [<ffffffff8153fb81>] platform_device_add+0x111/0x270
> [ 1618.179663]        [<ffffffffc0394128>] dwc2_pci_probe+0xe8/0x1d2 [dwc2_pci]
> [ 1618.179665]        [<ffffffff81446085>] local_pci_probe+0x45/0xa0
> [ 1618.179668]        [<ffffffff81447451>] pci_device_probe+0xe1/0x130
> [ 1618.179669]        [<ffffffff8153db54>] driver_probe_device+0x224/0x480
> [ 1618.179671]        [<ffffffff8153de38>] __driver_attach+0x88/0x90
> [ 1618.179672]        [<ffffffff8153b6d6>] bus_for_each_dev+0x66/0xa0
> [ 1618.179674]        [<ffffffff8153d31e>] driver_attach+0x1e/0x20
> [ 1618.179675]        [<ffffffff8153ce8e>] bus_add_driver+0x1ee/0x280
> [ 1618.179677]        [<ffffffff8153e930>] driver_register+0x60/0xe0
> [ 1618.179678]        [<ffffffff81445a60>] __pci_register_driver+0x60/0x70
> [ 1618.179680]        [<ffffffffc000601e>] 0xffffffffc000601e
> [ 1618.179681]        [<ffffffff81002123>] do_one_initcall+0xb3/0x200
> [ 1618.179684]        [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
> [ 1618.179687]        [<ffffffff81120e48>] load_module+0x21a8/0x2840
> [ 1618.179689]        [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
> [ 1618.179691]        [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
> [ 1618.179693] 
> [ 1618.179693] -> #0 (&hsotg->init_mutex){+.+.+.}:
> [ 1618.179695]        [<ffffffff810d97f5>] __lock_acquire+0x1d35/0x1db0
> [ 1618.179697]        [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
> [ 1618.179698]        [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
> [ 1618.179700]        [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
> [ 1618.179703]        [<ffffffffc0374a34>] udc_bind_to_driver+0xa4/0x100 [udc_core]
> [ 1618.179705]        [<ffffffffc0374bca>] usb_gadget_probe_driver+0x7a/0xd0 [udc_core]
> [ 1618.179707]        [<ffffffffc059a674>] usb_composite_probe+0xa4/0xc0 [libcomposite]
> [ 1618.179709]        [<ffffffffc0474010>] msg_init+0x10/0x1000 [g_mass_storage]
> [ 1618.179711]        [<ffffffff81002123>] do_one_initcall+0xb3/0x200
> [ 1618.179713]        [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
> [ 1618.179714]        [<ffffffff81120e48>] load_module+0x21a8/0x2840
> [ 1618.179716]        [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
> [ 1618.179717]        [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
> [ 1618.179719] 
> [ 1618.179719] other info that might help us debug this:
> [ 1618.179719] 
> [ 1618.179720]  Possible unsafe locking scenario:
> [ 1618.179720] 
> [ 1618.179721]        CPU0                    CPU1
> [ 1618.179722]        ----                    ----
> [ 1618.179722]   lock(udc_lock);
> [ 1618.179723]                                lock(&hsotg->init_mutex);

It seems like init_mutex is completely unnecessary in this driver. In
fact, why are you trying to hold a mutex while inside a spinlock ?
Marek Szyprowski Oct. 6, 2015, 8:55 a.m. UTC | #3
Hello,

On 2015-10-06 01:27, Felipe Balbi wrote:
> John Youn <John.Youn@synopsys.com> writes:
>
> Hi,
>
>> On 10/2/2015 12:45 AM, Marek Szyprowski wrote:
>>> DWC2 module on some platforms needs three additional hardware
>>> resources: phy controller, clock and power supply. All of them must be
>>> enabled/activated to properly initialize and operate. This was initially
>>> handled in s3c-hsotg driver, which has been converted to 'gadget' part
>>> of dwc2 driver. Unfortunately, not all of this code got moved to common
>>> platform code, what resulted in accessing DWC2 registers without
>>> enabling low-level hardware resources. This fails for example on Exynos
>>> SoCs. This patch moves all the code for managing those resources to
>>> common platform.c file and provides convenient wrappers for controlling
>>> them.
>>>
>>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>> ---
>>> Changelog:
>>> v4:
>>> - fixed broken conditional compilation and adjusted comments in dwc2_hsotg
>>>    structure documentation
>>>
>>> v3:
>>> - rebased onto latest 'testing/next' from Felipe Balbi (includes
>>>    s3c_hsotg -> dwc2 rename)
>>>
>>> v2:
>>> - moved setting of ll_hw_enabled flag to enable/disable functions,
>>>    as suggested by John Youn
>>> - moved setting of phy width to dwc2_lowlevel_init function
>>> ---
>>>   drivers/usb/dwc2/core.h     |  24 +++--
>>>   drivers/usb/dwc2/gadget.c   | 193 ++++--------------------------------
>>>   drivers/usb/dwc2/platform.c | 234 +++++++++++++++++++++++++++++++++++++-------
>>>   3 files changed, 228 insertions(+), 223 deletions(-)
>>>
>> Hi Marek,
>>
>> I still see lockdep warnings.
>>
>> Any ideas about these?
>>
>>
>> [ 1618.179611] ======================================================
>> [ 1618.179612] [ INFO: possible circular locking dependency detected ]
>> [ 1618.179613] 4.3.0-rc3-snps-00125-g744fd93 #28 Not tainted
>> [ 1618.179614] -------------------------------------------------------
>> [ 1618.179615] modprobe/2658 is trying to acquire lock:
>> [ 1618.179616]  (&hsotg->init_mutex){+.+.+.}, at: [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
>> [ 1618.179622]
>> [ 1618.179622] but task is already holding lock:
>> [ 1618.179623]  (udc_lock){+.+.+.}, at: [<ffffffffc0374b8a>] usb_gadget_probe_driver+0x3a/0xd0 [udc_core]
>> [ 1618.179627]
>> [ 1618.179627] which lock already depends on the new lock.
>> [ 1618.179627]
>> [ 1618.179628]
>> [ 1618.179628] the existing dependency chain (in reverse order) is:
>> [ 1618.179629]
>> [ 1618.179629] -> #1 (udc_lock){+.+.+.}:
>> [ 1618.179631]        [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
>> [ 1618.179635]        [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
>> [ 1618.179638]        [<ffffffffc0374da7>] usb_add_gadget_udc_release+0x187/0x240 [udc_core]
>> [ 1618.179640]        [<ffffffffc0374e70>] usb_add_gadget_udc+0x10/0x20 [udc_core]
>> [ 1618.179642]        [<ffffffffc043b30c>] dwc2_gadget_init+0x47c/0x580 [dwc2]
>> [ 1618.179645]        [<ffffffffc042d2f2>] dwc2_driver_probe+0x422/0x4b0 [dwc2]
>> [ 1618.179648]        [<ffffffff8153fe94>] platform_drv_probe+0x34/0x90
>> [ 1618.179650]        [<ffffffff8153db54>] driver_probe_device+0x224/0x480
>> [ 1618.179652]        [<ffffffff8153deb1>] __device_attach_driver+0x71/0xa0
>> [ 1618.179654]        [<ffffffff8153b78d>] bus_for_each_drv+0x5d/0x90
>> [ 1618.179655]        [<ffffffff8153d83f>] __device_attach+0xbf/0x140
>> [ 1618.179657]        [<ffffffff8153df23>] device_initial_probe+0x13/0x20
>> [ 1618.179658]        [<ffffffff8153cb03>] bus_probe_device+0xa3/0xb0
>> [ 1618.179660]        [<ffffffff8153a76d>] device_add+0x40d/0x690
>> [ 1618.179661]        [<ffffffff8153fb81>] platform_device_add+0x111/0x270
>> [ 1618.179663]        [<ffffffffc0394128>] dwc2_pci_probe+0xe8/0x1d2 [dwc2_pci]
>> [ 1618.179665]        [<ffffffff81446085>] local_pci_probe+0x45/0xa0
>> [ 1618.179668]        [<ffffffff81447451>] pci_device_probe+0xe1/0x130
>> [ 1618.179669]        [<ffffffff8153db54>] driver_probe_device+0x224/0x480
>> [ 1618.179671]        [<ffffffff8153de38>] __driver_attach+0x88/0x90
>> [ 1618.179672]        [<ffffffff8153b6d6>] bus_for_each_dev+0x66/0xa0
>> [ 1618.179674]        [<ffffffff8153d31e>] driver_attach+0x1e/0x20
>> [ 1618.179675]        [<ffffffff8153ce8e>] bus_add_driver+0x1ee/0x280
>> [ 1618.179677]        [<ffffffff8153e930>] driver_register+0x60/0xe0
>> [ 1618.179678]        [<ffffffff81445a60>] __pci_register_driver+0x60/0x70
>> [ 1618.179680]        [<ffffffffc000601e>] 0xffffffffc000601e
>> [ 1618.179681]        [<ffffffff81002123>] do_one_initcall+0xb3/0x200
>> [ 1618.179684]        [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
>> [ 1618.179687]        [<ffffffff81120e48>] load_module+0x21a8/0x2840
>> [ 1618.179689]        [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
>> [ 1618.179691]        [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
>> [ 1618.179693]
>> [ 1618.179693] -> #0 (&hsotg->init_mutex){+.+.+.}:
>> [ 1618.179695]        [<ffffffff810d97f5>] __lock_acquire+0x1d35/0x1db0
>> [ 1618.179697]        [<ffffffff810da56d>] lock_acquire+0xdd/0x1f0
>> [ 1618.179698]        [<ffffffff818658a6>] mutex_lock_nested+0x76/0x3e0
>> [ 1618.179700]        [<ffffffffc043aa3c>] dwc2_hsotg_udc_start+0x5c/0x200 [dwc2]
>> [ 1618.179703]        [<ffffffffc0374a34>] udc_bind_to_driver+0xa4/0x100 [udc_core]
>> [ 1618.179705]        [<ffffffffc0374bca>] usb_gadget_probe_driver+0x7a/0xd0 [udc_core]
>> [ 1618.179707]        [<ffffffffc059a674>] usb_composite_probe+0xa4/0xc0 [libcomposite]
>> [ 1618.179709]        [<ffffffffc0474010>] msg_init+0x10/0x1000 [g_mass_storage]
>> [ 1618.179711]        [<ffffffff81002123>] do_one_initcall+0xb3/0x200
>> [ 1618.179713]        [<ffffffff811a8a41>] do_init_module+0x5f/0x1e7
>> [ 1618.179714]        [<ffffffff81120e48>] load_module+0x21a8/0x2840
>> [ 1618.179716]        [<ffffffff8112170a>] SyS_finit_module+0x9a/0xc0
>> [ 1618.179717]        [<ffffffff81869c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
>> [ 1618.179719]
>> [ 1618.179719] other info that might help us debug this:
>> [ 1618.179719]
>> [ 1618.179720]  Possible unsafe locking scenario:
>> [ 1618.179720]
>> [ 1618.179721]        CPU0                    CPU1
>> [ 1618.179722]        ----                    ----
>> [ 1618.179722]   lock(udc_lock);
>> [ 1618.179723]                                lock(&hsotg->init_mutex);
> It seems like init_mutex is completely unnecessary in this driver. In
> fact, why are you trying to hold a mutex while inside a spinlock ?

init_mutex is a leftover from the time, when s3c-hsotg driver didn't 
implement
proper pull up/down control and emulated it by enabling disabling phy. 
It can
be removed now. btw, the possible lockup pointed by John is an 
interaction of
two mutexes, not a case of taking mutex under a spinlock.

I will send an updated patch in a few minutes.

Best regards
diff mbox

Patch

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 3056981..3db5ef2 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -578,6 +578,15 @@  struct dwc2_hregs_backup {
  *                      - USB_DR_MODE_PERIPHERAL
  *                      - USB_DR_MODE_HOST
  *                      - USB_DR_MODE_OTG
+ * @hcd_enabled		Host mode sub-driver initialization indicator.
+ * @gadget_enabled	Peripheral mode sub-driver initialization indicator.
+ * l@l_hw_enabled	Status of low-level hardware resources.
+ * @phy:                The otg phy transceiver structure for phy control.
+ * @uphy:               The otg phy transceiver structure for old USB phy control.
+ * @plat:               The platform specific configuration data. This can be removed once
+ *                      all SoCs support usb transceiver.
+ * @supplies:           Definition of USB power supplies
+ * @phyif:              PHY interface width
  * @lock:		Spinlock that protects all the driver data structures
  * @priv:		Stores a pointer to the struct usb_hcd
  * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
@@ -670,12 +679,6 @@  struct dwc2_hregs_backup {
  * These are for peripheral mode:
  *
  * @driver:             USB gadget driver
- * @phy:                The otg phy transceiver structure for phy control.
- * @uphy:               The otg phy transceiver structure for old USB phy control.
- * @plat:               The platform specific configuration data. This can be removed once
- *                      all SoCs support usb transceiver.
- * @supplies:           Definition of USB power supplies
- * @phyif:              PHY interface width
  * @dedicated_fifos:    Set if the hardware has dedicated IN-EP fifos.
  * @num_of_eps:         Number of available EPs (excluding EP0)
  * @debug_root:         Root directrory for debugfs.
@@ -705,10 +708,13 @@  struct dwc2_hsotg {
 	enum usb_dr_mode dr_mode;
 	unsigned int hcd_enabled:1;
 	unsigned int gadget_enabled:1;
+	unsigned int ll_hw_enabled:1;
 
 	struct phy *phy;
 	struct usb_phy *uphy;
+	struct dwc2_hsotg_plat *plat;
 	struct regulator_bulk_data supplies[ARRAY_SIZE(dwc2_hsotg_supply_names)];
+	u32 phyif;
 
 	spinlock_t lock;
 	struct mutex init_mutex;
@@ -812,9 +818,6 @@  struct dwc2_hsotg {
 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 	/* Gadget structures */
 	struct usb_gadget_driver *driver;
-	struct dwc2_hsotg_plat *plat;
-
-	u32 phyif;
 	int fifo_mem;
 	unsigned int dedicated_fifos:1;
 	unsigned char num_of_eps;
@@ -1103,7 +1106,8 @@  extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
 
 extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
 
-
+extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
+extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
 
 /*
  * Dump core registers and SPRAM
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 19202c1c..c283c9d 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -25,15 +25,11 @@ 
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
 #include <linux/of_platform.h>
-#include <linux/phy/phy.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/phy.h>
-#include <linux/platform_data/s3c-hsotg.h>
 
 #include "core.h"
 #include "hw.h"
@@ -3022,50 +3018,6 @@  static struct usb_ep_ops dwc2_hsotg_ep_ops = {
 };
 
 /**
- * dwc2_hsotg_phy_enable - enable platform phy dev
- * @hsotg: The driver state
- *
- * A wrapper for platform code responsible for controlling
- * low-level USB code
- */
-static void dwc2_hsotg_phy_enable(struct dwc2_hsotg *hsotg)
-{
-	struct platform_device *pdev = to_platform_device(hsotg->dev);
-
-	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
-
-	if (hsotg->uphy)
-		usb_phy_init(hsotg->uphy);
-	else if (hsotg->plat && hsotg->plat->phy_init)
-		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
-	else {
-		phy_init(hsotg->phy);
-		phy_power_on(hsotg->phy);
-	}
-}
-
-/**
- * dwc2_hsotg_phy_disable - disable platform phy dev
- * @hsotg: The driver state
- *
- * A wrapper for platform code responsible for controlling
- * low-level USB code
- */
-static void dwc2_hsotg_phy_disable(struct dwc2_hsotg *hsotg)
-{
-	struct platform_device *pdev = to_platform_device(hsotg->dev);
-
-	if (hsotg->uphy)
-		usb_phy_shutdown(hsotg->uphy);
-	else if (hsotg->plat && hsotg->plat->phy_exit)
-		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
-	else {
-		phy_power_off(hsotg->phy);
-		phy_exit(hsotg->phy);
-	}
-}
-
-/**
  * dwc2_hsotg_init - initalize the usb core
  * @hsotg: The driver state
  */
@@ -3146,14 +3098,12 @@  static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
 	hsotg->gadget.dev.of_node = hsotg->dev->of_node;
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 
-	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
-				    hsotg->supplies);
-	if (ret) {
-		dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
-		goto err;
+	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
+		ret = dwc2_lowlevel_hw_enable(hsotg);
+		if (ret)
+			goto err;
 	}
 
-	dwc2_hsotg_phy_enable(hsotg);
 	if (!IS_ERR_OR_NULL(hsotg->uphy))
 		otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget);
 
@@ -3211,9 +3161,9 @@  static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
 
 	if (!IS_ERR_OR_NULL(hsotg->uphy))
 		otg_set_peripheral(hsotg->uphy->otg, NULL);
-	dwc2_hsotg_phy_disable(hsotg);
 
-	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
+	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
+		dwc2_lowlevel_hw_disable(hsotg);
 
 	mutex_unlock(&hsotg->init_mutex);
 
@@ -3557,15 +3507,11 @@  static inline void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg) { }
 int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 {
 	struct device *dev = hsotg->dev;
-	struct dwc2_hsotg_plat *plat = dev->platform_data;
 	int epnum;
 	int ret;
 	int i;
 	u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE;
 
-	/* Set default UTMI width */
-	hsotg->phyif = GUSBCFG_PHYIF16;
-
 	/* Initialize to legacy fifo configuration values */
 	hsotg->g_rx_fifo_sz = 2048;
 	hsotg->g_np_g_tx_fifo_sz = 1024;
@@ -3579,32 +3525,6 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 	for (i = 0; i < MAX_EPS_CHANNELS; i++)
 		dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
 						hsotg->g_tx_fifo_sz[i]);
-	/*
-	 * If platform probe couldn't find a generic PHY or an old style
-	 * USB PHY, fall back to pdata
-	 */
-	if (IS_ERR_OR_NULL(hsotg->phy) && IS_ERR_OR_NULL(hsotg->uphy)) {
-		plat = dev_get_platdata(dev);
-		if (!plat) {
-			dev_err(dev,
-			"no platform data or transceiver defined\n");
-			return -EPROBE_DEFER;
-		}
-		hsotg->plat = plat;
-	} else if (hsotg->phy) {
-		/*
-		 * If using the generic PHY framework, check if the PHY bus
-		 * width is 8-bit and set the phyif appropriately.
-		 */
-		if (phy_get_bus_width(hsotg->phy) == 8)
-			hsotg->phyif = GUSBCFG_PHYIF8;
-	}
-
-	hsotg->clk = devm_clk_get(dev, "otg");
-	if (IS_ERR(hsotg->clk)) {
-		hsotg->clk = NULL;
-		dev_dbg(dev, "cannot get otg clock\n");
-	}
 
 	hsotg->gadget.max_speed = USB_SPEED_HIGH;
 	hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
@@ -3614,38 +3534,6 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 	else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
 		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
 
-	/* reset the system */
-
-	ret = clk_prepare_enable(hsotg->clk);
-	if (ret) {
-		dev_err(dev, "failed to enable otg clk\n");
-		goto err_clk;
-	}
-
-
-	/* regulators */
-
-	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
-		hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
-
-	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies),
-				 hsotg->supplies);
-	if (ret) {
-		dev_err(dev, "failed to request supplies: %d\n", ret);
-		goto err_clk;
-	}
-
-	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
-				    hsotg->supplies);
-
-	if (ret) {
-		dev_err(dev, "failed to enable supplies: %d\n", ret);
-		goto err_clk;
-	}
-
-	/* usb phy enable */
-	dwc2_hsotg_phy_enable(hsotg);
-
 	/*
 	 * Force Device mode before initialization.
 	 * This allows correctly configuring fifo for device mode.
@@ -3663,7 +3551,7 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 	ret = dwc2_hsotg_hw_cfg(hsotg);
 	if (ret) {
 		dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret);
-		goto err_clk;
+		return ret;
 	}
 
 	dwc2_hsotg_init(hsotg);
@@ -3675,35 +3563,28 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 			DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
 	if (!hsotg->ctrl_buff) {
 		dev_err(dev, "failed to allocate ctrl request buff\n");
-		ret = -ENOMEM;
-		goto err_supplies;
+		return -ENOMEM;
 	}
 
 	hsotg->ep0_buff = devm_kzalloc(hsotg->dev,
 			DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
 	if (!hsotg->ep0_buff) {
 		dev_err(dev, "failed to allocate ctrl reply buff\n");
-		ret = -ENOMEM;
-		goto err_supplies;
+		return -ENOMEM;
 	}
 
 	ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED,
 				dev_name(hsotg->dev), hsotg);
 	if (ret < 0) {
-		dwc2_hsotg_phy_disable(hsotg);
-		clk_disable_unprepare(hsotg->clk);
-		regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
-				       hsotg->supplies);
 		dev_err(dev, "cannot claim IRQ for gadget\n");
-		goto err_supplies;
+		return ret;
 	}
 
 	/* hsotg->num_of_eps holds number of EPs other than ep0 */
 
 	if (hsotg->num_of_eps == 0) {
 		dev_err(dev, "wrong number of EPs (zero)\n");
-		ret = -EINVAL;
-		goto err_supplies;
+		return -EINVAL;
 	}
 
 	/* setup endpoint information */
@@ -3717,8 +3598,7 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 						     GFP_KERNEL);
 	if (!hsotg->ctrl_req) {
 		dev_err(dev, "failed to allocate ctrl req\n");
-		ret = -ENOMEM;
-		goto err_supplies;
+		return -ENOMEM;
 	}
 
 	/* initialise the endpoints now the core has been initialised */
@@ -3731,30 +3611,13 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 								epnum, 0);
 	}
 
-	/* disable power and clock */
-	dwc2_hsotg_phy_disable(hsotg);
-
-	ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
-				    hsotg->supplies);
-	if (ret) {
-		dev_err(dev, "failed to disable supplies: %d\n", ret);
-		goto err_supplies;
-	}
-
 	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
 	if (ret)
-		goto err_supplies;
+		return ret;
 
 	dwc2_hsotg_dump(hsotg);
 
 	return 0;
-
-err_supplies:
-	dwc2_hsotg_phy_disable(hsotg);
-err_clk:
-	clk_disable_unprepare(hsotg->clk);
-
-	return ret;
 }
 
 /**
@@ -3764,7 +3627,6 @@  err_clk:
 int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg)
 {
 	usb_del_gadget_udc(&hsotg->gadget);
-	clk_disable_unprepare(hsotg->clk);
 
 	return 0;
 }
@@ -3772,12 +3634,9 @@  int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg)
 int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
 {
 	unsigned long flags;
-	int ret = 0;
 
 	if (hsotg->lx_state != DWC2_L0)
-		return ret;
-
-	mutex_lock(&hsotg->init_mutex);
+		return 0;
 
 	if (hsotg->driver) {
 		int ep;
@@ -3792,52 +3651,34 @@  int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
 		hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 
-		dwc2_hsotg_phy_disable(hsotg);
-
 		for (ep = 0; ep < hsotg->num_of_eps; ep++) {
 			if (hsotg->eps_in[ep])
 				dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
 			if (hsotg->eps_out[ep])
 				dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
 		}
-
-		ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
-					     hsotg->supplies);
-		clk_disable(hsotg->clk);
 	}
 
-	mutex_unlock(&hsotg->init_mutex);
-
-	return ret;
+	return 0;
 }
 
 int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
 {
 	unsigned long flags;
-	int ret = 0;
 
 	if (hsotg->lx_state == DWC2_L2)
-		return ret;
-
-	mutex_lock(&hsotg->init_mutex);
+		return 0;
 
 	if (hsotg->driver) {
 		dev_info(hsotg->dev, "resuming usb gadget %s\n",
 			 hsotg->driver->driver.name);
 
-		clk_enable(hsotg->clk);
-		ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
-					    hsotg->supplies);
-
-		dwc2_hsotg_phy_enable(hsotg);
-
 		spin_lock_irqsave(&hsotg->lock, flags);
 		dwc2_hsotg_core_init_disconnected(hsotg, false);
 		if (hsotg->enabled)
 			dwc2_hsotg_core_connect(hsotg);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
-	mutex_unlock(&hsotg->init_mutex);
 
-	return ret;
+	return 0;
 }
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index b920e43..a62514f 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -37,11 +37,14 @@ 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/of_device.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_data/s3c-hsotg.h>
 
 #include <linux/usb/of.h>
 
@@ -111,6 +114,145 @@  static const struct dwc2_core_params params_rk3066 = {
 	.hibernation			= -1,
 };
 
+static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
+{
+	struct platform_device *pdev = to_platform_device(hsotg->dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+				    hsotg->supplies);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(hsotg->clk);
+	if (ret)
+		return ret;
+
+	if (hsotg->uphy)
+		ret = usb_phy_init(hsotg->uphy);
+	else if (hsotg->plat && hsotg->plat->phy_init)
+		ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
+	else {
+		ret = phy_power_on(hsotg->phy);
+		if (ret == 0)
+			ret = phy_init(hsotg->phy);
+	}
+
+	return ret;
+}
+
+/**
+ * dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources
+ * @hsotg: The driver state
+ *
+ * A wrapper for platform code responsible for controlling
+ * low-level USB platform resources (phy, clock, regulators)
+ */
+int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
+{
+	int ret = __dwc2_lowlevel_hw_enable(hsotg);
+
+	if (ret == 0)
+		hsotg->ll_hw_enabled = true;
+	return ret;
+}
+
+static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
+{
+	struct platform_device *pdev = to_platform_device(hsotg->dev);
+	int ret = 0;
+
+	if (hsotg->uphy)
+		usb_phy_shutdown(hsotg->uphy);
+	else if (hsotg->plat && hsotg->plat->phy_exit)
+		ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
+	else {
+		ret = phy_exit(hsotg->phy);
+		if (ret == 0)
+			ret = phy_power_off(hsotg->phy);
+	}
+	if (ret)
+		return ret;
+
+	clk_disable_unprepare(hsotg->clk);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
+				     hsotg->supplies);
+
+	return ret;
+}
+
+/**
+ * dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources
+ * @hsotg: The driver state
+ *
+ * A wrapper for platform code responsible for controlling
+ * low-level USB platform resources (phy, clock, regulators)
+ */
+int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
+{
+	int ret = __dwc2_lowlevel_hw_disable(hsotg);
+
+	if (ret == 0)
+		hsotg->ll_hw_enabled = false;
+	return ret;
+}
+
+static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
+{
+	int i, ret;
+
+	/* Set default UTMI width */
+	hsotg->phyif = GUSBCFG_PHYIF16;
+
+	/*
+	 * Attempt to find a generic PHY, then look for an old style
+	 * USB PHY and then fall back to pdata
+	 */
+	hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
+	if (IS_ERR(hsotg->phy)) {
+		hsotg->phy = NULL;
+		hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
+		if (IS_ERR(hsotg->uphy))
+			hsotg->uphy = NULL;
+		else
+			hsotg->plat = dev_get_platdata(hsotg->dev);
+	}
+
+	if (hsotg->phy) {
+		/*
+		 * If using the generic PHY framework, check if the PHY bus
+		 * width is 8-bit and set the phyif appropriately.
+		 */
+		if (phy_get_bus_width(hsotg->phy) == 8)
+			hsotg->phyif = GUSBCFG_PHYIF8;
+	}
+
+	if (!hsotg->phy && !hsotg->uphy && !hsotg->plat) {
+		dev_err(hsotg->dev, "no platform data or transceiver defined\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* Clock */
+	hsotg->clk = devm_clk_get(hsotg->dev, "otg");
+	if (IS_ERR(hsotg->clk)) {
+		hsotg->clk = NULL;
+		dev_dbg(hsotg->dev, "cannot get otg clock\n");
+	}
+
+	/* Regulators */
+	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
+		hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
+
+	ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
+				      hsotg->supplies);
+	if (ret) {
+		dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
 /**
  * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
  * DWC_otg driver
@@ -126,12 +268,19 @@  static int dwc2_driver_remove(struct platform_device *dev)
 {
 	struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
 
+	mutex_lock(&hsotg->init_mutex);
+
 	dwc2_debugfs_exit(hsotg);
 	if (hsotg->hcd_enabled)
 		dwc2_hcd_remove(hsotg);
 	if (hsotg->gadget_enabled)
 		dwc2_hsotg_remove(hsotg);
 
+	if (hsotg->ll_hw_enabled)
+		dwc2_lowlevel_hw_disable(hsotg);
+
+	mutex_unlock(&hsotg->init_mutex);
+
 	return 0;
 }
 
@@ -163,8 +312,6 @@  static int dwc2_driver_probe(struct platform_device *dev)
 	struct dwc2_core_params defparams;
 	struct dwc2_hsotg *hsotg;
 	struct resource *res;
-	struct phy *phy;
-	struct usb_phy *uphy;
 	int retval;
 	int irq;
 
@@ -233,32 +380,13 @@  static int dwc2_driver_probe(struct platform_device *dev)
 			"Configuration mismatch. Forcing peripheral mode\n");
 	}
 
-	/*
-	 * Attempt to find a generic PHY, then look for an old style
-	 * USB PHY
-	 */
-	phy = devm_phy_get(&dev->dev, "usb2-phy");
-	if (IS_ERR(phy)) {
-		hsotg->phy = NULL;
-		uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
-		if (IS_ERR(uphy))
-			hsotg->uphy = NULL;
-		else
-			hsotg->uphy = uphy;
-	} else {
-		hsotg->phy = phy;
-		phy_power_on(hsotg->phy);
-		phy_init(hsotg->phy);
-	}
+	retval = dwc2_lowlevel_hw_init(hsotg);
+	if (retval)
+		return retval;
 
 	spin_lock_init(&hsotg->lock);
 	mutex_init(&hsotg->init_mutex);
 
-	/* Detect config values from hardware */
-	retval = dwc2_get_hwparams(hsotg);
-	if (retval)
-		return retval;
-
 	hsotg->core_params = devm_kzalloc(&dev->dev,
 				sizeof(*hsotg->core_params), GFP_KERNEL);
 	if (!hsotg->core_params)
@@ -266,13 +394,24 @@  static int dwc2_driver_probe(struct platform_device *dev)
 
 	dwc2_set_all_params(hsotg->core_params, -1);
 
+	retval = dwc2_lowlevel_hw_enable(hsotg);
+	if (retval)
+		return retval;
+
+	/* Detect config values from hardware */
+	retval = dwc2_get_hwparams(hsotg);
+	if (retval)
+		goto error;
+
 	/* Validate parameter values */
 	dwc2_set_parameters(hsotg, params);
 
+	mutex_lock(&hsotg->init_mutex);
+
 	if (hsotg->dr_mode != USB_DR_MODE_HOST) {
 		retval = dwc2_gadget_init(hsotg, irq);
 		if (retval)
-			return retval;
+			goto err_unlock;
 		hsotg->gadget_enabled = 1;
 	}
 
@@ -281,7 +420,7 @@  static int dwc2_driver_probe(struct platform_device *dev)
 		if (retval) {
 			if (hsotg->gadget_enabled)
 				dwc2_hsotg_remove(hsotg);
-			return retval;
+			goto err_unlock;
 		}
 		hsotg->hcd_enabled = 1;
 	}
@@ -290,6 +429,18 @@  static int dwc2_driver_probe(struct platform_device *dev)
 
 	dwc2_debugfs_init(hsotg);
 
+	/* Gadget code manages lowlevel hw on its own */
+	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
+		dwc2_lowlevel_hw_disable(hsotg);
+
+	mutex_unlock(&hsotg->init_mutex);
+
+	return 0;
+
+err_unlock:
+	mutex_unlock(&hsotg->init_mutex);
+error:
+	dwc2_lowlevel_hw_disable(hsotg);
 	return retval;
 }
 
@@ -298,13 +449,16 @@  static int __maybe_unused dwc2_suspend(struct device *dev)
 	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (dwc2_is_device_mode(dwc2)) {
-		ret = dwc2_hsotg_suspend(dwc2);
-	} else {
-		phy_exit(dwc2->phy);
-		phy_power_off(dwc2->phy);
+	mutex_lock(&dwc2->init_mutex);
+
+	if (dwc2_is_device_mode(dwc2))
+		dwc2_hsotg_suspend(dwc2);
+
+	if (dwc2->ll_hw_enabled)
+		ret = __dwc2_lowlevel_hw_disable(dwc2);
+
+	mutex_unlock(&dwc2->init_mutex);
 
-	}
 	return ret;
 }
 
@@ -313,13 +467,19 @@  static int __maybe_unused dwc2_resume(struct device *dev)
 	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (dwc2_is_device_mode(dwc2)) {
-		ret = dwc2_hsotg_resume(dwc2);
-	} else {
-		phy_power_on(dwc2->phy);
-		phy_init(dwc2->phy);
+	mutex_lock(&dwc2->init_mutex);
 
+	if (dwc2->ll_hw_enabled) {
+		ret = __dwc2_lowlevel_hw_enable(dwc2);
+		if (ret)
+			goto err;
 	}
+
+	if (dwc2_is_device_mode(dwc2))
+		ret = dwc2_hsotg_resume(dwc2);
+err:
+	mutex_unlock(&dwc2->init_mutex);
+
 	return ret;
 }