diff mbox

[2/5] mmc: tmio: Provide separate interrupt handlers

Message ID 1313460499-3377-3-git-send-email-horms@verge.net.au (mailing list archive)
State New, archived
Headers show

Commit Message

Simon Horman Aug. 16, 2011, 2:08 a.m. UTC
Provide separate interrupt handlers which may be used by platforms where
SDHI has three interrupt sources.

This involves two key changes to the logic:
1. Do not assume that only one interrupt has occurred.
   In particular because tmio_mmc_irq() handles interrupts
   from three sources. Also, because this allows
   the logic to be simplified.
2. Just ignore spurious interrupts.
   Its not clear to me that they can ever occur.

This patch also removes the commented-out handling of CRC and other errors.

Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>

---

* SDCARD portion tested on AP4/Mackerel
* SDIO portion untested

v2
As suggested by Guennadi Liakhovetski
* Combine 3 patches into one
* Reduce the number of __tmio_..._irq() functions
* Rename "...card_access..." functions as "...sdcard..."
---
 drivers/mmc/host/tmio_mmc.h     |    3 +
 drivers/mmc/host/tmio_mmc_pio.c |  121 +++++++++++++++++++++++----------------
 2 files changed, 75 insertions(+), 49 deletions(-)

Comments

Guennadi Liakhovetski Aug. 16, 2011, 7:41 a.m. UTC | #1
On Tue, 16 Aug 2011, Simon Horman wrote:

> Provide separate interrupt handlers which may be used by platforms where
> SDHI has three interrupt sources.

Yes, this looks much simpler and cleaner to me now, than 3 original 
patches. It might change a bit after you change your PATCH 1/5, 

> 
> This involves two key changes to the logic:
> 1. Do not assume that only one interrupt has occurred.
>    In particular because tmio_mmc_irq() handles interrupts
>    from three sources. Also, because this allows
>    the logic to be simplified.
> 2. Just ignore spurious interrupts.
>    Its not clear to me that they can ever occur.
> 
> This patch also removes the commented-out handling of CRC and other errors.
> 
> Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> Cc: Magnus Damm <magnus.damm@gmail.com>
> Signed-off-by: Simon Horman <horms@verge.net.au>
> 
> ---
> 
> * SDCARD portion tested on AP4/Mackerel
> * SDIO portion untested
> 
> v2
> As suggested by Guennadi Liakhovetski
> * Combine 3 patches into one
> * Reduce the number of __tmio_..._irq() functions
> * Rename "...card_access..." functions as "...sdcard..."
> ---
>  drivers/mmc/host/tmio_mmc.h     |    3 +
>  drivers/mmc/host/tmio_mmc_pio.c |  121 +++++++++++++++++++++++----------------
>  2 files changed, 75 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
> index 1cf8db5..3020f98 100644
> --- a/drivers/mmc/host/tmio_mmc.h
> +++ b/drivers/mmc/host/tmio_mmc.h
> @@ -97,6 +97,9 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
>  void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
>  void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
>  irqreturn_t tmio_mmc_irq(int irq, void *devid);
> +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid);
> +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid);
> +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid);
>  
>  static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
>  					 unsigned long *flags)
> diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
> index c60b15f..e9640f2 100644
> --- a/drivers/mmc/host/tmio_mmc_pio.c
> +++ b/drivers/mmc/host/tmio_mmc_pio.c
> @@ -547,45 +547,20 @@ out:
>  	spin_unlock(&host->lock);
>  }
>  
> -irqreturn_t tmio_mmc_irq(int irq, void *devid)
> +static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
> +				       int *ireg, int *status)
>  {
> -	struct tmio_mmc_host *host = devid;
> -	struct mmc_host *mmc = host->mmc;
> -	struct tmio_mmc_data *pdata = host->pdata;
> -	unsigned int ireg, status;
> -	unsigned int sdio_ireg, sdio_status;
> -
> -	pr_debug("MMC IRQ begin\n");
> -
> -	status = sd_ctrl_read32(host, CTL_STATUS);
> -	ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
> +	*status = sd_ctrl_read32(host, CTL_STATUS);
> +	*ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
>  
> -	sdio_ireg = 0;
> -	if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
> -		sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
> -		host->sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
> -		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL &
> -				~host->sdio_irq_mask;
> -
> -		sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
> -
> -		if (sdio_ireg && !host->sdio_irq_enabled) {
> -			pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
> -				   sdio_status, host->sdio_irq_mask, sdio_ireg);
> -			tmio_mmc_enable_sdio_irq(mmc, 0);
> -			goto out;
> -		}
> -
> -		if (mmc->caps & MMC_CAP_SDIO_IRQ &&
> -			sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
> -			mmc_signal_sdio_irq(mmc);
> -
> -		if (sdio_ireg)
> -			goto out;
> -	}
> +	pr_debug_status(*status);
> +	pr_debug_status(*ireg);
> +}
>  
> -	pr_debug_status(status);
> -	pr_debug_status(ireg);
> +static void __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
> +				       int ireg, int status)
> +{
> +	struct mmc_host *mmc = host->mmc;
>  
>  	/* Card insert / remove attempts */
>  	if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
> @@ -595,43 +570,91 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
>  		     ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) &&
>  		    !work_pending(&mmc->detect.work))
>  			mmc_detect_change(host->mmc, msecs_to_jiffies(100));
> -		goto out;
>  	}
> +}
>  
> -	/* CRC and other errors */
> -/*	if (ireg & TMIO_STAT_ERR_IRQ)
> - *		handled |= tmio_error_irq(host, irq, stat);
> - */
> +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid)
> +{
> +	unsigned int ireg, status;
> +	struct tmio_mmc_host *host = devid;
> +
> +	tmio_mmc_card_irq_status(host, &ireg, &status);
> +	__tmio_mmc_card_detect_irq(host, ireg, status);
>  
> +	return IRQ_HANDLED;
> +}
> +EXPORT_SYMBOL(tmio_mmc_card_detect_irq);
> +
> +void __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg, int status)

