]>
Commit | Line | Data |
---|---|---|
91861a69 SL |
1 | From 3fea93f091ededb4c47887372bedaeae2d9ae5b9 Mon Sep 17 00:00:00 2001 |
2 | From: Ben Dooks <ben.dooks@codethink.co.uk> | |
3 | Date: Wed, 21 Nov 2018 16:13:19 +0000 | |
4 | Subject: dmaengine: tegra: avoid overflow of byte tracking | |
5 | ||
6 | [ Upstream commit e486df39305864604b7e25f2a95d51039517ac57 ] | |
7 | ||
8 | The dma_desc->bytes_transferred counter tracks the number of bytes | |
9 | moved by the DMA channel. This is then used to calculate the information | |
10 | passed back in the in the tegra_dma_tx_status callback, which is usually | |
11 | fine. | |
12 | ||
13 | When the DMA channel is configured as continous, then the bytes_transferred | |
14 | counter will increase over time and eventually overflow to become negative | |
15 | so the residue count will become invalid and the ALSA sound-dma code will | |
16 | report invalid hardware pointer values to the application. This results in | |
17 | some users becoming confused about the playout position and putting audio | |
18 | data in the wrong place. | |
19 | ||
20 | To fix this issue, always ensure the bytes_transferred field is modulo the | |
21 | size of the request. We only do this for the case of the cyclic transfer | |
22 | done ISR as anyone attempting to move 2GiB of DMA data in one transfer | |
23 | is unlikely. | |
24 | ||
25 | Note, we don't fix the issue that we should /never/ transfer a negative | |
26 | number of bytes so we could make those fields unsigned. | |
27 | ||
28 | Reviewed-by: Dmitry Osipenko <digetx@gmail.com> | |
29 | Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk> | |
30 | Acked-by: Jon Hunter <jonathanh@nvidia.com> | |
31 | Signed-off-by: Vinod Koul <vkoul@kernel.org> | |
32 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
33 | --- | |
34 | drivers/dma/tegra20-apb-dma.c | 5 ++++- | |
35 | 1 file changed, 4 insertions(+), 1 deletion(-) | |
36 | ||
37 | diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c | |
38 | index c8f79dcaaee8..67f201b8dcda 100644 | |
39 | --- a/drivers/dma/tegra20-apb-dma.c | |
40 | +++ b/drivers/dma/tegra20-apb-dma.c | |
41 | @@ -632,7 +632,10 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc, | |
42 | ||
43 | sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node); | |
44 | dma_desc = sgreq->dma_desc; | |
45 | - dma_desc->bytes_transferred += sgreq->req_len; | |
46 | + /* if we dma for long enough the transfer count will wrap */ | |
47 | + dma_desc->bytes_transferred = | |
48 | + (dma_desc->bytes_transferred + sgreq->req_len) % | |
49 | + dma_desc->bytes_requested; | |
50 | ||
51 | /* Callback need to be call */ | |
52 | if (!dma_desc->cb_count) | |
53 | -- | |
54 | 2.19.1 | |
55 |