drivers/clk/spacemit/ccu-k1.c | 3 ++- drivers/clk/spacemit/ccu_mix.h | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-)
The pll1_d8 clock is enabled by the boot loader, and is ultimately a
parent for numerous clocks, including those used by APB and AXI buses.
Guodong Xu discovered that this clock got disabled while responding to
getting -EPROBE_DEFER when requesting a reset controller.
The needed clock (CLK_DMA, along with its parents) had already been
enabled. To respond to the probe deferral return, the CLK_DMA clock
was disabled, and this led to parent clocks also reducing their enable
count. When the enable count for pll1_d8 was decremented it became 0,
which caused it to be disabled. This led to a system hang.
Marking that clock critical resolves this by preventing it from being
disabled.
Define a new macro CCU_FACTOR_GATE_DEFINE() to allow clock flags to
be supplied for a CCU_FACTOR_GATE clock.
Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC")
Signed-off-by: Alex Elder <elder@riscstar.com>
Tested-by: Guodong Xu <guodong@riscstar.com>
Reviewed-by: Haylen Chu <heylenay@4d2.org>
---
v3: Define struct with static scope; added Haylen's Reviewed-by
v2: Reworded the description to provide better detail
drivers/clk/spacemit/ccu-k1.c | 3 ++-
drivers/clk/spacemit/ccu_mix.h | 21 +++++++++++++--------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c
index cdde37a052353..df65009a07bb1 100644
--- a/drivers/clk/spacemit/ccu-k1.c
+++ b/drivers/clk/spacemit/ccu-k1.c
@@ -170,7 +170,8 @@ CCU_FACTOR_GATE_DEFINE(pll1_d4, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(3), 4,
CCU_FACTOR_GATE_DEFINE(pll1_d5, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(4), 5, 1);
CCU_FACTOR_GATE_DEFINE(pll1_d6, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(5), 6, 1);
CCU_FACTOR_GATE_DEFINE(pll1_d7, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(6), 7, 1);
-CCU_FACTOR_GATE_DEFINE(pll1_d8, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(7), 8, 1);
+CCU_FACTOR_GATE_FLAGS_DEFINE(pll1_d8, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(7), 8, 1,
+ CLK_IS_CRITICAL);
CCU_FACTOR_GATE_DEFINE(pll1_d11_223p4, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(15), 11, 1);
CCU_FACTOR_GATE_DEFINE(pll1_d13_189, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(16), 13, 1);
CCU_FACTOR_GATE_DEFINE(pll1_d23_106p8, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(20), 23, 1);
diff --git a/drivers/clk/spacemit/ccu_mix.h b/drivers/clk/spacemit/ccu_mix.h
index 51d19f5d6aacb..54d40cd39b275 100644
--- a/drivers/clk/spacemit/ccu_mix.h
+++ b/drivers/clk/spacemit/ccu_mix.h
@@ -101,16 +101,21 @@ static struct ccu_mix _name = { \
} \
}
+#define CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
+ _mul, _flags) \
+static struct ccu_mix _name = { \
+ .gate = CCU_GATE_INIT(_mask_gate), \
+ .factor = CCU_FACTOR_INIT(_div, _mul), \
+ .common = { \
+ .reg_ctrl = _reg_ctrl, \
+ CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, _flags) \
+ } \
+}
+
#define CCU_FACTOR_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
_mul) \
-static struct ccu_mix _name = { \
- .gate = CCU_GATE_INIT(_mask_gate), \
- .factor = CCU_FACTOR_INIT(_div, _mul), \
- .common = { \
- .reg_ctrl = _reg_ctrl, \
- CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, 0) \
- } \
-}
+ CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
+ _mul, 0)
#define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \
_mask_gate, _flags) \
base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
--
2.45.2
On Thu, 12 Jun 2025 17:48:55 -0500, Alex Elder wrote: > The pll1_d8 clock is enabled by the boot loader, and is ultimately a > parent for numerous clocks, including those used by APB and AXI buses. > Guodong Xu discovered that this clock got disabled while responding to > getting -EPROBE_DEFER when requesting a reset controller. > > The needed clock (CLK_DMA, along with its parents) had already been > enabled. To respond to the probe deferral return, the CLK_DMA clock > was disabled, and this led to parent clocks also reducing their enable > count. When the enable count for pll1_d8 was decremented it became 0, > which caused it to be disabled. This led to a system hang. > > [...] Applied, thanks! [1/1] clk: spacemit: mark K1 pll1_d8 as critical https://github.com/spacemit-com/linux/commit/7554729de27daf6d54bcf8689d863bbe267828bf Best regards, -- Yixun Lan
On 6/12/25 5:48 PM, Alex Elder wrote: > The pll1_d8 clock is enabled by the boot loader, and is ultimately a > parent for numerous clocks, including those used by APB and AXI buses. > Guodong Xu discovered that this clock got disabled while responding to > getting -EPROBE_DEFER when requesting a reset controller. > > The needed clock (CLK_DMA, along with its parents) had already been > enabled. To respond to the probe deferral return, the CLK_DMA clock > was disabled, and this led to parent clocks also reducing their enable > count. When the enable count for pll1_d8 was decremented it became 0, > which caused it to be disabled. This led to a system hang. > > Marking that clock critical resolves this by preventing it from being > disabled. > > Define a new macro CCU_FACTOR_GATE_DEFINE() to allow clock flags to > be supplied for a CCU_FACTOR_GATE clock. Is there any reason this bug fix cannot be merged? It was first posted a month ago, and although there was some initial discussion that led to revisions, this version has been waiting for over three weeks. -Alex > > Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC") > Signed-off-by: Alex Elder <elder@riscstar.com> > Tested-by: Guodong Xu <guodong@riscstar.com> > Reviewed-by: Haylen Chu <heylenay@4d2.org> > --- > v3: Define struct with static scope; added Haylen's Reviewed-by > v2: Reworded the description to provide better detail > > drivers/clk/spacemit/ccu-k1.c | 3 ++- > drivers/clk/spacemit/ccu_mix.h | 21 +++++++++++++-------- > 2 files changed, 15 insertions(+), 9 deletions(-) > > diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c > index cdde37a052353..df65009a07bb1 100644 > --- a/drivers/clk/spacemit/ccu-k1.c > +++ b/drivers/clk/spacemit/ccu-k1.c > @@ -170,7 +170,8 @@ CCU_FACTOR_GATE_DEFINE(pll1_d4, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(3), 4, > CCU_FACTOR_GATE_DEFINE(pll1_d5, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(4), 5, 1); > CCU_FACTOR_GATE_DEFINE(pll1_d6, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(5), 6, 1); > CCU_FACTOR_GATE_DEFINE(pll1_d7, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(6), 7, 1); > -CCU_FACTOR_GATE_DEFINE(pll1_d8, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(7), 8, 1); > +CCU_FACTOR_GATE_FLAGS_DEFINE(pll1_d8, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(7), 8, 1, > + CLK_IS_CRITICAL); > CCU_FACTOR_GATE_DEFINE(pll1_d11_223p4, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(15), 11, 1); > CCU_FACTOR_GATE_DEFINE(pll1_d13_189, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(16), 13, 1); > CCU_FACTOR_GATE_DEFINE(pll1_d23_106p8, CCU_PARENT_HW(pll1), APBS_PLL1_SWCR2, BIT(20), 23, 1); > diff --git a/drivers/clk/spacemit/ccu_mix.h b/drivers/clk/spacemit/ccu_mix.h > index 51d19f5d6aacb..54d40cd39b275 100644 > --- a/drivers/clk/spacemit/ccu_mix.h > +++ b/drivers/clk/spacemit/ccu_mix.h > @@ -101,16 +101,21 @@ static struct ccu_mix _name = { \ > } \ > } > > +#define CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ > + _mul, _flags) \ > +static struct ccu_mix _name = { \ > + .gate = CCU_GATE_INIT(_mask_gate), \ > + .factor = CCU_FACTOR_INIT(_div, _mul), \ > + .common = { \ > + .reg_ctrl = _reg_ctrl, \ > + CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, _flags) \ > + } \ > +} > + > #define CCU_FACTOR_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ > _mul) \ > -static struct ccu_mix _name = { \ > - .gate = CCU_GATE_INIT(_mask_gate), \ > - .factor = CCU_FACTOR_INIT(_div, _mul), \ > - .common = { \ > - .reg_ctrl = _reg_ctrl, \ > - CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, 0) \ > - } \ > -} > + CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ > + _mul, 0) > > #define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \ > _mask_gate, _flags) \ > > base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
Hi Alex, On 07:19 Mon 07 Jul , Alex Elder wrote: > On 6/12/25 5:48 PM, Alex Elder wrote: > > The pll1_d8 clock is enabled by the boot loader, and is ultimately a > > parent for numerous clocks, including those used by APB and AXI buses. > > Guodong Xu discovered that this clock got disabled while responding to > > getting -EPROBE_DEFER when requesting a reset controller. > > > > The needed clock (CLK_DMA, along with its parents) had already been > > enabled. To respond to the probe deferral return, the CLK_DMA clock > > was disabled, and this led to parent clocks also reducing their enable > > count. When the enable count for pll1_d8 was decremented it became 0, > > which caused it to be disabled. This led to a system hang. > > > > Marking that clock critical resolves this by preventing it from being > > disabled. > > > > Define a new macro CCU_FACTOR_GATE_DEFINE() to allow clock flags to > > be supplied for a CCU_FACTOR_GATE clock. > > Is there any reason this bug fix cannot be merged? It was > first posted a month ago, and although there was some initial > discussion that led to revisions, this version has been waiting > for over three weeks. > Ok, let me explain.. I've queued it at for-next but haven't sent out the "Applied" reply email, it should be eventually merged for version v6.17 if things goes well.. the reason that I haven't pushed it hard for fixes branch is that only DMA is affected for now, but DMA isn't fully activated in current mainline (No DT, No config merged), so I think it's fine if we target for-next.. -- Yixun Lan (dlan)
On 7/7/25 9:28 AM, Yixun Lan wrote: > Hi Alex, > > On 07:19 Mon 07 Jul , Alex Elder wrote: >> On 6/12/25 5:48 PM, Alex Elder wrote: >>> The pll1_d8 clock is enabled by the boot loader, and is ultimately a >>> parent for numerous clocks, including those used by APB and AXI buses. >>> Guodong Xu discovered that this clock got disabled while responding to >>> getting -EPROBE_DEFER when requesting a reset controller. >>> >>> The needed clock (CLK_DMA, along with its parents) had already been >>> enabled. To respond to the probe deferral return, the CLK_DMA clock >>> was disabled, and this led to parent clocks also reducing their enable >>> count. When the enable count for pll1_d8 was decremented it became 0, >>> which caused it to be disabled. This led to a system hang. >>> >>> Marking that clock critical resolves this by preventing it from being >>> disabled. >>> >>> Define a new macro CCU_FACTOR_GATE_DEFINE() to allow clock flags to >>> be supplied for a CCU_FACTOR_GATE clock. >> >> Is there any reason this bug fix cannot be merged? It was >> first posted a month ago, and although there was some initial >> discussion that led to revisions, this version has been waiting >> for over three weeks. >> > Ok, let me explain.. > > I've queued it at for-next but haven't sent out the "Applied" reply email, > it should be eventually merged for version v6.17 if things goes well.. > > the reason that I haven't pushed it hard for fixes branch is that only DMA > is affected for now, but DMA isn't fully activated in current mainline > (No DT, No config merged), so I think it's fine if we target for-next.. OK, thanks for the explanation Yixun. I've been working in the networking subsystem for a long time and they tend to push bug fixes out right away (once reviewed). But you're right, this particular bug fix does not affect any currently upstream code. -Alex
© 2016 - 2025 Red Hat, Inc.