"static" missing

> +{
>  	/* Command completion */
>  	if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
>  		tmio_mmc_ack_mmc_irqs(host,
>  			     TMIO_STAT_CMDRESPEND |
>  			     TMIO_STAT_CMDTIMEOUT);
>  		tmio_mmc_cmd_irq(host, status);
> -		goto out;

Well, removing these goto's certainly changes behaviour - at least 
theoretically. Imagine entering the ISR with status = TMIO_STAT_CMDRESPEND 
| TMIO_STAT_DATAEND. Before your patch the driver would ack and process 
the TMIO_STAT_CMDRESPEND and return dropping the TMIO_STAT_DATAEND status. 
Anc we don't know whether a second interrupt would follow with 
TMIO_STAT_DATAEND set. After your patch the driver will ack and process 
both. Since this driver runs on a variaty of hardware, unless fixing a 
problem or really improving something, I would keep the original 
behaviour. So, I would rather keep those exit points - just put "return" 
there.

>  	}
>  
>  	/* Data transfer */
>  	if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
>  		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
>  		tmio_mmc_pio_irq(host);
> -		goto out;
>  	}
>  
>  	/* Data transfer completion */
>  	if (ireg & TMIO_STAT_DATAEND) {
>  		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
>  		tmio_mmc_data_irq(host);
> -		goto out;
>  	}
> +}
> +
> +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid)
> +{
> +	unsigned int ireg, status;
> +	struct tmio_mmc_host *host = devid;
>  
> -	pr_warning("tmio_mmc: Spurious irq, disabling! "
> -		"0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg);
> -	pr_debug_status(status);
> -	tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask);
> +	tmio_mmc_card_irq_status(host, &ireg, &status);
> +	__tmio_mmc_sdcard_irq(host, ireg, status);
> +
> +	return IRQ_HANDLED;
> +}
> +EXPORT_SYMBOL(tmio_mmc_sdcard_irq);
> +
> +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
> +{
> +	struct tmio_mmc_host *host = devid;
> +	struct mmc_host *mmc = host->mmc;
> +	struct tmio_mmc_data *pdata = host->pdata;
> +	unsigned int ireg, status;
> +
> +	if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
> +		return IRQ_HANDLED;
> +
> +	status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
> +	ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
> +
> +	sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL);
> +
> +	if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
> +		mmc_signal_sdio_irq(mmc);
> +
> +	return IRQ_HANDLED;
> +}
> +EXPORT_SYMBOL(tmio_mmc_sdio_irq);
> +
> +irqreturn_t tmio_mmc_irq(int irq, void *devid)
> +{
> +	struct tmio_mmc_host *host = devid;
> +	unsigned int ireg, status;
> +
> +	pr_debug("MMC IRQ begin\n");
> +
> +	tmio_mmc_card_irq_status(host, &ireg, &status);
> +	__tmio_mmc_card_detect_irq(host, ireg, status);

Same here - I would return, if a card hot-plug event occurred.

> +	__tmio_mmc_sdcard_irq(host, ireg, status);

Ditto

> +
> +	tmio_mmc_sdio_irq(irq, devid);

Any specific reason, why you now process SDIO IRQs last?

>  
> -out:
>  	return IRQ_HANDLED;
>  }
>  EXPORT_SYMBOL(tmio_mmc_irq);
> -- 
> 1.7.5.4

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Simon Horman Aug. 16, 2011, 7:59 a.m. UTC | #2
On Tue, Aug 16, 2011 at 09:41:52AM +0200, Guennadi Liakhovetski wrote:
> On Tue, 16 Aug 2011, Simon Horman wrote:
> 
> > Provide separate interrupt handlers which may be used by platforms where
> > SDHI has three interrupt sources.
> 
> Yes, this looks much simpler and cleaner to me now, than 3 original 
> patches. It might change a bit after you change your PATCH 1/5, 
> 
> > 
> > This involves two key changes to the logic:
> > 1. Do not assume that only one interrupt has occurred.
> >    In particular because tmio_mmc_irq() handles interrupts
> >    from three sources. Also, because this allows
> >    the logic to be simplified.
> > 2. Just ignore spurious interrupts.
> >    Its not clear to me that they can ever occur.
> > 
> > This patch also removes the commented-out handling of CRC and other errors.
> > 
> > Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > Cc: Magnus Damm <magnus.damm@gmail.com>
> > Signed-off-by: Simon Horman <horms@verge.net.au>
> > 
> > ---
> > 
> > * SDCARD portion tested on AP4/Mackerel
> > * SDIO portion untested
> > 
> > v2
> > As suggested by Guennadi Liakhovetski
> > * Combine 3 patches into one
> > * Reduce the number of __tmio_..._irq() functions
> > * Rename "...card_access..." functions as "...sdcard..."
> > ---
> >  drivers/mmc/host/tmio_mmc.h     |    3 +
> >  drivers/mmc/host/tmio_mmc_pio.c |  121 +++++++++++++++++++++++----------------
> >  2 files changed, 75 insertions(+), 49 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
> > index 1cf8db5..3020f98 100644
> > --- a/drivers/mmc/host/tmio_mmc.h
> > +++ b/drivers/mmc/host/tmio_mmc.h
> > @@ -97,6 +97,9 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
> >  void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
> >  void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
> >  irqreturn_t tmio_mmc_irq(int irq, void *devid);
> > +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid);
> > +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid);
> > +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid);
> >  
> >  static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
> >  					 unsigned long *flags)
> > diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
> > index c60b15f..e9640f2 100644
> > --- a/drivers/mmc/host/tmio_mmc_pio.c
> > +++ b/drivers/mmc/host/tmio_mmc_pio.c
> > @@ -547,45 +547,20 @@ out:
> >  	spin_unlock(&host->lock);
> >  }
> >  
> > -irqreturn_t tmio_mmc_irq(int irq, void *devid)
> > +static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
> > +				       int *ireg, int *status)
> >  {
> > -	struct tmio_mmc_host *host = devid;
> > -	struct mmc_host *mmc = host->mmc;
> > -	struct tmio_mmc_data *pdata = host->pdata;
> > -	unsigned int ireg, status;
> > -	unsigned int sdio_ireg, sdio_status;
> > -
> > -	pr_debug("MMC IRQ begin\n");
> > -
> > -	status = sd_ctrl_read32(host, CTL_STATUS);
> > -	ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
> > +	*status = sd_ctrl_read32(host, CTL_STATUS);
> > +	*ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
> >  
> > -	sdio_ireg = 0;
> > -	if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
> > -		sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
> > -		host->sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
> > -		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL &
> > -				~host->sdio_irq_mask;
> > -
> > -		sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
> > -
> > -		if (sdio_ireg && !host->sdio_irq_enabled) {
> > -			pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
> > -				   sdio_status, host->sdio_irq_mask, sdio_ireg);
> > -			tmio_mmc_enable_sdio_irq(mmc, 0);
> > -			goto out;
> > -		}
> > -
> > -		if (mmc->caps & MMC_CAP_SDIO_IRQ &&
> > -			sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
> > -			mmc_signal_sdio_irq(mmc);
> > -
> > -		if (sdio_ireg)
> > -			goto out;
> > -	}
> > +	pr_debug_status(*status);
> > +	pr_debug_status(*ireg);
> > +}
> >  
> > -	pr_debug_status(status);
> > -	pr_debug_status(ireg);
> > +static void __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
> > +				       int ireg, int status)
> > +{
> > +	struct mmc_host *mmc = host->mmc;
> >  
> >  	/* Card insert / remove attempts */
> >  	if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
> > @@ -595,43 +570,91 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
> >  		     ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) &&
> >  		    !work_pending(&mmc->detect.work))
> >  			mmc_detect_change(host->mmc, msecs_to_jiffies(100));
> > -		goto out;
> >  	}
> > +}
> >  
> > -	/* CRC and other errors */
> > -/*	if (ireg & TMIO_STAT_ERR_IRQ)
> > - *		handled |= tmio_error_irq(host, irq, stat);
> > - */
> > +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid)
> > +{
> > +	unsigned int ireg, status;
> > +	struct tmio_mmc_host *host = devid;
> > +
> > +	tmio_mmc_card_irq_status(host, &ireg, &status);
> > +	__tmio_mmc_card_detect_irq(host, ireg, status);
> >  
> > +	return IRQ_HANDLED;
> > +}
> > +EXPORT_SYMBOL(tmio_mmc_card_detect_irq);
> > +
> > +void __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg, int status)
> 
> "static" missing
> 
> > +{
> >  	/* Command completion */
> >  	if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
> >  		tmio_mmc_ack_mmc_irqs(host,
> >  			     TMIO_STAT_CMDRESPEND |
> >  			     TMIO_STAT_CMDTIMEOUT);
> >  		tmio_mmc_cmd_irq(host, status);
> > -		goto out;
> 
> Well, removing these goto's certainly changes behaviour - at least 
> theoretically. Imagine entering the ISR with status = TMIO_STAT_CMDRESPEND 
> | TMIO_STAT_DATAEND. Before your patch the driver would ack and process 
> the TMIO_STAT_CMDRESPEND and return dropping the TMIO_STAT_DATAEND status. 
> Anc we don't know whether a second interrupt would follow with 
> TMIO_STAT_DATAEND set. After your patch the driver will ack and process 
> both. Since this driver runs on a variaty of hardware, unless fixing a 
> problem or really improving something, I would keep the original 
> behaviour. So, I would rather keep those exit points - just put "return" 
> there.

I specifically noted this change in the changelog, sorry if that wasn't
clear enough.

I will revert the behaviour as you suggest, although I suspect
that the new behaviour is correct.

> >  	}
> >  
> >  	/* Data transfer */
> >  	if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
> >  		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
> >  		tmio_mmc_pio_irq(host);
> > -		goto out;
> >  	}
> >  
> >  	/* Data transfer completion */
> >  	if (ireg & TMIO_STAT_DATAEND) {
> >  		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
> >  		tmio_mmc_data_irq(host);
> > -		goto out;
> >  	}
> > +}
> > +
> > +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid)
> > +{
> > +	unsigned int ireg, status;
> > +	struct tmio_mmc_host *host = devid;
> >  
> > -	pr_warning("tmio_mmc: Spurious irq, disabling! "
> > -		"0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg);
> > -	pr_debug_status(status);
> > -	tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask);
> > +	tmio_mmc_card_irq_status(host, &ireg, &status);
> > +	__tmio_mmc_sdcard_irq(host, ireg, status);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +EXPORT_SYMBOL(tmio_mmc_sdcard_irq);
> > +
> > +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
> > +{
> > +	struct tmio_mmc_host *host = devid;
> > +	struct mmc_host *mmc = host->mmc;
> > +	struct tmio_mmc_data *pdata = host->pdata;
> > +	unsigned int ireg, status;
> > +
> > +	if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
> > +		return IRQ_HANDLED;
> > +
> > +	status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
> > +	ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
> > +
> > +	sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL);
> > +
> > +	if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
> > +		mmc_signal_sdio_irq(mmc);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +EXPORT_SYMBOL(tmio_mmc_sdio_irq);
> > +
> > +irqreturn_t tmio_mmc_irq(int irq, void *devid)
> > +{
> > +	struct tmio_mmc_host *host = devid;
> > +	unsigned int ireg, status;
> > +
> > +	pr_debug("MMC IRQ begin\n");
> > +
> > +	tmio_mmc_card_irq_status(host, &ireg, &status);
> > +	__tmio_mmc_card_detect_irq(host, ireg, status);
> 
> Same here - I would return, if a card hot-plug event occurred.

Will do.

> > +	__tmio_mmc_sdcard_irq(host, ireg, status);
> 
> Ditto
> 
> > +
> > +	tmio_mmc_sdio_irq(irq, devid);
> 
> Any specific reason, why you now process SDIO IRQs last?

I believe this is in keeping with the ordering implied by original code.

> >  
> > -out:
> >  	return IRQ_HANDLED;
> >  }
> >  EXPORT_SYMBOL(tmio_mmc_irq);
> > -- 
> > 1.7.5.4
> 
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski Aug. 16, 2011, 11:13 a.m. UTC | #3
On Tue, 16 Aug 2011, Simon Horman wrote:

> On Tue, Aug 16, 2011 at 09:41:52AM +0200, Guennadi Liakhovetski wrote:
> > On Tue, 16 Aug 2011, Simon Horman wrote:

[snip]

> > > +irqreturn_t tmio_mmc_irq(int irq, void *devid)
> > > +{
> > > +	struct tmio_mmc_host *host = devid;
> > > +	unsigned int ireg, status;
> > > +
> > > +	pr_debug("MMC IRQ begin\n");
> > > +
> > > +	tmio_mmc_card_irq_status(host, &ireg, &status);
> > > +	__tmio_mmc_card_detect_irq(host, ireg, status);
> > 
> > Same here - I would return, if a card hot-plug event occurred.
> 
> Will do.
> 
> > > +	__tmio_mmc_sdcard_irq(host, ireg, status);
> > 
> > Ditto
> > 
> > > +
> > > +	tmio_mmc_sdio_irq(irq, devid);
> > 
> > Any specific reason, why you now process SDIO IRQs last?
> 
> I believe this is in keeping with the ordering implied by original code.

I believe it's not. The original version did SDIO first, then hotplug, 
then normal IO. I'm not necessarily saying, that the original code was 
correct or better, I'm just saying, it was different. As for which one we 
should prefer... I think, I'd check for hotplug first: if the card is 
removed, no reason to try to communicate with it. And we have to first 
report a new card, before reporting any IRQs from it. But then - IO or 
SDIO as second? Well, since SDIO IRQs are asynchronous, it shouldn't be a 
big problem for them to wait a bit, whereas normal IO IRQs are card's 
response to host's actions, so, the originator might want to know the 
result before processing any asynchronous events. So, I actually like your 
ordering better... But I'll give it a short spin with SDIO, unless you do 
it yourself.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Simon Horman Aug. 16, 2011, 11:45 a.m. UTC | #4
On Tue, Aug 16, 2011 at 01:13:06PM +0200, Guennadi Liakhovetski wrote:
> On Tue, 16 Aug 2011, Simon Horman wrote:
> 
> > On Tue, Aug 16, 2011 at 09:41:52AM +0200, Guennadi Liakhovetski wrote:
> > > On Tue, 16 Aug 2011, Simon Horman wrote:
> 
> [snip]
> 
> > > > +irqreturn_t tmio_mmc_irq(int irq, void *devid)
> > > > +{
> > > > +	struct tmio_mmc_host *host = devid;
> > > > +	unsigned int ireg, status;
> > > > +
> > > > +	pr_debug("MMC IRQ begin\n");
> > > > +
> > > > +	tmio_mmc_card_irq_status(host, &ireg, &status);
> > > > +	__tmio_mmc_card_detect_irq(host, ireg, status);
> > > 
> > > Same here - I would return, if a card hot-plug event occurred.
> > 
> > Will do.
> > 
> > > > +	__tmio_mmc_sdcard_irq(host, ireg, status);
> > > 
> > > Ditto
> > > 
> > > > +
> > > > +	tmio_mmc_sdio_irq(irq, devid);
> > > 
> > > Any specific reason, why you now process SDIO IRQs last?
> > 
> > I believe this is in keeping with the ordering implied by original code.
> 
> I believe it's not. The original version did SDIO first, then hotplug, 
> then normal IO.

My reading of the original code is that SDIO was the lowest priority
although its code appeared near the top of tmio_mmc_irq().

irqreturn_t tmio_mmc_irq(int irq, void *devid)
{
	...

	status = sd_ctrl_read32(host, CTL_STATUS);
	irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
	ireg = status & TMIO_MASK_IRQ & ~irq_mask;

	sdio_ireg = 0;
	if (!ireg pdata->flags & TMIO_MMC_SDIO_IRQ) {
		/* Handle SDIO Interrupt */
		...
		goto out;
	}

	/* Handle Card detect Interrupts */

	/* Handle other Interrupts */

	...
}

> I'm not necessarily saying, that the original code was 
> correct or better, I'm just saying, it was different. As for which one we 
> should prefer... I think, I'd check for hotplug first: if the card is 
> removed, no reason to try to communicate with it. And we have to first 
> report a new card, before reporting any IRQs from it. But then - IO or 
> SDIO as second? Well, since SDIO IRQs are asynchronous, it shouldn't be a 
> big problem for them to wait a bit, whereas normal IO IRQs are card's 
> response to host's actions, so, the originator might want to know the 
> result before processing any asynchronous events. So, I actually like your 
> ordering better... But I'll give it a short spin with SDIO, unless you do 
> it yourself.

I intend to test my code with SDIO, however I don't have access to hardware
at this exact moment. So if you could do so, that would be great.

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 1cf8db5..3020f98 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -97,6 +97,9 @@  void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 irqreturn_t tmio_mmc_irq(int irq, void *devid);
+irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid);
+irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid);
+irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid);
 
 static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
 					 unsigned long *flags)
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index c60b15f..e9640f2 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -547,45 +547,20 @@  out:
 	spin_unlock(&host->lock);
 }
 
