Re: [PATCH] mmc: dw_mmc: Remove old card detect infrastructure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux