diff options
Diffstat (limited to 'drivers/crypto/caam/jr.c')
-rw-r--r-- | drivers/crypto/caam/jr.c | 104 |
1 files changed, 90 insertions, 14 deletions
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 6d475a2e298c..73e5596f82bd 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -2,17 +2,18 @@ * CAAM/SEC 4.x transport/backend driver * JobR backend functionality * - * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Copyright 2008-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP */ #include <linux/of_irq.h> #include <linux/of_address.h> - #include "compat.h" #include "regs.h" #include "jr.h" #include "desc.h" #include "intern.h" +#include "inst_rng.h" struct jr_driver_data { /* List of Physical JobR's with the Driver */ @@ -26,6 +27,7 @@ static int caam_reset_hw_jr(struct device *dev) { struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); unsigned int timeout = 100000; + unsigned int reg_value; /* * mask interrupts since we are going to poll @@ -35,9 +37,11 @@ static int caam_reset_hw_jr(struct device *dev) /* initiate flush (required prior to reset) */ wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); - while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == - JRINT_ERR_HALT_INPROGRESS) && --timeout) + do { cpu_relax(); + reg_value = rd_reg32(&jrp->rregs->jrintstatus); + } while (((reg_value & JRINT_ERR_HALT_MASK) == + JRINT_ERR_HALT_INPROGRESS) && --timeout); if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE || timeout == 0) { @@ -48,8 +52,10 @@ static int caam_reset_hw_jr(struct device *dev) /* initiate reset */ timeout = 100000; wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); - while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) + do { cpu_relax(); + reg_value = rd_reg32(&jrp->rregs->jrcommand); + } while ((reg_value & JRCR_RESET) && --timeout); if (timeout == 0) { dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); @@ -100,6 +106,12 @@ static int caam_jr_remove(struct platform_device *pdev) jrpriv = dev_get_drvdata(jrdev); /* + * Deinstantiate RNG by first JR + */ + if (jrpriv->ridx == 0) + deinst_rng(pdev); + + /* * Return EBUSY if job ring already allocated. */ if (atomic_read(&jrpriv->tfm_count)) { @@ -297,8 +309,7 @@ EXPORT_SYMBOL(caam_jr_free); * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK, * -EBUSY if the queue is full, -EIO if it cannot map the caller's * descriptor. - * @dev: device of the job ring to be used. This device should have - * been assigned prior by caam_jr_register(). + * @dev: device of the job ring to be used. * @desc: points to a job descriptor that execute our request. All * descriptors (and all referenced data) must be in a DMAable * region, and all data references must be physical addresses @@ -358,7 +369,6 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, head_entry->desc_addr_dma = desc_dma; jrp->inpring[jrp->inp_ring_write_index] = cpu_to_caam_dma(desc_dma); - /* * Guarantee that the descriptor's DMA address has been written to * the next slot in the ring before the write index is updated, since @@ -395,6 +405,10 @@ static int caam_jr_init(struct device *dev) jrp = dev_get_drvdata(dev); + error = caam_reset_hw_jr(dev); + if (error) + goto out_kill_deq; + tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); /* Connect job ring interrupt handler. */ @@ -406,10 +420,6 @@ static int caam_jr_init(struct device *dev) goto out_kill_deq; } - error = caam_reset_hw_jr(dev); - if (error) - goto out_free_irq; - error = -ENOMEM; jrp->inpring = dma_alloc_coherent(dev, sizeof(*jrp->inpring) * JOBR_DEPTH, &inpbusaddr, GFP_KERNEL); @@ -474,7 +484,7 @@ static int caam_jr_probe(struct platform_device *pdev) struct device *jrdev; struct device_node *nprop; struct caam_job_ring __iomem *ctrl; - struct caam_drv_private_jr *jrpriv; + struct caam_drv_private_jr *jrpriv, *jrppriv; static int total_jobrs; int error; @@ -509,6 +519,10 @@ static int caam_jr_probe(struct platform_device *pdev) /* Identify the interrupt */ jrpriv->irq = irq_of_parse_and_map(nprop, 0); + if (jrpriv->irq <= 0) { + kfree(jrpriv); + return -EINVAL; + } /* Now do the platform independent part */ error = caam_jr_init(jrdev); /* now turn on hardware */ @@ -516,7 +530,7 @@ static int caam_jr_probe(struct platform_device *pdev) irq_dispose_mapping(jrpriv->irq); iounmap(ctrl); return error; - } + } jrpriv->dev = jrdev; spin_lock(&driver_data.jr_alloc_lock); @@ -525,9 +539,68 @@ static int caam_jr_probe(struct platform_device *pdev) atomic_set(&jrpriv->tfm_count, 0); + device_init_wakeup(&pdev->dev, 1); + device_set_wakeup_enable(&pdev->dev, false); + /* + * Instantiate RNG by JR rather than DECO + */ + spin_lock(&driver_data.jr_alloc_lock); + if (list_empty(&driver_data.jr_list)) { + spin_unlock(&driver_data.jr_alloc_lock); + dev_err(jrdev, "jr_list is empty\n"); + return -ENODEV; + } + jrppriv = list_first_entry(&driver_data.jr_list, + struct caam_drv_private_jr, list_node); + spin_unlock(&driver_data.jr_alloc_lock); + /* + * If this is the first available JR + * then try to instantiate RNG + */ + if (jrppriv->ridx == jrpriv->ridx) { + if (!of_machine_is_compatible("fsl,imx8qm") && + !of_machine_is_compatible("fsl,imx8qxp")) + /* + * This call is done for legacy SOCs: + * i.MX6 i.MX7 and i.MX8M (mScale). + */ + error = inst_rng_imx(pdev); + } + if (error != 0) { + spin_lock(&driver_data.jr_alloc_lock); + list_del(&jrpriv->list_node); + spin_unlock(&driver_data.jr_alloc_lock); + } + return error; +} + +#ifdef CONFIG_PM +static int caam_jr_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(jrpriv->irq); + + return 0; +} + +static int caam_jr_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(jrpriv->irq); + return 0; } +static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, + caam_jr_resume); +#endif + static struct of_device_id caam_jr_match[] = { { .compatible = "fsl,sec-v4.0-job-ring", @@ -543,6 +616,9 @@ static struct platform_driver caam_jr_driver = { .driver = { .name = "caam_jr", .of_match_table = caam_jr_match, +#ifdef CONFIG_PM + .pm = &caam_jr_pm_ops, +#endif }, .probe = caam_jr_probe, .remove = caam_jr_remove, |