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