media: intel-ipu3: cio2: Handle IRQs until INT_STS is cleared
authorBingbu Cao <bingbu.cao@intel.com>
Mon, 30 Apr 2018 14:30:40 +0000 (10:30 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Wed, 9 May 2018 19:45:08 +0000 (15:45 -0400)
Interrupt behavior shows that some time the frame end and frame start of
next frame is unstable and can range from several to hundreds of
micro-sec. In the case of ~10us, isr may not clear next sof interrupt
status in single handling, which prevents new interrupts from coming.

Fix this by handling all pending IRQs before exiting isr, so any abnormal
behavior results from very short interrupt status changes is protected.

Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
Signed-off-by: Andy Yeh <andy.yeh@intel.com>
Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/pci/intel/ipu3/ipu3-cio2.c

index 7d768ec0f824f1f2d21e589ab2812cce6ce6e50e..29027159eced88a57b9a39feba4197e45c1a2d00 100644 (file)
@@ -640,18 +640,10 @@ static const char *const cio2_port_errs[] = {
        "PKT2LONG",
 };
 
-static irqreturn_t cio2_irq(int irq, void *cio2_ptr)
+static void cio2_irq_handle_once(struct cio2_device *cio2, u32 int_status)
 {
-       struct cio2_device *cio2 = cio2_ptr;
        void __iomem *const base = cio2->base;
        struct device *dev = &cio2->pci_dev->dev;
-       u32 int_status, int_clear;
-
-       int_status = readl(base + CIO2_REG_INT_STS);
-       int_clear = int_status;
-
-       if (!int_status)
-               return IRQ_NONE;
 
        if (int_status & CIO2_INT_IOOE) {
                /*
@@ -770,9 +762,29 @@ static irqreturn_t cio2_irq(int irq, void *cio2_ptr)
                int_status &= ~(CIO2_INT_IOIE | CIO2_INT_IOIRQ);
        }
 
-       writel(int_clear, base + CIO2_REG_INT_STS);
        if (int_status)
                dev_warn(dev, "unknown interrupt 0x%x on INT\n", int_status);
+}
+
+static irqreturn_t cio2_irq(int irq, void *cio2_ptr)
+{
+       struct cio2_device *cio2 = cio2_ptr;
+       void __iomem *const base = cio2->base;
+       struct device *dev = &cio2->pci_dev->dev;
+       u32 int_status;
+
+       int_status = readl(base + CIO2_REG_INT_STS);
+       dev_dbg(dev, "isr enter - interrupt status 0x%x\n", int_status);
+       if (!int_status)
+               return IRQ_NONE;
+
+       do {
+               writel(int_status, base + CIO2_REG_INT_STS);
+               cio2_irq_handle_once(cio2, int_status);
+               int_status = readl(base + CIO2_REG_INT_STS);
+               if (int_status)
+                       dev_dbg(dev, "pending status 0x%x\n", int_status);
+       } while (int_status);
 
        return IRQ_HANDLED;
 }