Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: renesas_usbhs: Reorder clock handling and power management in probe

Reorder the initialization sequence in `usbhs_probe()` to enable runtime
PM before accessing registers, preventing potential crashes due to
uninitialized clocks.

Currently, in the probe path, registers are accessed before enabling the
clocks, leading to a synchronous external abort on the RZ/V2H SoC.
The problematic call flow is as follows:

usbhs_probe()
usbhs_sys_clock_ctrl()
usbhs_bset()
usbhs_write()
iowrite16() <-- Register access before enabling clocks

Since `iowrite16()` is performed without ensuring the required clocks are
enabled, this can lead to access errors. To fix this, enable PM runtime
early in the probe function and ensure clocks are acquired before register
access, preventing crashes like the following on RZ/V2H:

[13.272640] Internal error: synchronous external abort: 0000000096000010 [#1] PREEMPT SMP
[13.280814] Modules linked in: cec renesas_usbhs(+) drm_kms_helper fuse drm backlight ipv6
[13.289088] CPU: 1 UID: 0 PID: 195 Comm: (udev-worker) Not tainted 6.14.0-rc7+ #98
[13.296640] Hardware name: Renesas RZ/V2H EVK Board based on r9a09g057h44 (DT)
[13.303834] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[13.310770] pc : usbhs_bset+0x14/0x4c [renesas_usbhs]
[13.315831] lr : usbhs_probe+0x2e4/0x5ac [renesas_usbhs]
[13.321138] sp : ffff8000827e3850
[13.324438] x29: ffff8000827e3860 x28: 0000000000000000 x27: ffff8000827e3ca0
[13.331554] x26: ffff8000827e3ba0 x25: ffff800081729668 x24: 0000000000000025
[13.338670] x23: ffff0000c0f08000 x22: 0000000000000000 x21: ffff0000c0f08010
[13.345783] x20: 0000000000000000 x19: ffff0000c3b52080 x18: 00000000ffffffff
[13.352895] x17: 0000000000000000 x16: 0000000000000000 x15: ffff8000827e36ce
[13.360009] x14: 00000000000003d7 x13: 00000000000003d7 x12: 0000000000000000
[13.367122] x11: 0000000000000000 x10: 0000000000000aa0 x9 : ffff8000827e3750
[13.374235] x8 : ffff0000c1850b00 x7 : 0000000003826060 x6 : 000000000000001c
[13.381347] x5 : 000000030d5fcc00 x4 : ffff8000825c0000 x3 : 0000000000000000
[13.388459] x2 : 0000000000000400 x1 : 0000000000000000 x0 : ffff0000c3b52080
[13.395574] Call trace:
[13.398013] usbhs_bset+0x14/0x4c [renesas_usbhs] (P)
[13.403076] platform_probe+0x68/0xdc
[13.406738] really_probe+0xbc/0x2c0
[13.410306] __driver_probe_device+0x78/0x120
[13.414653] driver_probe_device+0x3c/0x154
[13.418825] __driver_attach+0x90/0x1a0
[13.422647] bus_for_each_dev+0x7c/0xe0
[13.426470] driver_attach+0x24/0x30
[13.430032] bus_add_driver+0xe4/0x208
[13.433766] driver_register+0x68/0x130
[13.437587] __platform_driver_register+0x24/0x30
[13.442273] renesas_usbhs_driver_init+0x20/0x1000 [renesas_usbhs]
[13.448450] do_one_initcall+0x60/0x1d4
[13.452276] do_init_module+0x54/0x1f8
[13.456014] load_module+0x1754/0x1c98
[13.459750] init_module_from_file+0x88/0xcc
[13.464004] __arm64_sys_finit_module+0x1c4/0x328
[13.468689] invoke_syscall+0x48/0x104
[13.472426] el0_svc_common.constprop.0+0xc0/0xe0
[13.477113] do_el0_svc+0x1c/0x28
[13.480415] el0_svc+0x30/0xcc
[13.483460] el0t_64_sync_handler+0x10c/0x138
[13.487800] el0t_64_sync+0x198/0x19c
[13.491453] Code: 2a0103e1 12003c42 12003c63 8b010084 (79400084)
[13.497522] ---[ end trace 0000000000000000 ]---

Fixes: f1407d5c66240 ("usb: renesas_usbhs: Add Renesas USBHS common code")
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Link: https://lore.kernel.org/r/20250407105002.107181-4-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Lad Prabhakar and committed by
Greg Kroah-Hartman
ffb34a60 8fb4c9d7

+38 -12
+38 -12
drivers/usb/renesas_usbhs/common.c
··· 685 685 INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); 686 686 spin_lock_init(usbhs_priv_to_lock(priv)); 687 687 688 + /* 689 + * Acquire clocks and enable power management (PM) early in the 690 + * probe process, as the driver accesses registers during 691 + * initialization. Ensure the device is active before proceeding. 692 + */ 693 + pm_runtime_enable(dev); 694 + 695 + ret = usbhsc_clk_get(dev, priv); 696 + if (ret) 697 + goto probe_pm_disable; 698 + 699 + ret = pm_runtime_resume_and_get(dev); 700 + if (ret) 701 + goto probe_clk_put; 702 + 703 + ret = usbhsc_clk_prepare_enable(priv); 704 + if (ret) 705 + goto probe_pm_put; 706 + 688 707 /* call pipe and module init */ 689 708 ret = usbhs_pipe_probe(priv); 690 709 if (ret < 0) 691 - return ret; 710 + goto probe_clk_dis_unprepare; 692 711 693 712 ret = usbhs_fifo_probe(priv); 694 713 if (ret < 0) ··· 724 705 if (ret) 725 706 goto probe_fail_rst; 726 707 727 - ret = usbhsc_clk_get(dev, priv); 728 - if (ret) 729 - goto probe_fail_clks; 730 - 731 708 /* 732 709 * device reset here because 733 710 * USB device might be used in boot loader. ··· 736 721 if (ret) { 737 722 dev_warn(dev, "USB function not selected (GPIO)\n"); 738 723 ret = -ENOTSUPP; 739 - goto probe_end_mod_exit; 724 + goto probe_assert_rest; 740 725 } 741 726 } 742 727 ··· 750 735 ret = usbhs_platform_call(priv, hardware_init, pdev); 751 736 if (ret < 0) { 752 737 dev_err(dev, "platform init failed.\n"); 753 - goto probe_end_mod_exit; 738 + goto probe_assert_rest; 754 739 } 755 740 756 741 /* reset phy for connection */ 757 742 usbhs_platform_call(priv, phy_reset, pdev); 758 743 759 - /* power control */ 760 - pm_runtime_enable(dev); 744 + /* 745 + * Disable the clocks that were enabled earlier in the probe path, 746 + * and let the driver handle the clocks beyond this point. 747 + */ 748 + usbhsc_clk_disable_unprepare(priv); 749 + pm_runtime_put(dev); 750 + 761 751 if (!usbhs_get_dparam(priv, runtime_pwctrl)) { 762 752 usbhsc_power_ctrl(priv, 1); 763 753 usbhs_mod_autonomy_mode(priv); ··· 779 759 780 760 return ret; 781 761 782 - probe_end_mod_exit: 783 - usbhsc_clk_put(priv); 784 - probe_fail_clks: 762 + probe_assert_rest: 785 763 reset_control_assert(priv->rsts); 786 764 probe_fail_rst: 787 765 usbhs_mod_remove(priv); ··· 787 769 usbhs_fifo_remove(priv); 788 770 probe_end_pipe_exit: 789 771 usbhs_pipe_remove(priv); 772 + probe_clk_dis_unprepare: 773 + usbhsc_clk_disable_unprepare(priv); 774 + probe_pm_put: 775 + pm_runtime_put(dev); 776 + probe_clk_put: 777 + usbhsc_clk_put(priv); 778 + probe_pm_disable: 779 + pm_runtime_disable(dev); 790 780 791 781 dev_info(dev, "probe failed (%d)\n", ret); 792 782