-irqreturn_t tmio_mmc_irq(int irq, void *devid)
+static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
+				       int *ireg, int *status)
 {
-	struct tmio_mmc_host *host = devid;
-	struct mmc_host *mmc = host->mmc;
-	struct tmio_mmc_data *pdata = host->pdata;
-	unsigned int ireg, status;
-	unsigned int sdio_ireg, sdio_status;
-
-	pr_debug("MMC IRQ begin\n");
-
-	status = sd_ctrl_read32(host, CTL_STATUS);
-	ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
+	*status = sd_ctrl_read32(host, CTL_STATUS);
+	*ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
 
-	sdio_ireg = 0;
-	if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
-		sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
-		host->sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
-		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL &
-				~host->sdio_irq_mask;
-
-		sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
-
-		if (sdio_ireg && !host->sdio_irq_enabled) {
-			pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
-				   sdio_status, host->sdio_irq_mask, sdio_ireg);
-			tmio_mmc_enable_sdio_irq(mmc, 0);
-			goto out;
-		}
-
-		if (mmc->caps & MMC_CAP_SDIO_IRQ &&
-			sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
-			mmc_signal_sdio_irq(mmc);
-
-		if (sdio_ireg)
-			goto out;
-	}
+	pr_debug_status(*status);
+	pr_debug_status(*ireg);
+}
 
