From 1c912e0e91c0d27e4af90e24da537745b9a6e238 Mon Sep 17 00:00:00 2001 From: lintao Date: Mon, 22 Sep 2014 10:14:03 +0800 Subject: [PATCH] mmc: add atomic operation for register --- drivers/mmc/host/rk_sdmmc.c | 29 +++++++++++++++++++++++++---- include/linux/mmc/rk_mmc.h | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/rk_sdmmc.c b/drivers/mmc/host/rk_sdmmc.c index 57fd3ea65c30..59d3299b9b6a 100755 --- a/drivers/mmc/host/rk_sdmmc.c +++ b/drivers/mmc/host/rk_sdmmc.c @@ -872,6 +872,7 @@ disable: static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) { int sg_len; + unsigned long flags; u32 temp; host->using_dma = 0; @@ -910,9 +911,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) mci_writel(host, CTRL, temp); /* Disable RX/TX IRQs, let DMA handle it */ + spin_lock_irqsave(&host->slock, flags); temp = mci_readl(host, INTMASK); temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->slock, flags); host->dma_ops->start(host, sg_len); @@ -922,6 +925,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) { u32 temp; + unsigned long flag; data->error = -EINPROGRESS; @@ -954,10 +958,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->part_buf_start = 0; host->part_buf_count = 0; + spin_lock_irqsave(&host->slock, flag); mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); temp = mci_readl(host, INTMASK); temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->slock, flag); temp = mci_readl(host, CTRL); temp &= ~SDMMC_CTRL_DMA_ENABLE; @@ -1704,11 +1710,11 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) { struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; - //unsigned long flags; + unsigned long flags; u32 int_mask; u32 sdio_int; - //spin_lock_irqsave(&host->lock, flags); + spin_lock_irqsave(&host->slock, flags); /* Enable/disable Slot Specific SDIO interrupt */ int_mask = mci_readl(host, INTMASK); @@ -1734,7 +1740,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) (int_mask & ~sdio_int)); } - //spin_unlock_irqrestore(&host->lock, flags); + spin_unlock_irqrestore(&host->slock, flags); } #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE @@ -3700,6 +3706,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) static void dw_mci_dealwith_timeout(struct dw_mci *host) { u32 ret, i, regs; + u32 sdio_int; switch(host->state){ case STATE_IDLE: @@ -3734,7 +3741,18 @@ static void dw_mci_dealwith_timeout(struct dw_mci *host) | SDMMC_INT_RXDR | SDMMC_INT_VSI | DW_MCI_ERROR_FLAGS; if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)) regs |= SDMMC_INT_CD; - mci_writel(host, INTMASK, regs); + + if ((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)) { + if (host->verid < DW_MMC_240A) + sdio_int = SDMMC_INT_SDIO(0); + else + sdio_int = SDMMC_INT_SDIO(8); + + if (mci_readl(host, INTMASK) & sdio_int) + regs |= sdio_int; + } + + mci_writel(host, INTMASK, regs); mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; @@ -3758,6 +3776,7 @@ static void dw_mci_dto_timeout(unsigned long host_data) disable_irq(host->irq); + dev_err(host->dev, "data_over interrupt timeout!\n"); host->data_status = SDMMC_INT_EBE; mci_writel(host, RINTSTS, 0xFFFFFFFF); dw_mci_dealwith_timeout(host); @@ -3862,6 +3881,8 @@ int dw_mci_probe(struct dw_mci *host) host->svi_flags = 0; spin_lock_init(&host->lock); + spin_lock_init(&host->slock); + INIT_LIST_HEAD(&host->queue); INIT_DELAYED_WORK(&host->resume_rescan, resume_rescan_enable); /* diff --git a/include/linux/mmc/rk_mmc.h b/include/linux/mmc/rk_mmc.h index 1a4bf4c75d37..34a0413d351b 100755 --- a/include/linux/mmc/rk_mmc.h +++ b/include/linux/mmc/rk_mmc.h @@ -128,6 +128,7 @@ struct mmc_data; */ struct dw_mci { spinlock_t lock; + spinlock_t slock; void __iomem *regs; struct scatterlist *sg; -- 2.34.1