aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2011-04-15 14:30:47 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 23:53:50 -0400
commit3b0beafc92406b98cbc2749b8db736f313d390b1 (patch)
treed782fec514beb5dbb4281adc6d6ec28b7c5915da /drivers
parent06e8935febe687e2a561707d4c7ca4245d261dbe (diff)
mmc: sh_mmcif: protect against a theoretical race
The MMC subsystem does not guarantee that host driver .request() and .set_ios() callbacks are serialised. Such concurrent calls, however, do not have to be meaningfully supported, drivers just have to make sure to avoid any severe problems. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Cc: Simon Horman <horms@verge.net.au> Cc: Magnus Damm <damm@opensource.se> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/host/sh_mmcif.c50
1 files changed, 42 insertions, 8 deletions
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index af97015a2fc7..d3871b67f77b 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -29,6 +29,7 @@
29#include <linux/mmc/sh_mmcif.h> 29#include <linux/mmc/sh_mmcif.h>
30#include <linux/pagemap.h> 30#include <linux/pagemap.h>
31#include <linux/platform_device.h> 31#include <linux/platform_device.h>
32#include <linux/spinlock.h>
32 33
33#define DRIVER_NAME "sh_mmcif" 34#define DRIVER_NAME "sh_mmcif"
34#define DRIVER_VERSION "2010-04-28" 35#define DRIVER_VERSION "2010-04-28"
@@ -153,6 +154,12 @@
153#define CLKDEV_MMC_DATA 20000000 /* 20MHz */ 154#define CLKDEV_MMC_DATA 20000000 /* 20MHz */
154#define CLKDEV_INIT 400000 /* 400 KHz */ 155#define CLKDEV_INIT 400000 /* 400 KHz */
155 156
157enum mmcif_state {
158 STATE_IDLE,
159 STATE_REQUEST,
160 STATE_IOS,
161};
162
156struct sh_mmcif_host { 163struct sh_mmcif_host {
157 struct mmc_host *mmc; 164 struct mmc_host *mmc;
158 struct mmc_data *data; 165 struct mmc_data *data;
@@ -164,6 +171,8 @@ struct sh_mmcif_host {
164 long timeout; 171 long timeout;
165 void __iomem *addr; 172 void __iomem *addr;
166 struct completion intr_wait; 173 struct completion intr_wait;
174 enum mmcif_state state;
175 spinlock_t lock;
167 176
168 /* DMA support */ 177 /* DMA support */
169 struct dma_chan *chan_rx; 178 struct dma_chan *chan_rx;
@@ -798,17 +807,31 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
798static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) 807static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
799{ 808{
800 struct sh_mmcif_host *host = mmc_priv(mmc); 809 struct sh_mmcif_host *host = mmc_priv(mmc);
810 unsigned long flags;
811
812 spin_lock_irqsave(&host->lock, flags);
813 if (host->state != STATE_IDLE) {
814 spin_unlock_irqrestore(&host->lock, flags);
815 mrq->cmd->error = -EAGAIN;
816 mmc_request_done(mmc, mrq);
817 return;
818 }
819
820 host->state = STATE_REQUEST;
821 spin_unlock_irqrestore(&host->lock, flags);
801 822
802 switch (mrq->cmd->opcode) { 823 switch (mrq->cmd->opcode) {
803 /* MMCIF does not support SD/SDIO command */ 824 /* MMCIF does not support SD/SDIO command */
804 case SD_IO_SEND_OP_COND: 825 case SD_IO_SEND_OP_COND:
805 case MMC_APP_CMD: 826 case MMC_APP_CMD:
827 host->state = STATE_IDLE;
806 mrq->cmd->error = -ETIMEDOUT; 828 mrq->cmd->error = -ETIMEDOUT;
807 mmc_request_done(mmc, mrq); 829 mmc_request_done(mmc, mrq);
808 return; 830 return;
809 case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ 831 case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
810 if (!mrq->data) { 832 if (!mrq->data) {
811 /* send_if_cond cmd (not support) */ 833 /* send_if_cond cmd (not support) */
834 host->state = STATE_IDLE;
812 mrq->cmd->error = -ETIMEDOUT; 835 mrq->cmd->error = -ETIMEDOUT;
813 mmc_request_done(mmc, mrq); 836 mmc_request_done(mmc, mrq);
814 return; 837 return;
@@ -830,12 +853,9 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
830 sh_mmcif_start_cmd(host, mrq, mrq->cmd); 853 sh_mmcif_start_cmd(host, mrq, mrq->cmd);
831 host->data = NULL; 854 host->data = NULL;
832 855
833 if (mrq->cmd->error != 0) { 856 if (!mrq->cmd->error && mrq->stop)
834 mmc_request_done(mmc, mrq);
835 return;
836 }
837 if (mrq->stop)
838 sh_mmcif_stop_cmd(host, mrq, mrq->stop); 857 sh_mmcif_stop_cmd(host, mrq, mrq->stop);
858 host->state = STATE_IDLE;
839 mmc_request_done(mmc, mrq); 859 mmc_request_done(mmc, mrq);
840} 860}
841 861
@@ -843,6 +863,16 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
843{ 863{
844 struct sh_mmcif_host *host = mmc_priv(mmc); 864 struct sh_mmcif_host *host = mmc_priv(mmc);
845 struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; 865 struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
866 unsigned long flags;
867
868 spin_lock_irqsave(&host->lock, flags);
869 if (host->state != STATE_IDLE) {
870 spin_unlock_irqrestore(&host->lock, flags);
871 return;
872 }
873
874 host->state = STATE_IOS;
875 spin_unlock_irqrestore(&host->lock, flags);
846 876
847 if (ios->power_mode == MMC_POWER_UP) { 877 if (ios->power_mode == MMC_POWER_UP) {
848 if (p->set_pwr) 878 if (p->set_pwr)
@@ -852,6 +882,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
852 sh_mmcif_clock_control(host, 0); 882 sh_mmcif_clock_control(host, 0);
853 if (ios->power_mode == MMC_POWER_OFF && p->down_pwr) 883 if (ios->power_mode == MMC_POWER_OFF && p->down_pwr)
854 p->down_pwr(host->pd); 884 p->down_pwr(host->pd);
885 host->state = STATE_IDLE;
855 return; 886 return;
856 } 887 }
857 888
@@ -859,6 +890,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
859 sh_mmcif_clock_control(host, ios->clock); 890 sh_mmcif_clock_control(host, ios->clock);
860 891
861 host->bus_width = ios->bus_width; 892 host->bus_width = ios->bus_width;
893 host->state = STATE_IDLE;
862} 894}
863 895
864static int sh_mmcif_get_cd(struct mmc_host *mmc) 896static int sh_mmcif_get_cd(struct mmc_host *mmc)
@@ -996,6 +1028,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
996 host->pd = pdev; 1028 host->pd = pdev;
997 1029
998 init_completion(&host->intr_wait); 1030 init_completion(&host->intr_wait);
1031 spin_lock_init(&host->lock);
999 1032
1000 mmc->ops = &sh_mmcif_ops; 1033 mmc->ops = &sh_mmcif_ops;
1001 mmc->f_max = host->clk; 1034 mmc->f_max = host->clk;
@@ -1025,6 +1058,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
1025 1058
1026 mmc_add_host(mmc); 1059 mmc_add_host(mmc);
1027 1060
1061 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
1062
1028 ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); 1063 ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
1029 if (ret) { 1064 if (ret) {
1030 dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); 1065 dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
@@ -1037,7 +1072,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
1037 goto clean_up2; 1072 goto clean_up2;
1038 } 1073 }
1039 1074
1040 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
1041 sh_mmcif_detect(host->mmc); 1075 sh_mmcif_detect(host->mmc);
1042 1076
1043 dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); 1077 dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
@@ -1063,11 +1097,11 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
1063 mmc_remove_host(host->mmc); 1097 mmc_remove_host(host->mmc);
1064 sh_mmcif_release_dma(host); 1098 sh_mmcif_release_dma(host);
1065 1099
1100 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
1101
1066 if (host->addr) 1102 if (host->addr)
1067 iounmap(host->addr); 1103 iounmap(host->addr);
1068 1104
1069 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
1070
1071 irq[0] = platform_get_irq(pdev, 0); 1105 irq[0] = platform_get_irq(pdev, 0);
1072 irq[1] = platform_get_irq(pdev, 1); 1106 irq[1] = platform_get_irq(pdev, 1);
1073 1107