2022-03-14 15:49:35

by Uwe Kleine-König

[permalink] [raw]
Subject: [PATCH v8 00/16] clk: provide new devm helpers for prepared and enabled clocks

Hello,

this is another try to convince the relevant people that
devm_clk_get_enabled() is a nice idea. Compared to v7 (back in May 2021) this
series is rebased to v5.17-rc8 and converts quite some drivers that open code
devm_clk_get_enabled() up to now (patches #3 - #11).

A concern about devm_clk_get_enabled() in v7 was that it helps people to be
lazy and I agree that in some situations when devm_clk_get_enabled() is used it
would be more efficient and sensible to care to only enable the clk when really
needed.

On the other hand, the function is right for some users, e.g. the watchdog
drivers. For the others it's not so simple to judge. Given that there are a
lot of drivers that are lazy even if doing so is some effort (i.e. calling
clk_prepare_enable() and devm_add_action()) convinces me, that introducing the
function family is sensible. (And if you want to work on these drivers,
grepping for devm_clk_get_enabled gives you a few candidates once the
series is in :-)

Otherwise looking at the diffstat of this series:

48 files changed, 257 insertions(+), 851 deletions(-)

is quite convincing. Just the first two patches (which introduce the new
functions) account for

2 files changed, 169 insertions(+), 17 deletions(-)

. A rough third of the added lines is documentation. The rest is driver
updates which then has:

46 files changed, 88 insertions(+), 834 deletions(-)

which makes a really nice cleanup.

The series is build-tested on arm64, m68k, powerpc, riscv, s390, sparc64
and x86_64 using an allmodconfig.

Best regards
Uwe

Uwe Kleine-König (16):
clk: generalize devm_clk_get() a bit
clk: Provide new devm_clk helpers for prepared and enabled clocks
hwmon: Make use of devm_clk_get_enabled()
iio: Make use of devm_clk_get_enabled()
hwrng: meson - Don't open-code devm_clk_get_optional_enabled()
bus: bt1: Don't open code devm_clk_get_enabled()
gpio: vf610: Simplify error handling in probe
drm/meson: dw-hdmi: Don't open code devm_clk_get_enabled()
rtc: ingenic: Simplify using devm_clk_get_enabled()
clk: meson: axg-audio: Don't duplicate devm_clk_get_enabled()
watchdog: Make use of devm_clk_get_enabled()
pwm: atmel: Simplify using devm_clk_get_prepared()
rtc: at91sam9: Simplify using devm_clk_get_enabled()
i2c: imx: Simplify using devm_clk_get_enabled()
spi: davinci: Simplify using devm_clk_get_enabled()
dmaengine: lgm: Fix error handling

drivers/bus/bt1-apb.c | 23 +------
drivers/bus/bt1-axi.c | 23 +------
drivers/char/hw_random/meson-rng.c | 20 +-----
drivers/clk/clk-devres.c | 96 ++++++++++++++++++++++-----
drivers/clk/meson/axg-audio.c | 36 ++--------
drivers/dma/lgm/lgm-dma.c | 8 +--
drivers/gpio/gpio-vf610.c | 45 +++----------
drivers/gpu/drm/meson/meson_dw_hdmi.c | 48 +++++---------
drivers/hwmon/axi-fan-control.c | 15 +----
drivers/hwmon/ltc2947-core.c | 17 +----
drivers/hwmon/mr75203.c | 26 +-------
drivers/hwmon/sparx5-temp.c | 19 +-----
drivers/i2c/busses/i2c-imx.c | 12 +---
drivers/iio/adc/ad7124.c | 15 +----
drivers/iio/adc/ad7768-1.c | 17 +----
drivers/iio/adc/ad9467.c | 17 +----
drivers/iio/adc/ingenic-adc.c | 15 +----
drivers/iio/adc/lpc18xx_adc.c | 18 +----
drivers/iio/adc/rockchip_saradc.c | 44 +-----------
drivers/iio/adc/ti-ads131e08.c | 19 +-----
drivers/iio/adc/xilinx-ams.c | 15 +----
drivers/iio/adc/xilinx-xadc-core.c | 18 +----
drivers/iio/frequency/adf4371.c | 17 +----
drivers/iio/frequency/admv1013.c | 15 +----
drivers/iio/frequency/adrf6780.c | 16 +----
drivers/iio/imu/adis16475.c | 15 +----
drivers/pwm/pwm-atmel.c | 16 +----
drivers/rtc/rtc-at91sam9.c | 22 ++----
drivers/rtc/rtc-jz4740.c | 21 +-----
drivers/spi/spi-davinci.c | 11 +--
drivers/watchdog/cadence_wdt.c | 17 +----
drivers/watchdog/davinci_wdt.c | 18 +----
drivers/watchdog/imgpdc_wdt.c | 31 +--------
drivers/watchdog/imx2_wdt.c | 15 +----
drivers/watchdog/imx7ulp_wdt.c | 15 +----
drivers/watchdog/loongson1_wdt.c | 17 +----
drivers/watchdog/lpc18xx_wdt.c | 30 +--------
drivers/watchdog/meson_gxbb_wdt.c | 16 +----
drivers/watchdog/of_xilinx_wdt.c | 16 +----
drivers/watchdog/pic32-dmt.c | 15 +----
drivers/watchdog/pic32-wdt.c | 17 +----
drivers/watchdog/pnx4008_wdt.c | 15 +----
drivers/watchdog/qcom-wdt.c | 16 +----
drivers/watchdog/rtd119x_wdt.c | 16 +----
drivers/watchdog/st_lpc_wdt.c | 16 +----
drivers/watchdog/stm32_iwdg.c | 31 +--------
drivers/watchdog/visconti_wdt.c | 18 +----
include/linux/clk.h | 90 ++++++++++++++++++++++++-
48 files changed, 257 insertions(+), 851 deletions(-)


base-commit: 09688c0166e76ce2fb85e86b9d99be8b0084cdf9
--
2.35.1


2022-03-14 20:50:58

by Uwe Kleine-König

[permalink] [raw]
Subject: [PATCH v8 01/16] clk: generalize devm_clk_get() a bit

Allow to add an exit hook to devm managed clocks. Also use
clk_get_optional() in devm_clk_get_optional instead of open coding it.
The generalisation will be used in the next commit to add some more
devm_clk helpers.

Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: Alexandru Ardelean <[email protected]>
Signed-off-by: Uwe Kleine-König <[email protected]>
---
drivers/clk/clk-devres.c | 67 ++++++++++++++++++++++++++++++----------
1 file changed, 50 insertions(+), 17 deletions(-)

diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index f9d5b7334341..fb7761888b30 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -4,39 +4,72 @@
#include <linux/export.h>
#include <linux/gfp.h>

+struct devm_clk_state {
+ struct clk *clk;
+ void (*exit)(struct clk *clk);
+};
+
static void devm_clk_release(struct device *dev, void *res)
{
- clk_put(*(struct clk **)res);
+ struct devm_clk_state *state = *(struct devm_clk_state **)res;
+
+ if (state->exit)
+ state->exit(state->clk);
+
+ clk_put(state->clk);
}

-struct clk *devm_clk_get(struct device *dev, const char *id)
+static struct clk *__devm_clk_get(struct device *dev, const char *id,
+ struct clk *(*get)(struct device *dev, const char *id),
+ int (*init)(struct clk *clk),
+ void (*exit)(struct clk *clk))
{
- struct clk **ptr, *clk;
+ struct devm_clk_state *state;
+ struct clk *clk;
+ int ret;

- ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
+ state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
+ if (!state)
return ERR_PTR(-ENOMEM);

- clk = clk_get(dev, id);
- if (!IS_ERR(clk)) {
- *ptr = clk;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
+ clk = get(dev, id);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err_clk_get;
}

+ if (init) {
+ ret = init(clk);
+ if (ret)
+ goto err_clk_init;
+ }
+
+ state->clk = clk;
+ state->exit = exit;
+
+ devres_add(dev, state);
+
return clk;
+
+err_clk_init:
+
+ clk_put(clk);
+err_clk_get:
+
+ devres_free(state);
+ return ERR_PTR(ret);
}
-EXPORT_SYMBOL(devm_clk_get);

-struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+struct clk *devm_clk_get(struct device *dev, const char *id)
{
- struct clk *clk = devm_clk_get(dev, id);
+ return __devm_clk_get(dev, id, clk_get, NULL, NULL);

- if (clk == ERR_PTR(-ENOENT))
- return NULL;
+}
+EXPORT_SYMBOL(devm_clk_get);

- return clk;
+struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+{
+ return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
}
EXPORT_SYMBOL(devm_clk_get_optional);

--
2.35.1

2022-03-15 00:51:30

by Uwe Kleine-König

[permalink] [raw]
Subject: [PATCH v8 03/16] hwmon: Make use of devm_clk_get_enabled()

Several drivers manually register a devm handler to disable their clk.
Convert them to devm_clk_get_enabled().

Signed-off-by: Uwe Kleine-König <[email protected]>
---
drivers/hwmon/axi-fan-control.c | 15 +--------------
drivers/hwmon/ltc2947-core.c | 17 +----------------
drivers/hwmon/mr75203.c | 26 +-------------------------
drivers/hwmon/sparx5-temp.c | 19 +------------------
4 files changed, 4 insertions(+), 73 deletions(-)

diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c
index d2092c17d993..ce404ed9c53e 100644
--- a/drivers/hwmon/axi-fan-control.c
+++ b/drivers/hwmon/axi-fan-control.c
@@ -393,11 +393,6 @@ static int axi_fan_control_init(struct axi_fan_control_data *ctl,
return ret;
}

-static void axi_fan_control_clk_disable(void *clk)
-{
- clk_disable_unprepare(clk);
-}
-
static const struct hwmon_channel_info *axi_fan_control_info[] = {
HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL),
@@ -477,20 +472,12 @@ static int axi_fan_control_probe(struct platform_device *pdev)
if (IS_ERR(ctl->base))
return PTR_ERR(ctl->base);

- clk = devm_clk_get(&pdev->dev, NULL);
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "clk_get failed with %ld\n", PTR_ERR(clk));
return PTR_ERR(clk);
}

