| From a2be37eedb52ea26938fa4cc9de1ff84963c57ad Mon Sep 17 00:00:00 2001 |
| From: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> |
| Date: Tue, 24 Feb 2026 11:42:04 +0100 |
| Subject: firmware: exynos-acpm: Drop fake 'const' on handle pointer |
| |
| From: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> |
| |
| commit a2be37eedb52ea26938fa4cc9de1ff84963c57ad upstream. |
| |
| All the functions operating on the 'handle' pointer are claiming it is a |
| pointer to const thus they should not modify the handle. In fact that's |
| a false statement, because first thing these functions do is drop the |
| cast to const with container_of: |
| |
| struct acpm_info *acpm = handle_to_acpm_info(handle); |
| |
| And with such cast the handle is easily writable with simple: |
| |
| acpm->handle.ops.pmic_ops.read_reg = NULL; |
| |
| The code is not correct logically, either, because functions like |
| acpm_get_by_node() and acpm_handle_put() are meant to modify the handle |
| reference counting, thus they must modify the handle. Modification here |
| happens anyway, even if the reference counting is stored in the |
| container which the handle is part of. |
| |
| The code does not have actual visible bug, but incorrect 'const' |
| annotations could lead to incorrect compiler decisions. |
| |
| Fixes: a88927b534ba ("firmware: add Exynos ACPM protocol driver") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> |
| Link: https://patch.msgid.link/20260224104203.42950-2-krzysztof.kozlowski@oss.qualcomm.com |
| Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/clk/samsung/clk-acpm.c | 4 - |
| drivers/firmware/samsung/exynos-acpm-dvfs.c | 4 - |
| drivers/firmware/samsung/exynos-acpm-dvfs.h | 4 - |
| drivers/firmware/samsung/exynos-acpm-pmic.c | 10 ++-- |
| drivers/firmware/samsung/exynos-acpm-pmic.h | 10 ++-- |
| drivers/firmware/samsung/exynos-acpm.c | 16 ++++--- |
| drivers/firmware/samsung/exynos-acpm.h | 2 |
| drivers/mfd/sec-acpm.c | 10 ++-- |
| include/linux/firmware/samsung/exynos-acpm-protocol.h | 40 +++++++----------- |
| 9 files changed, 48 insertions(+), 52 deletions(-) |
| |
| --- a/drivers/clk/samsung/clk-acpm.c |
| +++ b/drivers/clk/samsung/clk-acpm.c |
| @@ -20,7 +20,7 @@ struct acpm_clk { |
| u32 id; |
| struct clk_hw hw; |
| unsigned int mbox_chan_id; |
| - const struct acpm_handle *handle; |
| + struct acpm_handle *handle; |
| }; |
| |
| struct acpm_clk_variant { |
| @@ -113,7 +113,7 @@ static int acpm_clk_register(struct devi |
| |
| static int acpm_clk_probe(struct platform_device *pdev) |
| { |
| - const struct acpm_handle *acpm_handle; |
| + struct acpm_handle *acpm_handle; |
| struct clk_hw_onecell_data *clk_data; |
| struct clk_hw **hws; |
| struct device *dev = &pdev->dev; |
| --- a/drivers/firmware/samsung/exynos-acpm-dvfs.c |
| +++ b/drivers/firmware/samsung/exynos-acpm-dvfs.c |
| @@ -42,7 +42,7 @@ static void acpm_dvfs_init_set_rate_cmd( |
| cmd[3] = ktime_to_ms(ktime_get()); |
| } |
| |
| -int acpm_dvfs_set_rate(const struct acpm_handle *handle, |
| +int acpm_dvfs_set_rate(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, unsigned int clk_id, |
| unsigned long rate) |
| { |
| @@ -62,7 +62,7 @@ static void acpm_dvfs_init_get_rate_cmd( |
| cmd[3] = ktime_to_ms(ktime_get()); |
| } |
| |
| -unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle, |
| +unsigned long acpm_dvfs_get_rate(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, unsigned int clk_id) |
| { |
| struct acpm_xfer xfer; |
| --- a/drivers/firmware/samsung/exynos-acpm-dvfs.h |
| +++ b/drivers/firmware/samsung/exynos-acpm-dvfs.h |
| @@ -11,10 +11,10 @@ |
| |
| struct acpm_handle; |
| |
| -int acpm_dvfs_set_rate(const struct acpm_handle *handle, |
| +int acpm_dvfs_set_rate(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, unsigned int id, |
| unsigned long rate); |
| -unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle, |
| +unsigned long acpm_dvfs_get_rate(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, |
| unsigned int clk_id); |
| |
| --- a/drivers/firmware/samsung/exynos-acpm-pmic.c |
| +++ b/drivers/firmware/samsung/exynos-acpm-pmic.c |
| @@ -77,7 +77,7 @@ static void acpm_pmic_init_read_cmd(u32 |
| cmd[3] = ktime_to_ms(ktime_get()); |
| } |
| |
| -int acpm_pmic_read_reg(const struct acpm_handle *handle, |
| +int acpm_pmic_read_reg(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 *buf) |
| { |
| @@ -107,7 +107,7 @@ static void acpm_pmic_init_bulk_read_cmd |
| FIELD_PREP(ACPM_PMIC_VALUE, count); |
| } |
| |
| -int acpm_pmic_bulk_read(const struct acpm_handle *handle, |
| +int acpm_pmic_bulk_read(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 count, u8 *buf) |
| { |
| @@ -150,7 +150,7 @@ static void acpm_pmic_init_write_cmd(u32 |
| cmd[3] = ktime_to_ms(ktime_get()); |
| } |
| |
| -int acpm_pmic_write_reg(const struct acpm_handle *handle, |
| +int acpm_pmic_write_reg(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 value) |
| { |
| @@ -187,7 +187,7 @@ static void acpm_pmic_init_bulk_write_cm |
| } |
| } |
| |
| -int acpm_pmic_bulk_write(const struct acpm_handle *handle, |
| +int acpm_pmic_bulk_write(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 count, const u8 *buf) |
| { |
| @@ -220,7 +220,7 @@ static void acpm_pmic_init_update_cmd(u3 |
| cmd[3] = ktime_to_ms(ktime_get()); |
| } |
| |
| -int acpm_pmic_update_reg(const struct acpm_handle *handle, |
| +int acpm_pmic_update_reg(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 value, u8 mask) |
| { |
| --- a/drivers/firmware/samsung/exynos-acpm-pmic.h |
| +++ b/drivers/firmware/samsung/exynos-acpm-pmic.h |
| @@ -11,19 +11,19 @@ |
| |
| struct acpm_handle; |
| |
| -int acpm_pmic_read_reg(const struct acpm_handle *handle, |
| +int acpm_pmic_read_reg(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 *buf); |
| -int acpm_pmic_bulk_read(const struct acpm_handle *handle, |
| +int acpm_pmic_bulk_read(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 count, u8 *buf); |
| -int acpm_pmic_write_reg(const struct acpm_handle *handle, |
| +int acpm_pmic_write_reg(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 value); |
| -int acpm_pmic_bulk_write(const struct acpm_handle *handle, |
| +int acpm_pmic_bulk_write(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 count, const u8 *buf); |
| -int acpm_pmic_update_reg(const struct acpm_handle *handle, |
| +int acpm_pmic_update_reg(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| u8 value, u8 mask); |
| #endif /* __EXYNOS_ACPM_PMIC_H__ */ |
| --- a/drivers/firmware/samsung/exynos-acpm.c |
| +++ b/drivers/firmware/samsung/exynos-acpm.c |
| @@ -412,7 +412,7 @@ static int acpm_wait_for_message_respons |
| * |
| * Return: 0 on success, -errno otherwise. |
| */ |
| -int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer) |
| +int acpm_do_xfer(struct acpm_handle *handle, const struct acpm_xfer *xfer) |
| { |
| struct acpm_info *acpm = handle_to_acpm_info(handle); |
| struct exynos_mbox_msg msg; |
| @@ -674,7 +674,7 @@ static int acpm_probe(struct platform_de |
| * acpm_handle_put() - release the handle acquired by acpm_get_by_phandle. |
| * @handle: Handle acquired by acpm_get_by_phandle. |
| */ |
| -static void acpm_handle_put(const struct acpm_handle *handle) |
| +static void acpm_handle_put(struct acpm_handle *handle) |
| { |
| struct acpm_info *acpm = handle_to_acpm_info(handle); |
| struct device *dev = acpm->dev; |
| @@ -700,9 +700,11 @@ static void devm_acpm_release(struct dev |
| * @np: ACPM device tree node. |
| * |
| * Return: pointer to handle on success, ERR_PTR(-errno) otherwise. |
| + * |
| + * Note: handle CANNOT be pointer to const |
| */ |
| -static const struct acpm_handle *acpm_get_by_node(struct device *dev, |
| - struct device_node *np) |
| +static struct acpm_handle *acpm_get_by_node(struct device *dev, |
| + struct device_node *np) |
| { |
| struct platform_device *pdev; |
| struct device_link *link; |
| @@ -743,10 +745,10 @@ static const struct acpm_handle *acpm_ge |
| * |
| * Return: pointer to handle on success, ERR_PTR(-errno) otherwise. |
| */ |
| -const struct acpm_handle *devm_acpm_get_by_node(struct device *dev, |
| - struct device_node *np) |
| +struct acpm_handle *devm_acpm_get_by_node(struct device *dev, |
| + struct device_node *np) |
| { |
| - const struct acpm_handle **ptr, *handle; |
| + struct acpm_handle **ptr, *handle; |
| |
| ptr = devres_alloc(devm_acpm_release, sizeof(*ptr), GFP_KERNEL); |
| if (!ptr) |
| --- a/drivers/firmware/samsung/exynos-acpm.h |
| +++ b/drivers/firmware/samsung/exynos-acpm.h |
| @@ -17,7 +17,7 @@ struct acpm_xfer { |
| |
| struct acpm_handle; |
| |
| -int acpm_do_xfer(const struct acpm_handle *handle, |
| +int acpm_do_xfer(struct acpm_handle *handle, |
| const struct acpm_xfer *xfer); |
| |
| #endif /* __EXYNOS_ACPM_H__ */ |
| --- a/drivers/mfd/sec-acpm.c |
| +++ b/drivers/mfd/sec-acpm.c |
| @@ -367,7 +367,7 @@ static const struct regmap_config s2mpg1 |
| }; |
| |
| struct sec_pmic_acpm_shared_bus_context { |
| - const struct acpm_handle *acpm; |
| + struct acpm_handle *acpm; |
| unsigned int acpm_chan_id; |
| u8 speedy_channel; |
| }; |
| @@ -390,7 +390,7 @@ static int sec_pmic_acpm_bus_write(void |
| size_t count) |
| { |
| struct sec_pmic_acpm_bus_context *ctx = context; |
| - const struct acpm_handle *acpm = ctx->shared->acpm; |
| + struct acpm_handle *acpm = ctx->shared->acpm; |
| const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops; |
| size_t val_count = count - BITS_TO_BYTES(ACPM_ADDR_BITS); |
| const u8 *d = data; |
| @@ -410,7 +410,7 @@ static int sec_pmic_acpm_bus_read(void * |
| void *val_buf, size_t val_size) |
| { |
| struct sec_pmic_acpm_bus_context *ctx = context; |
| - const struct acpm_handle *acpm = ctx->shared->acpm; |
| + struct acpm_handle *acpm = ctx->shared->acpm; |
| const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops; |
| const u8 *r = reg_buf; |
| u8 reg; |
| @@ -429,7 +429,7 @@ static int sec_pmic_acpm_bus_reg_update_ |
| unsigned int val) |
| { |
| struct sec_pmic_acpm_bus_context *ctx = context; |
| - const struct acpm_handle *acpm = ctx->shared->acpm; |
| + struct acpm_handle *acpm = ctx->shared->acpm; |
| const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops; |
| |
| return pmic_ops->update_reg(acpm, ctx->shared->acpm_chan_id, ctx->type, reg & 0xff, |
| @@ -480,7 +480,7 @@ static int sec_pmic_acpm_probe(struct pl |
| struct regmap *regmap_common, *regmap_pmic, *regmap; |
| const struct sec_pmic_acpm_platform_data *pdata; |
| struct sec_pmic_acpm_shared_bus_context *shared_ctx; |
| - const struct acpm_handle *acpm; |
| + struct acpm_handle *acpm; |
| struct device *dev = &pdev->dev; |
| int ret, irq; |
| |
| --- a/include/linux/firmware/samsung/exynos-acpm-protocol.h |
| +++ b/include/linux/firmware/samsung/exynos-acpm-protocol.h |
| @@ -14,30 +14,24 @@ struct acpm_handle; |
| struct device_node; |
| |
| struct acpm_dvfs_ops { |
| - int (*set_rate)(const struct acpm_handle *handle, |
| - unsigned int acpm_chan_id, unsigned int clk_id, |
| - unsigned long rate); |
| - unsigned long (*get_rate)(const struct acpm_handle *handle, |
| + int (*set_rate)(struct acpm_handle *handle, unsigned int acpm_chan_id, |
| + unsigned int clk_id, unsigned long rate); |
| + unsigned long (*get_rate)(struct acpm_handle *handle, |
| unsigned int acpm_chan_id, |
| unsigned int clk_id); |
| }; |
| |
| struct acpm_pmic_ops { |
| - int (*read_reg)(const struct acpm_handle *handle, |
| - unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| - u8 *buf); |
| - int (*bulk_read)(const struct acpm_handle *handle, |
| - unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| - u8 count, u8 *buf); |
| - int (*write_reg)(const struct acpm_handle *handle, |
| - unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| - u8 value); |
| - int (*bulk_write)(const struct acpm_handle *handle, |
| - unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| - u8 count, const u8 *buf); |
| - int (*update_reg)(const struct acpm_handle *handle, |
| - unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, |
| - u8 value, u8 mask); |
| + int (*read_reg)(struct acpm_handle *handle, unsigned int acpm_chan_id, |
| + u8 type, u8 reg, u8 chan, u8 *buf); |
| + int (*bulk_read)(struct acpm_handle *handle, unsigned int acpm_chan_id, |
| + u8 type, u8 reg, u8 chan, u8 count, u8 *buf); |
| + int (*write_reg)(struct acpm_handle *handle, unsigned int acpm_chan_id, |
| + u8 type, u8 reg, u8 chan, u8 value); |
| + int (*bulk_write)(struct acpm_handle *handle, unsigned int acpm_chan_id, |
| + u8 type, u8 reg, u8 chan, u8 count, const u8 *buf); |
| + int (*update_reg)(struct acpm_handle *handle, unsigned int acpm_chan_id, |
| + u8 type, u8 reg, u8 chan, u8 value, u8 mask); |
| }; |
| |
| struct acpm_ops { |
| @@ -56,12 +50,12 @@ struct acpm_handle { |
| struct device; |
| |
| #if IS_ENABLED(CONFIG_EXYNOS_ACPM_PROTOCOL) |
| -const struct acpm_handle *devm_acpm_get_by_node(struct device *dev, |
| - struct device_node *np); |
| +struct acpm_handle *devm_acpm_get_by_node(struct device *dev, |
| + struct device_node *np); |
| #else |
| |
| -static inline const struct acpm_handle *devm_acpm_get_by_node(struct device *dev, |
| - struct device_node *np) |
| +static inline struct acpm_handle *devm_acpm_get_by_node(struct device *dev, |
| + struct device_node *np) |
| { |
| return NULL; |
| } |