summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorpopcornmix <popcornmix@gmail.com>2015-05-01 17:46:56 +0100
committerpopcornmix <popcornmix@gmail.com>2015-05-18 14:12:52 +0100
commit5d5b216323ff5dd030965b21983a72a350d6a33d (patch)
tree2936917266b922a47bdef9f1a46656128c94d93f /drivers
parentfe120f1eb52acddde33e12b03ebb16380f52fe51 (diff)
downloadlinux-5d5b216323ff5dd030965b21983a72a350d6a33d.tar.gz
bcm2835-mmc: Add locks when accessing sdhost registers
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/host/bcm2835-mmc.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c
index eef0d351768f..1c34f4769993 100644
--- a/drivers/mmc/host/bcm2835-mmc.c
+++ b/drivers/mmc/host/bcm2835-mmc.c
@@ -133,17 +133,20 @@ struct bcm2835_host {
static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg)
{
+ lockdep_assert_held_once(&host->lock);
writel(val, host->ioaddr + reg);
udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ)));
}
static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg)
{
+ lockdep_assert_held_once(&host->lock);
writel(val, host->ioaddr + reg);
}
static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg)
{
+ lockdep_assert_held_once(&host->lock);
return readl(host->ioaddr + reg);
}
@@ -255,7 +258,9 @@ static void bcm2835_mmc_dumpregs(struct bcm2835_host *host)
static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask)
{
unsigned long timeout;
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET);
if (mask & SDHCI_RESET_ALL)
@@ -273,19 +278,23 @@ static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask)
return;
}
timeout--;
+ spin_unlock_irqrestore(&host->lock, flags);
mdelay(1);
+ spin_lock_irqsave(&host->lock, flags);
}
if (100-timeout > 10 && 100-timeout > host->max_delay) {
host->max_delay = 100-timeout;
pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay);
}
+ spin_unlock_irqrestore(&host->lock, flags);
}
static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
{
+ unsigned long flags;
if (soft)
bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
else
@@ -297,8 +306,10 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
SDHCI_INT_RESPONSE;
+ spin_lock_irqsave(&host->lock, flags);
bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE);
bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ spin_unlock_irqrestore(&host->lock, flags);
if (soft) {
/* force clock reconfiguration */
@@ -497,11 +508,14 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host)
dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
}
if (desc) {
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
SDHCI_INT_SPACE_AVAIL);
host->tx_desc = desc;
desc->callback = bcm2835_mmc_dma_complete;
desc->callback_param = host;
+ spin_unlock_irqrestore(&host->lock, flags);
dmaengine_submit(desc);
dma_async_issue_pending(dma_chan);
}
@@ -1243,8 +1257,10 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param)
(mrq->data && (mrq->data->error ||
(mrq->data->stop && mrq->data->stop->error))))) {
+ spin_unlock_irqrestore(&host->lock, flags);
bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
+ spin_lock_irqsave(&host->lock, flags);
}
host->mrq = NULL;
@@ -1259,7 +1275,7 @@ static void bcm2835_mmc_tasklet_finish(unsigned long param)
-int bcm2835_mmc_add_host(struct bcm2835_host *host)
+static int bcm2835_mmc_add_host(struct bcm2835_host *host)
{
struct mmc_host *mmc = host->mmc;
struct device *dev = mmc->parent;
@@ -1287,8 +1303,6 @@ int bcm2835_mmc_add_host(struct bcm2835_host *host)
host->flags = SDHCI_AUTO_CMD23;
- spin_lock_init(&host->lock);
-
#ifdef FORCE_PIO
dev_info(dev, "Forcing PIO mode\n");
host->have_dma = false;