crypto: s5p-sss - fix incorrect usage of scatterlists api
[pandora-kernel.git] / drivers / crypto / s5p-sss.c
index 8115417..4f30887 100644 (file)
@@ -210,11 +210,11 @@ static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
 {
        int err;
 
-       if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
+       if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) {
                err = -EINVAL;
                goto exit;
        }
-       if (!sg_dma_len(sg)) {
+       if (!sg->length) {
                err = -EINVAL;
                goto exit;
        }
@@ -236,11 +236,11 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
 {
        int err;
 
-       if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
+       if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) {
                err = -EINVAL;
                goto exit;
        }
-       if (!sg_dma_len(sg)) {
+       if (!sg->length) {
                err = -EINVAL;
                goto exit;
        }
@@ -258,39 +258,51 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
        return err;
 }
 
-static void s5p_aes_tx(struct s5p_aes_dev *dev)
+/*
+ * 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.
+ */
+static bool s5p_aes_tx(struct s5p_aes_dev *dev)
 {
        int err = 0;
+       bool ret = false;
 
        s5p_unset_outdata(dev);
 
        if (!sg_is_last(dev->sg_dst)) {
                err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
-               if (err) {
+               if (err)
                        s5p_aes_complete(dev, err);
-                       return;
-               }
-
-               s5p_set_dma_outdata(dev, dev->sg_dst);
+               else
+                       ret = true;
        } else
                s5p_aes_complete(dev, err);
+
+       return ret;
 }
 
-static void s5p_aes_rx(struct s5p_aes_dev *dev)
+/*
+ * 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.
+ */
+static bool s5p_aes_rx(struct s5p_aes_dev *dev)
 {
        int err;
+       bool ret = false;
 
        s5p_unset_indata(dev);
 
        if (!sg_is_last(dev->sg_src)) {
                err = s5p_set_indata(dev, sg_next(dev->sg_src));
-               if (err) {
+               if (err)
                        s5p_aes_complete(dev, err);
-                       return;
-               }
-
-               s5p_set_dma_indata(dev, dev->sg_src);
+               else
+                       ret = true;
        }
+
+       return ret;
 }
 
 static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
@@ -299,19 +311,32 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
        struct s5p_aes_dev     *dev  = platform_get_drvdata(pdev);
        uint32_t                status;
        unsigned long           flags;
+       bool                    set_dma_tx = false;
+       bool                    set_dma_rx = false;
 
        spin_lock_irqsave(&dev->lock, flags);
 
        if (irq == dev->irq_fc) {
                status = SSS_READ(dev, FCINTSTAT);
                if (status & SSS_FCINTSTAT_BRDMAINT)
-                       s5p_aes_rx(dev);
+                       set_dma_rx = s5p_aes_rx(dev);
                if (status & SSS_FCINTSTAT_BTDMAINT)
-                       s5p_aes_tx(dev);
+                       set_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);
+
        spin_unlock_irqrestore(&dev->lock, flags);
 
        return IRQ_HANDLED;