]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: staging/ipu7: Ignore interrupts when device is suspended
authorBingbu Cao <bingbu.cao@intel.com>
Tue, 23 Dec 2025 07:23:00 +0000 (15:23 +0800)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Tue, 13 Jan 2026 11:47:55 +0000 (12:47 +0100)
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>
drivers/staging/media/ipu7/ipu7-buttress.c
drivers/staging/media/ipu7/ipu7.c

index e5707f5e300bac07946d99f2170ef3f3377d3758..40c6c8473357c60bbee2a740f3374bfb89120768 100644 (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);
 
index 5cddc09c72bf2cec941bfa19f4847fc738066300..6c8c3eea44acb2d3e0564cc2cfa8e6b5abba588a 100644 (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;
 }