[PATCH 6.18 534/752] media: staging/ipu7: Ignore interrupts when device is suspended

Sasha Levin
2026-02-28T17:55:47Z

From: Bingbu Cao <bingbu.cao@intel.com>

[ Upstream commit 9ad65684b9285c5d66fb417d50e91a25ef8c994d ]

IPU7 devices have shared interrupts with others. In some case when IPU7
device is suspended, driver get unexpected interrupt and invalid irq
status 0xffffffff from ISR_STATUS and PB LOCAL_STATUS registers as
interrupt is triggered from other device on shared irq line.

In order to avoid this issue use pm_runtime_get_if_active() to check if
IPU7 device is resumed, ignore the invalid irq status and use
synchronize_irq() in suspend.

Cc: Stable@vger.kernel.org
Fixes: b7fe4c0019b1 ("media: staging/ipu7: add Intel IPU7 PCI device driver")
Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/staging/media/ipu7/ipu7-buttress.c | 17 ++++++++++++++++-
drivers/staging/media/ipu7/ipu7.c | 4 ++++
2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/media/ipu7/ipu7-buttress.c b/drivers/staging/media/ipu7/ipu7-buttress.c
index e5707f5e300ba..40c6c8473357c 100644
--- a/drivers/staging/media/ipu7/ipu7-buttress.c
+++ b/drivers/staging/media/ipu7/ipu7-buttress.c
@@ -342,14 +342,23 @@ irqreturn_t ipu_buttress_isr(int irq, void *isp_ptr)
u32 disable_irqs = 0;
u32 irq_status;
unsigned int i;
+ int active;

- pm_runtime_get_noresume(dev);
+ active = pm_runtime_get_if_active(dev);
+ if (active <= 0)
+ return IRQ_NONE;

pb_irq = readl(isp->pb_base + INTERRUPT_STATUS);
writel(pb_irq, isp->pb_base + INTERRUPT_STATUS);

/* check btrs ATS, CFI and IMR errors, BIT(0) is unused for IPU */
pb_local_irq = readl(isp->pb_base + BTRS_LOCAL_INTERRUPT_MASK);
+ if (pb_local_irq == 0xffffffff) {
+ dev_warn_once(dev, "invalid PB irq status\n");
+ pm_runtime_put_noidle(dev);
+ return IRQ_NONE;
+ }
+
if (pb_local_irq & ~BIT(0)) {
dev_warn(dev, "PB interrupt status 0x%x local 0x%x\n", pb_irq,
pb_local_irq);
@@ -370,6 +379,12 @@ irqreturn_t ipu_buttress_isr(int irq, void *isp_ptr)
return IRQ_NONE;
}

+ if (irq_status == 0xffffffff) {
+ dev_warn_once(dev, "invalid irq status 0x%08x\n", irq_status);
+ pm_runtime_put_noidle(dev);
+ return IRQ_NONE;
+ }
+
do {
writel(irq_status, isp->base + BUTTRESS_REG_IRQ_CLEAR);

diff --git a/drivers/staging/media/ipu7/ipu7.c b/drivers/staging/media/ipu7/ipu7.c
index 5cddc09c72bf2..6c8c3eea44acb 100644
--- a/drivers/staging/media/ipu7/ipu7.c
+++ b/drivers/staging/media/ipu7/ipu7.c
@@ -2684,6 +2684,10 @@ static void ipu7_pci_reset_done(struct pci_dev *pdev)
*/
static int ipu7_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ synchronize_irq(pdev->irq);
+
return 0;
}

--
2.51.0