-	pr_debug_status(status);
-	pr_debug_status(ireg);
+static void __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
+				       int ireg, int status)
+{
+	struct mmc_host *mmc = host->mmc;
 
 	/* Card insert / remove attempts */
 	if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
@@ -595,43 +570,91 @@  irqreturn_t tmio_mmc_irq(int irq, void *devid)
 		     ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) &&
 		    !work_pending(&mmc->detect.work))
 			mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-		goto out;
 	}
+}
 
-	/* CRC and other errors */
-/*	if (ireg & TMIO_STAT_ERR_IRQ)
- *		handled |= tmio_error_irq(host, irq, stat);
- */
+irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid)
+{
+	unsigned int ireg, status;
+	struct tmio_mmc_host *host = devid;
+
+	tmio_mmc_card_irq_status(host, &ireg, &status);
+	__tmio_mmc_card_detect_irq(host, ireg, status);
 
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(tmio_mmc_card_detect_irq);
+
+void __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg, int status)
+{
 	/* Command completion */
 	if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
 		tmio_mmc_ack_mmc_irqs(host,
 			     TMIO_STAT_CMDRESPEND |
 			     TMIO_STAT_CMDTIMEOUT);
 		tmio_mmc_cmd_irq(host, status);
-		goto out;
 	}
 
 	/* Data transfer */
 	if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
 		tmio_mmc_pio_irq(host);
