* [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