}
 
 static int
-tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan,
-       struct tsi721_tx_desc *desc, struct scatterlist *sg,
+tsi721_desc_fill_init(struct tsi721_tx_desc *desc, struct scatterlist *sg,
        enum dma_rtype rtype, u32 sys_size)
 {
        struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
        u64 rio_addr;
 
-       if (sg_dma_len(sg) > TSI721_DMAD_BCOUNT1 + 1) {
-               dev_err(bdma_chan->dchan.device->dev,
-                       "SG element is too large\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(bdma_chan->dchan.device->dev,
-               "desc: 0x%llx, addr: 0x%llx len: 0x%x\n",
-               (u64)desc->txd.phys, (unsigned long long)sg_dma_address(sg),
-               sg_dma_len(sg));
-
-       dev_dbg(bdma_chan->dchan.device->dev,
-               "bd_ptr = %p did=%d raddr=0x%llx\n",
-               bd_ptr, desc->destid, desc->rio_addr);
-
        /* Initialize DMA descriptor */
        bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) |
                                        (rtype << 19) | desc->destid);
-       if (desc->interrupt)
-               bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
        bd_ptr->bcount = cpu_to_le32(((desc->rio_addr & 0x3) << 30) |
-                                       (sys_size << 26) | sg_dma_len(sg));
+                                    (sys_size << 26));
        rio_addr = (desc->rio_addr >> 2) |
                                ((u64)(desc->rio_addr_u & 0x3) << 62);
        bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff);
        return 0;
 }
 
+static int
+tsi721_desc_fill_end(struct tsi721_tx_desc *desc)
+{
+       struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
+
+       /* Update DMA descriptor */
+       if (desc->interrupt)
+               bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
+       bd_ptr->bcount |= cpu_to_le32(desc->bcount & TSI721_DMAD_BCOUNT1);
+
+       return 0;
+}
+
+
 static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan,
                                      struct tsi721_tx_desc *desc)
 {
        unsigned int i;
        u32 sys_size = dma_to_mport(dchan->device)->sys_size;
        enum dma_rtype rtype;
+       dma_addr_t next_addr = -1;
 
        if (!sgl || !sg_len) {
                dev_err(dchan->device->dev, "%s: No SG list\n", __func__);
        for_each_sg(sgl, sg, sg_len, i) {
                int err;
 
-               dev_dbg(dchan->device->dev, "%s: sg #%d\n", __func__, i);
+               if (sg_dma_len(sg) > TSI721_BDMA_MAX_BCOUNT) {
+                       dev_err(dchan->device->dev,
+                               "%s: SG entry %d is too large\n", __func__, i);
+                       goto err_desc_put;
+               }
+
+               /*
+                * If this sg entry forms contiguous block with previous one,
+                * try to merge it into existing DMA descriptor
+                */
+               if (desc) {
+                       if (next_addr == sg_dma_address(sg) &&
+                           desc->bcount + sg_dma_len(sg) <=
+                                               TSI721_BDMA_MAX_BCOUNT) {
+                               /* Adjust byte count of the descriptor */
+                               desc->bcount += sg_dma_len(sg);
+                               goto entry_done;
+                       }
+
+                       /*
+                        * Finalize this descriptor using total
+                        * byte count value.
+                        */
+                       tsi721_desc_fill_end(desc);
+                       dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
+                               __func__, desc->bcount);
+               }
+
+               /*
+                * Obtain and initialize a new descriptor
+                */
                desc = tsi721_desc_get(bdma_chan);
                if (!desc) {
                        dev_err(dchan->device->dev,
-                               "Not enough descriptors available\n");
-                       goto err_desc_get;
+                               "%s: Failed to get new descriptor for SG %d\n",
+                               __func__, i);
+                       goto err_desc_put;
                }
 
-               if (sg_is_last(sg))
-                       desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
-               else
-                       desc->interrupt = false;
-
                desc->destid = rext->destid;
                desc->rio_addr = rio_addr;
                desc->rio_addr_u = 0;
+               desc->bcount = sg_dma_len(sg);
+
+               dev_dbg(dchan->device->dev,
+                       "sg%d desc: 0x%llx, addr: 0x%llx len: %d\n",
+                       i, (u64)desc->txd.phys,
+                       (unsigned long long)sg_dma_address(sg),
+                       sg_dma_len(sg));
+
+               dev_dbg(dchan->device->dev,
+                       "bd_ptr = %p did=%d raddr=0x%llx\n",
+                       desc->hw_desc, desc->destid, desc->rio_addr);
 
-               err = tsi721_fill_desc(bdma_chan, desc, sg, rtype, sys_size);
+               err = tsi721_desc_fill_init(desc, sg, rtype, sys_size);
                if (err) {
                        dev_err(dchan->device->dev,
                                "Failed to build desc: %d\n", err);
-                       goto err_desc_get;
+                       goto err_desc_put;
                }
 
-               rio_addr += sg_dma_len(sg);
+               next_addr = sg_dma_address(sg);
 
                if (!first)
                        first = desc;
                else
                        list_add_tail(&desc->desc_node, &first->tx_list);
+
+entry_done:
+               if (sg_is_last(sg)) {
+                       desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
+                       tsi721_desc_fill_end(desc);
+                       dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
+                               __func__, desc->bcount);
+               } else {
+                       rio_addr += sg_dma_len(sg);
+                       next_addr += sg_dma_len(sg);
+               }
        }
 
        first->txd.cookie = -EBUSY;
 
        return &first->txd;
 
-err_desc_get:
+err_desc_put:
        tsi721_desc_put(bdma_chan, first);
        return NULL;
 }
                if (i == TSI721_DMACH_MAINT)
                        continue;
 
-               bdma_chan->bd_num = 64;
+               bdma_chan->bd_num = TSI721_BDMA_BD_RING_SZ;
                bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i);
 
                bdma_chan->dchan.device = &mport->dma;