-		goto out;
 	}
 
 	/* Data transfer completion */
 	if (ireg & TMIO_STAT_DATAEND) {
 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
 		tmio_mmc_data_irq(host);
-		goto out;
 	}
+}
+
+irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid)
+{
+	unsigned int ireg, status;
+	struct tmio_mmc_host *host = devid;
 
-	pr_warning("tmio_mmc: Spurious irq, disabling! "
-		"0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg);
-	pr_debug_status(status);
-	tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask);
+	tmio_mmc_card_irq_status(host, &ireg, &status);
+	__tmio_mmc_sdcard_irq(host, ireg, status);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(tmio_mmc_sdcard_irq);
+
+irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
+{
+	struct tmio_mmc_host *host = devid;
+	struct mmc_host *mmc = host->mmc;
+	struct tmio_mmc_data *pdata = host->pdata;
+	unsigned int ireg, status;
+
+	if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
+		return IRQ_HANDLED;
+
+	status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
+	ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
+
+	sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL);
+
+	if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
+		mmc_signal_sdio_irq(mmc);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(tmio_mmc_sdio_irq);
+
+irqreturn_t tmio_mmc_irq(int irq, void *devid)
+{
+	struct tmio_mmc_host *host = devid;
+	unsigned int ireg, status;
+
+	pr_debug("MMC IRQ begin\n");
+
+	tmio_mmc_card_irq_status(host, &ireg, &status);
+	__tmio_mmc_card_detect_irq(host, ireg, status);
+	__tmio_mmc_sdcard_irq(host, ireg, status);
+
+	tmio_mmc_sdio_irq(irq, devid);
 
-out:
 	return IRQ_HANDLED;
 }
 EXPORT_SYMBOL(tmio_mmc_irq);