From: Anders Berg <anders.b...@lsi.com>

One descriptor can only transfer up to 64K 128-bit words. To handle larger
transfers the driver is now able to chain multiple descriptors.

Signed-off-by: Anders Berg <anders.b...@lsi.com>
---
 drivers/dma/lsi-dma32.c |  188 ++++++++++++++++++++++++++---------------------
 drivers/dma/lsi-dma32.h |    4 +-
 2 files changed, 107 insertions(+), 85 deletions(-)

diff --git a/drivers/dma/lsi-dma32.c b/drivers/dma/lsi-dma32.c
index f08a1e8..837f3e1 100644
--- a/drivers/dma/lsi-dma32.c
+++ b/drivers/dma/lsi-dma32.c
@@ -61,7 +61,8 @@
 
 static unsigned int burst = 5;
 module_param(burst, uint, 0644);
-MODULE_PARM_DESC(burst, "Set preferred bust size during DMA transfters");
+MODULE_PARM_DESC(burst,
+                "Preferred burst setting (0=SINGLE,3=INCR4,5=INCR8,7=INCR16)");
 
 static void reset_channel(struct gpdma_channel *dmac)
 {
@@ -130,9 +131,8 @@ static int alloc_desc_table(struct gpdma_engine *engine)
                 * Controller can do full descriptor addresses, then we need no
                 * special alignment on the descriptor block.
                 */
-               order = ilog2((ALIGN(GPDMA_MAX_DESCRIPTORS *
-                                    sizeof(struct gpdma_desc),
-                                    PAGE_SIZE)) >> PAGE_SHIFT);
+               order = get_order(GPDMA_MAX_DESCRIPTORS *
+                                 sizeof(struct gpdma_desc));
        }
 
        engine->pool.va = (struct gpdma_desc *)
@@ -144,9 +144,11 @@ static int alloc_desc_table(struct gpdma_engine *engine)
        engine_dbg(engine, "order=%d pa=%#llx va=%p\n",
                   engine->pool.order, engine->pool.phys, engine->pool.va);
 
-       for (i = 0; i < GPDMA_MAX_DESCRIPTORS; i++)
-               engine->pool.free[i] = &engine->pool.va[i];
-       engine->pool.next = 0;
+       engine->pool.free = NULL;
+       for (i = 0; i < GPDMA_MAX_DESCRIPTORS-1; i++)
+               engine->pool.va[i].chain = &engine->pool.va[i+1];
+       engine->pool.va[GPDMA_MAX_DESCRIPTORS-1].chain = NULL;
+       engine->pool.free = &engine->pool.va[0];
 
        return 0;
 }
@@ -160,26 +162,48 @@ static void free_desc_table(struct gpdma_engine *engine)
 static struct gpdma_desc *get_descriptor(struct gpdma_engine *engine)
 {
        unsigned long flags;
-       struct gpdma_desc *desc = NULL;
+       struct gpdma_desc *desc;
 
        spin_lock_irqsave(&engine->lock, flags);
-       if (engine->pool.next < GPDMA_MAX_DESCRIPTORS)
-               desc = engine->pool.free[engine->pool.next++];
+       desc = engine->pool.free;
+       if (desc) {
+               engine->pool.free = desc->chain;
+               desc->chain = NULL;
+               desc->engine = engine;
+       }
        spin_unlock_irqrestore(&engine->lock, flags);
-       desc->engine = engine;
 
        return desc;
 }
 
