]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Mar 2017 16:26:04 +0000 (09:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Mar 2017 16:26:04 +0000 (09:26 -0700)
Pull crypto fixes from Herbert Xu:

 - self-test failure of crc32c on powerpc

 - regressions of ecb(aes) when used with xts/lrw in s5p-sss

 - a number of bugs in the omap RNG driver

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6:
  crypto: s5p-sss - Fix spinlock recursion on LRW(AES)
  hwrng: omap - Do not access INTMASK_REG on EIP76
  hwrng: omap - use devm_clk_get() instead of of_clk_get()
  hwrng: omap - write registers after enabling the clock
  crypto: s5p-sss - Fix completing crypto request in IRQ handler
  crypto: powerpc - Fix initialisation of crc32c context

arch/powerpc/crypto/crc32c-vpmsum_glue.c
drivers/char/hw_random/omap-rng.c
drivers/crypto/s5p-sss.c

index 9fa046d56ebadd6ad25e62b5a29a853b123cd30a..411994551afc138b0b733fdda2b6398140f7127c 100644 (file)
@@ -52,7 +52,7 @@ static int crc32c_vpmsum_cra_init(struct crypto_tfm *tfm)
 {
        u32 *key = crypto_tfm_ctx(tfm);
 
-       *key = 0;
+       *key = ~0;
 
        return 0;
 }
index 3ad86fdf954e96a71b16f436f2b22bd02e6cbd8f..b1ad12552b566a6892a7de411e9cd0c65cf25933 100644 (file)
@@ -397,9 +397,8 @@ static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
                                irq, err);
                        return err;
                }
-               omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK);
 
-               priv->clk = of_clk_get(pdev->dev.of_node, 0);
+               priv->clk = devm_clk_get(&pdev->dev, NULL);
                if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
                if (!IS_ERR(priv->clk)) {
@@ -408,6 +407,19 @@ static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
                                dev_err(&pdev->dev, "unable to enable the clk, "
                                                    "err = %d\n", err);
                }
+
+               /*
+                * On OMAP4, enabling the shutdown_oflo interrupt is
+                * done in the interrupt mask register. There is no
+                * such register on EIP76, and it's enabled by the
+                * same bit in the control register
+                */
+               if (priv->pdata->regs[RNG_INTMASK_REG])
+                       omap_rng_write(priv, RNG_INTMASK_REG,
+                                      RNG_SHUTDOWN_OFLO_MASK);
+               else
+                       omap_rng_write(priv, RNG_CONTROL_REG,
+                                      RNG_SHUTDOWN_OFLO_MASK);
        }
        return 0;
 }
index dce1af0ce85ce8ec6dbd7184f02776cb173c41f0..1b9da3dc799b05dff2971e6a5415cc3ae3d4bd85 100644 (file)
@@ -270,7 +270,7 @@ static void s5p_sg_copy_buf(void *buf, struct scatterlist *sg,
        scatterwalk_done(&walk, out, 0);
 }
 
-static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
+static void s5p_sg_done(struct s5p_aes_dev *dev)
 {
        if (dev->sg_dst_cpy) {
                dev_dbg(dev->dev,
@@ -281,8 +281,11 @@ static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
        }
        s5p_free_sg_cpy(dev, &dev->sg_src_cpy);
        s5p_free_sg_cpy(dev, &dev->sg_dst_cpy);
+}
 
-       /* holding a lock outside */
+/* Calls the completion. Cannot be called with dev->lock hold. */
+static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
+{
        dev->req->base.complete(&dev->req->base, err);
        dev->busy = false;
 }
@@ -368,51 +371,44 @@ exit:
 }
 
 /*
- * Returns true if new transmitting (output) data is ready and its
- * address+length have to be written to device (by calling
- * s5p_set_dma_outdata()). False otherwise.
+ * Returns -ERRNO on error (mapping of new data failed).
+ * On success returns:
+ *  - 0 if there is no more data,
+ *  - 1 if new transmitting (output) data is ready and its address+length
+ *     have to be written to device (by calling s5p_set_dma_outdata()).
  */
-static bool s5p_aes_tx(struct s5p_aes_dev *dev)
+static int s5p_aes_tx(struct s5p_aes_dev *dev)
 {
-       int err = 0;
-       bool ret = false;
+       int ret = 0;
 
        s5p_unset_outdata(dev);
 
        if (!sg_is_last(dev->sg_dst)) {
-               err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
-               if (err)
-                       s5p_aes_complete(dev, err);
-               else
-                       ret = true;
-       } else {
-               s5p_aes_complete(dev, err);
-
-               dev->busy = true;
-               tasklet_schedule(&dev->tasklet);
+               ret = s5p_set_outdata(dev, sg_next(dev->sg_dst));
+               if (!ret)
+                       ret = 1;
        }
 
        return ret;
 }
 
 /*
- * Returns true if new receiving (input) data is ready and its
- * address+length have to be written to device (by calling
- * s5p_set_dma_indata()). False otherwise.
+ * Returns -ERRNO on error (mapping of new data failed).
+ * On success returns:
+ *  - 0 if there is no more data,
+ *  - 1 if new receiving (input) data is ready and its address+length
+ *     have to be written to device (by calling s5p_set_dma_indata()).
  */
