media: staging/ipu7: Ignore interrupts when device is suspended

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: b7fe4c0019 ("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>
This commit is contained in:
Bingbu Cao 2025-12-23 15:23:00 +08:00 committed by Hans Verkuil
parent 6099f78e4c
commit 9ad65684b9
2 changed files with 20 additions and 1 deletions

View File

@ -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);

View File

@ -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;
}