aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/dw_mmc.c
diff options
context:
space:
mode:
authorDoug Anderson <dianders@chromium.org>2014-10-14 12:33:09 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-11-10 06:40:39 -0500
commit6130e7a9c34d01afbd4e7e215846d1f2d70333bb (patch)
treed0f1e4d512611b7260f5557a9a927f86173d727d /drivers/mmc/host/dw_mmc.c
parent51d346068876bf4972efc61969d02958a087f3ee (diff)
mmc: dw_mmc: Remove old card detect infrastructure
The dw_mmc driver had a bunch of code that ran whenever a card was ejected and inserted. However, this code was old and crufty and should be removed. Some evidence that it's really not needed: 1. Is is supposed to be legal to use 'cd-gpio' on dw_mmc instead of using the built-in card detect mechanism. The 'cd-gpio' code doesn't run any of the crufty old code but yet still works. 2. While looking at this, I realized that my old change (369ac86 mmc: dw_mmc: don't queue up a card detect at slot startup) actually castrated the old code a little bit already and nobody noticed. Specifically "last_detect_state" was left as 0 at bootup. That means that on the first card removal none of the crufty code ran. 3. I can run "while true; do dd if=/dev/mmcblk1 of=/dev/null; done" while ejecting and inserting an SD Card and the world doesn't explode. If some of the crufty old code is actually needed, we should justify it and also put it in some place where it will be run even with "cd-gpio". Note that in my case I'm using the "cd-gpio" mechanism but for various reasons the hardware triggers a dw_mmc "card detect" at bootup. That was actually causing a real bug. The card detect workqueue was running while the system was trying to enumerate the card. The "present != slot->last_detect_state" triggered and we were doing all kinds of crazy stuff and messing up enumeration. The new mechanism of just asking the core to check the card is much safer and then the bogus interrupt doesn't hurt. Signed-off-by: Doug Anderson <dianders@chromium.org> Tested-by: Jaehoon Chung <jh80.chung@samsung.com> Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Tested-by: alim.akhtar <alim.akhtar@samsung.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
-rw-r--r--drivers/mmc/host/dw_mmc.c121
1 files changed, 20 insertions, 101 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 545f62191afd..bb46b1b8d16b 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -34,7 +34,6 @@
34#include <linux/mmc/dw_mmc.h> 34#include <linux/mmc/dw_mmc.h>
35#include <linux/bitops.h> 35#include <linux/bitops.h>
36#include <linux/regulator/consumer.h> 36#include <linux/regulator/consumer.h>
37#include <linux/workqueue.h>
38#include <linux/of.h> 37#include <linux/of.h>
39#include <linux/of_gpio.h> 38#include <linux/of_gpio.h>
40#include <linux/mmc/slot-gpio.h> 39#include <linux/mmc/slot-gpio.h>
@@ -1959,6 +1958,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1959 tasklet_schedule(&host->tasklet); 1958 tasklet_schedule(&host->tasklet);
1960} 1959}
1961 1960
1961static void dw_mci_handle_cd(struct dw_mci *host)
1962{
1963 int i;
1964
1965 for (i = 0; i < host->num_slots; i++) {
1966 struct dw_mci_slot *slot = host->slot[i];
1967
1968 if (!slot)
1969 continue;
1970
1971 if (slot->mmc->ops->card_event)
1972 slot->mmc->ops->card_event(slot->mmc);
1973 mmc_detect_change(slot->mmc,
1974 msecs_to_jiffies(host->pdata->detect_delay_ms));
1975 }
1976}
1977
1962static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 1978static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1963{ 1979{
1964 struct dw_mci *host = dev_id; 1980 struct dw_mci *host = dev_id;
@@ -2034,7 +2050,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
2034 2050
2035 if (pending & SDMMC_INT_CD) { 2051 if (pending & SDMMC_INT_CD) {
2036 mci_writel(host, RINTSTS, SDMMC_INT_CD); 2052 mci_writel(host, RINTSTS, SDMMC_INT_CD);
2037 queue_work(host->card_workqueue, &host->card_work); 2053 dw_mci_handle_cd(host);
2038 } 2054 }
2039 2055
2040 /* Handle SDIO Interrupts */ 2056 /* Handle SDIO Interrupts */
@@ -2061,88 +2077,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
2061 return IRQ_HANDLED; 2077 return IRQ_HANDLED;
2062} 2078}
2063 2079
2064static void dw_mci_work_routine_card(struct work_struct *work)
2065{
2066 struct dw_mci *host = container_of(work, struct dw_mci, card_work);
2067 int i;
2068
2069 for (i = 0; i < host->num_slots; i++) {
2070 struct dw_mci_slot *slot = host->slot[i];
2071 struct mmc_host *mmc = slot->mmc;
2072 struct mmc_request *mrq;
2073 int present;
2074
2075 present = dw_mci_get_cd(mmc);
2076 while (present != slot->last_detect_state) {
2077 dev_dbg(&slot->mmc->class_dev, "card %s\n",
2078 present ? "inserted" : "removed");
2079
2080 spin_lock_bh(&host->lock);
2081
2082 /* Card change detected */
2083 slot->last_detect_state = present;
2084
2085 /* Clean up queue if present */
2086 mrq = slot->mrq;
2087 if (mrq) {
2088 if (mrq == host->mrq) {
2089 host->data = NULL;
2090 host->cmd = NULL;
2091
2092 switch (host->state) {
2093 case STATE_IDLE:
2094 case STATE_WAITING_CMD11_DONE:
2095 break;
2096 case STATE_SENDING_CMD11:
2097 case STATE_SENDING_CMD:
2098 mrq->cmd->error = -ENOMEDIUM;
2099 if (!mrq->data)
2100 break;
2101 /* fall through */
2102 case STATE_SENDING_DATA:
2103 mrq->data->error = -ENOMEDIUM;
2104 dw_mci_stop_dma(host);
2105 break;
2106 case STATE_DATA_BUSY:
2107 case STATE_DATA_ERROR:
2108 if (mrq->data->error == -EINPROGRESS)
2109 mrq->data->error = -ENOMEDIUM;
2110 /* fall through */
2111 case STATE_SENDING_STOP:
2112 if (mrq->stop)
2113 mrq->stop->error = -ENOMEDIUM;
2114 break;
2115 }
2116
2117 dw_mci_request_end(host, mrq);
2118 } else {
2119 list_del(&slot->queue_node);
2120 mrq->cmd->error = -ENOMEDIUM;
2121 if (mrq->data)
2122 mrq->data->error = -ENOMEDIUM;
2123 if (mrq->stop)
2124 mrq->stop->error = -ENOMEDIUM;
2125
2126 spin_unlock(&host->lock);
2127 mmc_request_done(slot->mmc, mrq);
2128 spin_lock(&host->lock);
2129 }
2130 }
2131
2132 /* Power down slot */
2133 if (present == 0)
2134 dw_mci_reset(host);
2135
2136 spin_unlock_bh(&host->lock);
2137
2138 present = dw_mci_get_cd(mmc);
2139 }
2140
2141 mmc_detect_change(slot->mmc,
2142 msecs_to_jiffies(host->pdata->detect_delay_ms));
2143 }
2144}
2145
2146#ifdef CONFIG_OF 2080#ifdef CONFIG_OF
2147/* given a slot id, find out the device node representing that slot */ 2081/* given a slot id, find out the device node representing that slot */
2148static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2082static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
@@ -2294,9 +2228,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2294 dw_mci_init_debugfs(slot); 2228 dw_mci_init_debugfs(slot);
2295#endif 2229#endif
2296 2230
2297 /* Card initially undetected */
2298 slot->last_detect_state = 0;
2299
2300 return 0; 2231 return 0;
2301 2232
2302err_host_allocated: 2233err_host_allocated:
@@ -2677,17 +2608,10 @@ int dw_mci_probe(struct dw_mci *host)
2677 host->data_offset = DATA_240A_OFFSET; 2608 host->data_offset = DATA_240A_OFFSET;
2678 2609
2679 tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 2610 tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
2680 host->card_workqueue = alloc_workqueue("dw-mci-card",
2681 WQ_MEM_RECLAIM, 1);
2682 if (!host->card_workqueue) {
2683 ret = -ENOMEM;
2684 goto err_dmaunmap;
2685 }
2686 INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2687 ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 2611 ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2688 host->irq_flags, "dw-mci", host); 2612 host->irq_flags, "dw-mci", host);
2689 if (ret) 2613 if (ret)
2690 goto err_workqueue; 2614 goto err_dmaunmap;
2691 2615
2692 if (host->pdata->num_slots) 2616 if (host->pdata->num_slots)
2693 host->num_slots = host->pdata->num_slots; 2617 host->num_slots = host->pdata->num_slots;
@@ -2723,7 +2647,7 @@ int dw_mci_probe(struct dw_mci *host)
2723 } else { 2647 } else {
2724 dev_dbg(host->dev, "attempted to initialize %d slots, " 2648 dev_dbg(host->dev, "attempted to initialize %d slots, "
2725 "but failed on all\n", host->num_slots); 2649 "but failed on all\n", host->num_slots);
2726 goto err_workqueue; 2650 goto err_dmaunmap;
2727 } 2651 }
2728 2652
2729 if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 2653 if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
@@ -2731,9 +2655,6 @@ int dw_mci_probe(struct dw_mci *host)
2731 2655
2732 return 0; 2656 return 0;
2733 2657
2734err_workqueue:
2735 destroy_workqueue(host->card_workqueue);
2736
2737err_dmaunmap: 2658err_dmaunmap:
2738 if (host->use_dma && host->dma_ops->exit) 2659 if (host->use_dma && host->dma_ops->exit)
2739 host->dma_ops->exit(host); 2660 host->dma_ops->exit(host);
@@ -2767,8 +2688,6 @@ void dw_mci_remove(struct dw_mci *host)
2767 mci_writel(host, CLKENA, 0); 2688 mci_writel(host, CLKENA, 0);
2768 mci_writel(host, CLKSRC, 0); 2689 mci_writel(host, CLKSRC, 0);
2769 2690
2770 destroy_workqueue(host->card_workqueue);
2771
2772 if (host->use_dma && host->dma_ops->exit) 2691 if (host->use_dma && host->dma_ops->exit)
2773 host->dma_ops->exit(host); 2692 host->dma_ops->exit(host);
2774 2693