- ret = clk_prepare_enable(clk);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&pdev->dev, axi_fan_control_clk_disable, clk);
- if (ret)
- return ret;
-
ctl->clk_rate = clk_get_rate(clk);
if (!ctl->clk_rate)
return -EINVAL;
diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c
index 5423466de697..626f5bf2c9c7 100644
--- a/drivers/hwmon/ltc2947-core.c
+++ b/drivers/hwmon/ltc2947-core.c
@@ -956,13 +956,6 @@ static struct attribute *ltc2947_attrs[] = {
};
ATTRIBUTE_GROUPS(ltc2947);

-static void ltc2947_clk_disable(void *data)
-{
- struct clk *extclk = data;
-
- clk_disable_unprepare(extclk);
-}
-
static int ltc2947_setup(struct ltc2947_data *st)
{
int ret;
@@ -989,7 +982,7 @@ static int ltc2947_setup(struct ltc2947_data *st)
return ret;

/* check external clock presence */
- extclk = devm_clk_get_optional(st->dev, NULL);
+ extclk = devm_clk_get_optional_enabled(st->dev, NULL);
if (IS_ERR(extclk))
return dev_err_probe(st->dev, PTR_ERR(extclk),
"Failed to get external clock\n");
@@ -1007,14 +1000,6 @@ static int ltc2947_setup(struct ltc2947_data *st)
return -EINVAL;
}

- ret = clk_prepare_enable(extclk);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(st->dev, ltc2947_clk_disable,
- extclk);
- if (ret)
- return ret;
/* as in table 1 of the datasheet */
if (rate_hz >= LTC2947_CLK_MIN && rate_hz <= 1000000)
pre = 0;
diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c
index 1ba1e3145969..0c691f291a64 100644
--- a/drivers/hwmon/mr75203.c
+++ b/drivers/hwmon/mr75203.c
@@ -461,24 +461,6 @@ static int pvt_get_regmap(struct platform_device *pdev, char *reg_name,
return 0;
}

-static void pvt_clk_disable(void *data)
-{
- struct pvt_device *pvt = data;
-
- clk_disable_unprepare(pvt->clk);
-}
-
-static int pvt_clk_enable(struct device *dev, struct pvt_device *pvt)
-{
- int ret;
-
- ret = clk_prepare_enable(pvt->clk);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(dev, pvt_clk_disable, pvt);
-}
-
static void pvt_reset_control_assert(void *data)
{
struct pvt_device *pvt = data;
@@ -515,16 +497,10 @@ static int mr75203_probe(struct platform_device *pdev)
if (ret)
return ret;

- pvt->clk = devm_clk_get(dev, NULL);
+ pvt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(pvt->clk))
return dev_err_probe(dev, PTR_ERR(pvt->clk), "failed to get clock\n");

- ret = pvt_clk_enable(dev, pvt);
- if (ret) {
- dev_err(dev, "failed to enable clock\n");
- return ret;
- }
-
pvt->rst = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(pvt->rst))
return dev_err_probe(dev, PTR_ERR(pvt->rst),
diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c
index 98be48e3a22a..04fd8505e5d6 100644
--- a/drivers/hwmon/sparx5-temp.c
+++ b/drivers/hwmon/sparx5-temp.c
@@ -26,13 +26,6 @@ struct s5_hwmon {
struct clk *clk;
};

-static void s5_temp_clk_disable(void *data)
-{
- struct clk *clk = data;
-
- clk_disable_unprepare(clk);
-}
-
static void s5_temp_enable(struct s5_hwmon *hwmon)
{
u32 val = readl(hwmon->base + TEMP_CFG);
@@ -113,7 +106,6 @@ static int s5_temp_probe(struct platform_device *pdev)
{
struct device *hwmon_dev;
struct s5_hwmon *hwmon;
- int ret;

hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
if (!hwmon)
@@ -123,19 +115,10 @@ static int s5_temp_probe(struct platform_device *pdev)
if (IS_ERR(hwmon->base))
return PTR_ERR(hwmon->base);

- hwmon->clk = devm_clk_get(&pdev->dev, NULL);
+ hwmon->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(hwmon->clk))
return PTR_ERR(hwmon->clk);

- ret = clk_prepare_enable(hwmon->clk);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&pdev->dev, s5_temp_clk_disable,
- hwmon->clk);
- if (ret)
- return ret;
-
s5_temp_enable(hwmon);

hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
--
2.35.1

2022-03-15 14:01:15

by Uwe Kleine-König

[permalink] [raw]
Subject: [PATCH v8 02/16] clk: Provide new devm_clk helpers for prepared and enabled clocks

When a driver keeps a clock prepared (or enabled) during the whole
lifetime of the driver, these helpers allow to simplify the drivers.

Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: Alexandru Ardelean <[email protected]>
Signed-off-by: Uwe Kleine-König <[email protected]>
---
drivers/clk/clk-devres.c | 31 ++++++++++++++
include/linux/clk.h | 90 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index fb7761888b30..4707fe718f0b 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -67,12 +67,43 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
}
EXPORT_SYMBOL(devm_clk_get);

+struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
+{
+ return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_prepared);
+
+struct clk *devm_clk_get_enabled(struct device *dev, const char *id)
+{
+ return __devm_clk_get(dev, id, clk_get,
+ clk_prepare_enable, clk_disable_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_enabled);
+
struct clk *devm_clk_get_optional(struct device *dev, const char *id)
{
return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
}
EXPORT_SYMBOL(devm_clk_get_optional);

+struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)
+{
+ return __devm_clk_get(dev, id, clk_get_optional,
+ clk_prepare, clk_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_optional_prepared);
+
+struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
+{
+ return __devm_clk_get(dev, id, clk_get_optional,
+ clk_prepare_enable, clk_disable_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_optional_enabled);
+
struct clk_bulk_devres {
struct clk_bulk_data *clks;
int num_clks;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 266e8de3cb51..b011dbba7109 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -449,7 +449,7 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
* the clock producer. (IOW, @id may be identical strings, but
* clk_get may return different clock producers depending on @dev.)
*
- * Drivers must assume that the clock source is not enabled.
+ * Drivers must assume that the clock source is neither prepared nor enabled.
*
* devm_clk_get should not be called from within interrupt context.
*
@@ -458,6 +458,47 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
*/
struct clk *devm_clk_get(struct device *dev, const char *id);

+/**
+ * devm_clk_get_prepared - devm_clk_get() + clk_prepare()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno. The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer. (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * The returned clk (if valid) is prepared. Drivers must however assume that the
+ * clock is not enabled.
+ *
+ * devm_clk_get_prepared should not be called from within interrupt context.
+ *
+ * The clock will automatically be unprepared and freed when the
+ * device is unbound from the bus.
+ */
+struct clk *devm_clk_get_prepared(struct device *dev, const char *id);
+
+/**
+ * devm_clk_get_enabled - devm_clk_get() + clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or valid IS_ERR()
+ * condition containing errno. The implementation uses @dev and @id to
+ * determine the clock consumer, and thereby the clock producer. (IOW, @id may
+ * be identical strings, but clk_get may return different clock producers
+ * depending on @dev.)
+ *
+ * The returned clk (if valid) is prepared and enabled.
+ *
+ * devm_clk_get_prepared should not be called from within interrupt context.
+ *
+ * The clock will automatically be disabled, unprepared and freed when the
+ * device is unbound from the bus.
+ */
+struct clk *devm_clk_get_enabled(struct device *dev, const char *id);
+
/**
* devm_clk_get_optional - lookup and obtain a managed reference to an optional
* clock producer.
@@ -469,6 +510,29 @@ struct clk *devm_clk_get(struct device *dev, const char *id);
*/
struct clk *devm_clk_get_optional(struct device *dev, const char *id);

+/**
+ * devm_clk_get_optional_prepared - devm_clk_get_optional() + clk_prepare()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get_prepared() except where there is no clock
+ * producer. In this case, instead of returning -ENOENT, the function returns
+ * NULL.
+ */
+struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id);
+
+/**
+ * devm_clk_get_optional_enabled - devm_clk_get_optional() +
+ * clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get_enabled() except where there is no clock
+ * producer. In this case, instead of returning -ENOENT, the function returns
+ * NULL.
+ */
+struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id);
+
/**
* devm_get_clk_from_child - lookup and obtain a managed reference to a
* clock producer from child node.
@@ -813,12 +877,36 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id)
return NULL;
}

+static inline struct clk *devm_clk_get_prepared(struct device *dev,
+ const char *id)
+{
+ return NULL;
+}
+
+static inline struct clk *devm_clk_get_enabled(struct device *dev,
+ const char *id)
+{
+ return NULL;
+}
+
static inline struct clk *devm_clk_get_optional(struct device *dev,
const char *id)
{
return NULL;
}

+static inline struct clk *devm_clk_get_optional_prepared(struct device *dev,
+ const char *id)
+{
+ return NULL;
+}
+
+static inline struct clk *devm_clk_get_optional_enabled(struct device *dev,
+ const char *id)
+{
+ return NULL;
+}
+
static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
struct clk_bulk_data *clks)
{
--
2.35.1

2022-03-16 14:27:41

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v8 03/16] hwmon: Make use of devm_clk_get_enabled()

On 3/14/22 07:16, Uwe Kleine-König wrote:
> Several drivers manually register a devm handler to disable their clk.
> Convert them to devm_clk_get_enabled().
>
> Signed-off-by: Uwe Kleine-König <[email protected]>

Let's see if it goes anywhere this time.

Acked-by: Guenter Roeck <[email protected]>

> ---
> drivers/hwmon/axi-fan-control.c | 15 +--------------
> drivers/hwmon/ltc2947-core.c | 17 +----------------
> drivers/hwmon/mr75203.c | 26 +-------------------------
> drivers/hwmon/sparx5-temp.c | 19 +------------------
> 4 files changed, 4 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c
> index d2092c17d993..ce404ed9c53e 100644
> --- a/drivers/hwmon/axi-fan-control.c
> +++ b/drivers/hwmon/axi-fan-control.c
> @@ -393,11 +393,6 @@ static int axi_fan_control_init(struct axi_fan_control_data *ctl,
> return ret;
> }
>
> -static void axi_fan_control_clk_disable(void *clk)
> -{
> - clk_disable_unprepare(clk);
> -}
> -
> static const struct hwmon_channel_info *axi_fan_control_info[] = {
> HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
> HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL),
> @@ -477,20 +472,12 @@ static int axi_fan_control_probe(struct platform_device *pdev)
> if (IS_ERR(ctl->base))
> return PTR_ERR(ctl->base);
>
> - clk = devm_clk_get(&pdev->dev, NULL);
> + clk = devm_clk_get_enabled(&pdev->dev, NULL);
> if (IS_ERR(clk)) {
> dev_err(&pdev->dev, "clk_get failed with %ld\n", PTR_ERR(clk));
> return PTR_ERR(clk);
> }
>
> - ret = clk_prepare_enable(clk);
> - if (ret)
> - return ret;
> -
> - ret = devm_add_action_or_reset(&pdev->dev, axi_fan_control_clk_disable, clk);
> - if (ret)
> - return ret;
> -
> ctl->clk_rate = clk_get_rate(clk);
> if (!ctl->clk_rate)
> return -EINVAL;
> diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c
> index 5423466de697..626f5bf2c9c7 100644
> --- a/drivers/hwmon/ltc2947-core.c
> +++ b/drivers/hwmon/ltc2947-core.c
> @@ -956,13 +956,6 @@ static struct attribute *ltc2947_attrs[] = {
> };
> ATTRIBUTE_GROUPS(ltc2947);
>
> -static void ltc2947_clk_disable(void *data)
> -{
> - struct clk *extclk = data;
> -
> - clk_disable_unprepare(extclk);
> -}
> -
> static int ltc2947_setup(struct ltc2947_data *st)
> {
> int ret;
> @@ -989,7 +982,7 @@ static int ltc2947_setup(struct ltc2947_data *st)
> return ret;
>
> /* check external clock presence */
> - extclk = devm_clk_get_optional(st->dev, NULL);
> + extclk = devm_clk_get_optional_enabled(st->dev, NULL);
> if (IS_ERR(extclk))
> return dev_err_probe(st->dev, PTR_ERR(extclk),
> "Failed to get external clock\n");
> @@ -1007,14 +1000,6 @@ static int ltc2947_setup(struct ltc2947_data *st)
> return -EINVAL;
> }
>
> - ret = clk_prepare_enable(extclk);
> - if (ret)
> - return ret;
> -
> - ret = devm_add_action_or_reset(st->dev, ltc2947_clk_disable,
> - extclk);
> - if (ret)
> - return ret;
> /* as in table 1 of the datasheet */
> if (rate_hz >= LTC2947_CLK_MIN && rate_hz <= 1000000)
> pre = 0;
> diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c
> index 1ba1e3145969..0c691f291a64 100644
> --- a/drivers/hwmon/mr75203.c
> +++ b/drivers/hwmon/mr75203.c
> @@ -461,24 +461,6 @@ static int pvt_get_regmap(struct platform_device *pdev, char *reg_name,
> return 0;
> }
>
> -static void pvt_clk_disable(void *data)
> -{
> - struct pvt_device *pvt = data;
> -
> - clk_disable_unprepare(pvt->clk);
> -}
> -
> -static int pvt_clk_enable(struct device *dev, struct pvt_device *pvt)
> -{
> - int ret;
> -
> - ret = clk_prepare_enable(pvt->clk);
> - if (ret)
> - return ret;
> -
> - return devm_add_action_or_reset(dev, pvt_clk_disable, pvt);
> -}
> -
> static void pvt_reset_control_assert(void *data)
> {
> struct pvt_device *pvt = data;
> @@ -515,16 +497,10 @@ static int mr75203_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> - pvt->clk = devm_clk_get(dev, NULL);
> + pvt->clk = devm_clk_get_enabled(dev, NULL);
> if (IS_ERR(pvt->clk))
> return dev_err_probe(dev, PTR_ERR(pvt->clk), "failed to get clock\n");
>
> - ret = pvt_clk_enable(dev, pvt);
> - if (ret) {
> - dev_err(dev, "failed to enable clock\n");
> - return ret;
> - }
> -
> pvt->rst = devm_reset_control_get_exclusive(dev, NULL);
> if (IS_ERR(pvt->rst))
> return dev_err_probe(dev, PTR_ERR(pvt->rst),
> diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c
> index 98be48e3a22a..04fd8505e5d6 100644
> --- a/drivers/hwmon/sparx5-temp.c
> +++ b/drivers/hwmon/sparx5-temp.c
> @@ -26,13 +26,6 @@ struct s5_hwmon {
> struct clk *clk;
> };
>
> -static void s5_temp_clk_disable(void *data)
> -{
> - struct clk *clk = data;
> -
> - clk_disable_unprepare(clk);
> -}
> -
> static void s5_temp_enable(struct s5_hwmon *hwmon)
> {
> u32 val = readl(hwmon->base + TEMP_CFG);
> @@ -113,7 +106,6 @@ static int s5_temp_probe(struct platform_device *pdev)
> {
> struct device *hwmon_dev;
> struct s5_hwmon *hwmon;
> - int ret;
>
> hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
> if (!hwmon)
> @@ -123,19 +115,10 @@ static int s5_temp_probe(struct platform_device *pdev)
> if (IS_ERR(hwmon->base))
> return PTR_ERR(hwmon->base);
>
> - hwmon->clk = devm_clk_get(&pdev->dev, NULL);
> + hwmon->clk = devm_clk_get_enabled(&pdev->dev, NULL);
> if (IS_ERR(hwmon->clk))
> return PTR_ERR(hwmon->clk);
>
> - ret = clk_prepare_enable(hwmon->clk);
> - if (ret)
> - return ret;
> -
> - ret = devm_add_action_or_reset(&pdev->dev, s5_temp_clk_disable,
> - hwmon->clk);
> - if (ret)
> - return ret;
> -
> s5_temp_enable(hwmon);
>
> hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,

2022-03-16 14:49:46

by Uwe Kleine-König

[permalink] [raw]
Subject: [PATCH v8 05/16] hwrng: meson - Don't open-code devm_clk_get_optional_enabled()

devm_clk_get_enabled() returns a clock prepared and enabled and already
registers a devm exit handler to disable (and unprepare) the clock.

Signed-off-by: Uwe Kleine-König <[email protected]>
---
drivers/char/hw_random/meson-rng.c | 20 ++------------------
1 file changed, 2 insertions(+), 18 deletions(-)

diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c
index 8bb30282ca46..06db5a93e257 100644
--- a/drivers/char/hw_random/meson-rng.c
+++ b/drivers/char/hw_random/meson-rng.c
@@ -33,16 +33,10 @@ static int meson_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
return sizeof(u32);
}

-static void meson_rng_clk_disable(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int meson_rng_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_rng_data *data;
- int ret;

data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -54,20 +48,10 @@ static int meson_rng_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);

- data->core_clk = devm_clk_get_optional(dev, "core");
+ data->core_clk = devm_clk_get_optional_enabled(dev, "core");
if (IS_ERR(data->core_clk))
return dev_err_probe(dev, PTR_ERR(data->core_clk),
- "Failed to get core clock\n");
-
- if (data->core_clk) {
- ret = clk_prepare_enable(data->core_clk);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(dev, meson_rng_clk_disable,
- data->core_clk);
- if (ret)
- return ret;
- }
+ "Failed to get enabled core clock\n");

data->rng.name = pdev->name;
data->rng.read = meson_rng_read;
--
2.35.1

2022-03-17 04:11:48

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v8 00/16] clk: provide new devm helpers for prepared and enabled clocks

On Mon, Mar 14, 2022 at 5:14 PM Uwe Kleine-König
<[email protected]> wrote:
>
> Hello,
>
> this is another try to convince the relevant people that
> devm_clk_get_enabled() is a nice idea. Compared to v7 (back in May 2021) this
> series is rebased to v5.17-rc8 and converts quite some drivers that open code
> devm_clk_get_enabled() up to now (patches #3 - #11).
>
> A concern about devm_clk_get_enabled() in v7 was that it helps people to be
> lazy and I agree that in some situations when devm_clk_get_enabled() is used it
> would be more efficient and sensible to care to only enable the clk when really
> needed.
>
> On the other hand, the function is right for some users, e.g. the watchdog
> drivers. For the others it's not so simple to judge. Given that there are a
> lot of drivers that are lazy even if doing so is some effort (i.e. calling
> clk_prepare_enable() and devm_add_action()) convinces me, that introducing the
> function family is sensible. (And if you want to work on these drivers,
> grepping for devm_clk_get_enabled gives you a few candidates once the
> series is in :-)

FWIW,
Reviewed-by: Andy Shevchenko <[email protected]>
for drivers/iio

Thanks for doing this!

> Otherwise looking at the diffstat of this series:
>
> 48 files changed, 257 insertions(+), 851 deletions(-)
>
> is quite convincing. Just the first two patches (which introduce the new
> functions) account for
>
> 2 files changed, 169 insertions(+), 17 deletions(-)
>
> . A rough third of the added lines is documentation. The rest is driver
> updates which then has:
>
> 46 files changed, 88 insertions(+), 834 deletions(-)
>
> which makes a really nice cleanup.
>
> The series is build-tested on arm64, m68k, powerpc, riscv, s390, sparc64
> and x86_64 using an allmodconfig.
>
> Best regards
> Uwe
>
> Uwe Kleine-König (16):
> clk: generalize devm_clk_get() a bit
> clk: Provide new devm_clk helpers for prepared and enabled clocks
> hwmon: Make use of devm_clk_get_enabled()
> iio: Make use of devm_clk_get_enabled()
> hwrng: meson - Don't open-code devm_clk_get_optional_enabled()
> bus: bt1: Don't open code devm_clk_get_enabled()
> gpio: vf610: Simplify error handling in probe
> drm/meson: dw-hdmi: Don't open code devm_clk_get_enabled()
> rtc: ingenic: Simplify using devm_clk_get_enabled()
> clk: meson: axg-audio: Don't duplicate devm_clk_get_enabled()
> watchdog: Make use of devm_clk_get_enabled()
> pwm: atmel: Simplify using devm_clk_get_prepared()
> rtc: at91sam9: Simplify using devm_clk_get_enabled()
> i2c: imx: Simplify using devm_clk_get_enabled()
> spi: davinci: Simplify using devm_clk_get_enabled()
> dmaengine: lgm: Fix error handling
>
> drivers/bus/bt1-apb.c | 23 +------
> drivers/bus/bt1-axi.c | 23 +------
> drivers/char/hw_random/meson-rng.c | 20 +-----
> drivers/clk/clk-devres.c | 96 ++++++++++++++++++++++-----
> drivers/clk/meson/axg-audio.c | 36 ++--------
> drivers/dma/lgm/lgm-dma.c | 8 +--
> drivers/gpio/gpio-vf610.c | 45 +++----------
> drivers/gpu/drm/meson/meson_dw_hdmi.c | 48 +++++---------
> drivers/hwmon/axi-fan-control.c | 15 +----
> drivers/hwmon/ltc2947-core.c | 17 +----
> drivers/hwmon/mr75203.c | 26 +-------
> drivers/hwmon/sparx5-temp.c | 19 +-----
> drivers/i2c/busses/i2c-imx.c | 12 +---
> drivers/iio/adc/ad7124.c | 15 +----
> drivers/iio/adc/ad7768-1.c | 17 +----
> drivers/iio/adc/ad9467.c | 17 +----
> drivers/iio/adc/ingenic-adc.c | 15 +----
> drivers/iio/adc/lpc18xx_adc.c | 18 +----
> drivers/iio/adc/rockchip_saradc.c | 44 +-----------
> drivers/iio/adc/ti-ads131e08.c | 19 +-----
> drivers/iio/adc/xilinx-ams.c | 15 +----
> drivers/iio/adc/xilinx-xadc-core.c | 18 +----
> drivers/iio/frequency/adf4371.c | 17 +----
> drivers/iio/frequency/admv1013.c | 15 +----
> drivers/iio/frequency/adrf6780.c | 16 +----
> drivers/iio/imu/adis16475.c | 15 +----
> drivers/pwm/pwm-atmel.c | 16 +----
> drivers/rtc/rtc-at91sam9.c | 22 ++----
> drivers/rtc/rtc-jz4740.c | 21 +-----
> drivers/spi/spi-davinci.c | 11 +--
> drivers/watchdog/cadence_wdt.c | 17 +----
> drivers/watchdog/davinci_wdt.c | 18 +----
> drivers/watchdog/imgpdc_wdt.c | 31 +--------
> drivers/watchdog/imx2_wdt.c | 15 +----
> drivers/watchdog/imx7ulp_wdt.c | 15 +----
> drivers/watchdog/loongson1_wdt.c | 17 +----
> drivers/watchdog/lpc18xx_wdt.c | 30 +--------
> drivers/watchdog/meson_gxbb_wdt.c | 16 +----
> drivers/watchdog/of_xilinx_wdt.c | 16 +----
> drivers/watchdog/pic32-dmt.c | 15 +----
> drivers/watchdog/pic32-wdt.c | 17 +----
> drivers/watchdog/pnx4008_wdt.c | 15 +----
> drivers/watchdog/qcom-wdt.c | 16 +----
> drivers/watchdog/rtd119x_wdt.c | 16 +----
> drivers/watchdog/st_lpc_wdt.c | 16 +----
> drivers/watchdog/stm32_iwdg.c | 31 +--------
> drivers/watchdog/visconti_wdt.c | 18 +----
> include/linux/clk.h | 90 ++++++++++++++++++++++++-
> 48 files changed, 257 insertions(+), 851 deletions(-)
>
>
> base-commit: 09688c0166e76ce2fb85e86b9d99be8b0084cdf9
> --
> 2.35.1
>


--
With Best Regards,
Andy Shevchenko

2022-03-17 06:00:48

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v8 05/16] hwrng: meson - Don't open-code devm_clk_get_optional_enabled()

On 14/03/2022 15:16, Uwe Kleine-König wrote:
> devm_clk_get_enabled() returns a clock prepared and enabled and already
> registers a devm exit handler to disable (and unprepare) the clock.
>
> Signed-off-by: Uwe Kleine-König <[email protected]>
> ---
> drivers/char/hw_random/meson-rng.c | 20 ++------------------
> 1 file changed, 2 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c
> index 8bb30282ca46..06db5a93e257 100644
> --- a/drivers/char/hw_random/meson-rng.c
> +++ b/drivers/char/hw_random/meson-rng.c
> @@ -33,16 +33,10 @@ static int meson_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> return sizeof(u32);
> }
>
> -static void meson_rng_clk_disable(void *data)
> -{
> - clk_disable_unprepare(data);
> -}
> -
> static int meson_rng_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> struct meson_rng_data *data;
> - int ret;
>
> data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> if (!data)
> @@ -54,20 +48,10 @@ static int meson_rng_probe(struct platform_device *pdev)
> if (IS_ERR(data->base))
> return PTR_ERR(data->base);
>
> - data->core_clk = devm_clk_get_optional(dev, "core");
> + data->core_clk = devm_clk_get_optional_enabled(dev, "core");
> if (IS_ERR(data->core_clk))
> return dev_err_probe(dev, PTR_ERR(data->core_clk),
> - "Failed to get core clock\n");
> -
> - if (data->core_clk) {
> - ret = clk_prepare_enable(data->core_clk);
> - if (ret)
> - return ret;
> - ret = devm_add_action_or_reset(dev, meson_rng_clk_disable,
> - data->core_clk);
> - if (ret)
> - return ret;
> - }
> + "Failed to get enabled core clock\n");
>
> data->rng.name = pdev->name;
> data->rng.read = meson_rng_read;

