diff options
author | Viresh Kumar <viresh.kumar@st.com> | 2011-08-05 06:02:40 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2011-08-25 10:03:39 -0400 |
commit | e0719165801fad04073e7dcd90e4afd02aba3fb7 (patch) | |
tree | 8b1cb65f26487d6fa0aba776e88c8e9b7f0aa22c /drivers | |
parent | 03af500f743f486648fc8afc38593e9844411945 (diff) |
dmaengine/amba-pl08x: Align lli_len to max(src.width, dst.width)
Currently lli_len is aligned to min of two widths, which looks to be incorrect.
Instead it should be aligned to max of both widths.
Lets say, total_size = 441 bytes
MIN: lets check if min() suits or not:
CASE 1: srcwidth = 1, dstwidth = 4
min(src, dst) = 1
i.e. We program transfer size in control reg to 441.
Now, till 440 bytes everything is fine, but on the last byte DMAC can't transfer
1 byte to dst, as its width is 4.
CASE 2: srcwidth = 4, dstwidth = 1
min(src, dst) = 1
i.e. we program transfer size in control reg to 110 (data transferred = 110 * srcwidth).
So, here too 1 byte is left, but on the source side.
MAX: Lets check if max() suits or not:
CASE 3: srcwidth = 1, dstwidth = 4
max(src, dst) = 4
Aligned size is 440
i.e. We program transfer size in control reg to 440.
Now, all 440 bytes will be transferred without any issues.
CASE 4: srcwidth = 4, dstwidth = 1
max(src, dst) = 4
Aligned size is 440
i.e. We program transfer size in control reg to 110 (data transferred = 110 * srcwidth).
Now, also all 440 bytes will be transferred without any issues.
Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 45d8a5d5bccd..4bcf6036f35d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -669,20 +669,22 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
669 | * width left | 669 | * width left |
670 | */ | 670 | */ |
671 | while (bd.remainder > (mbus->buswidth - 1)) { | 671 | while (bd.remainder > (mbus->buswidth - 1)) { |
672 | size_t lli_len, tsize; | 672 | size_t lli_len, tsize, width; |
673 | 673 | ||
674 | /* | 674 | /* |
675 | * If enough left try to send max possible, | 675 | * If enough left try to send max possible, |
676 | * otherwise try to send the remainder | 676 | * otherwise try to send the remainder |
677 | */ | 677 | */ |
678 | lli_len = min(bd.remainder, max_bytes_per_lli); | 678 | lli_len = min(bd.remainder, max_bytes_per_lli); |
679 | |||
679 | /* | 680 | /* |
680 | * Check against minimum bus alignment: Calculate actual | 681 | * Check against maximum bus alignment: Calculate actual |
681 | * transfer size in relation to bus width and get a | 682 | * transfer size in relation to bus width and get a |
682 | * maximum remainder of the smallest bus width - 1 | 683 | * maximum remainder of the highest bus width - 1 |
683 | */ | 684 | */ |
684 | tsize = lli_len / min(mbus->buswidth, sbus->buswidth); | 685 | width = max(mbus->buswidth, sbus->buswidth); |
685 | lli_len = tsize * min(mbus->buswidth, sbus->buswidth); | 686 | lli_len = (lli_len / width) * width; |
687 | tsize = lli_len / bd.srcbus.buswidth; | ||
686 | 688 | ||
687 | dev_vdbg(&pl08x->adev->dev, | 689 | dev_vdbg(&pl08x->adev->dev, |
688 | "%s fill lli with single lli chunk of " | 690 | "%s fill lli with single lli chunk of " |