Linux on ARM based TI OMAP SoCs
 help / color / mirror / Atom feed
* [PATCH 13/28] mfd: twl-core: Clear pm_power_off callback in twl_remove()
       [not found] <20261021121245.3111563-1-lee@kernel.org>
@ 2026-10-21 12:09 ` Lee Jones
  2026-10-21 12:09 ` [PATCH 14/28] mfd: twl-core: Clear twl_priv pointer on teardown and probe failure Lee Jones
  2026-10-21 12:09 ` [PATCH 24/28] mfd: tps65217: Manage IRQ domain teardown via devres Lee Jones
  2 siblings, 0 replies; 3+ messages in thread
From: Lee Jones @ 2026-10-21 12:09 UTC (permalink / raw)
  To: lee, Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
	Tony Lindgren, Kai Svahn, syed khasim, linux-omap, mfd,
	linux-kernel
  Cc: stable

When a TWL6030-class device is configured as the system power
controller, twl_probe() registers twl6030_power_off() as the global
pm_power_off callback.  However, twl_remove() does not clear
pm_power_off when tearing down the device on late probe failure or
driver unbind, leaving a dangling callback that dereferences the freed
twl_priv context during system shutdown.

Reset pm_power_off to NULL in twl_remove() when it points to
twl6030_power_off().

Fixes: ca9414a1d087 ("mfd: twl-core: Add power off implementation for twl603x")
Closes: https://sashiko.dev/#/bug/linux-f5847f26-c868-416a-b926-3fc3da57802d
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/mfd/twl-core.c | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index c024a28b057e..64b45fe79159 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -672,10 +672,26 @@ static void clocks_init(struct device *dev)
 /*----------------------------------------------------------------------*/
 
 
+static void twl6030_power_off(void)
+{
+	int err;
+	u8 val;
+
+	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, TWL6030_PHOENIX_DEV_ON);
+	if (err)
+		return;
+
+	val |= TWL6030_APP_DEVOFF | TWL6030_CON_DEVOFF | TWL6030_MOD_DEVOFF;
+	twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, TWL6030_PHOENIX_DEV_ON);
+}
+
 static void twl_remove(struct i2c_client *client)
 {
 	unsigned i, num_slaves;
 
+	if (pm_power_off == twl6030_power_off)
+		pm_power_off = NULL;
+
 	if (twl_class_is_4030())
 		twl4030_exit_irq();
 	else
@@ -692,19 +708,6 @@ static void twl_remove(struct i2c_client *client)
 	twl_priv->ready = false;
 }
 
-static void twl6030_power_off(void)
-{
-	int err;
-	u8 val;
-
-	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, TWL6030_PHOENIX_DEV_ON);
-	if (err)
-		return;
-
-	val |= TWL6030_APP_DEVOFF | TWL6030_CON_DEVOFF | TWL6030_MOD_DEVOFF;
-	twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, TWL6030_PHOENIX_DEV_ON);
-}
-
 
 static struct of_dev_auxdata twl_auxdata_lookup[] = {
 	OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL),
-- 
2.56.0.218.g1ec904b173-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 14/28] mfd: twl-core: Clear twl_priv pointer on teardown and probe failure
       [not found] <20261021121245.3111563-1-lee@kernel.org>
  2026-10-21 12:09 ` [PATCH 13/28] mfd: twl-core: Clear pm_power_off callback in twl_remove() Lee Jones
@ 2026-10-21 12:09 ` Lee Jones
  2026-10-21 12:09 ` [PATCH 24/28] mfd: tps65217: Manage IRQ domain teardown via devres Lee Jones
  2 siblings, 0 replies; 3+ messages in thread
From: Lee Jones @ 2026-10-21 12:09 UTC (permalink / raw)
  To: lee, Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
	Tony Lindgren, Kai Svahn, syed khasim, Samuel Ortiz,
	Peter Ujfalusi, linux-omap, mfd, linux-kernel
  Cc: stable

twl_probe() allocates the file-scope twl_priv state with devm_kzalloc()
and checks for a non-NULL twl_priv at entry to reject multiple device
instances.  However, twl_remove() and the early error paths in
twl_probe() never reset twl_priv to NULL, a failure when adding MFD
child devices bypasses twl_remove() by jumping to free instead of fail,
and twl_remove() tears down the IRQ domain and dummy I2C clients before
child devices are unregistered.  After devres frees the underlying
memory on probe failure or unbind, twl_priv remains a dangling pointer,
causing subsequent exported API calls to dereference freed memory and
blocking future probe attempts with -EBUSY.

Unregister DT-populated and MFD child devices at the start of
twl_remove(), ensure mfd_add_devices() failures unwind via fail, and
reset twl_priv to NULL in twl_remove() and on probe error exit.

Fixes: 80a97ccd33be ("mfd: twl-core: Collect global variables behind one private structure (global)")
Closes: https://sashiko.dev/#/bug/linux-73e82f84-94de-4d08-82a4-f22d42a1dedf
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/mfd/twl-core.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 64b45fe79159..21fc0acb827b 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -689,6 +689,11 @@ static void twl_remove(struct i2c_client *client)
 {
 	unsigned i, num_slaves;
 
+	of_platform_depopulate(&client->dev);
+
+	if (twl_class_is_6030())
+		mfd_remove_devices(&client->dev);
+
 	if (pm_power_off == twl6030_power_off)
 		pm_power_off = NULL;
 
@@ -706,6 +711,7 @@ static void twl_remove(struct i2c_client *client)
 		twl->client = NULL;
 	}
 	twl_priv->ready = false;
+	twl_priv = NULL;
 }
 
 
@@ -880,10 +886,10 @@ twl_probe(struct i2c_client *client)
 			num_cells = ARRAY_SIZE(twl6030_cells);
 		}
 
