Skip to content

Commit 522c961

Browse files
authored
clk: sunxi-ng: ccu_common: Replace ktime-dependent lock wait loop with udelay (#10119)
The Allwinner sunxi-ng clock control unit (CCU) driver utilizes readl_relaxed_poll_timeout_atomic() inside ccu_helper_wait_for_lock() to wait for PLLs to lock. This timeout loop relies internally on ktime_get() and timekeeping APIs. During early boot or clock transitions (such as CPUfreq DVFS scaling), the system's clock sources and timekeeping may be unstable or temporarily suspended. This causes ktime_get() to fail to increment or return invalid readings, turning the timeout calculation into an infinite busy-wait loop and triggering critical RCU stalls / kernel lockups. Decouple the PLL lock wait loop from the timekeeping framework by replacing the poll timeout loop with a robust, timekeeping-independent iteration loop utilizing udelay(1) (up to 100,000 iterations / 100ms timeout limit). This avoids timekeeping dependencies during sensitive frequency scaling operations and prevents infinite CPU lockups when timer interrupts are suspended. Assisted-by: Antigravity <antigravity@google.com> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
1 parent e46f5a4 commit 522c961

4 files changed

Lines changed: 71 additions & 0 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--- a/drivers/clk/sunxi-ng/ccu_common.c
2+
+++ b/drivers/clk/sunxi-ng/ccu_common.c
3+
@@ -10,6 +10,7 @@
4+
#include <linux/device.h>
5+
#include <linux/iopoll.h>
6+
#include <linux/module.h>
7+
+#include <linux/delay.h>
8+
#include <linux/slab.h>
9+
10+
#include "ccu_common.h"
11+
@@ -25,7 +26,7 @@
12+
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
13+
{
14+
void __iomem *addr;
15+
- u32 reg;
16+
+ int i;
17+
18+
if (!lock)
19+
return;
20+
@@ -35,7 +36,14 @@
21+
else
22+
addr = common->base + common->reg;
23+
24+
- WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
25+
+ for (i = 0; i < 100000; i++) {
26+
+ if (readl_relaxed(addr) & lock)
27+
+ return;
28+
+ udelay(1);
29+
+ }
30+
+ if (readl_relaxed(addr) & lock)
31+
+ return;
32+
+ pr_warn("%s: clock lock timeout\n", clk_hw_get_name(&common->hw));
33+
}
34+
EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, "SUNXI_CCU");

patch/kernel/archive/sunxi-6.18/series.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,4 +564,5 @@
564564
patches.armbian/drv-usb-gadget-composite-rename-serial-manufacturer.patch
565565
patches.armbian/drv-video-st7796s-fb-tft-driver.patch
566566
patches.armbian/include-uapi-drm_fourcc-add-ARM-tiled-format-modifier.patch
567+
patches.armbian/0996-sunxi-ng-ccu-common-atomic-lock-wait.patch
567568
patches.armbian/0999-rtw88-sdio-fix-interrupt-storm.patch
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--- a/drivers/clk/sunxi-ng/ccu_common.c
2+
+++ b/drivers/clk/sunxi-ng/ccu_common.c
3+
@@ -10,6 +10,7 @@
4+
#include <linux/device.h>
5+
#include <linux/iopoll.h>
6+
#include <linux/module.h>
7+
+#include <linux/delay.h>
8+
#include <linux/slab.h>
9+
10+
#include "ccu_common.h"
11+
@@ -25,7 +26,7 @@
12+
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
13+
{
14+
void __iomem *addr;
15+
- u32 reg;
16+
+ int i;
17+
18+
if (!lock)
19+
return;
20+
@@ -35,7 +36,14 @@
21+
else
22+
addr = common->base + common->reg;
23+
24+
- WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 25, 70000));
25+
+ for (i = 0; i < 100000; i++) {
26+
+ if (readl_relaxed(addr) & lock)
27+
+ return;
28+
+ udelay(1);
29+
+ }
30+
+ if (readl_relaxed(addr) & lock)
31+
+ return;
32+
+ pr_warn("%s: clock lock timeout\n", clk_hw_get_name(&common->hw));
33+
}
34+
EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, "SUNXI_CCU");
35+

patch/kernel/archive/sunxi-7.0/series.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@
520520
patches.armbian/drv-usb-gadget-composite-rename-serial-manufacturer.patch
521521
patches.armbian/drv-video-st7796s-fb-tft-driver.patch
522522
patches.armbian/include-uapi-drm_fourcc-add-ARM-tiled-format-modifier.patch
523+
patches.armbian/0996-sunxi-ng-ccu-common-atomic-lock-wait.patch
523524
patches.armbian/0997-i2c-mv64xxx-pin-runtime-pm.patch
524525
patches.armbian/0998-sunxi-mmc-pin-runtime-pm.patch
525526
patches.armbian/0999-rtw88-sdio-fix-interrupt-storm.patch

0 commit comments

Comments
 (0)