Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alexandre Bounine and committed by
Linus Torvalds
40f847ba 3f59b067

+82 -33
+4
drivers/rapidio/devices/tsi721.h
··· 644 644 645 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 + 647 650 struct tsi721_tx_desc { 648 651 struct dma_async_tx_descriptor txd; 649 652 struct tsi721_dma_desc *hw_desc; ··· 655 652 u64 rio_addr; 656 653 /* upper 2-bits of 66-bit RIO address */ 657 654 u8 rio_addr_u; 655 + u32 bcount; 658 656 bool interrupt; 659 657 struct list_head desc_node; 660 658 struct list_head tx_list;
+78 -33
drivers/rapidio/devices/tsi721_dma.c
··· 304 304 } 305 305 306 306 static int 307 - tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan, 308 - struct tsi721_tx_desc *desc, struct scatterlist *sg, 307 + tsi721_desc_fill_init(struct tsi721_tx_desc *desc, struct scatterlist *sg, 309 308 enum dma_rtype rtype, u32 sys_size) 310 309 { 311 310 struct tsi721_dma_desc *bd_ptr = desc->hw_desc; 312 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 313 /* Initialize DMA descriptor */ 330 314 bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) | 331 315 (rtype << 19) | desc->destid); 332 - if (desc->interrupt) 333 - bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF); 334 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 318 rio_addr = (desc->rio_addr >> 2) | 337 319 ((u64)(desc->rio_addr_u & 0x3) << 62); 338 320 bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff); ··· 327 345 328 346 return 0; 329 347 } 348 + 349 + static int 350 + tsi721_desc_fill_end(struct tsi721_tx_desc *desc) 351 + { 352 + struct tsi721_dma_desc *bd_ptr = desc->hw_desc; 353 + 354 + /* Update DMA descriptor */ 355 + if (desc->interrupt) 356 + bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF); 357 + bd_ptr->bcount |= cpu_to_le32(desc->bcount & TSI721_DMAD_BCOUNT1); 358 + 359 + return 0; 360 + } 361 + 330 362 331 363 static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan, 332 364 struct tsi721_tx_desc *desc) ··· 670 674 unsigned int i; 671 675 u32 sys_size = dma_to_mport(dchan->device)->sys_size; 672 676 enum dma_rtype rtype; 677 + dma_addr_t next_addr = -1; 673 678 674 679 if (!sgl || !sg_len) { 675 680 dev_err(dchan->device->dev, "%s: No SG list\n", __func__); ··· 701 704 for_each_sg(sgl, sg, sg_len, i) { 702 705 int err; 703 706 704 - dev_dbg(dchan->device->dev, "%s: sg #%d\n", __func__, i); 707 + if (sg_dma_len(sg) > TSI721_BDMA_MAX_BCOUNT) { 708 + dev_err(dchan->device->dev, 709 + "%s: SG entry %d is too large\n", __func__, i); 710 + goto err_desc_put; 711 + } 712 + 713 + /* 714 + * If this sg entry forms contiguous block with previous one, 715 + * try to merge it into existing DMA descriptor 716 + */ 717 + if (desc) { 718 + if (next_addr == sg_dma_address(sg) && 719 + desc->bcount + sg_dma_len(sg) <= 720 + TSI721_BDMA_MAX_BCOUNT) { 721 + /* Adjust byte count of the descriptor */ 722 + desc->bcount += sg_dma_len(sg); 723 + goto entry_done; 724 + } 725 + 726 + /* 727 + * Finalize this descriptor using total 728 + * byte count value. 729 + */ 730 + tsi721_desc_fill_end(desc); 731 + dev_dbg(dchan->device->dev, "%s: desc final len: %d\n", 732 + __func__, desc->bcount); 733 + } 734 + 735 + /* 736 + * Obtain and initialize a new descriptor 737 + */ 705 738 desc = tsi721_desc_get(bdma_chan); 706 739 if (!desc) { 707 740 dev_err(dchan->device->dev, 708 - "Not enough descriptors available\n"); 709 - goto err_desc_get; 741 + "%s: Failed to get new descriptor for SG %d\n", 742 + __func__, i); 743 + goto err_desc_put; 710 744 } 711 - 712 - if (sg_is_last(sg)) 713 - desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0; 714 - else 715 - desc->interrupt = false; 716 745 717 746 desc->destid = rext->destid; 718 747 desc->rio_addr = rio_addr; 719 748 desc->rio_addr_u = 0; 749 + desc->bcount = sg_dma_len(sg); 720 750 721 - err = tsi721_fill_desc(bdma_chan, desc, sg, rtype, sys_size); 751 + dev_dbg(dchan->device->dev, 752 + "sg%d desc: 0x%llx, addr: 0x%llx len: %d\n", 753 + i, (u64)desc->txd.phys, 754 + (unsigned long long)sg_dma_address(sg), 755 + sg_dma_len(sg)); 756 + 757 + dev_dbg(dchan->device->dev, 758 + "bd_ptr = %p did=%d raddr=0x%llx\n", 759 + desc->hw_desc, desc->destid, desc->rio_addr); 760 + 761 + err = tsi721_desc_fill_init(desc, sg, rtype, sys_size); 722 762 if (err) { 723 763 dev_err(dchan->device->dev, 724 764 "Failed to build desc: %d\n", err); 725 - goto err_desc_get; 765 + goto err_desc_put; 726 766 } 727 767 728 - rio_addr += sg_dma_len(sg); 768 + next_addr = sg_dma_address(sg); 729 769 730 770 if (!first) 731 771 first = desc; 732 772 else 733 773 list_add_tail(&desc->desc_node, &first->tx_list); 774 + 775 + entry_done: 776 + if (sg_is_last(sg)) { 777 + desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0; 778 + tsi721_desc_fill_end(desc); 779 + dev_dbg(dchan->device->dev, "%s: desc final len: %d\n", 780 + __func__, desc->bcount); 781 + } else { 782 + rio_addr += sg_dma_len(sg); 783 + next_addr += sg_dma_len(sg); 784 + } 734 785 } 735 786 736 787 first->txd.cookie = -EBUSY; ··· 786 741 787 742 return &first->txd; 788 743 789 - err_desc_get: 744 + err_desc_put: 790 745 tsi721_desc_put(bdma_chan, first); 791 746 return NULL; 792 747 } ··· 837 792 if (i == TSI721_DMACH_MAINT) 838 793 continue; 839 794 840 - bdma_chan->bd_num = 64; 795 + bdma_chan->bd_num = TSI721_BDMA_BD_RING_SZ; 841 796 bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i); 842 797 843 798 bdma_chan->dchan.device = &mport->dma;