]>
Commit | Line | Data |
---|---|---|
7f30898e GKH |
1 | From c5637476bbf9bb86c7f0413b8f4822a73d8d2d07 Mon Sep 17 00:00:00 2001 |
2 | From: Maxime Jayat <maxime.jayat@mobile-devices.fr> | |
3 | Date: Thu, 22 Feb 2018 12:39:55 +0100 | |
4 | Subject: dmaengine: at_xdmac: fix rare residue corruption | |
5 | ||
6 | From: Maxime Jayat <maxime.jayat@mobile-devices.fr> | |
7 | ||
8 | commit c5637476bbf9bb86c7f0413b8f4822a73d8d2d07 upstream. | |
9 | ||
10 | Despite the efforts made to correctly read the NDA and CUBC registers, | |
11 | the order in which the registers are read could sometimes lead to an | |
12 | inconsistent state. | |
13 | ||
14 | Re-using the timeline from the comments, this following timing of | |
15 | registers reads could lead to reading NDA with value "@desc2" and | |
16 | CUBC with value "MAX desc1": | |
17 | ||
18 | INITD -------- ------------ | |
19 | |____________________| | |
20 | _______________________ _______________ | |
21 | NDA @desc2 \/ @desc3 | |
22 | _______________________/\_______________ | |
23 | __________ ___________ _______________ | |
24 | CUBC 0 \/ MAX desc1 \/ MAX desc2 | |
25 | __________/\___________/\_______________ | |
26 | | | | | | |
27 | Events:(1)(2) (3)(4) | |
28 | ||
29 | (1) check_nda = @desc2 | |
30 | (2) initd = 1 | |
31 | (3) cur_ubc = MAX desc1 | |
32 | (4) cur_nda = @desc2 | |
33 | ||
34 | This is allowed by the condition ((check_nda == cur_nda) && initd), | |
35 | despite cur_ubc and cur_nda being in the precise state we don't want. | |
36 | ||
37 | This error leads to incorrect residue computation. | |
38 | ||
39 | Fix it by inversing the order in which CUBC and INITD are read. This | |
40 | makes sure that NDA and CUBC are always read together either _before_ | |
41 | INITD goes to 0 or _after_ it is back at 1. | |
42 | The case where NDA is read before INITD is at 0 and CUBC is read after | |
43 | INITD is back at 1 will be rejected by check_nda and cur_nda being | |
44 | different. | |
45 | ||
46 | Fixes: 53398f488821 ("dmaengine: at_xdmac: fix residue corruption") | |
47 | Cc: stable@vger.kernel.org | |
48 | Signed-off-by: Maxime Jayat <maxime.jayat@mobile-devices.fr> | |
49 | Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com> | |
50 | Signed-off-by: Vinod Koul <vinod.koul@intel.com> | |
51 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
52 | ||
53 | --- | |
54 | drivers/dma/at_xdmac.c | 4 ++-- | |
55 | 1 file changed, 2 insertions(+), 2 deletions(-) | |
56 | ||
57 | --- a/drivers/dma/at_xdmac.c | |
58 | +++ b/drivers/dma/at_xdmac.c | |
59 | @@ -1471,10 +1471,10 @@ at_xdmac_tx_status(struct dma_chan *chan | |
60 | for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { | |
61 | check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; | |
62 | rmb(); | |
63 | - initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); | |
64 | - rmb(); | |
65 | cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); | |
66 | rmb(); | |
67 | + initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); | |
68 | + rmb(); | |
69 | cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; | |
70 | rmb(); | |
71 |