+static phys_addr_t desc_to_paddr(const struct gpdma_channel *dmac,
+                                const struct gpdma_desc *desc)
+{
+       phys_addr_t paddr = virt_to_phys(&desc->hw);
+       WARN_ON(paddr & 0xf);
+       if (dmac->engine->chip->flags & LSIDMA_NEXT_FULL)
+               paddr |= 0x8;
+       else
+               paddr &= 0xfffff;
+
+       return paddr;
+}
+
 static void free_descriptor(struct virt_dma_desc *vd)
 {
        struct gpdma_desc *desc = to_gpdma_desc(vd);
        struct gpdma_engine *engine = desc->engine;
        unsigned long flags;
+       struct gpdma_desc *tail;
+
+       BUG_ON(desc == NULL);
+
+       for (tail = desc; tail->chain != NULL; tail = tail->chain)
+               ;
 
        spin_lock_irqsave(&engine->lock, flags);
-       BUG_ON(engine->pool.next == 0);
-       engine->pool.free[--engine->pool.next] = desc;
+       tail->chain = engine->pool.free;
+       engine->pool.free = desc;
        spin_unlock_irqrestore(&engine->lock, flags);
 }
 
@@ -220,14 +244,9 @@ static void gpdma_start(struct gpdma_channel *dmac)
                        return;
        }
 