Acked-by: Neil Armstrong <[email protected]>

2022-03-20 13:41:39

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v8 02/16] clk: Provide new devm_clk helpers for prepared and enabled clocks

On Mon, 14 Mar 2022 15:16:29 +0100
Uwe Kleine-König <[email protected]> wrote:

> When a driver keeps a clock prepared (or enabled) during the whole
> lifetime of the driver, these helpers allow to simplify the drivers.
>
> Reviewed-by: Jonathan Cameron <[email protected]>
> Reviewed-by: Alexandru Ardelean <[email protected]>
> Signed-off-by: Uwe Kleine-König <[email protected]>

One trivial thing below.

> ---
> drivers/clk/clk-devres.c | 31 ++++++++++++++
> include/linux/clk.h | 90 +++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 120 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
> index fb7761888b30..4707fe718f0b 100644
> --- a/drivers/clk/clk-devres.c
> +++ b/drivers/clk/clk-devres.c
> @@ -67,12 +67,43 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
> }
> EXPORT_SYMBOL(devm_clk_get);
>
> +struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
> +{
> + return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);

Nitpick but this spacing before } in functions is rather unusual and not
in keeping with the existing code in this file.

> +
> +}
> +EXPORT_SYMBOL(devm_clk_get_prepared);
> +
> +struct clk *devm_clk_get_enabled(struct device *dev, const char *id)
> +{
> + return __devm_clk_get(dev, id, clk_get,
> + clk_prepare_enable, clk_disable_unprepare);
> +
> +}
> +EXPORT_SYMBOL(devm_clk_get_enabled);
> +
> struct clk *devm_clk_get_optional(struct device *dev, const char *id)
> {
> return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
> }
> EXPORT_SYMBOL(devm_clk_get_optional);
>
> +struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)
> +{
> + return __devm_clk_get(dev, id, clk_get_optional,
> + clk_prepare, clk_unprepare);
> +
> +}
> +EXPORT_SYMBOL(devm_clk_get_optional_prepared);
> +
> +struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
> +{
> + return __devm_clk_get(dev, id, clk_get_optional,
> + clk_prepare_enable, clk_disable_unprepare);
> +
> +}
> +EXPORT_SYMBOL(devm_clk_get_optional_enabled);
> +
> struct clk_bulk_devres {
> struct clk_bulk_data *clks;
> int num_clks;
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 266e8de3cb51..b011dbba7109 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -449,7 +449,7 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
> * the clock producer. (IOW, @id may be identical strings, but
> * clk_get may return different clock producers depending on @dev.)
> *
> - * Drivers must assume that the clock source is not enabled.
> + * Drivers must assume that the clock source is neither prepared nor enabled.
> *
> * devm_clk_get should not be called from within interrupt context.
> *
> @@ -458,6 +458,47 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
> */
> struct clk *devm_clk_get(struct device *dev, const char *id);
>
> +/**
> + * devm_clk_get_prepared - devm_clk_get() + clk_prepare()
> + * @dev: device for clock "consumer"
> + * @id: clock consumer ID
> + *
> + * Returns a struct clk corresponding to the clock producer, or
> + * valid IS_ERR() condition containing errno. The implementation
> + * uses @dev and @id to determine the clock consumer, and thereby
> + * the clock producer. (IOW, @id may be identical strings, but
> + * clk_get may return different clock producers depending on @dev.)
> + *
> + * The returned clk (if valid) is prepared. Drivers must however assume that the
> + * clock is not enabled.
> + *
> + * devm_clk_get_prepared should not be called from within interrupt context.
> + *
> + * The clock will automatically be unprepared and freed when the
> + * device is unbound from the bus.
> + */
> +struct clk *devm_clk_get_prepared(struct device *dev, const char *id);
> +
> +/**
> + * devm_clk_get_enabled - devm_clk_get() + clk_prepare_enable()
> + * @dev: device for clock "consumer"
> + * @id: clock consumer ID
> + *
> + * Returns a struct clk corresponding to the clock producer, or valid IS_ERR()
> + * condition containing errno. The implementation uses @dev and @id to
> + * determine the clock consumer, and thereby the clock producer. (IOW, @id may
> + * be identical strings, but clk_get may return different clock producers
> + * depending on @dev.)
> + *
> + * The returned clk (if valid) is prepared and enabled.
> + *
> + * devm_clk_get_prepared should not be called from within interrupt context.
> + *
> + * The clock will automatically be disabled, unprepared and freed when the
> + * device is unbound from the bus.
> + */
> +struct clk *devm_clk_get_enabled(struct device *dev, const char *id);
> +
> /**
> * devm_clk_get_optional - lookup and obtain a managed reference to an optional
> * clock producer.
> @@ -469,6 +510,29 @@ struct clk *devm_clk_get(struct device *dev, const char *id);
> */
> struct clk *devm_clk_get_optional(struct device *dev, const char *id);
>
> +/**
> + * devm_clk_get_optional_prepared - devm_clk_get_optional() + clk_prepare()
> + * @dev: device for clock "consumer"
> + * @id: clock consumer ID
> + *
> + * Behaves the same as devm_clk_get_prepared() except where there is no clock
> + * producer. In this case, instead of returning -ENOENT, the function returns
> + * NULL.
> + */
> +struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id);
> +
> +/**
> + * devm_clk_get_optional_enabled - devm_clk_get_optional() +
> + * clk_prepare_enable()
> + * @dev: device for clock "consumer"
> + * @id: clock consumer ID
> + *
> + * Behaves the same as devm_clk_get_enabled() except where there is no clock
> + * producer. In this case, instead of returning -ENOENT, the function returns
> + * NULL.
> + */
> +struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id);
> +
> /**
> * devm_get_clk_from_child - lookup and obtain a managed reference to a
> * clock producer from child node.
> @@ -813,12 +877,36 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id)
> return NULL;
> }
>
> +static inline struct clk *devm_clk_get_prepared(struct device *dev,
> + const char *id)
> +{
> + return NULL;
> +}
> +
> +static inline struct clk *devm_clk_get_enabled(struct device *dev,
> + const char *id)
> +{
> + return NULL;
> +}
> +
> static inline struct clk *devm_clk_get_optional(struct device *dev,
> const char *id)
> {
> return NULL;
> }
>
> +static inline struct clk *devm_clk_get_optional_prepared(struct device *dev,
> + const char *id)
> +{
> + return NULL;
> +}
> +
> +static inline struct clk *devm_clk_get_optional_enabled(struct device *dev,
> + const char *id)
> +{
> + return NULL;
> +}
> +
> static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
> struct clk_bulk_data *clks)
> {

2022-03-21 22:26:39

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [PATCH v8 02/16] clk: Provide new devm_clk helpers for prepared and enabled clocks

On Sat, Mar 19, 2022 at 06:29:36PM +0000, Jonathan Cameron wrote:
> On Mon, 14 Mar 2022 15:16:29 +0100
> Uwe Kleine-K?nig <[email protected]> wrote:
>
> > When a driver keeps a clock prepared (or enabled) during the whole
> > lifetime of the driver, these helpers allow to simplify the drivers.
> >
> > Reviewed-by: Jonathan Cameron <[email protected]>
> > Reviewed-by: Alexandru Ardelean <[email protected]>
> > Signed-off-by: Uwe Kleine-K?nig <[email protected]>
>
> One trivial thing below.
>
> > ---
> > drivers/clk/clk-devres.c | 31 ++++++++++++++
> > include/linux/clk.h | 90 +++++++++++++++++++++++++++++++++++++++-
> > 2 files changed, 120 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
> > index fb7761888b30..4707fe718f0b 100644
> > --- a/drivers/clk/clk-devres.c
> > +++ b/drivers/clk/clk-devres.c
> > @@ -67,12 +67,43 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
> > }
> > EXPORT_SYMBOL(devm_clk_get);
> >
> > +struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
> > +{
> > + return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);
>
> Nitpick but this spacing before } in functions is rather unusual and not
> in keeping with the existing code in this file.
>
> > +
> > +}

ack, I fixed that in my tree, so this will be part of an v9. I won't
send it just for this change, though. I fixed three further functions
that had a similar empty line, too.

Thanks for looking
Uwe

--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | https://www.pengutronix.de/ |


Attachments:
(No filename) (1.72 kB)
signature.asc (499.00 B)
Download all attachments

2022-06-21 19:59:08

by Jon Hunter

[permalink] [raw]
Subject: Re: [PATCH v8 01/16] clk: generalize devm_clk_get() a bit

Hi Uwe,

On 14/03/2022 14:16, Uwe Kleine-König wrote:
> Allow to add an exit hook to devm managed clocks. Also use
> clk_get_optional() in devm_clk_get_optional instead of open coding it.
> The generalisation will be used in the next commit to add some more
> devm_clk helpers.
>
> Reviewed-by: Jonathan Cameron <[email protected]>
> Reviewed-by: Alexandru Ardelean <[email protected]>
> Signed-off-by: Uwe Kleine-König <[email protected]>
> ---
> drivers/clk/clk-devres.c | 67 ++++++++++++++++++++++++++++++----------
> 1 file changed, 50 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
> index f9d5b7334341..fb7761888b30 100644
> --- a/drivers/clk/clk-devres.c
> +++ b/drivers/clk/clk-devres.c
> @@ -4,39 +4,72 @@
> #include <linux/export.h>
> #include <linux/gfp.h>
>
> +struct devm_clk_state {
> + struct clk *clk;
> + void (*exit)(struct clk *clk);
> +};
> +
> static void devm_clk_release(struct device *dev, void *res)
> {
> - clk_put(*(struct clk **)res);
> + struct devm_clk_state *state = *(struct devm_clk_state **)res;
> +
> + if (state->exit)
> + state->exit(state->clk);
> +
> + clk_put(state->clk);
> }
>
> -struct clk *devm_clk_get(struct device *dev, const char *id)
> +static struct clk *__devm_clk_get(struct device *dev, const char *id,
> + struct clk *(*get)(struct device *dev, const char *id),
> + int (*init)(struct clk *clk),
> + void (*exit)(struct clk *clk))
> {
> - struct clk **ptr, *clk;
> + struct devm_clk_state *state;
> + struct clk *clk;
> + int ret;
>
> - ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
> - if (!ptr)
> + state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
> + if (!state)
> return ERR_PTR(-ENOMEM);
>
> - clk = clk_get(dev, id);
> - if (!IS_ERR(clk)) {
> - *ptr = clk;
> - devres_add(dev, ptr);
> - } else {
> - devres_free(ptr);
> + clk = get(dev, id);
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + goto err_clk_get;
> }
>
> + if (init) {
> + ret = init(clk);
> + if (ret)
> + goto err_clk_init;
> + }
> +
> + state->clk = clk;
> + state->exit = exit;
> +
> + devres_add(dev, state);
> +
> return clk;
> +
> +err_clk_init:
> +
> + clk_put(clk);
> +err_clk_get:
> +
> + devres_free(state);
> + return ERR_PTR(ret);
> }
> -EXPORT_SYMBOL(devm_clk_get);
>
> -struct clk *devm_clk_get_optional(struct device *dev, const char *id)
> +struct clk *devm_clk_get(struct device *dev, const char *id)
> {
> - struct clk *clk = devm_clk_get(dev, id);
> + return __devm_clk_get(dev, id, clk_get, NULL, NULL);
>
> - if (clk == ERR_PTR(-ENOENT))
> - return NULL;
> +}
> +EXPORT_SYMBOL(devm_clk_get);
>
> - return clk;
> +struct clk *devm_clk_get_optional(struct device *dev, const char *id)
> +{
> + return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
> }
> EXPORT_SYMBOL(devm_clk_get_optional);
>


Some of our Tegra boards are not booting with the current -next and
bisect is pointing to this commit. Looking at the boot log I am
seeing the following panic ...

[ 2.097048] 8<--- cut here ---
[ 2.097053] Unable to handle kernel paging request at virtual address c216c810
[ 2.097060] [c216c810] *pgd=0201141e(bad)
[ 2.097079] Internal error: Oops: 8000000d [#1] SMP ARM
[ 2.097088] Modules linked in:
[ 2.097097] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.19.0-rc3-next-20220621-g34d1d36073ea #1
[ 2.097107] Hardware name: NVIDIA Tegra SoC (Flattened Device Tree)
[ 2.097113] PC is at 0xc216c810
[ 2.097123] LR is at devm_clk_release+0x18/0x24
[ 2.097150] pc : [<c216c810>] lr : [<c088cb04>] psr: a0000013
[ 2.097155] sp : f080dde8 ip : 000006cf fp : c18d4854
[ 2.097161] r10: c1501850 r9 : c1a04d10 r8 : c1c4efa0
[ 2.097166] r7 : c216c810 r6 : f080de1c r5 : c2737680 r4 : c26a9680
[ 2.097172] r3 : c216c810 r2 : 00000000 r1 : c2737840 r0 : c2082840
[ 2.097179] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 2.097187] Control: 10c5387d Table: 0020404a DAC: 00000051
[ 2.097191] Register r0 information: slab kmalloc-192 start c2082840 pointer offset 0 size 192
[ 2.097216] Register r1 information: slab kmalloc-128 start c2737800 pointer offset 64 size 128
[ 2.097236] Register r2 information: NULL pointer
[ 2.097244] Register r3 information: slab kmalloc-1k start c216c800 pointer offset 16 size 1024
[ 2.097263] Register r4 information: slab kmalloc-64 start c26a9680 pointer offset 0 size 64
[ 2.097282] Register r5 information: slab kmalloc-128 start c2737680 pointer offset 0 size 128
[ 2.097301] Register r6 information: 2-page vmalloc region starting at 0xf080c000 allocated at kernel_clone+0xb4/0x3e8
[ 2.097321] Register r7 information: slab kmalloc-1k start c216c800 pointer offset 16 size 1024
[ 2.097341] Register r8 information: non-slab/vmalloc memory
[ 2.097348] Register r9 information: non-slab/vmalloc memory
[ 2.097355] Register r10 information: non-slab/vmalloc memory
[ 2.097362] Register r11 information: non-slab/vmalloc memory
[ 2.097369] Register r12 information: non-paged memory
[ 2.097375] Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
[ 2.097384] Stack: (0xf080dde8 to 0xf080e000)
[ 2.097394] dde0: c2737800 c0a72d38 c18d4854 c0530490 c216c810 f080de1c
[ 2.097404] de00: c2120000 00000005 c216c9c0 80000013 0000017e c0a73d68 00000008 c2629e00
[ 2.097413] de20: c2737880 5640e141 c216c810 c216c810 00000205 c1c09dd4 00000000 c27375b8
[ 2.097422] de40: c2091700 c0a6e9a0 c216c810 c0a6f288 c216c810 c1c09dd4 c216c810 00000000
[ 2.097430] de60: c27375b8 c0a6f3c0 c1caa8e0 c216c810 c216c810 c0a6f450 00000000 c216c810
[ 2.097439] de80: c1c09dd4 c2120000 c27375b8 c0a6f850 00000000 c1c09dd4 c0a6f7c4 c0a6d4c0
[ 2.097447] dea0: 00000000 c2091458 c2286434 5640e141 c1be7f08 c1c09dd4 c2737580 c1be7f08
[ 2.097455] dec0: 00000000 c0a6e484 c1615714 c1be7c50 c1c09dd4 c2120000 c189a99c 00000000
[ 2.097464] dee0: c2120000 c0a701a0 c1c494e0 c2120000 c189a99c c0302144 0000017d c0364438
[ 2.097472] df00: c16da8bc c1626700 00000000 00000006 00000006 c16554c8 00000000 c2120000
[ 2.097480] df20: c15105bc c14f9778 c2091700 c20917d9 00000000 5640e141 c1a88930 c16da8bc
[ 2.097488] df40: c1c59000 5640e141 c16da8bc c1c59000 c1953b4c c18d4834 00000007 c1801340
[ 2.097497] df60: 00000006 00000006 00000000 c18004dc c2120000 c18004dc f080df74 c1a04cc0
[ 2.097505] df80: c106bbf0 00000000 00000000 00000000 00000000 00000000 00000000 c106bc08
[ 2.097513] dfa0: 00000000 c106bbf0 00000000 c03001a8 00000000 00000000 00000000 00000000
[ 2.097520] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 2.097528] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[ 2.097542] devm_clk_release from release_nodes+0x58/0xc0
[ 2.097575] release_nodes from devres_release_all+0x7c/0xc0
[ 2.097596] devres_release_all from device_unbind_cleanup+0xc/0x60
[ 2.097626] device_unbind_cleanup from really_probe+0x1f4/0x2a8
[ 2.097650] really_probe from __driver_probe_device+0x84/0xe4
[ 2.097673] __driver_probe_device from driver_probe_device+0x30/0xd0
[ 2.097696] driver_probe_device from __driver_attach+0x8c/0xf0
[ 2.097713] __driver_attach from bus_for_each_dev+0x70/0xb0
[ 2.097729] bus_for_each_dev from bus_add_driver+0x168/0x1f4
[ 2.097749] bus_add_driver from driver_register+0x7c/0x118
[ 2.097766] driver_register from do_one_initcall+0x44/0x1ec
[ 2.097784] do_one_initcall from kernel_init_freeable+0x1d4/0x224
[ 2.097803] kernel_init_freeable from kernel_init+0x18/0x12c
[ 2.097820] kernel_init from ret_from_fork+0x14/0x2c
[ 2.097831] Exception stack(0xf080dfb0 to 0xf080dff8)
[ 2.097839] dfa0: 00000000 00000000 00000000 00000000
[ 2.097847] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 2.097854] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 2.097862] Code: c2288680 ffffffff 00000000 00000000 (c2288680)
[ 2.097872] ---[ end trace 0000000000000000 ]---


Let me know if you have any thoughts.

Cheers
Jon

--
nvpublic

2022-06-21 21:12:13

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [PATCH v8 01/16] clk: generalize devm_clk_get() a bit

On Tue, Jun 21, 2022 at 08:57:00PM +0100, Jon Hunter wrote:
> Some of our Tegra boards are not booting with the current -next and
> bisect is pointing to this commit. Looking at the boot log I am
> seeing the following panic ...
>
> [ 2.097048] 8<--- cut here ---
> [ 2.097053] Unable to handle kernel paging request at virtual address c216c810
> [ 2.097060] [c216c810] *pgd=0201141e(bad)
> [ 2.097079] Internal error: Oops: 8000000d [#1] SMP ARM
> [ 2.097088] Modules linked in:
> [ 2.097097] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.19.0-rc3-next-20220621-g34d1d36073ea #1
> [ 2.097107] Hardware name: NVIDIA Tegra SoC (Flattened Device Tree)
> [ 2.097113] PC is at 0xc216c810
> [ 2.097123] LR is at devm_clk_release+0x18/0x24
> [ 2.097150] pc : [<c216c810>] lr : [<c088cb04>] psr: a0000013
> [ 2.097155] sp : f080dde8 ip : 000006cf fp : c18d4854
> [ 2.097161] r10: c1501850 r9 : c1a04d10 r8 : c1c4efa0
> [ 2.097166] r7 : c216c810 r6 : f080de1c r5 : c2737680 r4 : c26a9680
> [ 2.097172] r3 : c216c810 r2 : 00000000 r1 : c2737840 r0 : c2082840
> [ 2.097179] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
> [ 2.097187] Control: 10c5387d Table: 0020404a DAC: 00000051
> [ 2.097191] Register r0 information: slab kmalloc-192 start c2082840 pointer offset 0 size 192
> [ 2.097216] Register r1 information: slab kmalloc-128 start c2737800 pointer offset 64 size 128
> [ 2.097236] Register r2 information: NULL pointer
> [ 2.097244] Register r3 information: slab kmalloc-1k start c216c800 pointer offset 16 size 1024
> [ 2.097263] Register r4 information: slab kmalloc-64 start c26a9680 pointer offset 0 size 64
> [ 2.097282] Register r5 information: slab kmalloc-128 start c2737680 pointer offset 0 size 128
> [ 2.097301] Register r6 information: 2-page vmalloc region starting at 0xf080c000 allocated at kernel_clone+0xb4/0x3e8
> [ 2.097321] Register r7 information: slab kmalloc-1k start c216c800 pointer offset 16 size 1024
> [ 2.097341] Register r8 information: non-slab/vmalloc memory
> [ 2.097348] Register r9 information: non-slab/vmalloc memory
> [ 2.097355] Register r10 information: non-slab/vmalloc memory
> [ 2.097362] Register r11 information: non-slab/vmalloc memory
> [ 2.097369] Register r12 information: non-paged memory
> [ 2.097375] Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> [ 2.097384] Stack: (0xf080dde8 to 0xf080e000)
> [ 2.097394] dde0: c2737800 c0a72d38 c18d4854 c0530490 c216c810 f080de1c
> [ 2.097404] de00: c2120000 00000005 c216c9c0 80000013 0000017e c0a73d68 00000008 c2629e00
> [ 2.097413] de20: c2737880 5640e141 c216c810 c216c810 00000205 c1c09dd4 00000000 c27375b8
> [ 2.097422] de40: c2091700 c0a6e9a0 c216c810 c0a6f288 c216c810 c1c09dd4 c216c810 00000000
> [ 2.097430] de60: c27375b8 c0a6f3c0 c1caa8e0 c216c810 c216c810 c0a6f450 00000000 c216c810
> [ 2.097439] de80: c1c09dd4 c2120000 c27375b8 c0a6f850 00000000 c1c09dd4 c0a6f7c4 c0a6d4c0
> [ 2.097447] dea0: 00000000 c2091458 c2286434 5640e141 c1be7f08 c1c09dd4 c2737580 c1be7f08
> [ 2.097455] dec0: 00000000 c0a6e484 c1615714 c1be7c50 c1c09dd4 c2120000 c189a99c 00000000
> [ 2.097464] dee0: c2120000 c0a701a0 c1c494e0 c2120000 c189a99c c0302144 0000017d c0364438
> [ 2.097472] df00: c16da8bc c1626700 00000000 00000006 00000006 c16554c8 00000000 c2120000
> [ 2.097480] df20: c15105bc c14f9778 c2091700 c20917d9 00000000 5640e141 c1a88930 c16da8bc
> [ 2.097488] df40: c1c59000 5640e141 c16da8bc c1c59000 c1953b4c c18d4834 00000007 c1801340
> [ 2.097497] df60: 00000006 00000006 00000000 c18004dc c2120000 c18004dc f080df74 c1a04cc0
> [ 2.097505] df80: c106bbf0 00000000 00000000 00000000 00000000 00000000 00000000 c106bc08
> [ 2.097513] dfa0: 00000000 c106bbf0 00000000 c03001a8 00000000 00000000 00000000 00000000
> [ 2.097520] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> [ 2.097528] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
> [ 2.097542] devm_clk_release from release_nodes+0x58/0xc0
> [ 2.097575] release_nodes from devres_release_all+0x7c/0xc0
> [ 2.097596] devres_release_all from device_unbind_cleanup+0xc/0x60
> [ 2.097626] device_unbind_cleanup from really_probe+0x1f4/0x2a8
> [ 2.097650] really_probe from __driver_probe_device+0x84/0xe4
> [ 2.097673] __driver_probe_device from driver_probe_device+0x30/0xd0
> [ 2.097696] driver_probe_device from __driver_attach+0x8c/0xf0
> [ 2.097713] __driver_attach from bus_for_each_dev+0x70/0xb0
> [ 2.097729] bus_for_each_dev from bus_add_driver+0x168/0x1f4
> [ 2.097749] bus_add_driver from driver_register+0x7c/0x118
> [ 2.097766] driver_register from do_one_initcall+0x44/0x1ec
> [ 2.097784] do_one_initcall from kernel_init_freeable+0x1d4/0x224
> [ 2.097803] kernel_init_freeable from kernel_init+0x18/0x12c
> [ 2.097820] kernel_init from ret_from_fork+0x14/0x2c
> [ 2.097831] Exception stack(0xf080dfb0 to 0xf080dff8)
> [ 2.097839] dfa0: 00000000 00000000 00000000 00000000
> [ 2.097847] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> [ 2.097854] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
> [ 2.097862] Code: c2288680 ffffffff 00000000 00000000 (c2288680)
> [ 2.097872] ---[ end trace 0000000000000000 ]---
>
>
> Let me know if you have any thoughts.

Yeah, sorry, there is already a fix at
https://lore.kernel.org/linux-clk/[email protected]

(Pro tipp: The commit in next has a Link: footer. If you follow the
link, you find the thread that was actually applied (i.e. v9) and where
the fix is also contained.)

@Stephen: It would be a great favour to our testers if you could apply
the fix ...

Best regards
Uwe

--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | https://www.pengutronix.de/ |


Attachments:
(No filename) (6.04 kB)
signature.asc (499.00 B)
Download all attachments

2022-06-22 10:37:18

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v8 01/16] clk: generalize devm_clk_get() a bit

On Tue, Jun 21, 2022 at 11:01 PM Uwe Kleine-König
<[email protected]> wrote:
> On Tue, Jun 21, 2022 at 08:57:00PM +0100, Jon Hunter wrote:

...

> (Pro tipp: The commit in next has a Link: footer. If you follow the
> link, you find the thread that was actually applied (i.e. v9) and where
> the fix is also contained.)

Even easier, you may take a message-id from the Link and supply to `b4`:

b4 mbox ${message-id}
mutt -f ${message-id}.mbx # or whatever MUA that handles mboxes


Dunno if `b4` has capability to parse Link instead of message-id.

--
With Best Regards,
Andy Shevchenko

2022-06-22 11:16:33

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v8 01/16] clk: generalize devm_clk_get() a bit

On 22/06/2022 12:36, Andy Shevchenko wrote:
> On Tue, Jun 21, 2022 at 11:01 PM Uwe Kleine-König
> <[email protected]> wrote:
>> On Tue, Jun 21, 2022 at 08:57:00PM +0100, Jon Hunter wrote:
>
> ...
>
>> (Pro tipp: The commit in next has a Link: footer. If you follow the
>> link, you find the thread that was actually applied (i.e. v9) and where
>> the fix is also contained.)
>
> Even easier, you may take a message-id from the Link and supply to `b4`:
>
> b4 mbox ${message-id}
> mutt -f ${message-id}.mbx # or whatever MUA that handles mboxes
>
>
> Dunno if `b4` has capability to parse Link instead of message-id.
>

It does:


$ b4 mbox https://lore.kernel.org/r/[email protected]
Looking up https://lore.kernel.org/r/20220616144915.3988071-1-windhl%40126.com
Grabbing thread from lore.kernel.org/all/20220616144915.3988071-1-windhl%40126.com/t.mbox.gz
5 messages in the thread
Saved ./[email protected]

Neil

2022-06-22 15:42:09

by Jon Hunter

[permalink] [raw]
Subject: Re: [PATCH v8 01/16] clk: generalize devm_clk_get() a bit



On 21/06/2022 21:49, Uwe Kleine-König wrote:
> On Tue, Jun 21, 2022 at 08:57:00PM +0100, Jon Hunter wrote:
>> Some of our Tegra boards are not booting with the current -next and
>> bisect is pointing to this commit. Looking at the boot log I am
>> seeing the following panic ...
>>
>> [ 2.097048] 8<--- cut here ---
>> [ 2.097053] Unable to handle kernel paging request at virtual address c216c810
>> [ 2.097060] [c216c810] *pgd=0201141e(bad)
>> [ 2.097079] Internal error: Oops: 8000000d [#1] SMP ARM
>> [ 2.097088] Modules linked in:
>> [ 2.097097] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.19.0-rc3-next-20220621-g34d1d36073ea #1
>> [ 2.097107] Hardware name: NVIDIA Tegra SoC (Flattened Device Tree)
>> [ 2.097113] PC is at 0xc216c810
>> [ 2.097123] LR is at devm_clk_release+0x18/0x24
>> [ 2.097150] pc : [<c216c810>] lr : [<c088cb04>] psr: a0000013
>> [ 2.097155] sp : f080dde8 ip : 000006cf fp : c18d4854
>> [ 2.097161] r10: c1501850 r9 : c1a04d10 r8 : c1c4efa0
>> [ 2.097166] r7 : c216c810 r6 : f080de1c r5 : c2737680 r4 : c26a9680
>> [ 2.097172] r3 : c216c810 r2 : 00000000 r1 : c2737840 r0 : c2082840
>> [ 2.097179] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
>> [ 2.097187] Control: 10c5387d Table: 0020404a DAC: 00000051
>> [ 2.097191] Register r0 information: slab kmalloc-192 start c2082840 pointer offset 0 size 192
>> [ 2.097216] Register r1 information: slab kmalloc-128 start c2737800 pointer offset 64 size 128
>> [ 2.097236] Register r2 information: NULL pointer
>> [ 2.097244] Register r3 information: slab kmalloc-1k start c216c800 pointer offset 16 size 1024
>> [ 2.097263] Register r4 information: slab kmalloc-64 start c26a9680 pointer offset 0 size 64
>> [ 2.097282] Register r5 information: slab kmalloc-128 start c2737680 pointer offset 0 size 128
>> [ 2.097301] Register r6 information: 2-page vmalloc region starting at 0xf080c000 allocated at kernel_clone+0xb4/0x3e8
>> [ 2.097321] Register r7 information: slab kmalloc-1k start c216c800 pointer offset 16 size 1024
>> [ 2.097341] Register r8 information: non-slab/vmalloc memory
>> [ 2.097348] Register r9 information: non-slab/vmalloc memory
>> [ 2.097355] Register r10 information: non-slab/vmalloc memory
>> [ 2.097362] Register r11 information: non-slab/vmalloc memory
>> [ 2.097369] Register r12 information: non-paged memory
>> [ 2.097375] Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>> [ 2.097384] Stack: (0xf080dde8 to 0xf080e000)
>> [ 2.097394] dde0: c2737800 c0a72d38 c18d4854 c0530490 c216c810 f080de1c
>> [ 2.097404] de00: c2120000 00000005 c216c9c0 80000013 0000017e c0a73d68 00000008 c2629e00
>> [ 2.097413] de20: c2737880 5640e141 c216c810 c216c810 00000205 c1c09dd4 00000000 c27375b8
>> [ 2.097422] de40: c2091700 c0a6e9a0 c216c810 c0a6f288 c216c810 c1c09dd4 c216c810 00000000
>> [ 2.097430] de60: c27375b8 c0a6f3c0 c1caa8e0 c216c810 c216c810 c0a6f450 00000000 c216c810
>> [ 2.097439] de80: c1c09dd4 c2120000 c27375b8 c0a6f850 00000000 c1c09dd4 c0a6f7c4 c0a6d4c0
>> [ 2.097447] dea0: 00000000 c2091458 c2286434 5640e141 c1be7f08 c1c09dd4 c2737580 c1be7f08
>> [ 2.097455] dec0: 00000000 c0a6e484 c1615714 c1be7c50 c1c09dd4 c2120000 c189a99c 00000000
>> [ 2.097464] dee0: c2120000 c0a701a0 c1c494e0 c2120000 c189a99c c0302144 0000017d c0364438
>> [ 2.097472] df00: c16da8bc c1626700 00000000 00000006 00000006 c16554c8 00000000 c2120000
>> [ 2.097480] df20: c15105bc c14f9778 c2091700 c20917d9 00000000 5640e141 c1a88930 c16da8bc
>> [ 2.097488] df40: c1c59000 5640e141 c16da8bc c1c59000 c1953b4c c18d4834 00000007 c1801340
>> [ 2.097497] df60: 00000006 00000006 00000000 c18004dc c2120000 c18004dc f080df74 c1a04cc0
>> [ 2.097505] df80: c106bbf0 00000000 00000000 00000000 00000000 00000000 00000000 c106bc08
>> [ 2.097513] dfa0: 00000000 c106bbf0 00000000 c03001a8 00000000 00000000 00000000 00000000
>> [ 2.097520] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
>> [ 2.097528] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
>> [ 2.097542] devm_clk_release from release_nodes+0x58/0xc0
>> [ 2.097575] release_nodes from devres_release_all+0x7c/0xc0
>> [ 2.097596] devres_release_all from device_unbind_cleanup+0xc/0x60
>> [ 2.097626] device_unbind_cleanup from really_probe+0x1f4/0x2a8
>> [ 2.097650] really_probe from __driver_probe_device+0x84/0xe4
>> [ 2.097673] __driver_probe_device from driver_probe_device+0x30/0xd0
>> [ 2.097696] driver_probe_device from __driver_attach+0x8c/0xf0
>> [ 2.097713] __driver_attach from bus_for_each_dev+0x70/0xb0
>> [ 2.097729] bus_for_each_dev from bus_add_driver+0x168/0x1f4
>> [ 2.097749] bus_add_driver from driver_register+0x7c/0x118
>> [ 2.097766] driver_register from do_one_initcall+0x44/0x1ec
>> [ 2.097784] do_one_initcall from kernel_init_freeable+0x1d4/0x224
>> [ 2.097803] kernel_init_freeable from kernel_init+0x18/0x12c
>> [ 2.097820] kernel_init from ret_from_fork+0x14/0x2c
>> [ 2.097831] Exception stack(0xf080dfb0 to 0xf080dff8)
>> [ 2.097839] dfa0: 00000000 00000000 00000000 00000000
>> [ 2.097847] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
>> [ 2.097854] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
>> [ 2.097862] Code: c2288680 ffffffff 00000000 00000000 (c2288680)
>> [ 2.097872] ---[ end trace 0000000000000000 ]---
>>
>>
>> Let me know if you have any thoughts.
>
> Yeah, sorry, there is already a fix at
> https://lore.kernel.org/linux-clk/[email protected]

Thanks! Works for me.

Tested-by: Jon Hunter <[email protected]>

> (Pro tipp: The commit in next has a Link: footer. If you follow the
> link, you find the thread that was actually applied (i.e. v9) and where
> the fix is also contained.

Thanks for the tip!

Jon

--
nvpublic