-		status = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
-					      cells, num_cells, NULL, 0, NULL);
+		status = mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+					 cells, num_cells, NULL, 0, NULL);
 		if (status < 0)
-			goto free;
+			goto fail;
 
 		if (of_device_is_system_power_controller(node)) {
 			if (!pm_power_off)
@@ -900,8 +906,10 @@ twl_probe(struct i2c_client *client)
 	if (status < 0)
 		twl_remove(client);
 free:
-	if (status < 0)
+	if (status < 0) {
 		platform_device_unregister(pdev);
+		twl_priv = NULL;
+	}
 
 	return status;
 }
-- 
2.56.0.218.g1ec904b173-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 24/28] mfd: tps65217: Manage IRQ domain teardown via devres
       [not found] <20261021121245.3111563-1-lee@kernel.org>
  2026-10-21 12:09 ` [PATCH 13/28] mfd: twl-core: Clear pm_power_off callback in twl_remove() Lee Jones
  2026-10-21 12:09 ` [PATCH 14/28] mfd: twl-core: Clear twl_priv pointer on teardown and probe failure Lee Jones
@ 2026-10-21 12:09 ` Lee Jones
  2 siblings, 0 replies; 3+ messages in thread
From: Lee Jones @ 2026-10-21 12:09 UTC (permalink / raw)
  To: lee, Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
	Tony Lindgren, AnilKumar Ch, Milo Kim, linux-omap, mfd,
	linux-kernel
  Cc: stable

tps65217_irq_init() creates tps->irq_domain with an unmanaged call and
requests the parent interrupt via devm_request_threaded_irq(), while
tps65217_remove() manually disposes mappings and removes
tps->irq_domain.  Because tps65217_remove() executes before devres
teardown, the IRQ domain is destroyed while tps65217_irq_thread() and
child MFD devices are still active, allowing a concurrent interrupt to
dereference a freed or NULL domain.  Furthermore, if probe fails after
irq_domain_create_linear() or if tps65217_irq_init() fails, the IRQ
domain is leaked, and if the device is probed without an interrupt
(client->irq == 0), tps65217_remove() unconditionally passes a NULL
tps->irq_domain to irq_domain_remove().

Register a devres action to tear down the IRQ domain in
tps65217_irq_init() prior to devm_request_threaded_irq(), propagate
errors from tps65217_irq_init() in tps65217_probe(), and drop
tps65217_remove().

Fixes: 40a50f8b307d ("mfd: tps65217: Fix page fault on unloading modules")
Closes: https://sashiko.dev/#/bug/linux-7e358c08-6d75-48be-87d2-35dc037ea953
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/mfd/tps65217.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index c240fac0ede7..a1e9b9e22d82 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -146,6 +146,21 @@ static const struct irq_domain_ops tps65217_irq_domain_ops = {
 	.map = tps65217_irq_map,
 };
 
+static void tps65217_irq_exit(void *data)
+{
+	struct tps65217 *tps = data;
+	unsigned int virq;
+
+	for (int i = 0; i < TPS65217_NUM_IRQ; i++) {
+		virq = irq_find_mapping(tps->irq_domain, i);
+		if (virq)
+			irq_dispose_mapping(virq);
+	}
+
+	irq_domain_remove(tps->irq_domain);
+	tps->irq_domain = NULL;
+}
+
 static int tps65217_irq_init(struct tps65217 *tps, int irq)
 {
 	int ret;
@@ -165,6 +180,10 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
 		return -ENOMEM;
 	}
 
+	ret = devm_add_action_or_reset(tps->dev, tps65217_irq_exit, tps);
+	if (ret)
+		return ret;
+
 	ret = devm_request_threaded_irq(tps->dev, irq, NULL,
 					tps65217_irq_thread, IRQF_ONESHOT,
 					"tps65217-irq", tps);
@@ -333,7 +352,9 @@ static int tps65217_probe(struct i2c_client *client)
 	}
 
 	if (client->irq) {
-		tps65217_irq_init(tps, client->irq);
+		ret = tps65217_irq_init(tps, client->irq);
+		if (ret)
+			return ret;
 	} else {
 		int i;
 
@@ -373,22 +394,6 @@ static int tps65217_probe(struct i2c_client *client)
 	return 0;
 }
 
-static void tps65217_remove(struct i2c_client *client)
-{
-	struct tps65217 *tps = i2c_get_clientdata(client);
-	unsigned int virq;
-	int i;
-
-	for (i = 0; i < TPS65217_NUM_IRQ; i++) {
-		virq = irq_find_mapping(tps->irq_domain, i);
-		if (virq)
-			irq_dispose_mapping(virq);
-	}
-
-	irq_domain_remove(tps->irq_domain);
-	tps->irq_domain = NULL;
-}
-
 static const struct i2c_device_id tps65217_id_table[] = {
 	{"tps65217", TPS65217},
 	{ /* sentinel */ }
@@ -402,7 +407,6 @@ static struct i2c_driver tps65217_driver = {
 	},
 	.id_table	= tps65217_id_table,
 	.probe		= tps65217_probe,
-	.remove		= tps65217_remove,
 };
 
 static int __init tps65217_init(void)
-- 
2.56.0.218.g1ec904b173-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-21 12:16 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20261021121245.3111563-1-lee@kernel.org>
2026-10-21 12:09 ` [PATCH 13/28] mfd: twl-core: Clear pm_power_off callback in twl_remove() Lee Jones
2026-10-21 12:09 ` [PATCH 14/28] mfd: twl-core: Clear twl_priv pointer on teardown and probe failure Lee Jones
2026-10-21 12:09 ` [PATCH 24/28] mfd: tps65217: Manage IRQ domain teardown via devres Lee Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox