linux/drivers/crypto/caam/jr.c
<<
>>
Prefs
   1/*
   2 * CAAM/SEC 4.x transport/backend driver
   3 * JobR backend functionality
   4 *
   5 * Copyright 2008-2012 Freescale Semiconductor, Inc.
   6 */
   7
   8#include <linux/of_irq.h>
   9#include <linux/of_address.h>
  10
  11#include "compat.h"
  12#include "regs.h"
  13#include "jr.h"
  14#include "desc.h"
  15#include "intern.h"
  16
  17struct jr_driver_data {
  18        /* List of Physical JobR's with the Driver */
  19        struct list_head        jr_list;
  20        spinlock_t              jr_alloc_lock;  /* jr_list lock */
  21} ____cacheline_aligned;
  22
  23static struct jr_driver_data driver_data;
  24
  25static int caam_reset_hw_jr(struct device *dev)
  26{
  27        struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
  28        unsigned int timeout = 100000;
  29
  30        /*
  31         * mask interrupts since we are going to poll
  32         * for reset completion status
  33         */
  34        clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
  35
  36        /* initiate flush (required prior to reset) */
  37        wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
  38        while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
  39                JRINT_ERR_HALT_INPROGRESS) && --timeout)
  40                cpu_relax();
  41
  42        if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
  43            JRINT_ERR_HALT_COMPLETE || timeout == 0) {
  44                dev_err(dev, "failed to flush job ring %d\n", jrp->ridx);
  45                return -EIO;
  46        }
  47
  48        /* initiate reset */
  49        timeout = 100000;
  50        wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
  51        while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
  52                cpu_relax();
  53
  54        if (timeout == 0) {
  55                dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
  56                return -EIO;
  57        }
  58
  59        /* unmask interrupts */
  60        clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
  61
  62        return 0;
  63}
  64
  65/*
  66 * Shutdown JobR independent of platform property code
  67 */
  68static int caam_jr_shutdown(struct device *dev)
  69{
  70        struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
  71        dma_addr_t inpbusaddr, outbusaddr;
  72        int ret;
  73
  74        ret = caam_reset_hw_jr(dev);
  75
  76        /* Release interrupt */
  77        free_irq(jrp->irq, dev);
  78
  79        /* Free rings */
  80        inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
  81        outbusaddr = rd_reg64(&jrp->rregs->outring_base);
  82        dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH,
  83                          jrp->inpring, inpbusaddr);
  84        dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH,
  85                          jrp->outring, outbusaddr);
  86        kfree(jrp->entinfo);
  87
  88        return ret;
  89}
  90
  91static int caam_jr_remove(struct platform_device *pdev)
  92{
  93        int ret;
  94        struct device *jrdev;
  95        struct caam_drv_private_jr *jrpriv;
  96
  97        jrdev = &pdev->dev;
  98        jrpriv = dev_get_drvdata(jrdev);
  99
 100        /*
 101         * Return EBUSY if job ring already allocated.
 102         */
 103        if (atomic_read(&jrpriv->tfm_count)) {
 104                dev_err(jrdev, "Device is busy\n");
 105                return -EBUSY;
 106        }
 107
 108        /* Remove the node from Physical JobR list maintained by driver */
 109        spin_lock(&driver_data.jr_alloc_lock);
 110        list_del(&jrpriv->list_node);
 111        spin_unlock(&driver_data.jr_alloc_lock);
 112
 113        /* Release ring */
 114        ret = caam_jr_shutdown(jrdev);
 115        if (ret)
 116                dev_err(jrdev, "Failed to shut down job ring\n");
 117        irq_dispose_mapping(jrpriv->irq);
 118
 119        return ret;
 120}
 121
 122/* Main per-ring interrupt handler */
 123static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
 124{
 125        struct device *dev = st_dev;
 126        struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
 127        u32 irqstate;
 128
 129        /*
 130         * Check the output ring for ready responses, kick
 131         * the threaded irq if jobs done.
 132         */
 133        irqstate = rd_reg32(&jrp->rregs->jrintstatus);
 134        if (!irqstate)
 135                return IRQ_NONE;
 136
 137        /*
 138         * If JobR error, we got more development work to do
 139         * Flag a bug now, but we really need to shut down and
 140         * restart the queue (and fix code).
 141         */
 142        if (irqstate & JRINT_JR_ERROR) {
 143                dev_err(dev, "job ring error: irqstate: %08x\n", irqstate);
 144                BUG();
 145        }
 146
 147        /* mask valid interrupts */
 148        clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
 149
 150        /* Have valid interrupt at this point, just ACK and trigger */
 151        wr_reg32(&jrp->rregs->jrintstatus, irqstate);
 152
 153        return IRQ_WAKE_THREAD;
 154}
 155
 156static irqreturn_t caam_jr_threadirq(int irq, void *st_dev)
 157{
 158        int hw_idx, sw_idx, i, head, tail;
 159        struct device *dev = st_dev;
 160        struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
 161        void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
 162        u32 *userdesc, userstatus;
 163        void *userarg;
 164
 165        while (rd_reg32(&jrp->rregs->outring_used)) {
 166
 167                head = ACCESS_ONCE(jrp->head);
 168
 169                spin_lock(&jrp->outlock);
 170
 171                sw_idx = tail = jrp->tail;
 172                hw_idx = jrp->out_ring_read_index;
 173
 174                for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
 175                        sw_idx = (tail + i) & (JOBR_DEPTH - 1);
 176
 177                        if (jrp->outring[hw_idx].desc ==
 178                            caam_dma_to_cpu(jrp->entinfo[sw_idx].desc_addr_dma))
 179                                break; /* found */
 180                }
 181                /* we should never fail to find a matching descriptor */
 182                BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0);
 183
 184                /* Unmap just-run descriptor so we can post-process */
 185                dma_unmap_single(dev, jrp->outring[hw_idx].desc,
 186                                 jrp->entinfo[sw_idx].desc_size,
 187                                 DMA_TO_DEVICE);
 188
 189                /* mark completed, avoid matching on a recycled desc addr */
 190                jrp->entinfo[sw_idx].desc_addr_dma = 0;
 191
 192                /* Stash callback params for use outside of lock */
 193                usercall = jrp->entinfo[sw_idx].callbk;
 194                userarg = jrp->entinfo[sw_idx].cbkarg;
 195                userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
 196                userstatus = caam32_to_cpu(jrp->outring[hw_idx].jrstatus);
 197
 198                /*
 199                 * Make sure all information from the job has been obtained
 200                 * before telling CAAM that the job has been removed from the
 201                 * output ring.
 202                 */
 203                mb();
 204
 205                /* set done */
 206                wr_reg32(&jrp->rregs->outring_rmvd, 1);
 207
 208                jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) &
 209                                           (JOBR_DEPTH - 1);
 210
 211                /*
 212                 * if this job completed out-of-order, do not increment
 213                 * the tail.  Otherwise, increment tail by 1 plus the
 214                 * number of subsequent jobs already completed out-of-order
 215                 */
 216                if (sw_idx == tail) {
 217                        do {
 218                                tail = (tail + 1) & (JOBR_DEPTH - 1);
 219                        } while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 &&
 220                                 jrp->entinfo[tail].desc_addr_dma == 0);
 221
 222                        jrp->tail = tail;
 223                }
 224
 225                spin_unlock(&jrp->outlock);
 226
 227                /* Finally, execute user's callback */
 228                usercall(dev, userdesc, userstatus, userarg);
 229        }
 230
 231        /* reenable / unmask IRQs */
 232        clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
 233
 234        return IRQ_HANDLED;
 235}
 236
 237/**
 238 * caam_jr_alloc() - Alloc a job ring for someone to use as needed.
 239 *
 240 * returns :  pointer to the newly allocated physical
 241 *            JobR dev can be written to if successful.
 242 **/
 243struct device *caam_jr_alloc(void)
 244{
 245        struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
 246        struct device *dev = ERR_PTR(-ENODEV);
 247        int min_tfm_cnt = INT_MAX;
 248        int tfm_cnt;
 249
 250        spin_lock(&driver_data.jr_alloc_lock);
 251
 252        if (list_empty(&driver_data.jr_list)) {
 253                spin_unlock(&driver_data.jr_alloc_lock);
 254                return ERR_PTR(-ENODEV);
 255        }
 256
 257        list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) {
 258                tfm_cnt = atomic_read(&jrpriv->tfm_count);
 259                if (tfm_cnt < min_tfm_cnt) {
 260                        min_tfm_cnt = tfm_cnt;
 261                        min_jrpriv = jrpriv;
 262                }
 263                if (!min_tfm_cnt)
 264                        break;
 265        }
 266
 267        if (min_jrpriv) {
 268                atomic_inc(&min_jrpriv->tfm_count);
 269                dev = min_jrpriv->dev;
 270        }
 271        spin_unlock(&driver_data.jr_alloc_lock);
 272
 273        return dev;
 274}
 275EXPORT_SYMBOL(caam_jr_alloc);
 276
 277/**
 278 * caam_jr_free() - Free the Job Ring
 279 * @rdev     - points to the dev that identifies the Job ring to
 280 *             be released.
 281 **/
 282void caam_jr_free(struct device *rdev)
 283{
 284        struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev);
 285
 286        atomic_dec(&jrpriv->tfm_count);
 287}
 288EXPORT_SYMBOL(caam_jr_free);
 289
 290/**
 291 * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
 292 * -EBUSY if the queue is full, -EIO if it cannot map the caller's
 293 * descriptor.
 294 * @dev:  device of the job ring to be used. This device should have
 295 *        been assigned prior by caam_jr_register().
 296 * @desc: points to a job descriptor that execute our request. All
 297 *        descriptors (and all referenced data) must be in a DMAable
 298 *        region, and all data references must be physical addresses
 299 *        accessible to CAAM (i.e. within a PAMU window granted
 300 *        to it).
 301 * @cbk:  pointer to a callback function to be invoked upon completion
 302 *        of this request. This has the form:
 303 *        callback(struct device *dev, u32 *desc, u32 stat, void *arg)
 304 *        where:
 305 *        @dev:    contains the job ring device that processed this
 306 *                 response.
 307 *        @desc:   descriptor that initiated the request, same as
 308 *                 "desc" being argued to caam_jr_enqueue().
 309 *        @status: untranslated status received from CAAM. See the
 310 *                 reference manual for a detailed description of
 311 *                 error meaning, or see the JRSTA definitions in the
 312 *                 register header file
 313 *        @areq:   optional pointer to an argument passed with the
 314 *                 original request
 315 * @areq: optional pointer to a user argument for use at callback
 316 *        time.
 317 **/
 318int caam_jr_enqueue(struct device *dev, u32 *desc,
 319                    void (*cbk)(struct device *dev, u32 *desc,
 320                                u32 status, void *areq),
 321                    void *areq)
 322{
 323        struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
 324        struct caam_jrentry_info *head_entry;
 325        int head, tail, desc_size;
 326        dma_addr_t desc_dma;
 327
 328        desc_size = (caam32_to_cpu(*desc) & HDR_JD_LENGTH_MASK) * sizeof(u32);
 329        desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE);
 330        if (dma_mapping_error(dev, desc_dma)) {
 331                dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n");
 332                return -EIO;
 333        }
 334
 335        spin_lock_bh(&jrp->inplock);
 336
 337        head = jrp->head;
 338        tail = ACCESS_ONCE(jrp->tail);
 339
 340        if (!rd_reg32(&jrp->rregs->inpring_avail) ||
 341            CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
 342                spin_unlock_bh(&jrp->inplock);
 343                dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
 344                return -EBUSY;
 345        }
 346
 347        head_entry = &jrp->entinfo[head];
 348        head_entry->desc_addr_virt = desc;
 349        head_entry->desc_size = desc_size;
 350        head_entry->callbk = (void *)cbk;
 351        head_entry->cbkarg = areq;
 352        head_entry->desc_addr_dma = desc_dma;
 353
 354        jrp->inpring[jrp->inp_ring_write_index] = cpu_to_caam_dma(desc_dma);
 355
 356        /*
 357         * Guarantee that the descriptor's DMA address has been written to
 358         * the next slot in the ring before the write index is updated, since
 359         * other cores may update this index independently.
 360         */
 361        smp_wmb();
 362
 363        jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) &
 364                                    (JOBR_DEPTH - 1);
 365        jrp->head = (head + 1) & (JOBR_DEPTH - 1);
 366
 367        /*
 368         * Ensure that all job information has been written before
 369         * notifying CAAM that a new job was added to the input ring.
 370         */
 371        wmb();
 372
 373        wr_reg32(&jrp->rregs->inpring_jobadd, 1);
 374
 375        spin_unlock_bh(&jrp->inplock);
 376
 377        return 0;
 378}
 379EXPORT_SYMBOL(caam_jr_enqueue);
 380
 381/*
 382 * Init JobR independent of platform property detection
 383 */
 384static int caam_jr_init(struct device *dev)
 385{
 386        struct caam_drv_private_jr *jrp;
 387        dma_addr_t inpbusaddr, outbusaddr;
 388        int i, error;
 389
 390        jrp = dev_get_drvdata(dev);
 391
 392        /* Connect job ring interrupt handler. */
 393        error = request_threaded_irq(jrp->irq, caam_jr_interrupt,
 394                                     caam_jr_threadirq, IRQF_SHARED,
 395                                     dev_name(dev), dev);
 396        if (error) {
 397                dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
 398                        jrp->ridx, jrp->irq);
 399                goto out_kill_deq;
 400        }
 401
 402        error = caam_reset_hw_jr(dev);
 403        if (error)
 404                goto out_free_irq;
 405
 406        error = -ENOMEM;
 407        jrp->inpring = dma_alloc_coherent(dev, sizeof(*jrp->inpring) *
 408                                          JOBR_DEPTH, &inpbusaddr, GFP_KERNEL);
 409        if (!jrp->inpring)
 410                goto out_free_irq;
 411
 412        jrp->outring = dma_alloc_coherent(dev, sizeof(*jrp->outring) *
 413                                          JOBR_DEPTH, &outbusaddr, GFP_KERNEL);
 414        if (!jrp->outring)
 415                goto out_free_inpring;
 416
 417        jrp->entinfo = kcalloc(JOBR_DEPTH, sizeof(*jrp->entinfo), GFP_KERNEL);
 418        if (!jrp->entinfo)
 419                goto out_free_outring;
 420
 421        for (i = 0; i < JOBR_DEPTH; i++)
 422                jrp->entinfo[i].desc_addr_dma = !0;
 423
 424        /* Setup rings */
 425        jrp->inp_ring_write_index = 0;
 426        jrp->out_ring_read_index = 0;
 427        jrp->head = 0;
 428        jrp->tail = 0;
 429
 430        wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
 431        wr_reg64(&jrp->rregs->outring_base, outbusaddr);
 432        wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
 433        wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
 434
 435        jrp->ringsize = JOBR_DEPTH;
 436
 437        spin_lock_init(&jrp->inplock);
 438        spin_lock_init(&jrp->outlock);
 439
 440        /* Select interrupt coalescing parameters */
 441        clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
 442                      (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
 443                      (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
 444
 445        return 0;
 446
 447out_free_outring:
 448        dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH,
 449                          jrp->outring, outbusaddr);
 450out_free_inpring:
 451        dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH,
 452                          jrp->inpring, inpbusaddr);
 453        dev_err(dev, "can't allocate job rings for %d\n", jrp->ridx);
 454out_free_irq:
 455        free_irq(jrp->irq, dev);
 456out_kill_deq:
 457        return error;
 458}
 459
 460
 461/*
 462 * Probe routine for each detected JobR subsystem.
 463 */
 464static int caam_jr_probe(struct platform_device *pdev)
 465{
 466        struct device *jrdev;
 467        struct device_node *nprop;
 468        struct caam_job_ring __iomem *ctrl;
 469        struct caam_drv_private_jr *jrpriv;
 470        static int total_jobrs;
 471        int error;
 472
 473        jrdev = &pdev->dev;
 474        jrpriv = devm_kmalloc(jrdev, sizeof(*jrpriv), GFP_KERNEL);
 475        if (!jrpriv)
 476                return -ENOMEM;
 477
 478        dev_set_drvdata(jrdev, jrpriv);
 479
 480        /* save ring identity relative to detection */
 481        jrpriv->ridx = total_jobrs++;
 482
 483        nprop = pdev->dev.of_node;
 484        /* Get configuration properties from device tree */
 485        /* First, get register page */
 486        ctrl = of_iomap(nprop, 0);
 487        if (!ctrl) {
 488                dev_err(jrdev, "of_iomap() failed\n");
 489                return -ENOMEM;
 490        }
 491
 492        jrpriv->rregs = (struct caam_job_ring __force *)ctrl;
 493
 494        if (sizeof(dma_addr_t) == sizeof(u64))
 495                if (of_device_is_compatible(nprop, "fsl,sec-v5.0-job-ring"))
 496                        dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(40));
 497                else
 498                        dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(36));
 499        else
 500                dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(32));
 501
 502        /* Identify the interrupt */
 503        jrpriv->irq = irq_of_parse_and_map(nprop, 0);
 504
 505        /* Now do the platform independent part */
 506        error = caam_jr_init(jrdev); /* now turn on hardware */
 507        if (error) {
 508                irq_dispose_mapping(jrpriv->irq);
 509                iounmap(ctrl);
 510                return error;
 511        }
 512
 513        jrpriv->dev = jrdev;
 514        spin_lock(&driver_data.jr_alloc_lock);
 515        list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
 516        spin_unlock(&driver_data.jr_alloc_lock);
 517
 518        atomic_set(&jrpriv->tfm_count, 0);
 519
 520        return 0;
 521}
 522
 523static struct of_device_id caam_jr_match[] = {
 524        {
 525                .compatible = "fsl,sec-v4.0-job-ring",
 526        },
 527        {
 528                .compatible = "fsl,sec4.0-job-ring",
 529        },
 530        {},
 531};
 532MODULE_DEVICE_TABLE(of, caam_jr_match);
 533
 534static struct platform_driver caam_jr_driver = {
 535        .driver = {
 536                .name = "caam_jr",
 537                .of_match_table = caam_jr_match,
 538        },
 539        .probe       = caam_jr_probe,
 540        .remove      = caam_jr_remove,
 541};
 542
 543static int __init jr_driver_init(void)
 544{
 545        spin_lock_init(&driver_data.jr_alloc_lock);
 546        INIT_LIST_HEAD(&driver_data.jr_list);
 547        return platform_driver_register(&caam_jr_driver);
 548}
 549
 550static void __exit jr_driver_exit(void)
 551{
 552        platform_driver_unregister(&caam_jr_driver);
 553}
 554
 555module_init(jr_driver_init);
 556module_exit(jr_driver_exit);
 557
 558MODULE_LICENSE("GPL");
 559MODULE_DESCRIPTION("FSL CAAM JR request backend");
 560MODULE_AUTHOR("Freescale Semiconductor - NMG/STC");
 561
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.