linux/drivers/dma/pl330.c

3051 lines
68 KiB

dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dmaengine: pl330: do not generate unaligned access When PL330 is used with !MMU the following fault is seen: Unhandled fault: alignment exception (0x801) at 0x8f26a002 Internal error: : 801 [#1] ARM Modules linked in: CPU: 0 PID: 640 Comm: dma0chan0-copy0 Not tainted 4.8.0-6a82063-clean+ #1600 Hardware name: ARM-Versatile Express task: 8f1baa80 task.stack: 8e6fe000 PC is at _setup_req+0x4c/0x350 LR is at 0x8f2cbc00 pc : [<801ea538>] lr : [<8f2cbc00>] psr: 60000093 sp : 8e6ffdc0 ip : 00000000 fp : 00000000 r10: 00000000 r9 : 8f2cba10 r8 : 8f2cbc00 r7 : 80000013 r6 : 8f21a050 r5 : 8f21a000 r4 : 8f2ac800 r3 : 8e6ffe18 r2 : 00944251 r1 : ffffffbc r0 : 8f26a000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none Control: 00c5387c Process dma0chan0-copy0 (pid: 640, stack limit = 0x8e6fe210) Stack: (0x8e6ffdc0 to 0x8e700000) fdc0: 00000001 60000093 00000000 8f2cba10 8f26a000 00000004 8f0ae000 8f2cbc00 fde0: 8f0ae000 8f2ac800 8f21a000 8f21a050 80000013 8f2cbc00 8f2cba10 00000000 fe00: 60000093 801ebca0 8e6ffe18 000013ff 40000093 00000000 00944251 8f2ac800 fe20: a0000013 8f2b1320 00001986 00000000 00000001 000013ff 8f1e4f00 8f2cba10 fe40: 8e6fff6c 801e9044 00000003 00000000 fef98c80 002faf07 8e6ffe7c 00000000 fe60: 00000002 00000000 00001986 8f1f158d 8f1e4f00 80568de4 00000002 00000000 fe80: 00001986 8f1f53ff 40000001 80580500 8f1f158d 8001e00c 00000000 cfdfdfdf fea0: fdae2a25 00000001 00000004 8e6fe000 00000008 00000010 00000000 00000005 fec0: 8f2b1330 8f2b1334 8e6ffe80 8e6ffe8c 00001986 00000000 8f21a014 00000001 fee0: 8e6ffe60 8e6ffe78 00000002 00000000 000013ff 00000001 80568de4 8f1e8018 ff00: 0000158d 8055ec30 00000001 803f6b00 00001986 8f2cba10 fdae2a25 00000001 ff20: 8f1baca8 8e6fff24 8e6fff24 00000000 8e6fff24 ac6f3037 00000000 00000000 ff40: 00000000 8e6fe000 8f1e4f40 00000000 8f1e4f40 8f1e4f00 801e84ec 00000000 ff60: 00000000 00000000 00000000 80031714 dfdfdfcf 00000000 dfdfdfcf 8f1e4f00 ff80: 00000000 8e6fff84 8e6fff84 00000000 8e6fff90 8e6fff90 8e6fffac 8f1e4f40 ffa0: 80031640 00000000 00000000 8000f548 00000000 00000000 00000000 00000000 ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 dfdfdfcf cfdfdfdf [<801ea538>] (_setup_req) from [<801ebca0>] (pl330_tasklet+0x41c/0x490) [<801ebca0>] (pl330_tasklet) from [<801e9044>] (dmatest_func+0xb58/0x149c) [<801e9044>] (dmatest_func) from [<80031714>] (kthread+0xd4/0xec) [<80031714>] (kthread) from [<8000f548>] (ret_from_fork+0x14/0x2c) Code: e3a03001 e3e01043 e5c03001 e59d3048 (e5802002) This happens because _emit_{ADDH,MOV,GO) accessing to unaligned data while writing to buffer. Fix it with writing to buffer byte by byte. Reviewed-by: Robin Murphy <robin.murphy@arm.com> Tested-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2016-12-07 13:17:40 +00:00
dmaengine: pl330: do not generate unaligned access When PL330 is used with !MMU the following fault is seen: Unhandled fault: alignment exception (0x801) at 0x8f26a002 Internal error: : 801 [#1] ARM Modules linked in: CPU: 0 PID: 640 Comm: dma0chan0-copy0 Not tainted 4.8.0-6a82063-clean+ #1600 Hardware name: ARM-Versatile Express task: 8f1baa80 task.stack: 8e6fe000 PC is at _setup_req+0x4c/0x350 LR is at 0x8f2cbc00 pc : [<801ea538>] lr : [<8f2cbc00>] psr: 60000093 sp : 8e6ffdc0 ip : 00000000 fp : 00000000 r10: 00000000 r9 : 8f2cba10 r8 : 8f2cbc00 r7 : 80000013 r6 : 8f21a050 r5 : 8f21a000 r4 : 8f2ac800 r3 : 8e6ffe18 r2 : 00944251 r1 : ffffffbc r0 : 8f26a000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none Control: 00c5387c Process dma0chan0-copy0 (pid: 640, stack limit = 0x8e6fe210) Stack: (0x8e6ffdc0 to 0x8e700000) fdc0: 00000001 60000093 00000000 8f2cba10 8f26a000 00000004 8f0ae000 8f2cbc00 fde0: 8f0ae000 8f2ac800 8f21a000 8f21a050 80000013 8f2cbc00 8f2cba10 00000000 fe00: 60000093 801ebca0 8e6ffe18 000013ff 40000093 00000000 00944251 8f2ac800 fe20: a0000013 8f2b1320 00001986 00000000 00000001 000013ff 8f1e4f00 8f2cba10 fe40: 8e6fff6c 801e9044 00000003 00000000 fef98c80 002faf07 8e6ffe7c 00000000 fe60: 00000002 00000000 00001986 8f1f158d 8f1e4f00 80568de4 00000002 00000000 fe80: 00001986 8f1f53ff 40000001 80580500 8f1f158d 8001e00c 00000000 cfdfdfdf fea0: fdae2a25 00000001 00000004 8e6fe000 00000008 00000010 00000000 00000005 fec0: 8f2b1330 8f2b1334 8e6ffe80 8e6ffe8c 00001986 00000000 8f21a014 00000001 fee0: 8e6ffe60 8e6ffe78 00000002 00000000 000013ff 00000001 80568de4 8f1e8018 ff00: 0000158d 8055ec30 00000001 803f6b00 00001986 8f2cba10 fdae2a25 00000001 ff20: 8f1baca8 8e6fff24 8e6fff24 00000000 8e6fff24 ac6f3037 00000000 00000000 ff40: 00000000 8e6fe000 8f1e4f40 00000000 8f1e4f40 8f1e4f00 801e84ec 00000000 ff60: 00000000 00000000 00000000 80031714 dfdfdfcf 00000000 dfdfdfcf 8f1e4f00 ff80: 00000000 8e6fff84 8e6fff84 00000000 8e6fff90 8e6fff90 8e6fffac 8f1e4f40 ffa0: 80031640 00000000 00000000 8000f548 00000000 00000000 00000000 00000000 ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 dfdfdfcf cfdfdfdf [<801ea538>] (_setup_req) from [<801ebca0>] (pl330_tasklet+0x41c/0x490) [<801ebca0>] (pl330_tasklet) from [<801e9044>] (dmatest_func+0xb58/0x149c) [<801e9044>] (dmatest_func) from [<80031714>] (kthread+0xd4/0xec) [<80031714>] (kthread) from [<8000f548>] (ret_from_fork+0x14/0x2c) Code: e3a03001 e3e01043 e5c03001 e59d3048 (e5802002) This happens because _emit_{ADDH,MOV,GO) accessing to unaligned data while writing to buffer. Fix it with writing to buffer byte by byte. Reviewed-by: Robin Murphy <robin.murphy@arm.com> Tested-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2016-12-07 13:17:40 +00:00
dmaengine: pl330: fix bug that cause start the same descs in cyclic This bug will cause NULL pointer after commit dfac17, and cause wrong package in I2S DMA transfer before commit dfac17. Tested on RK3288-pinky2 board. Detail: I2S DMA transfer(sound/core/pcm_dmaengine.c): dmaengine_pcm_prepare_and_submit --> dmaengine_prep_dma_cyclic --> pl330_prep_dma_cyclic --> the case: 1. pl330_submit_req(desc0): thrd->req[0].desc = desc0, thrd->lstenq = 0 2. pl330_submit_req(desc1): thrd->req[1].desc = desc1, thrd->lstenq = 1 3. _start(desc0) by submit_req: thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 0 4. pl330_update(desc0 OK): thrd->req[0].desc = NULL, desc0 to req_done list because: idx = active = thrd->req_running = 0 5. _start(desc1) by pl330_update: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 0, but thrd->req[0].desc == NULL, so: idx = thrd->lstenq = 1 6. pl330_submit_req(desc2): thrd->req[0].desc = desc2, thrd->lstenq = 0 7. _start(desc1) by submit_req: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 1 Note: _start started the same descs _start should start desc2 here, NOT desc1 8. pl330_update(desc1 OK): thrd->req[1].desc = NULL, desc1 to req_done list because: idx = active = thrd->req_running = 1 9. _start(desc2) by pl330_update : thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 0 10.pl330_update(desc1 OK, NOT desc2): thrd->req[0].desc = NULL, desc2 to req_done list because: idx = active = thrd->req_running = 0 11.pl330_submit_req(desc3): thrd->req[0].desc = desc3, thrd->lstenq = 0 12.pl330_submit_req(desc4): thrd->req[1].desc = desc4, thrd->lstenq = 1 13._start(desc3) by submit_req: thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 0 14.pl330_update(desc2 OK NOT desc3): thrd->req[0].desc = NULL desc3 to req_done list because: idx = active = thrd->req_running = 0 15._start(desc4) by pl330_update: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 0, but thrd->req[0].desc == NULL, so: idx = thrd->lstenq = 1 16.pl330_submit_req(desc5): thrd->req[0].desc = desc5, thrd->lstenq = 0 17._start(desc4) by submit_req: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 1 18.pl330_update(desc3 OK NOT desc4): thrd->req[1].desc = NULL desc4 to req_done list because: idx = active = thrd->req_running = 1 19._start(desc4) by pl330_update: thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 1, but thrd->req[1].desc == NULL, so: idx = thrd->lstenq = 0 20.pl330_update(desc4 OK): thrd->req[0].desc = NULL, desc5 to req_done list because: idx = active = thrd->req_running = 0 21.pl330_update(desc4 OK): 1) before commit dfac17(set req_running -1 in pl330_update/mark_free()): because: active = -1, abort result: desc0-desc5's callback are all called, but step 10 and step 18 go wrong. 2) before commit dfac17: idx = active = thrd->req_runnig = 0 --> descdone = thrd->req[0] = NULL --> list_add_tail(&descdone->rqd, &pl330->req_done); --> got NULL pointer!!! Signed-off-by: Addy Ke <addy.ke@rock-chips.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-12-08 19:28:20 +08:00
dmaengine: pl330: fix bug that cause start the same descs in cyclic This bug will cause NULL pointer after commit dfac17, and cause wrong package in I2S DMA transfer before commit dfac17. Tested on RK3288-pinky2 board. Detail: I2S DMA transfer(sound/core/pcm_dmaengine.c): dmaengine_pcm_prepare_and_submit --> dmaengine_prep_dma_cyclic --> pl330_prep_dma_cyclic --> the case: 1. pl330_submit_req(desc0): thrd->req[0].desc = desc0, thrd->lstenq = 0 2. pl330_submit_req(desc1): thrd->req[1].desc = desc1, thrd->lstenq = 1 3. _start(desc0) by submit_req: thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 0 4. pl330_update(desc0 OK): thrd->req[0].desc = NULL, desc0 to req_done list because: idx = active = thrd->req_running = 0 5. _start(desc1) by pl330_update: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 0, but thrd->req[0].desc == NULL, so: idx = thrd->lstenq = 1 6. pl330_submit_req(desc2): thrd->req[0].desc = desc2, thrd->lstenq = 0 7. _start(desc1) by submit_req: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 1 Note: _start started the same descs _start should start desc2 here, NOT desc1 8. pl330_update(desc1 OK): thrd->req[1].desc = NULL, desc1 to req_done list because: idx = active = thrd->req_running = 1 9. _start(desc2) by pl330_update : thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 0 10.pl330_update(desc1 OK, NOT desc2): thrd->req[0].desc = NULL, desc2 to req_done list because: idx = active = thrd->req_running = 0 11.pl330_submit_req(desc3): thrd->req[0].desc = desc3, thrd->lstenq = 0 12.pl330_submit_req(desc4): thrd->req[1].desc = desc4, thrd->lstenq = 1 13._start(desc3) by submit_req: thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 0 14.pl330_update(desc2 OK NOT desc3): thrd->req[0].desc = NULL desc3 to req_done list because: idx = active = thrd->req_running = 0 15._start(desc4) by pl330_update: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 0, but thrd->req[0].desc == NULL, so: idx = thrd->lstenq = 1 16.pl330_submit_req(desc5): thrd->req[0].desc = desc5, thrd->lstenq = 0 17._start(desc4) by submit_req: thrd->req_running = 1 because: idx = 1 - thrd->lstenq = 1 18.pl330_update(desc3 OK NOT desc4): thrd->req[1].desc = NULL desc4 to req_done list because: idx = active = thrd->req_running = 1 19._start(desc4) by pl330_update: thrd->req_running = 0 because: idx = 1 - thrd->lstenq = 1, but thrd->req[1].desc == NULL, so: idx = thrd->lstenq = 0 20.pl330_update(desc4 OK): thrd->req[0].desc = NULL, desc5 to req_done list because: idx = active = thrd->req_running = 0 21.pl330_update(desc4 OK): 1) before commit dfac17(set req_running -1 in pl330_update/mark_free()): because: active = -1, abort result: desc0-desc5's callback are all called, but step 10 and step 18 go wrong. 2) before commit dfac17: idx = active = thrd->req_runnig = 0 --> descdone = thrd->req[0] = NULL --> list_add_tail(&descdone->rqd, &pl330->req_done); --> got NULL pointer!!! Signed-off-by: Addy Ke <addy.ke@rock-chips.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-12-08 19:28:20 +08:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dmaengine: pl330: fix double lock The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2017-01-11 14:00:21 +01:00
dmaengine: pl330: fix double lock The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2017-01-11 14:00:21 +01:00
dmaengine: pl330: fix double lock The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2017-01-11 14:00:21 +01:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dmaengine: pl330: fix double lock The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2017-01-11 14:00:21 +01:00
dmaengine: pl330: fix double lock The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2017-01-11 14:00:21 +01:00
dmaengine: pl330: fix double lock The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2017-01-11 14:00:21 +01:00
dma: pl330: ensure DMA descriptors are zero-initialised I see the following splat with 3.13-rc1 when attempting to perform DMA: [ 253.004516] Alignment trap: not handling instruction e1902f9f at [<c0204b40>] [ 253.004583] Unhandled fault: alignment exception (0x221) at 0xdfdfdfd7 [ 253.004646] Internal error: : 221 [#1] PREEMPT SMP ARM [ 253.004691] Modules linked in: dmatest(+) [last unloaded: dmatest] [ 253.004798] CPU: 0 PID: 671 Comm: kthreadd Not tainted 3.13.0-rc1+ #2 [ 253.004864] task: df9b0900 ti: df03e000 task.ti: df03e000 [ 253.004937] PC is at dmaengine_unmap_put+0x14/0x34 [ 253.005010] LR is at pl330_tasklet+0x3c8/0x550 [ 253.005087] pc : [<c0204b44>] lr : [<c0207478>] psr: a00e0193 [ 253.005087] sp : df03fe48 ip : 00000000 fp : df03bf18 [ 253.005178] r10: bf00e108 r9 : 00000001 r8 : 00000000 [ 253.005245] r7 : df837040 r6 : dfb41800 r5 : df837048 r4 : df837000 [ 253.005316] r3 : dfdfdfcf r2 : dfb41f80 r1 : df837048 r0 : dfdfdfd7 [ 253.005384] Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel [ 253.005459] Control: 30c5387d Table: 9fb9ba80 DAC: fffffffd [ 253.005520] Process kthreadd (pid: 671, stack limit = 0xdf03e248) This is due to desc->txd.unmap containing garbage (uninitialised memory). Rather than add another dummy initialisation to _init_desc, instead ensure that the descriptors are zero-initialised during allocation and remove the dummy, per-field initialisation. Cc: Andriy Shevchenko <andriy.shevchenko@intel.com> Acked-by: Jassi Brar <jassisinghbrar@gmail.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2013-12-02 18:01:30 +00:00
dmaengine: pl330: Correct device assignment. Commit f6f2421c0a1c removed pl330_info structure by embedding it into pl330_dmac structure, but did not ensure that the dmac->ddma.dev pointer gets initialised before use. When dma_alloc_coherent() gets called on arm64 a WARN() gets triggered due to dev being NULL. ------------[ cut here ]------------ WARNING: CPU: 1 PID: 1 at arch/arm64/mm/dma-mapping.c:49 __dma_alloc_coherent+0xd0/0xe0() Use an actual device structure for DMA allocation Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 3.17.0+ #5 Call trace: [<ffffffc000087f24>] dump_backtrace+0x0/0x130 [<ffffffc000088064>] show_stack+0x10/0x1c [<ffffffc0004e8af8>] dump_stack+0x74/0xb8 [<ffffffc0000aa444>] warn_slowpath_common+0x8c/0xb4 [<ffffffc0000aa4b8>] warn_slowpath_fmt+0x4c/0x58 [<ffffffc000092580>] __dma_alloc_coherent+0xcc/0xe0 [<ffffffc000092734>] __dma_alloc_noncoherent+0x64/0x158 [<ffffffc000312cd8>] pl330_probe+0x650/0x8f0 [<ffffffc00030e1d4>] amba_probe+0xa0/0xc8 [<ffffffc000350240>] really_probe+0xc4/0x22c [<ffffffc0003504b4>] __driver_attach+0xa0/0xa8 [<ffffffc00034e5fc>] bus_for_each_dev+0x54/0x98 [<ffffffc00034fd8c>] driver_attach+0x1c/0x28 [<ffffffc00034fa08>] bus_add_driver+0x14c/0x204 [<ffffffc000350b84>] driver_register+0x64/0x130 [<ffffffc00030dcf8>] amba_driver_register+0x50/0x5c [<ffffffc0006a60d0>] pl330_driver_init+0x10/0x1c [<ffffffc0000814ac>] do_one_initcall+0x88/0x19c [<ffffffc00068dab8>] kernel_init_freeable+0x140/0x1e0 [<ffffffc0004e5e18>] kernel_init+0x10/0xd4 ---[ end trace 76f2d47a444e523e ]--- (NULL device *): dmac_alloc_resources:1821 Can't allocate memory! (NULL device *): Unable to create channels for DMAC This patch will also ensure that any dev_err messages are printed with the appropriate device name. Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Signed-off-by: Andrew Jackson <Andrew.Jackson@arm.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-11-06 11:39:47 +00:00
dma: pl330: Fix handling of TERMINATE_ALL while processing completed descriptors The pl330 DMA driver is broken in regard to handling a terminate all request while it is processing the list of completed descriptors. This is most visible when calling dmaengine_terminate_all() from within the descriptors callback for cyclic transfers. In this case the TERMINATE_ALL transfer will clear the work_list and stop the transfer. But after all callbacks for all completed descriptors have been handled the descriptors will be re-enqueued into the (now empty) work_list. So the next time dma_async_issue_pending() is called for the channel these descriptors will be transferred again which will cause data corruption. Similar issues can occur if dmaengine_terminate_all() is not called from within the descriptor callback but runs on a different CPU at the same time as the completed descriptor list is processed. This patch introduces a new per channel list which will hold the completed descriptors. While processing the list the channel's lock will be held to avoid racing against dmaengine_terminate_all(). The lock will be released when calling the descriptors callback though. Since the list of completed descriptors might be modified (e.g. by calling dmaengine_terminate_all() from the callback) we can not use the normal list iterator macros. Instead we'll need to check for each loop iteration again if there are still items in the list. The drivers TERMINATE_ALL implementation is updated to move descriptors from both the work_list as well the new completed_list back to the descriptor pool. This makes sure that none of the descripts finds its way back into the work list and also that we do not call any futher complete callbacks after dmaengine_terminate_all() has been called. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2013-08-27 20:34:05 +02:00
dmaengine: pl330: Fix NULL pointer dereference on probe failure If dma_async_device_register() returns error and probe should clean up and return error, a NULL pointer exception happens because of dereference of not allocated channel thread: Dmesg log (from early printk): dma-pl330 12680000.pdma: unable to register DMAC DMA pl330_control: removing pch: eeac4000, chan: eeac4014, thread: (null) Unable to handle kernel NULL pointer dereference at virtual address 0000000c pgd = c0004000 [0000000c] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 2 PID: 1 Comm: swapper/0 Not tainted 3.17.0-rc3-next-20140904-00005-g6cc4c1937d90-dirty #427 task: ee80a800 ti: ee888000 task.ti: ee888000 PC is at _stop+0x8/0x2c8 LR is at pl330_control+0x70/0x2e8 pc : [<c0205dc8>] lr : [<c020623c>] psr: 60000193 sp : ee889df8 ip : 00000002 fp : 00000000 r10: eeac4014 r9 : ee0e62bc r8 : 00000000 r7 : eeac405c r6 : 60000113 r5 : ee0e6210 r4 : eeac4000 r3 : 00000002 r2 : 00000002 r1 : 00010000 r0 : 00000000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 4000404a DAC: 00000015 Process swapper/0 (pid: 1, stack limit = 0xee888240) Stack: (0xee889df8 to 0xee88a000) 9de0: 00000002 eeac4000 9e00: ee0e6210 eeac4000 ee0e6210 60000113 eeac405c c020623c 00000000 c020725c 9e20: ee889e20 ee889e20 ee0e6210 eeac4080 00200200 00100100 eeac4014 00000020 9e40: ee0e6218 c0208374 00000000 ee9bb340 ee0e6210 00000000 00000000 c0605cd8 9e60: ee970000 c0605c84 ee9700f8 00000000 c05c4270 00000000 00000000 c0203b3c 9e80: ee970000 c06624a8 00000000 c0605c84 00000000 c023f890 ee970000 c0605c84 9ea0: ee970034 00000000 c05b23d0 c023fa3c 00000000 c0605c84 c023f9b0 c023e0d4 9ec0: ee947e78 ee9b9440 c0605c84 eea1e780 c0605acc c023f094 c0513b50 c0605c84 9ee0: c05ecbd8 c0605c84 c05ecbd8 ee11ba40 c0626500 c0240064 00000000 c05ecbd8 9f00: c05ecbd8 c0008964 c040f13c 0000009f c0626500 c057465c ee80a800 60000113 9f20: 00000000 c05efdb0 60000113 00000000 ef7fc89d c0421168 0000008f c003787c 9f40: c0573d6c 00000006 ef7fc8bb 00000006 c05efd50 ef7fc800 c05dfbc4 00000006 9f60: c05c4264 c0626500 0000008f c05c4270 c059b518 c059bcb4 00000006 00000006 9f80: c059b518 c003c08c 00000000 c040091c 00000000 00000000 00000000 00000000 9fa0: 00000000 c0400924 00000000 c000e7b8 00000000 00000000 00000000 00000000 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 c0c0c0c0 c0c0c0c0 [<c0205dc8>] (_stop) from [<c020623c>] (pl330_control+0x70/0x2e8) [<c020623c>] (pl330_control) from [<c0208374>] (pl330_probe+0x594/0x75c) [<c0208374>] (pl330_probe) from [<c0203b3c>] (amba_probe+0xb8/0x120) [<c0203b3c>] (amba_probe) from [<c023f890>] (driver_probe_device+0x10c/0x22c) [<c023f890>] (driver_probe_device) from [<c023fa3c>] (__driver_attach+0x8c/0x90) [<c023fa3c>] (__driver_attach) from [<c023e0d4>] (bus_for_each_dev+0x54/0x88) [<c023e0d4>] (bus_for_each_dev) from [<c023f094>] (bus_add_driver+0xd4/0x1d0) [<c023f094>] (bus_add_driver) from [<c0240064>] (driver_register+0x78/0xf4) [<c0240064>] (driver_register) from [<c0008964>] (do_one_initcall+0x80/0x1d0) [<c0008964>] (do_one_initcall) from [<c059bcb4>] (kernel_init_freeable+0x108/0x1d4) [<c059bcb4>] (kernel_init_freeable) from [<c0400924>] (kernel_init+0x8/0xec) [<c0400924>] (kernel_init) from [<c000e7b8>] (ret_from_fork+0x14/0x3c) Code: e5813010 e12fff1e e92d40f0 e24dd00c (e590200c) ---[ end trace c94b2f4f38dff3bf ]--- This happens because the necessary resources were not yet allocated - no call to pl330_alloc_chan_resources(). Terminate the thread and free channel resource only if channel thread is not NULL. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Cc: <stable@vger.kernel.org> Fixes: 0b94c5771705 ("DMA: PL330: Add check if device tree compatible") Reviewed-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-09-29 14:42:20 +02:00
dmaengine: pl330: Fix NULL pointer dereference on probe failure If dma_async_device_register() returns error and probe should clean up and return error, a NULL pointer exception happens because of dereference of not allocated channel thread: Dmesg log (from early printk): dma-pl330 12680000.pdma: unable to register DMAC DMA pl330_control: removing pch: eeac4000, chan: eeac4014, thread: (null) Unable to handle kernel NULL pointer dereference at virtual address 0000000c pgd = c0004000 [0000000c] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 2 PID: 1 Comm: swapper/0 Not tainted 3.17.0-rc3-next-20140904-00005-g6cc4c1937d90-dirty #427 task: ee80a800 ti: ee888000 task.ti: ee888000 PC is at _stop+0x8/0x2c8 LR is at pl330_control+0x70/0x2e8 pc : [<c0205dc8>] lr : [<c020623c>] psr: 60000193 sp : ee889df8 ip : 00000002 fp : 00000000 r10: eeac4014 r9 : ee0e62bc r8 : 00000000 r7 : eeac405c r6 : 60000113 r5 : ee0e6210 r4 : eeac4000 r3 : 00000002 r2 : 00000002 r1 : 00010000 r0 : 00000000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 4000404a DAC: 00000015 Process swapper/0 (pid: 1, stack limit = 0xee888240) Stack: (0xee889df8 to 0xee88a000) 9de0: 00000002 eeac4000 9e00: ee0e6210 eeac4000 ee0e6210 60000113 eeac405c c020623c 00000000 c020725c 9e20: ee889e20 ee889e20 ee0e6210 eeac4080 00200200 00100100 eeac4014 00000020 9e40: ee0e6218 c0208374 00000000 ee9bb340 ee0e6210 00000000 00000000 c0605cd8 9e60: ee970000 c0605c84 ee9700f8 00000000 c05c4270 00000000 00000000 c0203b3c 9e80: ee970000 c06624a8 00000000 c0605c84 00000000 c023f890 ee970000 c0605c84 9ea0: ee970034 00000000 c05b23d0 c023fa3c 00000000 c0605c84 c023f9b0 c023e0d4 9ec0: ee947e78 ee9b9440 c0605c84 eea1e780 c0605acc c023f094 c0513b50 c0605c84 9ee0: c05ecbd8 c0605c84 c05ecbd8 ee11ba40 c0626500 c0240064 00000000 c05ecbd8 9f00: c05ecbd8 c0008964 c040f13c 0000009f c0626500 c057465c ee80a800 60000113 9f20: 00000000 c05efdb0 60000113 00000000 ef7fc89d c0421168 0000008f c003787c 9f40: c0573d6c 00000006 ef7fc8bb 00000006 c05efd50 ef7fc800 c05dfbc4 00000006 9f60: c05c4264 c0626500 0000008f c05c4270 c059b518 c059bcb4 00000006 00000006 9f80: c059b518 c003c08c 00000000 c040091c 00000000 00000000 00000000 00000000 9fa0: 00000000 c0400924 00000000 c000e7b8 00000000 00000000 00000000 00000000 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 c0c0c0c0 c0c0c0c0 [<c0205dc8>] (_stop) from [<c020623c>] (pl330_control+0x70/0x2e8) [<c020623c>] (pl330_control) from [<c0208374>] (pl330_probe+0x594/0x75c) [<c0208374>] (pl330_probe) from [<c0203b3c>] (amba_probe+0xb8/0x120) [<c0203b3c>] (amba_probe) from [<c023f890>] (driver_probe_device+0x10c/0x22c) [<c023f890>] (driver_probe_device) from [<c023fa3c>] (__driver_attach+0x8c/0x90) [<c023fa3c>] (__driver_attach) from [<c023e0d4>] (bus_for_each_dev+0x54/0x88) [<c023e0d4>] (bus_for_each_dev) from [<c023f094>] (bus_add_driver+0xd4/0x1d0) [<c023f094>] (bus_add_driver) from [<c0240064>] (driver_register+0x78/0xf4) [<c0240064>] (driver_register) from [<c0008964>] (do_one_initcall+0x80/0x1d0) [<c0008964>] (do_one_initcall) from [<c059bcb4>] (kernel_init_freeable+0x108/0x1d4) [<c059bcb4>] (kernel_init_freeable) from [<c0400924>] (kernel_init+0x8/0xec) [<c0400924>] (kernel_init) from [<c000e7b8>] (ret_from_fork+0x14/0x3c) Code: e5813010 e12fff1e e92d40f0 e24dd00c (e590200c) ---[ end trace c94b2f4f38dff3bf ]--- This happens because the necessary resources were not yet allocated - no call to pl330_alloc_chan_resources(). Terminate the thread and free channel resource only if channel thread is not NULL. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Cc: <stable@vger.kernel.org> Fixes: 0b94c5771705 ("DMA: PL330: Add check if device tree compatible") Reviewed-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-09-29 14:42:20 +02:00
dmaengine: pl330: Fix NULL pointer dereference on driver unbind Fix a NULL pointer dereference after unbinding the driver, if channel resources were not yet allocated (no call to pl330_alloc_chan_resources()): $ echo 12850000.mdma > /sys/bus/amba/drivers/dma-pl330/unbind [ 13.606533] DMA pl330_control: removing pch: eeab6800, chan: eeab6814, thread: (null) [ 13.614472] Unable to handle kernel NULL pointer dereference at virtual address 0000000c [ 13.622537] pgd = ee284000 [ 13.625228] [0000000c] *pgd=6e1e4831, *pte=00000000, *ppte=00000000 [ 13.631482] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 13.636859] Modules linked in: [ 13.639903] CPU: 0 PID: 1 Comm: sh Not tainted 3.17.0-rc3-next-20140904-00004-g7020ffc33ca3-dirty #420 [ 13.649187] task: ee80a800 ti: ee888000 task.ti: ee888000 [ 13.654589] PC is at _stop+0x8/0x2c8 [ 13.658131] LR is at pl330_control+0x70/0x2e8 [ 13.662468] pc : [<c0206028>] lr : [<c020649c>] psr: 60000093 [ 13.662468] sp : ee889e58 ip : 00000001 fp : 000bab70 [ 13.673922] r10: eeab6814 r9 : ee16debc r8 : 00000000 [ 13.679131] r7 : eeab685c r6 : 60000013 r5 : ee16de10 r4 : eeab6800 [ 13.685641] r3 : 00000002 r2 : 00000000 r1 : 00010000 r0 : 00000000 [ 13.692153] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 13.699357] Control: 10c5387d Table: 6e28404a DAC: 00000015 [ 13.705085] Process sh (pid: 1, stack limit = 0xee888240) [ 13.710466] Stack: (0xee889e58 to 0xee88a000) [ 13.714808] 9e40: 00000002 eeab6800 [ 13.722969] 9e60: ee16de10 eeab6800 ee16de10 60000013 eeab685c c020649c 00000000 c040280c [ 13.731128] 9e80: ee889e80 ee889e80 ee16de18 ee16de10 eeab6880 eeab6814 00200200 eeab68a8 [ 13.739287] 9ea0: 00100100 c0208048 00000000 c0409fc4 eea80800 eea808f8 c0605c44 0000000e [ 13.747446] 9ec0: 0000000e eeb3960c eeb39600 c0203c48 eea80800 c0605c44 c0605a8c c023f694 [ 13.755605] 9ee0: ee80a800 eea80834 eea80800 c023f704 ee80a800 eea80800 c0605c44 c023e8ec [ 13.763764] 9f00: 0000000e ee149780 ee29e580 ee889f80 ee29e580 c023e19c 0000000e c01167e4 [ 13.771923] 9f20: c01167a0 00000000 00000000 c0115e88 00000000 00000000 ee0b1a00 0000000e [ 13.780082] 9f40: b6f48000 ee889f80 0000000e ee888000 b6f48000 c00bfadc 00000000 00000003 [ 13.788241] 9f60: 00000000 00000000 00000000 ee0b1a00 ee0b1a00 0000000e b6f48000 c00bfdf4 [ 13.796401] 9f80: 00000000 00000000 ffffffff 0000000e b6f48000 b6edc5d0 00000004 c000e7a4 [ 13.804560] 9fa0: 00000000 c000e620 0000000e b6f48000 00000001 b6f48000 0000000e 00000000 [ 13.812719] 9fc0: 0000000e b6f48000 b6edc5d0 00000004 0000000e b6f4c8c0 000c3470 000bab70 [ 13.820879] 9fe0: 00000000 bed2aa50 b6e18bdc b6e6b52c 60000010 00000001 c0c0c0c0 c0c0c0c0 [ 13.829058] [<c0206028>] (_stop) from [<c020649c>] (pl330_control+0x70/0x2e8) [ 13.836165] [<c020649c>] (pl330_control) from [<c0208048>] (pl330_remove+0xb0/0xdc) [ 13.843800] [<c0208048>] (pl330_remove) from [<c0203c48>] (amba_remove+0x24/0xc0) [ 13.851272] [<c0203c48>] (amba_remove) from [<c023f694>] (__device_release_driver+0x70/0xc4) [ 13.859685] [<c023f694>] (__device_release_driver) from [<c023f704>] (device_release_driver+0x1c/0x28) [ 13.868971] [<c023f704>] (device_release_driver) from [<c023e8ec>] (unbind_store+0x58/0x90) [ 13.877303] [<c023e8ec>] (unbind_store) from [<c023e19c>] (drv_attr_store+0x20/0x2c) [ 13.885036] [<c023e19c>] (drv_attr_store) from [<c01167e4>] (sysfs_kf_write+0x44/0x48) [ 13.892928] [<c01167e4>] (sysfs_kf_write) from [<c0115e88>] (kernfs_fop_write+0xc0/0x17c) [ 13.901090] [<c0115e88>] (kernfs_fop_write) from [<c00bfadc>] (vfs_write+0xa0/0x1a8) [ 13.908812] [<c00bfadc>] (vfs_write) from [<c00bfdf4>] (SyS_write+0x40/0x8c) [ 13.915850] [<c00bfdf4>] (SyS_write) from [<c000e620>] (ret_fast_syscall+0x0/0x30) [ 13.923392] Code: e5813010 e12fff1e e92d40f0 e24dd00c (e590200c) [ 13.929467] ---[ end trace 10064e15a5929cf8 ]--- Terminate the thread and free channel resource only if channel resources were allocated (thread is not NULL). Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Cc: <stable@vger.kernel.org> Fixes: b3040e40675e ("DMA: PL330: Add dma api driver") Reviewed-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-09-29 14:42:21 +02:00
dmaengine: pl330: Fix NULL pointer dereference on driver unbind Fix a NULL pointer dereference after unbinding the driver, if channel resources were not yet allocated (no call to pl330_alloc_chan_resources()): $ echo 12850000.mdma > /sys/bus/amba/drivers/dma-pl330/unbind [ 13.606533] DMA pl330_control: removing pch: eeab6800, chan: eeab6814, thread: (null) [ 13.614472] Unable to handle kernel NULL pointer dereference at virtual address 0000000c [ 13.622537] pgd = ee284000 [ 13.625228] [0000000c] *pgd=6e1e4831, *pte=00000000, *ppte=00000000 [ 13.631482] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 13.636859] Modules linked in: [ 13.639903] CPU: 0 PID: 1 Comm: sh Not tainted 3.17.0-rc3-next-20140904-00004-g7020ffc33ca3-dirty #420 [ 13.649187] task: ee80a800 ti: ee888000 task.ti: ee888000 [ 13.654589] PC is at _stop+0x8/0x2c8 [ 13.658131] LR is at pl330_control+0x70/0x2e8 [ 13.662468] pc : [<c0206028>] lr : [<c020649c>] psr: 60000093 [ 13.662468] sp : ee889e58 ip : 00000001 fp : 000bab70 [ 13.673922] r10: eeab6814 r9 : ee16debc r8 : 00000000 [ 13.679131] r7 : eeab685c r6 : 60000013 r5 : ee16de10 r4 : eeab6800 [ 13.685641] r3 : 00000002 r2 : 00000000 r1 : 00010000 r0 : 00000000 [ 13.692153] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 13.699357] Control: 10c5387d Table: 6e28404a DAC: 00000015 [ 13.705085] Process sh (pid: 1, stack limit = 0xee888240) [ 13.710466] Stack: (0xee889e58 to 0xee88a000) [ 13.714808] 9e40: 00000002 eeab6800 [ 13.722969] 9e60: ee16de10 eeab6800 ee16de10 60000013 eeab685c c020649c 00000000 c040280c [ 13.731128] 9e80: ee889e80 ee889e80 ee16de18 ee16de10 eeab6880 eeab6814 00200200 eeab68a8 [ 13.739287] 9ea0: 00100100 c0208048 00000000 c0409fc4 eea80800 eea808f8 c0605c44 0000000e [ 13.747446] 9ec0: 0000000e eeb3960c eeb39600 c0203c48 eea80800 c0605c44 c0605a8c c023f694 [ 13.755605] 9ee0: ee80a800 eea80834 eea80800 c023f704 ee80a800 eea80800 c0605c44 c023e8ec [ 13.763764] 9f00: 0000000e ee149780 ee29e580 ee889f80 ee29e580 c023e19c 0000000e c01167e4 [ 13.771923] 9f20: c01167a0 00000000 00000000 c0115e88 00000000 00000000 ee0b1a00 0000000e [ 13.780082] 9f40: b6f48000 ee889f80 0000000e ee888000 b6f48000 c00bfadc 00000000 00000003 [ 13.788241] 9f60: 00000000 00000000 00000000 ee0b1a00 ee0b1a00 0000000e b6f48000 c00bfdf4 [ 13.796401] 9f80: 00000000 00000000 ffffffff 0000000e b6f48000 b6edc5d0 00000004 c000e7a4 [ 13.804560] 9fa0: 00000000 c000e620 0000000e b6f48000 00000001 b6f48000 0000000e 00000000 [ 13.812719] 9fc0: 0000000e b6f48000 b6edc5d0 00000004 0000000e b6f4c8c0 000c3470 000bab70 [ 13.820879] 9fe0: 00000000 bed2aa50 b6e18bdc b6e6b52c 60000010 00000001 c0c0c0c0 c0c0c0c0 [ 13.829058] [<c0206028>] (_stop) from [<c020649c>] (pl330_control+0x70/0x2e8) [ 13.836165] [<c020649c>] (pl330_control) from [<c0208048>] (pl330_remove+0xb0/0xdc) [ 13.843800] [<c0208048>] (pl330_remove) from [<c0203c48>] (amba_remove+0x24/0xc0) [ 13.851272] [<c0203c48>] (amba_remove) from [<c023f694>] (__device_release_driver+0x70/0xc4) [ 13.859685] [<c023f694>] (__device_release_driver) from [<c023f704>] (device_release_driver+0x1c/0x28) [ 13.868971] [<c023f704>] (device_release_driver) from [<c023e8ec>] (unbind_store+0x58/0x90) [ 13.877303] [<c023e8ec>] (unbind_store) from [<c023e19c>] (drv_attr_store+0x20/0x2c) [ 13.885036] [<c023e19c>] (drv_attr_store) from [<c01167e4>] (sysfs_kf_write+0x44/0x48) [ 13.892928] [<c01167e4>] (sysfs_kf_write) from [<c0115e88>] (kernfs_fop_write+0xc0/0x17c) [ 13.901090] [<c0115e88>] (kernfs_fop_write) from [<c00bfadc>] (vfs_write+0xa0/0x1a8) [ 13.908812] [<c00bfadc>] (vfs_write) from [<c00bfdf4>] (SyS_write+0x40/0x8c) [ 13.915850] [<c00bfdf4>] (SyS_write) from [<c000e620>] (ret_fast_syscall+0x0/0x30) [ 13.923392] Code: e5813010 e12fff1e e92d40f0 e24dd00c (e590200c) [ 13.929467] ---[ end trace 10064e15a5929cf8 ]--- Terminate the thread and free channel resource only if channel resources were allocated (thread is not NULL). Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Cc: <stable@vger.kernel.org> Fixes: b3040e40675e ("DMA: PL330: Add dma api driver") Reviewed-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
2014-09-29 14:42:21 +02:00