Hi, Doug. Add one comment. On 10/16/2014 05:19 PM, Jaehoon Chung wrote: > Hi, Doug. > > Looks good to me. > > Tested-by: Jaehoon Chung <jh80.chung@xxxxxxxxxxx> > with exynos3/4 series. > > Need to check exynos5 with using other "card detect" mechanism. > > Best Regards, > Jaehoon Chung > > On 10/15/2014 01:33 AM, Doug Anderson wrote: >> 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. Did you read the Card-detect Recommendation? There is a Recommendation for Card-detect(CDT) at TRM. We don't read the CDETECT register(0x50) anywhere. Could you share this register value after detecting? And I think "last_detect_state" is used for "software should read card detect register and store in memory." Best Regards, Jaehoon Chung >> >> Signed-off-by: Doug Anderson <dianders@xxxxxxxxxxxx> >> --- >> drivers/mmc/host/dw_mmc.c | 121 ++++++++------------------------------------- >> drivers/mmc/host/dw_mmc.h | 2 - >> include/linux/mmc/dw_mmc.h | 2 - >> 3 files changed, 20 insertions(+), 105 deletions(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 69f0cc6..6a86495 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -34,7 +34,6 @@ >> #include <linux/mmc/dw_mmc.h> >> #include <linux/bitops.h> >> #include <linux/regulator/consumer.h> >> -#include <linux/workqueue.h> >> #include <linux/of.h> >> #include <linux/of_gpio.h> >> #include <linux/mmc/slot-gpio.h> >> @@ -1954,6 +1953,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) >> tasklet_schedule(&host->tasklet); >> } >> >> +static void dw_mci_handle_cd(struct dw_mci *host) >> +{ >> + int i; >> + >> + for (i = 0; i < host->num_slots; i++) { >> + struct dw_mci_slot *slot = host->slot[i]; >> + >> + if (!slot) >> + continue; >> + >> + if (slot->mmc->ops->card_event) >> + slot->mmc->ops->card_event(slot->mmc); >> + mmc_detect_change(slot->mmc, >> + msecs_to_jiffies(host->pdata->detect_delay_ms)); >> + } >> +} >> + >> static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) >> { >> struct dw_mci *host = dev_id; >> @@ -2029,7 +2045,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) >> >> if (pending & SDMMC_INT_CD) { >> mci_writel(host, RINTSTS, SDMMC_INT_CD); >> - queue_work(host->card_workqueue, &host->card_work); >> + dw_mci_handle_cd(host); >> } >> >> /* Handle SDIO Interrupts */ >> @@ -2056,88 +2072,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) >> return IRQ_HANDLED; >> } >> >> -static void dw_mci_work_routine_card(struct work_struct *work) >> -{ >> - struct dw_mci *host = container_of(work, struct dw_mci, card_work); >> - int i; >> - >> - for (i = 0; i < host->num_slots; i++) { >> - struct dw_mci_slot *slot = host->slot[i]; >> - struct mmc_host *mmc = slot->mmc; >> - struct mmc_request *mrq; >> - int present; >> - >> - present = dw_mci_get_cd(mmc); >> - while (present != slot->last_detect_state) { >> - dev_dbg(&slot->mmc->class_dev, "card %s\n", >> - present ? "inserted" : "removed"); >> - >> - spin_lock_bh(&host->lock); >> - >> - /* Card change detected */ >> - slot->last_detect_state = present; >> - >> - /* Clean up queue if present */ >> - mrq = slot->mrq; >> - if (mrq) { >> - if (mrq == host->mrq) { >> - host->data = NULL; >> - host->cmd = NULL; >> - >> - switch (host->state) { >> - case STATE_IDLE: >> - case STATE_WAITING_CMD11_DONE: >> - break; >> - case STATE_SENDING_CMD11: >> - case STATE_SENDING_CMD: >> - mrq->cmd->error = -ENOMEDIUM; >> - if (!mrq->data) >> - break; >> - /* fall through */ >> - case STATE_SENDING_DATA: >> - mrq->data->error = -ENOMEDIUM; >> - dw_mci_stop_dma(host); >> - break; >> - case STATE_DATA_BUSY: >> - case STATE_DATA_ERROR: >> - if (mrq->data->error == -EINPROGRESS) >> - mrq->data->error = -ENOMEDIUM; >> - /* fall through */ >> - case STATE_SENDING_STOP: >> - if (mrq->stop) >> - mrq->stop->error = -ENOMEDIUM; >> - break; >> - } >> - >> - dw_mci_request_end(host, mrq); >> - } else { >> - list_del(&slot->queue_node); >> - mrq->cmd->error = -ENOMEDIUM; >> - if (mrq->data) >> - mrq->data->error = -ENOMEDIUM; >> - if (mrq->stop) >> - mrq->stop->error = -ENOMEDIUM; >> - >> - spin_unlock(&host->lock); >> - mmc_request_done(slot->mmc, mrq); >> - spin_lock(&host->lock); >> - } >> - } >> - >> - /* Power down slot */ >> - if (present == 0) >> - dw_mci_reset(host); >> - >> - spin_unlock_bh(&host->lock); >> - >> - present = dw_mci_get_cd(mmc); >> - } >> - >> - mmc_detect_change(slot->mmc, >> - msecs_to_jiffies(host->pdata->detect_delay_ms)); >> - } >> -} >> - >> #ifdef CONFIG_OF >> /* given a slot id, find out the device node representing that slot */ >> static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) >> @@ -2289,9 +2223,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) >> dw_mci_init_debugfs(slot); >> #endif >> >> - /* Card initially undetected */ >> - slot->last_detect_state = 0; >> - >> return 0; >> >> err_host_allocated: >> @@ -2672,17 +2603,10 @@ int dw_mci_probe(struct dw_mci *host) >> host->data_offset = DATA_240A_OFFSET; >> >> tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); >> - host->card_workqueue = alloc_workqueue("dw-mci-card", >> - WQ_MEM_RECLAIM, 1); >> - if (!host->card_workqueue) { >> - ret = -ENOMEM; >> - goto err_dmaunmap; >> - } >> - INIT_WORK(&host->card_work, dw_mci_work_routine_card); >> ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, >> host->irq_flags, "dw-mci", host); >> if (ret) >> - goto err_workqueue; >> + goto err_dmaunmap; >> >> if (host->pdata->num_slots) >> host->num_slots = host->pdata->num_slots; >> @@ -2718,7 +2642,7 @@ int dw_mci_probe(struct dw_mci *host) >> } else { >> dev_dbg(host->dev, "attempted to initialize %d slots, " >> "but failed on all\n", host->num_slots); >> - goto err_workqueue; >> + goto err_dmaunmap; >> } >> >> if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) >> @@ -2726,9 +2650,6 @@ int dw_mci_probe(struct dw_mci *host) >> >> return 0; >> >> -err_workqueue: >> - destroy_workqueue(host->card_workqueue); >> - >> err_dmaunmap: >> if (host->use_dma && host->dma_ops->exit) >> host->dma_ops->exit(host); >> @@ -2762,8 +2683,6 @@ void dw_mci_remove(struct dw_mci *host) >> mci_writel(host, CLKENA, 0); >> mci_writel(host, CLKSRC, 0); >> >> - destroy_workqueue(host->card_workqueue); >> - >> if (host->use_dma && host->dma_ops->exit) >> host->dma_ops->exit(host); >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 01b99e8..71d4995 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -214,7 +214,6 @@ extern int dw_mci_resume(struct dw_mci *host); >> * with CONFIG_MMC_CLKGATE. >> * @flags: Random state bits associated with the slot. >> * @id: Number of this slot. >> - * @last_detect_state: Most recently observed card detect state. >> */ >> struct dw_mci_slot { >> struct mmc_host *mmc; >> @@ -234,7 +233,6 @@ struct dw_mci_slot { >> #define DW_MMC_CARD_PRESENT 0 >> #define DW_MMC_CARD_NEED_INIT 1 >> int id; >> - int last_detect_state; >> }; >> >> struct dw_mci_tuning_data { >> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h >> index 0013669..69d0814 100644 >> --- a/include/linux/mmc/dw_mmc.h >> +++ b/include/linux/mmc/dw_mmc.h >> @@ -135,7 +135,6 @@ struct dw_mci { >> struct mmc_command stop_abort; >> unsigned int prev_blksz; >> unsigned char timing; >> - struct workqueue_struct *card_workqueue; >> >> /* DMA interface members*/ >> int use_dma; >> @@ -154,7 +153,6 @@ struct dw_mci { >> u32 stop_cmdr; >> u32 dir_status; >> struct tasklet_struct tasklet; >> - struct work_struct card_work; >> unsigned long pending_events; >> unsigned long completed_events; >> enum dw_mci_state state; >> > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html