aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2014-04-07 18:38:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-07 19:36:07 -0400
commit40f847baf50debfd42ad66f862bfcfea069ffbe7 (patch)
tree01c5e585f81aa6c9e3f43d99192c642a5538fe4c
parent3f59b067c5140766591a64a3117d86978c57509b (diff)
drivers/rapidio/devices/tsi721_dma.c: optimize use of BDMA descriptors
Combine SG entries describing single contiguous memory block into one Tsi721 BDMA descriptor. This reduces number of hardware descriptors required for large data transfers and improves performance on the PCIe side by reducing number of descriptor fetch requests. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rapidio/devices/tsi721.h4
-rw-r--r--drivers/rapidio/devices/tsi721_dma.c111
2 files changed, 82 insertions, 33 deletions
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index 7061ac0ad428..0305675270ee 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -644,6 +644,9 @@ enum tsi721_smsg_int_flag {
644 644
645#ifdef CONFIG_RAPIDIO_DMA_ENGINE 645#ifdef CONFIG_RAPIDIO_DMA_ENGINE
646 646
647#define TSI721_BDMA_BD_RING_SZ 128
648#define TSI721_BDMA_MAX_BCOUNT (TSI721_DMAD_BCOUNT1 + 1)
649
647struct tsi721_tx_desc { 650struct tsi721_tx_desc {
648 struct dma_async_tx_descriptor txd; 651 struct dma_async_tx_descriptor txd;
649 struct tsi721_dma_desc *hw_desc; 652 struct tsi721_dma_desc *hw_desc;
@@ -652,6 +655,7 @@ struct tsi721_tx_desc {
652 u64 rio_addr; 655 u64 rio_addr;
653 /* upper 2-bits of 66-bit RIO address */ 656 /* upper 2-bits of 66-bit RIO address */
654 u8 rio_addr_u; 657 u8 rio_addr_u;
658 u32 bcount;
655 bool interrupt; 659 bool interrupt;
656 struct list_head desc_node; 660 struct list_head desc_node;
657 struct list_head tx_list; 661 struct list_head tx_list;
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c
index 91245f5dbe81..9b60b1f3261c 100644
--- a/drivers/rapidio/devices/tsi721_dma.c
+++ b/drivers/rapidio/devices/tsi721_dma.c
@@ -304,35 +304,17 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan)
304} 304}
305 305
306static int 306static int
307tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan, 307tsi721_desc_fill_init(struct tsi721_tx_desc *desc, struct scatterlist *sg,
308 struct tsi721_tx_desc *desc, struct scatterlist *sg,
309 enum dma_rtype rtype, u32 sys_size) 308 enum dma_rtype rtype, u32 sys_size)
310{ 309{
311 struct tsi721_dma_desc *bd_ptr = desc->hw_desc; 310 struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
312 u64 rio_addr; 311 u64 rio_addr;
313 312
314 if (sg_dma_len(sg) > TSI721_DMAD_BCOUNT1 + 1) {
315 dev_err(bdma_chan->dchan.device->dev,
316 "SG element is too large\n");
317 return -EINVAL;
318 }
319
320 dev_dbg(bdma_chan->dchan.device->dev,
321 "desc: 0x%llx, addr: 0x%llx len: 0x%x\n",
322 (u64)desc->txd.phys, (unsigned long long)sg_dma_address(sg),
323 sg_dma_len(sg));
324
325 dev_dbg(bdma_chan->dchan.device->dev,
326 "bd_ptr = %p did=%d raddr=0x%llx\n",
327 bd_ptr, desc->destid, desc->rio_addr);
328
329 /* Initialize DMA descriptor */ 313 /* Initialize DMA descriptor */
330 bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) | 314 bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) |
331 (rtype << 19) | desc->destid); 315 (rtype << 19) | desc->destid);
332 if (desc->interrupt)
333 bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
334 bd_ptr->bcount = cpu_to_le32(((desc->rio_addr & 0x3) << 30) | 316 bd_ptr->bcount = cpu_to_le32(((desc->rio_addr & 0x3) << 30) |
335 (sys_size << 26) | sg_dma_len(sg)); 317 (sys_size << 26));
336 rio_addr = (desc->rio_addr >> 2) | 318 rio_addr = (desc->rio_addr >> 2) |
337 ((u64)(desc->rio_addr_u & 0x3) << 62); 319 ((u64)(desc->rio_addr_u & 0x3) << 62);
338 bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff); 320 bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff);
@@ -346,6 +328,20 @@ tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan,
346 return 0; 328 return 0;
347} 329}
348 330
331static int
332tsi721_desc_fill_end(struct tsi721_tx_desc *desc)
333{
334 struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
335
336 /* Update DMA descriptor */
337 if (desc->interrupt)
338 bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
339 bd_ptr->bcount |= cpu_to_le32(desc->bcount & TSI721_DMAD_BCOUNT1);
340
341 return 0;
342}
343
344
349static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan, 345static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan,
350 struct tsi721_tx_desc *desc) 346 struct tsi721_tx_desc *desc)
351{ 347{
@@ -674,6 +670,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
674 unsigned int i; 670 unsigned int i;
675 u32 sys_size = dma_to_mport(dchan->device)->sys_size; 671 u32 sys_size = dma_to_mport(dchan->device)->sys_size;
676 enum dma_rtype rtype; 672 enum dma_rtype rtype;
673 dma_addr_t next_addr = -1;
677 674
678 if (!sgl || !sg_len) { 675 if (!sgl || !sg_len) {
679 dev_err(dchan->device->dev, "%s: No SG list\n", __func__); 676 dev_err(dchan->device->dev, "%s: No SG list\n", __func__);
@@ -704,36 +701,84 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
704 for_each_sg(sgl, sg, sg_len, i) { 701 for_each_sg(sgl, sg, sg_len, i) {
705 int err; 702 int err;
706 703
707 dev_dbg(dchan->device->dev, "%s: sg #%d\n", __func__, i); 704 if (sg_dma_len(sg) > TSI721_BDMA_MAX_BCOUNT) {
705 dev_err(dchan->device->dev,
706 "%s: SG entry %d is too large\n", __func__, i);
707 goto err_desc_put;
708 }
709
710 /*
711 * If this sg entry forms contiguous block with previous one,
712 * try to merge it into existing DMA descriptor
713 */
714 if (desc) {
715 if (next_addr == sg_dma_address(sg) &&
716 desc->bcount + sg_dma_len(sg) <=
717 TSI721_BDMA_MAX_BCOUNT) {
718 /* Adjust byte count of the descriptor */
719 desc->bcount += sg_dma_len(sg);
720 goto entry_done;
721 }
722
723 /*
724 * Finalize this descriptor using total
725 * byte count value.
726 */
727 tsi721_desc_fill_end(desc);
728 dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
729 __func__, desc->bcount);
730 }
731
732 /*
733 * Obtain and initialize a new descriptor
734 */
708 desc = tsi721_desc_get(bdma_chan); 735 desc = tsi721_desc_get(bdma_chan);
709 if (!desc) { 736 if (!desc) {
710 dev_err(dchan->device->dev, 737 dev_err(dchan->device->dev,
711 "Not enough descriptors available\n"); 738 "%s: Failed to get new descriptor for SG %d\n",
712 goto err_desc_get; 739 __func__, i);
740 goto err_desc_put;
713 } 741 }
714 742
715 if (sg_is_last(sg))
716 desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
717 else
718 desc->interrupt = false;
719
720 desc->destid = rext->destid; 743 desc->destid = rext->destid;
721 desc->rio_addr = rio_addr; 744 desc->rio_addr = rio_addr;
722 desc->rio_addr_u = 0; 745 desc->rio_addr_u = 0;
746 desc->bcount = sg_dma_len(sg);
747
748 dev_dbg(dchan->device->dev,
749 "sg%d desc: 0x%llx, addr: 0x%llx len: %d\n",
750 i, (u64)desc->txd.phys,
751 (unsigned long long)sg_dma_address(sg),
752 sg_dma_len(sg));
753
754 dev_dbg(dchan->device->dev,
755 "bd_ptr = %p did=%d raddr=0x%llx\n",
756 desc->hw_desc, desc->destid, desc->rio_addr);
723 757
724 err = tsi721_fill_desc(bdma_chan, desc, sg, rtype, sys_size); 758 err = tsi721_desc_fill_init(desc, sg, rtype, sys_size);
725 if (err) { 759 if (err) {
726 dev_err(dchan->device->dev, 760 dev_err(dchan->device->dev,
727 "Failed to build desc: %d\n", err); 761 "Failed to build desc: %d\n", err);
728 goto err_desc_get; 762 goto err_desc_put;
729 } 763 }
730 764
731 rio_addr += sg_dma_len(sg); 765 next_addr = sg_dma_address(sg);
732 766
733 if (!first) 767 if (!first)
734 first = desc; 768 first = desc;
735 else 769 else
736 list_add_tail(&desc->desc_node, &first->tx_list); 770 list_add_tail(&desc->desc_node, &first->tx_list);
771
772entry_done:
773 if (sg_is_last(sg)) {
774 desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
775 tsi721_desc_fill_end(desc);
776 dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
777 __func__, desc->bcount);
778 } else {
779 rio_addr += sg_dma_len(sg);
780 next_addr += sg_dma_len(sg);
781 }
737 } 782 }
738 783
739 first->txd.cookie = -EBUSY; 784 first->txd.cookie = -EBUSY;
@@ -741,7 +786,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
741 786
742 return &first->txd; 787 return &first->txd;
743 788
744err_desc_get: 789err_desc_put:
745 tsi721_desc_put(bdma_chan, first); 790 tsi721_desc_put(bdma_chan, first);
746 return NULL; 791 return NULL;
747} 792}
@@ -792,7 +837,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
792 if (i == TSI721_DMACH_MAINT) 837 if (i == TSI721_DMACH_MAINT)
793 continue; 838 continue;
794 839
795 bdma_chan->bd_num = 64; 840 bdma_chan->bd_num = TSI721_BDMA_BD_RING_SZ;
796 bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i); 841 bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i);
797 842
798 bdma_chan->dchan.device = &mport->dma; 843 bdma_chan->dchan.device = &mport->dma;