diff mbox series

[v5,107/111] pwm: Ensure that pwm_chips are allocated using pwmchip_alloc()

Message ID 89afb1f6191aff726f537b5d450cc74f90236ea4.1706182805.git.u.kleine-koenig@pengutronix.de
State Superseded
Headers show
Series pwm: Improve lifetime tracking for pwm_chips | expand

Commit Message

Uwe Kleine-König Jan. 25, 2024, 12:10 p.m. UTC
Memory holding a struct device must not be freed before the reference
count drops to zero. So a struct pwm_chip must not live in memory
freed by a driver on unbind. All in-tree drivers were fixed accordingly,
but as out-of-tree drivers, that were not adapted, still compile fine,
catch these in pwmchip_add().

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/core.c  | 10 ++++++++++
 include/linux/pwm.h |  2 ++
 2 files changed, 12 insertions(+)
diff mbox series

Patch

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index b821a2b0b172..80acae5fed11 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -472,6 +472,7 @@  struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
 
 	chip->dev = parent;
 	chip->npwm = npwm;
+	chip->uses_pwmchip_alloc = true;
 
 	pwmchip_set_drvdata(chip, pwmchip_priv(chip));
 
@@ -528,6 +529,15 @@  int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 	if (!chip || !chip->dev || !chip->ops || !chip->npwm)
 		return -EINVAL;
 
+	/*
+	 * a struct pwm_chip must be allocated using (devm_)pwmchip_alloc,
+	 * otherwise the embedded struct device might disappear too early
+	 * resulting in memory corruption.
+	 * Catch drivers that were not converted appropriately.
+	 */
+	if (!chip->uses_pwmchip_alloc)
+		return -EINVAL;
+
 	if (!pwm_ops_check(chip))
 		return -EINVAL;
 
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 8bc7504aa7d4..1620a1eef165 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -272,6 +272,7 @@  struct pwm_ops {
  * @npwm: number of PWMs controlled by this chip
  * @of_xlate: request a PWM device given a device tree PWM specifier
  * @atomic: can the driver's ->apply() be called in atomic context
+ * @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this chip
  * @driver_data: Private pointer for driver specific info
  * @pwms: array of PWM devices allocated by the framework
  */
@@ -287,6 +288,7 @@  struct pwm_chip {
 	bool atomic;
 
 	/* only used internally by the PWM framework */
+	bool uses_pwmchip_alloc;
 	void *driver_data;
 	struct pwm_device *pwms;
 };