crypto: talitos - Implement done interrupt mitigation
authorLee Nipper <lee.nipper@freescale.com>
Sun, 12 Oct 2008 12:29:34 +0000 (20:29 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 25 Dec 2008 00:01:10 +0000 (11:01 +1100)
In talitos_interrupt, upon one done interrupt, mask further done interrupts,
and ack only any error interrupt.
In talitos_done, unmask done interrupts after completing processing.
In flush_channel, ack each done channel processed.
Keep done overflow interrupts masked because even though each pkt
is ack'ed, a few done overflows still occur.

Signed-off-by: Lee Nipper <lee.nipper@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/talitos.c
drivers/crypto/talitos.h

index c429f684c79d68a1c049ae41bfafd63eff8db442..b5c2c9340a9cbcf5ee81ff21805bf7440bd61f2b 100644 (file)
@@ -319,9 +319,11 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
 
                /* descriptors with their done bits set don't get the error */
                rmb();
-               if ((request->desc->hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
+               if ((request->desc->hdr & DESC_HDR_DONE) == DESC_HDR_DONE) {
                        status = 0;
-               else
+                       /* Ack each pkt completed on channel */
+                       out_be32(priv->reg + TALITOS_ICR, (1 << (ch * 2)));
+               } else
                        if (!error)
                                break;
                        else
@@ -369,6 +371,11 @@ static void talitos_done(unsigned long data)
 
        for (ch = 0; ch < priv->num_channels; ch++)
                flush_channel(dev, ch, 0, 0);
+
+       /* At this point, all completed channels have been processed.
+        * Unmask done interrupts for channels completed later on.
+        */
+       setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE);
 }
 
 /*
@@ -557,15 +564,22 @@ static irqreturn_t talitos_interrupt(int irq, void *data)
        isr = in_be32(priv->reg + TALITOS_ISR);
        isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
 
-       /* ack */
-       out_be32(priv->reg + TALITOS_ICR, isr);
-       out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
+       if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo)) {
+               /*
+                * Acknowledge error interrupts here.
+                * Done interrupts are ack'ed as part of done_task.
+                */
+               out_be32(priv->reg + TALITOS_ICR, isr);
+               out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
 
-       if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo))
                talitos_error((unsigned long)data, isr, isr_lo);
-       else
-               if (likely(isr & TALITOS_ISR_CHDONE))
+       } else
+               if (likely(isr & TALITOS_ISR_CHDONE)) {
+                       /* mask further done interrupts. */
+                       clrbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE);
+                       /* done_task will unmask done interrupts at exit */
                        tasklet_schedule(&priv->done_task);
+               }
 
        return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE;
 }
index c48a405abf70c90a1f3cd177d8cde363abd36bb4..e6b87770df03847685b014ddaab706e027466cb7 100644 (file)
@@ -37,7 +37,8 @@
 #define TALITOS_MCR_LO                 0x1038
 #define   TALITOS_MCR_SWR              0x1     /* s/w reset */
 #define TALITOS_IMR                    0x1008  /* interrupt mask register */
-#define   TALITOS_IMR_INIT             0x10fff /* enable channel IRQs */
+#define   TALITOS_IMR_INIT             0x100ff /* enable channel IRQs */
+#define   TALITOS_IMR_DONE             0x00055 /* done IRQs */
 #define TALITOS_IMR_LO                 0x100C
 #define   TALITOS_IMR_LO_INIT          0x20000 /* allow RNGU error IRQs */
 #define TALITOS_ISR                    0x1010  /* interrupt status register */