summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/apbio.c
diff options
context:
space:
mode:
authorXin Xie <xxie@nvidia.com>2011-03-17 16:02:13 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:41:59 -0800
commitc4d9788f65b4939758dd0e2e98fe1af73aa85093 (patch)
tree2633ac6c5fdc55a08fa8f4fd08c6704440e0eab9 /arch/arm/mach-tegra/apbio.c
parent673bb291bd7d06ccf4e5a6664bae4e9f32e18a99 (diff)
[ARM]: tegra: fix APB DMA transfer timeout
In one bug report, the APB readl DMA transfer took up to 300mS. And after apb_readl() has the timeout, the kernel crashed due to the NULL pointer dereference. In the apb_readl(), after the timeout the tegra_dma_req is destroyed at the function return. But the DMA interrupt handler later will try to delete the same destroyed DMA request link list node which will cause the kernel crash. Fix this by dequeue the DMA request if the DMA transfer timeout happens. Reviewed-on: http://git-master/r/23413 (cherry picked from commit 41d4494d0d3235b8f0c605364d5bd0370f3d5323) Original-Change-Id: Id62b73ea4b81294a85ff1dfcfd96fede07f9497d Reviewed-on: http://git-master/r/23775 Reviewed-by: Jonathan Mayo <jmayo@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com> Tested-by: Bharat Nihalani <bnihalani@nvidia.com> Rebase-Id: R372818cbf33d71ce9b416577d8bcf339ee874352
Diffstat (limited to 'arch/arm/mach-tegra/apbio.c')
-rw-r--r--arch/arm/mach-tegra/apbio.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index b5e6caf20104..967c0fe1e74a 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -66,10 +66,12 @@ static inline u32 apb_readl(unsigned long offset)
tegra_dma_enqueue_req(tegra_apb_dma, &req);
ret = wait_for_completion_timeout(&tegra_apb_wait,
- msecs_to_jiffies(50));
+ msecs_to_jiffies(400));
- if (WARN(ret == 0, "apb read dma timed out"))
+ if (WARN(ret == 0, "apb read dma timed out")) {
+ tegra_dma_dequeue_req(tegra_apb_dma, &req);
*(u32 *)tegra_apb_bb = 0;
+ }
mutex_unlock(&tegra_apb_dma_lock);
return *((u32 *)tegra_apb_bb);
@@ -103,7 +105,10 @@ static inline void apb_writel(u32 value, unsigned long offset)
tegra_dma_enqueue_req(tegra_apb_dma, &req);
ret = wait_for_completion_timeout(&tegra_apb_wait,
- msecs_to_jiffies(50));
+ msecs_to_jiffies(400));
+
+ if (WARN(ret == 0, "apb write dma timed out"))
+ tegra_dma_dequeue_req(tegra_apb_dma, &req);
mutex_unlock(&tegra_apb_dma_lock);
}