Skip to content

Commit ffb635b

Browse files
tombamchehab
authored andcommitted
media: rkisp1: Fix IRQ handling due to shared interrupts
The driver requests the interrupts as IRQF_SHARED, so the interrupt handlers can be called at any time. If such a call happens while the ISP is powered down, the SoC will hang as the driver tries to access the ISP registers. This can be reproduced even without the platform sharing the IRQ line: Enable CONFIG_DEBUG_SHIRQ and unload the driver, and the board will hang. Fix this by adding a new field, 'irqs_enabled', which is used to bail out from the interrupt handler when the ISP is not operational. Link: https://lore.kernel.org/r/20231218-rkisp-shirq-fix-v1-2-173007628248@ideasonboard.com Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
1 parent a107d64 commit ffb635b

File tree

5 files changed

+33
-0
lines changed

5 files changed

+33
-0
lines changed

drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,9 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
725725
unsigned int i;
726726
u32 status;
727727

728+
if (!rkisp1->irqs_enabled)
729+
return IRQ_NONE;
730+
728731
status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS);
729732
if (!status)
730733
return IRQ_NONE;

drivers/media/platform/rockchip/rkisp1/rkisp1-common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ struct rkisp1_debug {
450450
* @debug: debug params to be exposed on debugfs
451451
* @info: version-specific ISP information
452452
* @irqs: IRQ line numbers
453+
* @irqs_enabled: the hardware is enabled and can cause interrupts
453454
*/
454455
struct rkisp1_device {
455456
void __iomem *base_addr;
@@ -471,6 +472,7 @@ struct rkisp1_device {
471472
struct rkisp1_debug debug;
472473
const struct rkisp1_info *info;
473474
int irqs[RKISP1_NUM_IRQS];
475+
bool irqs_enabled;
474476
};
475477

476478
/*

drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ irqreturn_t rkisp1_csi_isr(int irq, void *ctx)
196196
struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
197197
u32 val, status;
198198

199+
if (!rkisp1->irqs_enabled)
200+
return IRQ_NONE;
201+
199202
status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
200203
if (!status)
201204
return IRQ_NONE;

drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,24 @@ static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
305305
{
306306
struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
307307

308+
rkisp1->irqs_enabled = false;
309+
/* Make sure the IRQ handler will see the above */
310+
mb();
311+
312+
/*
313+
* Wait until any running IRQ handler has returned. The IRQ handler
314+
* may get called even after this (as it's a shared interrupt line)
315+
* but the 'irqs_enabled' flag will make the handler return immediately.
316+
*/
317+
for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
318+
if (rkisp1->irqs[il] == -1)
319+
continue;
320+
321+
/* Skip if the irq line is the same as previous */
322+
if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il])
323+
synchronize_irq(rkisp1->irqs[il]);
324+
}
325+
308326
clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
309327
return pinctrl_pm_select_sleep_state(dev);
310328
}
@@ -321,6 +339,10 @@ static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
321339
if (ret)
322340
return ret;
323341

342+
rkisp1->irqs_enabled = true;
343+
/* Make sure the IRQ handler will see the above */
344+
mb();
345+
324346
return 0;
325347
}
326348

drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,9 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx)
976976
struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
977977
u32 status, isp_err;
978978

979+
if (!rkisp1->irqs_enabled)
980+
return IRQ_NONE;
981+
979982
status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS);
980983
if (!status)
981984
return IRQ_NONE;

0 commit comments

Comments
 (0)