Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb...
[firefly-linux-kernel-4.4.55.git] / drivers / dma / sun6i-dma.c
index 609c5d8cb94763c3d0e2cd367ab70f2b4f4c94cc..1f92a56fd2b6c38279872a2257d997b9ec2ff9ca 100644 (file)
@@ -562,8 +562,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
        v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
        if (!v_lli) {
                dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
-               kfree(txd);
-               return NULL;
+               goto err_txd_free;
        }
 
        ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig);
@@ -583,6 +582,8 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 
 err_dma_free:
        dma_pool_free(sdev->pool, v_lli, p_lli);
+err_txd_free:
+       kfree(txd);
        return NULL;
 }
 
@@ -614,17 +615,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
 
        for_each_sg(sgl, sg, sg_len, i) {
                v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
-               if (!v_lli) {
-                       kfree(txd);
-                       return NULL;
-               }
+               if (!v_lli)
+                       goto err_lli_free;
 
                if (dir == DMA_MEM_TO_DEV) {
                        ret = sun6i_dma_cfg_lli(v_lli, sg_dma_address(sg),
                                                sconfig->dst_addr, sg_dma_len(sg),
                                                sconfig);
                        if (ret)
-                               goto err_dma_free;
+                               goto err_cur_lli_free;
 
                        v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE |
                                DMA_CHAN_CFG_SRC_LINEAR_MODE |
@@ -642,7 +641,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
                                                sg_dma_address(sg), sg_dma_len(sg),
                                                sconfig);
                        if (ret)
-                               goto err_dma_free;
+                               goto err_cur_lli_free;
 
                        v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE |
                                DMA_CHAN_CFG_SRC_IO_MODE |
@@ -665,8 +664,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
 
        return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
 
-err_dma_free:
+err_cur_lli_free:
        dma_pool_free(sdev->pool, v_lli, p_lli);
+err_lli_free:
+       for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
+               dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
+       kfree(txd);
        return NULL;
 }
 
@@ -836,8 +839,8 @@ static inline void sun6i_kill_tasklet(struct sun6i_dma_dev *sdev)
        /* Prevent spurious interrupts from scheduling the tasklet */
        atomic_inc(&sdev->tasklet_shutdown);
 
-       /* Make sure all interrupts are handled */
-       synchronize_irq(sdev->irq);
+       /* Make sure we won't have any further interrupts */
+       devm_free_irq(sdev->slave.dev, sdev->irq, sdev);
 
        /* Actually prevent the tasklet from being scheduled */
        tasklet_kill(&sdev->task);