-       paddr = virt_to_phys(&desc->hw);
-       WARN_ON(paddr & 0xf);
-       if (dmac->engine->chip->flags & LSIDMA_NEXT_FULL) {
-               /* Physical address of descriptor to load */
-               writel((u32)paddr | 0x8, dmac->base + DMA_NXT_DESCR);
-       } else {
-               writel((u32)paddr & 0xfffff, dmac->base + DMA_NXT_DESCR);
-       }
+       /* Physical address of descriptor to load */
+       paddr = desc_to_paddr(dmac, desc);
+       writel((u32)paddr, dmac->base + DMA_NXT_DESCR);
 
        if (dmac->engine->chip->flags & LSIDMA_SEG_REGS) {
                /* Segment bits [39..32] of descriptor, src and dst addresses */
@@ -417,73 +436,76 @@ gpdma_prep_memcpy(struct dma_chan *chan,
                  unsigned long dma_flags)
 {
        struct gpdma_channel *dmac = to_gpdma_chan(chan);
-       struct gpdma_desc *desc;
-       u16 rot_len, x_count, src_size, access_size;
-       u16 src_burst = burst;
-       u16 dst_burst = burst;
+       struct gpdma_desc *first = NULL, *prev = NULL, *new;
+       u32 rot_len, x_count, src_size, access;
 
-       desc = get_descriptor(dmac->engine);
-       if (desc == NULL) {
-               ch_dbg(dmac, "ERROR: No descriptor\n");
+       if (size == 0)
                return NULL;
-       }
 
-       /* Maximize memory access width based on job src, dst and length */
-       switch (ffs((u32)dst | (u32)src | size)) {
-       case 1:
-               src_size = 1;
-               access_size = (0 << 3);
-               break;
-       case 2:
-               src_size = 2;
-               access_size = (1 << 3);
-               break;
-       case 3:
-               src_size = 4;
-               access_size = (2 << 3);
-               break;
-       case 4:
-               src_size = 8;
-               access_size = (3 << 3);
-               break;
-       default:
-               src_size = 16;
-               access_size = (4 << 3);
-               break;
-       }
+       do {
+               new = get_descriptor(dmac->engine);
+               if (new == NULL) {
+                       ch_dbg(dmac, "ERROR: No descriptor\n");
+                       goto fail;
+               }
 
-       ch_dbg(dmac, "dst=%#llx src=%#llx size=%u mod=%d\n",
-               dst, src, size, src_size);
-       x_count = (size/src_size) - 1;
-       rot_len = (2 * src_size) - 1;
+               /* Maximize access width based on job src, dst and length */
+               access = min(ffs((u32)dst | (u32)src | size) - 1, 4);
+               src_size = 1 << access;
 
-       /*
-        * Fill in descriptor in memory.
-        */
-       desc->hw.src_x_ctr     = cpu_to_le16(x_count);
-       desc->hw.src_y_ctr     = 0;
-       desc->hw.src_x_mod     = cpu_to_le32(src_size);
-       desc->hw.src_y_mod     = 0;
-       desc->hw.src_addr      = cpu_to_le32(src & 0xffffffff);
-       desc->hw.src_data_mask = ~0;
-       desc->hw.src_access    = cpu_to_le16((rot_len << 6) |
-                                            access_size |
-                                            (src_burst & 7));
-       desc->hw.dst_access    = cpu_to_le16(access_size |
-                                            (dst_burst & 7));
-       desc->hw.ch_config     = cpu_to_le32(DMA_CONFIG_ONE_SHOT(1));
-       desc->hw.next_ptr      = 0;
-       desc->hw.dst_x_ctr     = cpu_to_le16(x_count);
-       desc->hw.dst_y_ctr     = 0;
-       desc->hw.dst_x_mod     = cpu_to_le32(src_size);
-       desc->hw.dst_y_mod     = 0;
-       desc->hw.dst_addr      = cpu_to_le32(dst & 0xffffffff);
-
-       /* Setup sw descriptor */
-       desc->src        = src;
-       desc->dst        = dst;
-
-       return vchan_tx_prep(&dmac->vc, &desc->vdesc, DMA_CTRL_ACK);
+               /* Counter register is limited to 64K */
+               x_count = min((size >> access), (size_t)SZ_64K);
+               rot_len = (2 * src_size) - 1;
+
+               /*
+                * Fill in descriptor in memory.
+                */
+               new->hw.src_x_ctr     = cpu_to_le16(x_count - 1);
+               new->hw.src_y_ctr     = 0;
+               new->hw.src_x_mod     = cpu_to_le32(src_size);
+               new->hw.src_y_mod     = 0;
+               new->hw.src_addr      = cpu_to_le32(src & 0xffffffff);
+               new->hw.src_data_mask = ~0;
+               new->hw.src_access    = cpu_to_le16((rot_len << 6) |
+                                                   (access << 3) |
+                                                   (burst & 7));
+               new->hw.dst_access    = cpu_to_le16((access << 3) |
+                                                   (burst & 7));
+               new->hw.ch_config     = cpu_to_le32(DMA_CONFIG_ONE_SHOT(1));
+               new->hw.next_ptr      = 0;
+               new->hw.dst_x_ctr     = cpu_to_le16(x_count - 1);
+               new->hw.dst_y_ctr     = 0;
+               new->hw.dst_x_mod     = cpu_to_le32(src_size);
+               new->hw.dst_y_mod     = 0;
+               new->hw.dst_addr      = cpu_to_le32(dst & 0xffffffff);
+
+               /* Setup sw descriptor */
+               new->src        = src;
+               new->dst        = dst;
+
+               if (!first) {
+                       first = new;
+               } else {
+                       prev->hw.next_ptr = desc_to_paddr(dmac, new);
+                       prev->chain = new;
+                       prev->hw.ch_config &=
+                               ~cpu_to_le32(DMA_CONFIG_LAST_BLOCK |
+                                            DMA_CONFIG_INT_DST_EOT);
+               }
+               prev = new;
+
+               size -= x_count << access;
+               src  += x_count << access;
+               dst  += x_count << access;
+
+       } while (size > 0);
+
+       return vchan_tx_prep(&dmac->vc, &first->vdesc, DMA_CTRL_ACK);
+
+fail:
+       if (first)
+               free_descriptor(&first->vdesc);
+       return NULL;
 }
 
 /**
diff --git a/drivers/dma/lsi-dma32.h b/drivers/dma/lsi-dma32.h
index b4248cd..37ed31b 100644
--- a/drivers/dma/lsi-dma32.h
+++ b/drivers/dma/lsi-dma32.h
@@ -153,6 +153,7 @@ struct gpdma_engine;
 
 struct gpdma_desc {
        struct descriptor               hw;
+       struct gpdma_desc              *chain;
        dma_addr_t                      src;
        dma_addr_t                      dst;
        struct gpdma_engine            *engine;
@@ -209,8 +210,7 @@ struct gpdma_engine {
                u32                     order;
                dma_addr_t              phys;
                struct gpdma_desc       *va;
-               int                     next;
-               struct gpdma_desc       *free[GPDMA_MAX_DESCRIPTORS];
+               struct gpdma_desc       *free;
        } pool;
        struct dma_device               dma_device;
 };
-- 
1.7.9.5

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to