forked from Minki/linux
crypto: caam - get rid of tasklet
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>
This commit is contained in:
parent
65cf164a4a
commit
66d2e20280
@ -41,7 +41,6 @@ struct caam_drv_private_jr {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
int ridx;
|
int ridx;
|
||||||
struct caam_job_ring __iomem *rregs; /* JobR's register space */
|
struct caam_job_ring __iomem *rregs; /* JobR's register space */
|
||||||
struct tasklet_struct irqtask;
|
|
||||||
int irq; /* One per queue */
|
int irq; /* One per queue */
|
||||||
|
|
||||||
/* Number of scatterlist crypt transforms active on the JobR */
|
/* Number of scatterlist crypt transforms active on the JobR */
|
||||||
|
@ -73,8 +73,6 @@ static int caam_jr_shutdown(struct device *dev)
|
|||||||
|
|
||||||
ret = caam_reset_hw_jr(dev);
|
ret = caam_reset_hw_jr(dev);
|
||||||
|
|
||||||
tasklet_kill(&jrp->irqtask);
|
|
||||||
|
|
||||||
/* Release interrupt */
|
/* Release interrupt */
|
||||||
free_irq(jrp->irq, dev);
|
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
|
* Check the output ring for ready responses, kick
|
||||||
* tasklet if jobs done.
|
* the threaded irq if jobs done.
|
||||||
*/
|
*/
|
||||||
irqstate = rd_reg32(&jrp->rregs->jrintstatus);
|
irqstate = rd_reg32(&jrp->rregs->jrintstatus);
|
||||||
if (!irqstate)
|
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 */
|
/* Have valid interrupt at this point, just ACK and trigger */
|
||||||
wr_reg32(&jrp->rregs->jrintstatus, irqstate);
|
wr_reg32(&jrp->rregs->jrintstatus, irqstate);
|
||||||
|
|
||||||
preempt_disable();
|
return IRQ_WAKE_THREAD;
|
||||||
tasklet_schedule(&jrp->irqtask);
|
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deferred service handler, run as interrupt-fired tasklet */
|
static irqreturn_t caam_jr_threadirq(int irq, void *st_dev)
|
||||||
static void caam_jr_dequeue(unsigned long devarg)
|
|
||||||
{
|
{
|
||||||
int hw_idx, sw_idx, i, head, tail;
|
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);
|
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
|
||||||
void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
|
void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
|
||||||
u32 *userdesc, userstatus;
|
u32 *userdesc, userstatus;
|
||||||
@ -237,6 +230,8 @@ static void caam_jr_dequeue(unsigned long devarg)
|
|||||||
|
|
||||||
/* reenable / unmask IRQs */
|
/* reenable / unmask IRQs */
|
||||||
clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
|
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);
|
jrp = dev_get_drvdata(dev);
|
||||||
|
|
||||||
tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
|
|
||||||
|
|
||||||
/* Connect job ring interrupt handler. */
|
/* Connect job ring interrupt handler. */
|
||||||
error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED,
|
error = request_threaded_irq(jrp->irq, caam_jr_interrupt,
|
||||||
dev_name(dev), dev);
|
caam_jr_threadirq, IRQF_SHARED,
|
||||||
|
dev_name(dev), dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
|
dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
|
||||||
jrp->ridx, jrp->irq);
|
jrp->ridx, jrp->irq);
|
||||||
@ -460,7 +454,6 @@ out_free_inpring:
|
|||||||
out_free_irq:
|
out_free_irq:
|
||||||
free_irq(jrp->irq, dev);
|
free_irq(jrp->irq, dev);
|
||||||
out_kill_deq:
|
out_kill_deq:
|
||||||
tasklet_kill(&jrp->irqtask);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user