lkml.org 
[lkml]   [2011]   [Apr]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V3 6/7] dmaengine/dw_dmac: Divide one sg to many desc, if sg len is greater than DWC_MAX_COUNT
    Date
    If len passed in sg for slave_sg transfers is greater than DWC_MAX_COUNT, then
    driver programmes controller incorrectly. This patch adds code to handle this
    situation by allocation more than one desc for same sg.

    Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
    ---
    drivers/dma/dw_dmac.c | 65 +++++++++++++++++++++++++++++++++----------------
    1 files changed, 44 insertions(+), 21 deletions(-)

    diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
    index 964d2d6..014654d 100644
    --- a/drivers/dma/dw_dmac.c
    +++ b/drivers/dma/dw_dmac.c
    @@ -707,9 +707,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
    reg = dws->tx_reg;
    for_each_sg(sgl, sg, sg_len, i) {
    struct dw_desc *desc;
    - u32 len;
    - u32 mem;
    + u32 len, dlen, mem;

    + mem = sg_phys(sg);
    + len = sg_dma_len(sg);
    + mem_width = 2;
    + if (unlikely(mem & 3 || len & 3))
    + mem_width = 0;
    +
    +slave_sg_todev_fill_desc:
    desc = dwc_desc_get(dwc);
    if (!desc) {
    dev_err(chan2dev(chan),
    @@ -717,16 +723,19 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
    goto err_desc_get;
    }

    - mem = sg_phys(sg);
    - len = sg_dma_len(sg);
    - mem_width = 2;
    - if (unlikely(mem & 3 || len & 3))
    - mem_width = 0;
    -
    desc->lli.sar = mem;
    desc->lli.dar = reg;
    desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
    - desc->lli.ctlhi = len >> mem_width;
    + if ((len >> mem_width) > DWC_MAX_COUNT) {
    + dlen = DWC_MAX_COUNT << mem_width;
    + mem += dlen;
    + len -= dlen;
    + } else {
    + dlen = len;
    + len = 0;
    + }
    +
    + desc->lli.ctlhi = dlen >> mem_width;

    if (!first) {
    first = desc;
    @@ -740,7 +749,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
    &first->tx_list);
    }
    prev = desc;
    - total_len += len;
    + total_len += dlen;
    +
    + if (len)
    + goto slave_sg_todev_fill_desc;
    }
    break;
    case DMA_FROM_DEVICE:
    @@ -753,15 +765,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
    reg = dws->rx_reg;
    for_each_sg(sgl, sg, sg_len, i) {
    struct dw_desc *desc;
    - u32 len;
    - u32 mem;
    -
    - desc = dwc_desc_get(dwc);
    - if (!desc) {
    - dev_err(chan2dev(chan),
    - "not enough descriptors available\n");
    - goto err_desc_get;
    - }
    + u32 len, dlen, mem;

    mem = sg_phys(sg);
    len = sg_dma_len(sg);
    @@ -769,10 +773,26 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
    if (unlikely(mem & 3 || len & 3))
    mem_width = 0;

    +slave_sg_fromdev_fill_desc:
    + desc = dwc_desc_get(dwc);
    + if (!desc) {
    + dev_err(chan2dev(chan),
    + "not enough descriptors available\n");
    + goto err_desc_get;
    + }
    +
    desc->lli.sar = reg;
    desc->lli.dar = mem;
    desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
    - desc->lli.ctlhi = len >> reg_width;
    + if ((len >> reg_width) > DWC_MAX_COUNT) {
    + dlen = DWC_MAX_COUNT << reg_width;
    + mem += dlen;
    + len -= dlen;
    + } else {
    + dlen = len;
    + len = 0;
    + }
    + desc->lli.ctlhi = dlen >> reg_width;

    if (!first) {
    first = desc;
    @@ -786,7 +806,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
    &first->tx_list);
    }
    prev = desc;
    - total_len += len;
    + total_len += dlen;
    +
    + if (len)
    + goto slave_sg_fromdev_fill_desc;
    }
    break;
    default:
    --
    1.7.3.4


    \
     
     \ /
      Last update: 2011-04-27 11:41    [W:0.041 / U:3.256 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site