-static bool s5p_aes_rx(struct s5p_aes_dev *dev)
+static int s5p_aes_rx(struct s5p_aes_dev *dev/*, bool *set_dma*/)
 {
-       int err;
-       bool ret = false;
+       int ret = 0;
 
        s5p_unset_indata(dev);
 
        if (!sg_is_last(dev->sg_src)) {
-               err = s5p_set_indata(dev, sg_next(dev->sg_src));
-               if (err)
-                       s5p_aes_complete(dev, err);
-               else
-                       ret = true;
+               ret = s5p_set_indata(dev, sg_next(dev->sg_src));
+               if (!ret)
+                       ret = 1;
        }
 
        return ret;
@@ -422,33 +418,73 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
        struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
-       bool set_dma_tx = false;
-       bool set_dma_rx = false;
+       int err_dma_tx = 0;
+       int err_dma_rx = 0;
+       bool tx_end = false;
        unsigned long flags;
        uint32_t status;
+       int err;
 
        spin_lock_irqsave(&dev->lock, flags);
 
+       /*
+        * Handle rx or tx interrupt. If there is still data (scatterlist did not
+        * reach end), then map next scatterlist entry.
+        * In case of such mapping error, s5p_aes_complete() should be called.
+        *
+        * If there is no more data in tx scatter list, call s5p_aes_complete()
+        * and schedule new tasklet.
+        */
        status = SSS_READ(dev, FCINTSTAT);
        if (status & SSS_FCINTSTAT_BRDMAINT)
-               set_dma_rx = s5p_aes_rx(dev);
-       if (status & SSS_FCINTSTAT_BTDMAINT)
-               set_dma_tx = s5p_aes_tx(dev);
+               err_dma_rx = s5p_aes_rx(dev);
+
+       if (status & SSS_FCINTSTAT_BTDMAINT) {
+               if (sg_is_last(dev->sg_dst))
+                       tx_end = true;
+               err_dma_tx = s5p_aes_tx(dev);
+       }
 
        SSS_WRITE(dev, FCINTPEND, status);
 
-       /*
-        * Writing length of DMA block (either receiving or transmitting)
-        * will start the operation immediately, so this should be done
-        * at the end (even after clearing pending interrupts to not miss the
-        * interrupt).
-        */
-       if (set_dma_tx)
-               s5p_set_dma_outdata(dev, dev->sg_dst);
-       if (set_dma_rx)
-               s5p_set_dma_indata(dev, dev->sg_src);
+       if (err_dma_rx < 0) {
+               err = err_dma_rx;
+               goto error;
+       }
+       if (err_dma_tx < 0) {
+               err = err_dma_tx;
+               goto error;
+       }
+
+       if (tx_end) {
+               s5p_sg_done(dev);
+
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               s5p_aes_complete(dev, 0);
+               dev->busy = true;
+               tasklet_schedule(&dev->tasklet);
+       } else {
+               /*
+                * Writing length of DMA block (either receiving or
+                * transmitting) will start the operation immediately, so this
+                * should be done at the end (even after clearing pending
+                * interrupts to not miss the interrupt).
+                */
+               if (err_dma_tx == 1)
+                       s5p_set_dma_outdata(dev, dev->sg_dst);
+               if (err_dma_rx == 1)
+                       s5p_set_dma_indata(dev, dev->sg_src);
 
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+
+       return IRQ_HANDLED;
+
+error:
+       s5p_sg_done(dev);
        spin_unlock_irqrestore(&dev->lock, flags);
+       s5p_aes_complete(dev, err);
 
        return IRQ_HANDLED;
 }
@@ -597,8 +633,9 @@ outdata_error:
        s5p_unset_indata(dev);
 
 indata_error:
-       s5p_aes_complete(dev, err);
+       s5p_sg_done(dev);
        spin_unlock_irqrestore(&dev->lock, flags);
+       s5p_aes_complete(dev, err);
 }
 
 static void s5p_tasklet_cb(unsigned long data)
@@ -805,8 +842,9 @@ static int s5p_aes_probe(struct platform_device *pdev)
                dev_warn(dev, "feed control interrupt is not available.\n");
                goto err_irq;
        }
-       err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt,
-                              IRQF_SHARED, pdev->name, pdev);
+       err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL,
+                                       s5p_aes_interrupt, IRQF_ONESHOT,
+                                       pdev->name, pdev);
        if (err < 0) {
                dev_warn(dev, "feed control interrupt is not available.\n");
                goto err_irq;