drivers/irqchip/irq-imx-irqsteer.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
Add irq_bus_lock/sync_unlock handlers.
Without these handlers, the power domain is automatically activated during
clk_prepare. However, on certain platforms like i.MX8QM and i.MX8QXP, the
power-on phase may involve sleep function calls, which can lead to random
system dumps during driver probes at system boot.
By adding these handlers, the actual power-on actions are moved to occur
before clk_prepare, thus resolving the system dump issue.
The following is the example of system dump on i.MX8QM MEK.
[ 3.135799] BUG: scheduling while atomic: kworker/u13:1/48/0x00000002
[ 3.142270] Modules linked in:
[ 3.145349] CPU: 0 PID: 48 Comm: kworker/u13:1 Not tainted 6.6.3-lts-next-g5a913c7fc95d #1
[ 3.153616] Hardware name: Freescale i.MX8QM MEK (DT)
[ 3.158678] Workqueue: events_unbound deferred_probe_work_func
[ 3.164529] Call trace:
[ 3.166981] dump_backtrace+0x90/0xe8
[ 3.170652] show_stack+0x18/0x24
[ 3.173971] dump_stack_lvl+0x48/0x60
[ 3.177644] dump_stack+0x18/0x24
[ 3.180964] __schedule_bug+0x54/0x6c
[ 3.184628] __schedule+0x7f0/0xa94
[ 3.188121] schedule+0x5c/0xc4
[ 3.191266] schedule_preempt_disabled+0x24/0x40
[ 3.195887] __mutex_lock.constprop.0+0x2c0/0x540
[ 3.200596] __mutex_lock_slowpath+0x14/0x20
[ 3.204870] mutex_lock+0x48/0x54
[ 3.208189] clk_prepare_lock+0x44/0xa0
[ 3.212040] clk_prepare+0x20/0x44
[ 3.215452] imx_irqsteer_resume+0x28/0xe0
[ 3.219552] pm_generic_runtime_resume+0x2c/0x44
[ 3.224174] __genpd_runtime_resume+0x30/0x80
[ 3.228535] genpd_runtime_resume+0xc8/0x2c0
[ 3.232809] __rpm_callback+0x48/0x1d8
[ 3.236562] rpm_callback+0x6c/0x78
[ 3.240055] rpm_resume+0x490/0x6b4
[ 3.243549] __pm_runtime_resume+0x50/0x94
[ 3.247648] irq_chip_pm_get+0x2c/0xa0
[ 3.251401] __irq_do_set_handler+0x178/0x24c
[ 3.255762] irq_set_chained_handler_and_data+0x60/0xa4
[ 3.260992] mxc_gpio_probe+0x160/0x4b0
[ 3.264840] platform_probe+0x68/0xc8
[ 3.268506] really_probe+0x148/0x2b0
[ 3.272172] __driver_probe_device+0x78/0x12c
[ 3.276536] driver_probe_device+0xd8/0x15c
[ 3.280721] __device_attach_driver+0xb8/0x134
[ 3.285169] bus_for_each_drv+0x88/0xe8
[ 3.289009] __device_attach+0xa0/0x190
[ 3.292849] device_initial_probe+0x14/0x20
[ 3.297036] bus_probe_device+0xac/0xb0
[ 3.300876] deferred_probe_work_func+0x80/0xb8
[ 3.305411] process_one_work+0x138/0x248
[ 3.309427] worker_thread+0x320/0x438
[ 3.313177] kthread+0x110/0x114
[ 3.316409] ret_from_fork+0x10/0x20
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
---
drivers/irqchip/irq-imx-irqsteer.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 20cf7a9e9ece..f81e4ff3aec3 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -36,6 +36,7 @@ struct irqsteer_data {
int channel;
struct irq_domain *domain;
u32 *saved_reg;
+ struct device *dev;
};
static int imx_irqsteer_get_reg_index(struct irqsteer_data *data,
@@ -72,10 +73,26 @@ static void imx_irqsteer_irq_mask(struct irq_data *d)
raw_spin_unlock_irqrestore(&data->lock, flags);
}
+static void imx_irqsteer_irq_bus_lock(struct irq_data *d)
+{
+ struct irqsteer_data *data = d->chip_data;
+
+ pm_runtime_get_sync(data->dev);
+}
+
+static void imx_irqsteer_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct irqsteer_data *data = d->chip_data;
+
+ pm_runtime_put_autosuspend(data->dev);
+}
+
static const struct irq_chip imx_irqsteer_irq_chip = {
.name = "irqsteer",
.irq_mask = imx_irqsteer_irq_mask,
.irq_unmask = imx_irqsteer_irq_unmask,
+ .irq_bus_lock = imx_irqsteer_irq_bus_lock,
+ .irq_bus_sync_unlock = imx_irqsteer_irq_bus_sync_unlock,
};
static int imx_irqsteer_irq_map(struct irq_domain *h, unsigned int irq,
@@ -150,6 +167,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->dev = &pdev->dev;
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs)) {
dev_err(&pdev->dev, "failed to initialize reg\n");
--
2.34.1
The following commit has been merged into the irq/core branch of tip:
Commit-ID: 33b1c47d1fc0b5f06a393bb915db85baacba18ea
Gitweb: https://git.kernel.org/tip/33b1c47d1fc0b5f06a393bb915db85baacba18ea
Author: Shenwei Wang <shenwei.wang@nxp.com>
AuthorDate: Wed, 03 Jul 2024 11:32:50 -05:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Mon, 15 Jul 2024 15:13:56 +02:00
irqchip/imx-irqsteer: Handle runtime power management correctly
The power domain is automatically activated from clk_prepare(). However, on
certain platforms like i.MX8QM and i.MX8QXP, the power-on handling invokes
sleeping functions, which triggers the 'scheduling while atomic' bug in the
context switch path during device probing:
BUG: scheduling while atomic: kworker/u13:1/48/0x00000002
Call trace:
__schedule_bug+0x54/0x6c
__schedule+0x7f0/0xa94
schedule+0x5c/0xc4
schedule_preempt_disabled+0x24/0x40
__mutex_lock.constprop.0+0x2c0/0x540
__mutex_lock_slowpath+0x14/0x20
mutex_lock+0x48/0x54
clk_prepare_lock+0x44/0xa0
clk_prepare+0x20/0x44
imx_irqsteer_resume+0x28/0xe0
pm_generic_runtime_resume+0x2c/0x44
__genpd_runtime_resume+0x30/0x80
genpd_runtime_resume+0xc8/0x2c0
__rpm_callback+0x48/0x1d8
rpm_callback+0x6c/0x78
rpm_resume+0x490/0x6b4
__pm_runtime_resume+0x50/0x94
irq_chip_pm_get+0x2c/0xa0
__irq_do_set_handler+0x178/0x24c
irq_set_chained_handler_and_data+0x60/0xa4
mxc_gpio_probe+0x160/0x4b0
Cure this by implementing the irq_bus_lock/sync_unlock() interrupt chip
callbacks and handle power management in them as they are invoked from
non-atomic context.
[ tglx: Rewrote change log, added Fixes tag ]
Fixes: 0136afa08967 ("irqchip: Add driver for imx-irqsteer controller")
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20240703163250.47887-1-shenwei.wang@nxp.com
---
drivers/irqchip/irq-imx-irqsteer.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 20cf7a9..75a0e98 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -36,6 +36,7 @@ struct irqsteer_data {
int channel;
struct irq_domain *domain;
u32 *saved_reg;
+ struct device *dev;
};
static int imx_irqsteer_get_reg_index(struct irqsteer_data *data,
@@ -72,10 +73,26 @@ static void imx_irqsteer_irq_mask(struct irq_data *d)
raw_spin_unlock_irqrestore(&data->lock, flags);
}
+static void imx_irqsteer_irq_bus_lock(struct irq_data *d)
+{
+ struct irqsteer_data *data = d->chip_data;
+
+ pm_runtime_get_sync(data->dev);
+}
+
+static void imx_irqsteer_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct irqsteer_data *data = d->chip_data;
+
+ pm_runtime_put_autosuspend(data->dev);
+}
+
static const struct irq_chip imx_irqsteer_irq_chip = {
- .name = "irqsteer",
- .irq_mask = imx_irqsteer_irq_mask,
- .irq_unmask = imx_irqsteer_irq_unmask,
+ .name = "irqsteer",
+ .irq_mask = imx_irqsteer_irq_mask,
+ .irq_unmask = imx_irqsteer_irq_unmask,
+ .irq_bus_lock = imx_irqsteer_irq_bus_lock,
+ .irq_bus_sync_unlock = imx_irqsteer_irq_bus_sync_unlock,
};
static int imx_irqsteer_irq_map(struct irq_domain *h, unsigned int irq,
@@ -150,6 +167,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->dev = &pdev->dev;
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs)) {
dev_err(&pdev->dev, "failed to initialize reg\n");
The following commit has been merged into the irq/core branch of tip:
Commit-ID: cd0406fab8d4a16ec4f617c0a4b405bf70543b5b
Gitweb: https://git.kernel.org/tip/cd0406fab8d4a16ec4f617c0a4b405bf70543b5b
Author: Shenwei Wang <shenwei.wang@nxp.com>
AuthorDate: Wed, 03 Jul 2024 11:32:50 -05:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Thu, 11 Jul 2024 17:06:02 +02:00
irqchip/imx-irqsteer: Handle runtime power management correctly
The power domain is automatically activated from clk_prepare(). However, on
certain platforms like i.MX8QM and i.MX8QXP, the power-on handling invokes
sleeping functions, which triggers the 'scheduling while atomic' bug in the
context switch path during device probing:
BUG: scheduling while atomic: kworker/u13:1/48/0x00000002
Call trace:
__schedule_bug+0x54/0x6c
__schedule+0x7f0/0xa94
schedule+0x5c/0xc4
schedule_preempt_disabled+0x24/0x40
__mutex_lock.constprop.0+0x2c0/0x540
__mutex_lock_slowpath+0x14/0x20
mutex_lock+0x48/0x54
clk_prepare_lock+0x44/0xa0
clk_prepare+0x20/0x44
imx_irqsteer_resume+0x28/0xe0
pm_generic_runtime_resume+0x2c/0x44
__genpd_runtime_resume+0x30/0x80
genpd_runtime_resume+0xc8/0x2c0
__rpm_callback+0x48/0x1d8
rpm_callback+0x6c/0x78
rpm_resume+0x490/0x6b4
__pm_runtime_resume+0x50/0x94
irq_chip_pm_get+0x2c/0xa0
__irq_do_set_handler+0x178/0x24c
irq_set_chained_handler_and_data+0x60/0xa4
mxc_gpio_probe+0x160/0x4b0
Cure this by implementing the irq_bus_lock/sync_unlock() interrupt chip
callbacks and handle power management in them as they are invoked from
non-atomic context.
[ tglx: Rewrote change log, added Fixes tag ]
Fixes: 0136afa08967 ("irqchip: Add driver for imx-irqsteer controller")
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20240703163250.47887-1-shenwei.wang@nxp.com
---
drivers/irqchip/irq-imx-irqsteer.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 20cf7a9..75a0e98 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -36,6 +36,7 @@ struct irqsteer_data {
int channel;
struct irq_domain *domain;
u32 *saved_reg;
+ struct device *dev;
};
static int imx_irqsteer_get_reg_index(struct irqsteer_data *data,
@@ -72,10 +73,26 @@ static void imx_irqsteer_irq_mask(struct irq_data *d)
raw_spin_unlock_irqrestore(&data->lock, flags);
}
+static void imx_irqsteer_irq_bus_lock(struct irq_data *d)
+{
+ struct irqsteer_data *data = d->chip_data;
+
+ pm_runtime_get_sync(data->dev);
+}
+
+static void imx_irqsteer_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct irqsteer_data *data = d->chip_data;
+
+ pm_runtime_put_autosuspend(data->dev);
+}
+
static const struct irq_chip imx_irqsteer_irq_chip = {
- .name = "irqsteer",
- .irq_mask = imx_irqsteer_irq_mask,
- .irq_unmask = imx_irqsteer_irq_unmask,
+ .name = "irqsteer",
+ .irq_mask = imx_irqsteer_irq_mask,
+ .irq_unmask = imx_irqsteer_irq_unmask,
+ .irq_bus_lock = imx_irqsteer_irq_bus_lock,
+ .irq_bus_sync_unlock = imx_irqsteer_irq_bus_sync_unlock,
};
static int imx_irqsteer_irq_map(struct irq_domain *h, unsigned int irq,
@@ -150,6 +167,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->dev = &pdev->dev;
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs)) {
dev_err(&pdev->dev, "failed to initialize reg\n");
© 2016 - 2026 Red Hat, Inc.