[PATCH v4 00/68] clk: Make determine_rate mandatory for muxes
Hi,
This is a follow-up to a previous series that was printing a warning when a mux has a set_parent implementation but is missing determine_rate().
The rationale is that set_parent() is very likely to be useful when changing the rate, but it's determine_rate() that takes the parenting decision. If we're missing it, then the current parent is always going to be used, and thus set_parent() will not be used. The only exception being a direct call to clk_set_parent(), but those are fairly rare compared to clk_set_rate().
Stephen then asked to promote the warning to an error, and to fix up all the muxes that are in that situation first. So here it is :)
It was build-tested on x86, arm and arm64.
Affected drivers have been tracked down by the following coccinelle script:
virtual report
@ clk_ops @ identifier ops; position p; @@
struct clk_ops ops@p = { ... };
@ has_set_parent @ identifier clk_ops.ops; identifier set_parent_f; @@
struct clk_ops ops = { .set_parent = set_parent_f, };
@ has_determine_rate @ identifier clk_ops.ops; identifier determine_rate_f; @@
struct clk_ops ops = { .determine_rate = determine_rate_f, };
@ script:python depends on report && has_set_parent && !has_determine_rate @ ops << clk_ops.ops; set_parent_f << has_set_parent.set_parent_f; p << clk_ops.p; @@
coccilib.report.print_report(p[0], "ERROR: %s has set_parent (%s)" % (ops, set_parent_f))
Berlin is the only user still matching after this series has been applied, but it's because it uses a composite clock which throws the script off. The driver has been converted and shouldn't be a problem.
Let me know what you think, Maxime
Signed-off-by: Maxime Ripard maxime@cerno.tech --- Changes in v4: - Switch from __clk_mux_determine_rate to a new helper - Introduced unit tests for that new helper - Fix kunit regression - Reworded most of the commit logs - Link to v3: https://lore.kernel.org/r/20221018-clk-range-checks-fixes-v3-0-9a1358472d52@...
Changes in v3: - Rebased on top of next-20230404 - Link to v2: https://lore.kernel.org/r/20221018-clk-range-checks-fixes-v2-0-f6736dec138e@...
Changes in v2: - Drop all the patches already applied - Promote the clk registration warning to an error - Make all muxes use determine_rate - Link to v1: https://lore.kernel.org/r/20221018-clk-range-checks-fixes-v1-0-f3ef80518140@...
--- Maxime Ripard (66): clk: Export clk_hw_forward_rate_request() clk: test: Fix type sign of rounded rate variables clk: lan966x: Remove unused round_rate hook clk: nodrv: Add a determine_rate hook clk: test: Add a determine_rate hook clk: actions: composite: Add a determine_rate hook for pass clk clk: at91: main: Add a determine_rate hook clk: at91: sckc: Add a determine_rate hook clk: berlin: div: Add a determine_rate hook clk: cdce706: Add a determine_rate hook clk: k210: pll: Add a determine_rate hook clk: k210: aclk: Add a determine_rate hook clk: k210: mux: Add a determine_rate hook clk: lmk04832: clkout: Add a determine_rate hook clk: lochnagar: Add a determine_rate hook clk: qoriq: Add a determine_rate hook clk: si5341: Add a determine_rate hook clk: stm32f4: mux: Add a determine_rate hook clk: vc5: mux: Add a determine_rate hook clk: vc5: clkout: Add a determine_rate hook clk: wm831x: clkout: Add a determine_rate hook clk: davinci: da8xx-cfgchip: Add a determine_rate hook clk: davinci: da8xx-cfgchip: Add a determine_rate hook clk: imx: busy: Add a determine_rate hook clk: imx: fixup-mux: Add a determine_rate hook clk: imx: scu: Add a determine_rate hook clk: mediatek: cpumux: Add a determine_rate hook clk: pxa: Add a determine_rate hook clk: renesas: r9a06g032: Add a determine_rate hook clk: socfpga: gate: Add a determine_rate hook clk: stm32: core: Add a determine_rate hook clk: tegra: bpmp: Add a determine_rate hook clk: tegra: super: Add a determine_rate hook clk: tegra: periph: Add a determine_rate hook clk: ux500: prcmu: Add a determine_rate hook clk: ux500: sysctrl: Add a determine_rate hook clk: versatile: sp810: Add a determine_rate hook drm/tegra: sor: Add a determine_rate hook phy: cadence: sierra: Add a determine_rate hook phy: cadence: torrent: Add a determine_rate hook phy: ti: am654-serdes: Add a determine_rate hook phy: ti: j721e-wiz: Add a determine_rate hook rtc: sun6i: Add a determine_rate hook ASoC: tlv320aic32x4: Add a determine_rate hook clk: actions: composite: div: Switch to determine_rate clk: actions: composite: fact: Switch to determine_rate clk: at91: smd: Switch to determine_rate clk: axi-clkgen: Switch to determine_rate clk: cdce706: divider: Switch to determine_rate clk: cdce706: clkout: Switch to determine_rate clk: si5341: Switch to determine_rate clk: si5351: pll: Switch to determine_rate clk: si5351: msynth: Switch to determine_rate clk: si5351: clkout: Switch to determine_rate clk: da8xx: clk48: Switch to determine_rate clk: imx: scu: Switch to determine_rate clk: ingenic: cgu: Switch to determine_rate clk: ingenic: tcu: Switch to determine_rate clk: sprd: composite: Switch to determine_rate clk: st: flexgen: Switch to determine_rate clk: stm32: composite: Switch to determine_rate clk: tegra: periph: Switch to determine_rate clk: tegra: super: Switch to determine_rate ASoC: tlv320aic32x4: pll: Switch to determine_rate ASoC: tlv320aic32x4: div: Switch to determine_rate clk: Forbid to register a mux without determine_rate
Stephen Boyd (2): clk: Move no reparent case into a separate function clk: Introduce clk_hw_determine_rate_no_reparent()
drivers/clk/actions/owl-composite.c | 35 ++++-- drivers/clk/at91/clk-main.c | 1 + drivers/clk/at91/clk-smd.c | 29 +++-- drivers/clk/at91/sckc.c | 1 + drivers/clk/berlin/berlin2-div.c | 1 + drivers/clk/clk-axi-clkgen.c | 14 ++- drivers/clk/clk-cdce706.c | 30 ++--- drivers/clk/clk-k210.c | 3 + drivers/clk/clk-lan966x.c | 17 --- drivers/clk/clk-lmk04832.c | 1 + drivers/clk/clk-lochnagar.c | 1 + drivers/clk/clk-qoriq.c | 1 + drivers/clk/clk-si5341.c | 19 ++-- drivers/clk/clk-si5351.c | 67 ++++++----- drivers/clk/clk-stm32f4.c | 1 + drivers/clk/clk-versaclock5.c | 2 + drivers/clk/clk-wm831x.c | 1 + drivers/clk/clk.c | 108 ++++++++++++------ drivers/clk/clk_test.c | 180 +++++++++++++++++++++++++++++- drivers/clk/davinci/da8xx-cfgchip.c | 12 +- drivers/clk/imx/clk-busy.c | 1 + drivers/clk/imx/clk-fixup-mux.c | 1 + drivers/clk/imx/clk-scu.c | 20 +++- drivers/clk/ingenic/cgu.c | 15 +-- drivers/clk/ingenic/tcu.c | 19 ++-- drivers/clk/mediatek/clk-cpumux.c | 1 + drivers/clk/pxa/clk-pxa.c | 1 + drivers/clk/renesas/r9a06g032-clocks.c | 1 + drivers/clk/socfpga/clk-gate.c | 1 + drivers/clk/sprd/composite.c | 16 ++- drivers/clk/st/clk-flexgen.c | 15 +-- drivers/clk/stm32/clk-stm32-core.c | 33 ++++-- drivers/clk/tegra/clk-bpmp.c | 1 + drivers/clk/tegra/clk-periph.c | 17 ++- drivers/clk/tegra/clk-super.c | 16 ++- drivers/clk/ux500/clk-prcmu.c | 1 + drivers/clk/ux500/clk-sysctrl.c | 1 + drivers/clk/versatile/clk-sp810.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + drivers/phy/cadence/phy-cadence-sierra.c | 1 + drivers/phy/cadence/phy-cadence-torrent.c | 1 + drivers/phy/ti/phy-am654-serdes.c | 1 + drivers/phy/ti/phy-j721e-wiz.c | 1 + drivers/rtc/rtc-sun6i.c | 1 + include/linux/clk-provider.h | 2 + sound/soc/codecs/tlv320aic32x4-clk.c | 33 +++--- 46 files changed, 527 insertions(+), 199 deletions(-) --- base-commit: 145e5cddfe8b4bf607510b2dcf630d95f4db420f change-id: 20221018-clk-range-checks-fixes-2039f3523240
Best regards,
The tlv320aic32x4 clkin clock implements a mux with a set_parent hook, but doesn't provide a determine_rate implementation.
This is a bit odd, since set_parent() is there to, as its name implies, change the parent of a clock. However, the most likely candidates to trigger that parent change are either the assigned-clock-parents device tree property or a call to clk_set_rate(), with determine_rate() figuring out which parent is the best suited for a given rate.
The other trigger would be a call to clk_set_parent(), but it's far less used, and it doesn't look like there's any obvious user for that clock.
Similarly, it doesn't look like the device tree using that clock driver uses any of the assigned-clock properties on that clock.
So, the set_parent hook is effectively unused, possibly because of an oversight. However, it could also be an explicit decision by the original author to avoid any reparenting but through an explicit call to clk_set_parent().
The latter case would be equivalent to setting the determine_rate implementation to clk_hw_determine_rate_no_reparent(). Indeed, if no determine_rate implementation is provided, clk_round_rate() (through clk_core_round_rate_nolock()) will call itself on the parent if CLK_SET_RATE_PARENT is set, and will not change the clock rate otherwise.
And if it was an oversight, then we are at least explicit about our behavior now and it can be further refined down the line.
Cc: Jaroslav Kysela perex@perex.cz Cc: Liam Girdwood lgirdwood@gmail.com Cc: Mark Brown broonie@kernel.org Cc: Takashi Iwai tiwai@suse.com Cc: alsa-devel@alsa-project.org Signed-off-by: Maxime Ripard maxime@cerno.tech --- sound/soc/codecs/tlv320aic32x4-clk.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index 2f78e6820c75..80cbc6bc6847 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -292,6 +292,7 @@ static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw) }
static const struct clk_ops aic32x4_codec_clkin_ops = { + .determine_rate = clk_hw_determine_rate_no_reparent, .set_parent = clk_aic32x4_codec_clkin_set_parent, .get_parent = clk_aic32x4_codec_clkin_get_parent, };
The tlv320aic32x4 PLL clocks implements a mux with a set_parent hook, but doesn't provide a determine_rate implementation.
This is a bit odd, since set_parent() is there to, as its name implies, change the parent of a clock. However, the most likely candidate to trigger that parent change is a call to clk_set_rate(), with determine_rate() figuring out which parent is the best suited for a given rate.
The other trigger would be a call to clk_set_parent(), but it's far less used, and it doesn't look like there's any obvious user for that clock.
So, the set_parent hook is effectively unused, possibly because of an oversight. However, it could also be an explicit decision by the original author to avoid any reparenting but through an explicit call to clk_set_parent().
The driver does implement round_rate() though, which means that we can change the rate of the clock, but we will never get to change the parent.
However, It's hard to tell whether it's been done on purpose or not.
Since we'll start mandating a determine_rate() implementation, let's convert the round_rate() implementation to a determine_rate(), which will also make the current behavior explicit. And if it was an oversight, the clock behaviour can be adjusted later on.
Cc: Jaroslav Kysela perex@perex.cz Cc: Liam Girdwood lgirdwood@gmail.com Cc: Mark Brown broonie@kernel.org Cc: Takashi Iwai tiwai@suse.com Cc: alsa-devel@alsa-project.org Signed-off-by: Maxime Ripard maxime@cerno.tech --- sound/soc/codecs/tlv320aic32x4-clk.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index 80cbc6bc6847..e2de4617ab09 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -204,18 +204,23 @@ static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw, return clk_aic32x4_pll_calc_rate(&settings, parent_rate); }
-static long clk_aic32x4_pll_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) +static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_aic32x4_pll_muldiv settings; + unsigned long rate; int ret;
- ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate); + ret = clk_aic32x4_pll_calc_muldiv(&settings, req->rate, req->best_parent_rate); if (ret < 0) - return 0; + return -EINVAL;
- return clk_aic32x4_pll_calc_rate(&settings, *parent_rate); + rate = clk_aic32x4_pll_calc_rate(&settings, req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; }
static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, @@ -266,7 +271,7 @@ static const struct clk_ops aic32x4_pll_ops = { .unprepare = clk_aic32x4_pll_unprepare, .is_prepared = clk_aic32x4_pll_is_prepared, .recalc_rate = clk_aic32x4_pll_recalc_rate, - .round_rate = clk_aic32x4_pll_round_rate, + .determine_rate = clk_aic32x4_pll_determine_rate, .set_rate = clk_aic32x4_pll_set_rate, .set_parent = clk_aic32x4_pll_set_parent, .get_parent = clk_aic32x4_pll_get_parent,
The tlv320aic32x4 divider clocks implements a mux with a set_parent hook, but doesn't provide a determine_rate implementation.
This is a bit odd, since set_parent() is there to, as its name implies, change the parent of a clock. However, the most likely candidate to trigger that parent change is a call to clk_set_rate(), with determine_rate() figuring out which parent is the best suited for a given rate.
The other trigger would be a call to clk_set_parent(), but it's far less used, and it doesn't look like there's any obvious user for that clock.
So, the set_parent hook is effectively unused, possibly because of an oversight. However, it could also be an explicit decision by the original author to avoid any reparenting but through an explicit call to clk_set_parent().
The driver does implement round_rate() though, which means that we can change the rate of the clock, but we will never get to change the parent.
However, It's hard to tell whether it's been done on purpose or not.
Since we'll start mandating a determine_rate() implementation, let's convert the round_rate() implementation to a determine_rate(), which will also make the current behavior explicit. And if it was an oversight, the clock behaviour can be adjusted later on.
Cc: Jaroslav Kysela perex@perex.cz Cc: Liam Girdwood lgirdwood@gmail.com Cc: Mark Brown broonie@kernel.org Cc: Takashi Iwai tiwai@suse.com Cc: alsa-devel@alsa-project.org Signed-off-by: Maxime Ripard maxime@cerno.tech --- sound/soc/codecs/tlv320aic32x4-clk.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index e2de4617ab09..a7ec501b4c69 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -332,16 +332,17 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, AIC32X4_DIV_MASK, divisor); }
-static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long divisor;
- divisor = DIV_ROUND_UP(*parent_rate, rate); + divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate); if (divisor > 128) return -EINVAL;
- return DIV_ROUND_UP(*parent_rate, divisor); + req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor); + return 0; }
static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, @@ -360,7 +361,7 @@ static const struct clk_ops aic32x4_div_ops = { .prepare = clk_aic32x4_div_prepare, .unprepare = clk_aic32x4_div_unprepare, .set_rate = clk_aic32x4_div_set_rate, - .round_rate = clk_aic32x4_div_round_rate, + .determine_rate = clk_aic32x4_div_determine_rate, .recalc_rate = clk_aic32x4_div_recalc_rate, };
@@ -388,7 +389,7 @@ static const struct clk_ops aic32x4_bdiv_ops = { .set_parent = clk_aic32x4_bdiv_set_parent, .get_parent = clk_aic32x4_bdiv_get_parent, .set_rate = clk_aic32x4_div_set_rate, - .round_rate = clk_aic32x4_div_round_rate, + .determine_rate = clk_aic32x4_div_determine_rate, .recalc_rate = clk_aic32x4_div_recalc_rate, };
Quoting Maxime Ripard (2023-05-05 04:25:02)
Hi,
This is a follow-up to a previous series that was printing a warning when a mux has a set_parent implementation but is missing determine_rate().
The rationale is that set_parent() is very likely to be useful when changing the rate, but it's determine_rate() that takes the parenting decision. If we're missing it, then the current parent is always going to be used, and thus set_parent() will not be used. The only exception being a direct call to clk_set_parent(), but those are fairly rare compared to clk_set_rate().
Stephen then asked to promote the warning to an error, and to fix up all the muxes that are in that situation first. So here it is :)
I've applied this to clk-next after squashing in an export. Thanks for taking this on.
I'll have to monitor for wreckage with any in-flight drivers. I suspect I'll have to take out the last commit, but maybe we can just let those in-flight drivers get fixed up later.
participants (2)
-
Maxime Ripard
-
Stephen Boyd