summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2010-08-26 10:18:40 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2010-09-03 02:38:07 -0700
commita537fc2dce58424510fc514eb499c544ae1ac96e (patch)
tree10ad8fa3c1d05891940cfde93849c14134a33d4f
parent2349860b3df60934e6c04a8684cb51e6e1d39549 (diff)
[arm/tegra] dma: Dma allocation should be thread safe
The dma can be allocated from multiple client in run time and so it should be thread/smp safe. Returning proper error pointer in case of there is no dma to allocate. bug 723220 Change-Id: Ifb333d4b14e32be561e34a0d7668a2d631ac80c6 (cherry picked from commit db2d10f715fcdd6fdaf5fc7ea8e27a505f8332da) Reviewed-on: http://git-master/r/5769 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> Tested-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/dma.c17
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c6
2 files changed, 18 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index 7eb0bb758b67..ad9f3a05a68b 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -132,6 +132,8 @@ struct tegra_dma_channel {
#define NV_DMA_MAX_CHANNELS 32
+static DEFINE_SPINLOCK(global_dma_lock);
+
static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
@@ -471,6 +473,9 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
{
int channel;
struct tegra_dma_channel *ch;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&global_dma_lock, irq_flags);
/* first channel is the shared channel */
if (mode & TEGRA_DMA_SHARED) {
@@ -478,10 +483,14 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
} else {
channel = find_first_zero_bit(channel_usage,
ARRAY_SIZE(dma_channels));
- if (channel >= ARRAY_SIZE(dma_channels))
- return ERR_PTR(ENODEV);
+ if (channel >= ARRAY_SIZE(dma_channels)) {
+ spin_unlock_irqrestore(&global_dma_lock, irq_flags);
+ return ERR_PTR(-ENODEV);
+ }
}
__set_bit(channel, channel_usage);
+ spin_unlock_irqrestore(&global_dma_lock, irq_flags);
+
ch = &dma_channels[channel];
ch->mode = mode;
return ch;
@@ -490,10 +499,14 @@ EXPORT_SYMBOL(tegra_dma_allocate_channel);
void tegra_dma_free_channel(struct tegra_dma_channel *ch)
{
+ unsigned long irq_flags;
if (ch->mode & TEGRA_DMA_SHARED)
return;
tegra_dma_cancel(ch);
+ spin_lock_irqsave(&global_dma_lock, irq_flags);
__clear_bit(ch->id, channel_usage);
+ spin_unlock_irqrestore(&global_dma_lock, irq_flags);
+
}
EXPORT_SYMBOL(tegra_dma_free_channel);
diff --git a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c
index cf7fd9493820..26ee1e1a6457 100644
--- a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c
+++ b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c
@@ -57,7 +57,7 @@
#include "linux/module.h"
#include "mach/dma.h"
-
+#include "linux/err.h"
// Combined maximum spi/slink controllers
#define MAX_SPI_SLINK_INSTANCE (MAX_SLINK_CONTROLLERS + MAX_SPI_CONTROLLERS)
@@ -513,10 +513,10 @@ static NvError AllocateDmas(NvRmSpiHandle hRmSpiSlink)
hRmSpiSlink->hTxDma = NULL;
hRmSpiSlink->hRxDma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
- if (hRmSpiSlink->hRxDma)
+ if (!IS_ERR_OR_NULL(hRmSpiSlink->hRxDma))
{
hRmSpiSlink->hTxDma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
- if (!hRmSpiSlink->hTxDma)
+ if (IS_ERR_OR_NULL(hRmSpiSlink->hTxDma))
{
tegra_dma_free_channel(hRmSpiSlink->hRxDma);
hRmSpiSlink->hRxDma = NULL;