crypto: caam - get rid of tasklet
authorRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 8 Aug 2016 17:05:24 +0000 (18:05 +0100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Tue, 9 Aug 2016 10:47:28 +0000 (18:47 +0800)
Threaded interrupts can perform the function of the tasklet, and much
more safely too - without races when trying to take the tasklet and
interrupt down on device removal.

With the old code, there is a window where we call tasklet_kill().  If
the interrupt handler happens to be running on a different CPU, and
subsequently calls tasklet_schedule(), the tasklet will be re-scheduled
for execution.

Switching to a hardirq/threadirq combination implementation avoids this,
and it also means generic code deals with the teardown sequencing of the
threaded and non-threaded parts.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/caam/intern.h
drivers/crypto/caam/jr.c

index e2bcacc1a921675cf30f70a40816e1306a8c3ef9..5d4c05074a5c222b03011db9b0cc41b1078a7725 100644 (file)
@@ -41,7 +41,6 @@ struct caam_drv_private_jr {
        struct device           *dev;
        int ridx;
        struct caam_job_ring __iomem *rregs;    /* JobR's register space */
-       struct tasklet_struct irqtask;
        int irq;                        /* One per queue */
 
        /* Number of scatterlist crypt transforms active on the JobR */
index a81f551ac222a73153cdf166d5413cfda89fba9a..320228875e9a8187d4f03fc1b7868df15e32c271 100644 (file)
@@ -73,8 +73,6 @@ static int caam_jr_shutdown(struct device *dev)
 
        ret = caam_reset_hw_jr(dev);
 
-       tasklet_kill(&jrp->irqtask);
-
        /* Release interrupt */
        free_irq(jrp->irq, dev);
 
@@ -130,7 +128,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
 
        /*
         * Check the output ring for ready responses, kick
-        * tasklet if jobs done.
+        * the threaded irq if jobs done.
         */
        irqstate = rd_reg32(&jrp->rregs->jrintstatus);
        if (!irqstate)
@@ -152,18 +150,13 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
        /* Have valid interrupt at this point, just ACK and trigger */
        wr_reg32(&jrp->rregs->jrintstatus, irqstate);
 
-       preempt_disable();
-       tasklet_schedule(&jrp->irqtask);
-       preempt_enable();
-
-       return IRQ_HANDLED;
+       return IRQ_WAKE_THREAD;
 }
 
-/* Deferred service handler, run as interrupt-fired tasklet */
-static void caam_jr_dequeue(unsigned long devarg)
+static irqreturn_t caam_jr_threadirq(int irq, void *st_dev)
 {
        int hw_idx, sw_idx, i, head, tail;
-       struct device *dev = (struct device *)devarg;
+       struct device *dev = st_dev;
        struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
        void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
        u32 *userdesc, userstatus;
@@ -237,6 +230,8 @@ static void caam_jr_dequeue(unsigned long devarg)
 
        /* reenable / unmask IRQs */
        clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+
+       return IRQ_HANDLED;
 }
 
 /**
@@ -394,11 +389,10 @@ static int caam_jr_init(struct device *dev)
 
        jrp = dev_get_drvdata(dev);
 
-       tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
-
        /* Connect job ring interrupt handler. */
-       error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED,
-                           dev_name(dev), dev);
+       error = request_threaded_irq(jrp->irq, caam_jr_interrupt,
+                                    caam_jr_threadirq, IRQF_SHARED,
+                                    dev_name(dev), dev);
        if (error) {
                dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
                        jrp->ridx, jrp->irq);
@@ -460,7 +454,6 @@ out_free_inpring:
 out_free_irq:
        free_irq(jrp->irq, dev);
 out_kill_deq:
-       tasklet_kill(&jrp->irqtask);
        return error;
 }