Re: [PATCH V2] mmc: sdhci: supporting PCI MSI

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

 



On Tue, Nov 12, 2013 at 05:27:16PM +0800, Jackey Shen wrote:
> On Tue, Nov 12, 2013 at 03:44:40PM +0800, Aaron Lu wrote:
> > On 11/12/2013 02:56 PM, Jackey Shen wrote:
> > > Enable MSI support in sdhci-pci driver and provide the mechanism
> > > to fall back to Legacy Pin-based Interrupt if MSI register fails.
> > > 
> > > Tested with SD cards on AMD platform.
> > > 
> > 
> > ->
> > 
> > > Change from V1:
> > > - implement this PCI MSI feature in sdhci-pci.c instead of sdhci.c
> > 
> > Such words can be placed under the --- below so that it will not appear
> > in git log.
> > 
> > > 
> > > Signed-off-by: Jackey Shen <Jackey.Shen@xxxxxxx>
> > > Reviewed-by: Huang Rui <ray.huang@xxxxxxx>
> > > ---
> > 
> > ->
> > Put change related info Here.
> 
> OK. I will update my patch.
> 
> > 
> > >  drivers/mmc/host/Kconfig     | 11 +++++++++
> > >  drivers/mmc/host/sdhci-pci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++
> > >  drivers/mmc/host/sdhci.c     | 42 ++++++++++++++++++++++++++------
> > >  drivers/mmc/host/sdhci.h     |  2 ++
> > >  include/linux/mmc/sdhci.h    |  2 ++
> > >  5 files changed, 107 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > > index 7fc5099..a56cf27 100644
> > > --- a/drivers/mmc/host/Kconfig
> > > +++ b/drivers/mmc/host/Kconfig
> > > @@ -68,6 +68,17 @@ config MMC_SDHCI_PCI
> > >  
> > >  	  If unsure, say N.
> > >  
> > > +config MMC_SDHCI_PCI_MSI
> > > +	bool "SDHCI support with MSI on PCI bus"
> > > +	depends on MMC_SDHCI_PCI && PCI_MSI
> > > +	help
> > > +	  This enables PCI MSI (Message Signaled Interrupts) for Secure
> > > +	  Digital Host Controller Interface.
> > > +
> > > +	  If you have a controller with this capability, say Y or M here.
> > > +
> > > +	  If unsure, say N.
> > > +
> > >  config MMC_RICOH_MMC
> > >  	bool "Ricoh MMC Controller Disabler"
> > >  	depends on MMC_SDHCI_PCI
> > > diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
> > > index 8f75381..2ca29c0 100644
> > > --- a/drivers/mmc/host/sdhci-pci.c
> > > +++ b/drivers/mmc/host/sdhci-pci.c
> > > @@ -1143,10 +1143,68 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
> > >  		slot->hw_reset(host);
> > >  }
> > >  
> > > +#ifdef CONFIG_MMC_SDHCI_PCI_MSI
> > > +static int sdhci_pci_setup_msi(struct sdhci_host *host, irq_handler_t handler)
> > > +{
> > > +	int ret;
> > > +	struct pci_dev *pdev = to_pci_dev(host->mmc->parent);
> > > +
> > > +	host->msi_enabled = false;
> > > +
> > > +	ret = pci_enable_msi(pdev);
> > > +	if (ret) {
> > > +		pr_warn("%s: Failed to allocate MSI entry\n",
> > > +			mmc_hostname(host->mmc));
> > > +		return ret;
> > > +	}
> > > +
> > > +	ret = request_irq(pdev->irq, handler, 0,
> > > +		mmc_hostname(host->mmc), host);
> > > +	if (ret) {
> > > +		pr_warn("%s: Failed to request MSI IRQ %d: %d\n",
> > > +		       mmc_hostname(host->mmc), pdev->irq, ret);
> > > +		pci_disable_msi(pdev);
> > > +		return ret;
> > > +	}
> > > +
> > > +	host->irq = pdev->irq;
> > > +	host->msi_enabled = true;
> > > +	return ret;
> > > +}
> > 
> > What about we only call pci_enable_msi in sdhci-pci.c and then assign
> > host->irq appropriately before calling sdhci_add_host, will that work?
> > The only difference would be, request_irq will have SHARED flag, but I
> > suppose that's not a problem.
> > 
> There are 2 points for this part:
> 1. fall back to legacy interrupt right after MSI request fails;
> 2. prompt user more information about where error/warning occur.
> 
> > > +
> > > +static int sdhci_pci_enable_msi(struct sdhci_host *host, irq_handler_t handler)
> > > +{
> > > +	return sdhci_pci_setup_msi(host, handler);
> > > +}
> > > +
> > > +static void sdhci_pci_disable_msi(struct sdhci_host *host)
> > > +{
> > > +	struct pci_dev *pdev = to_pci_dev(host->mmc->parent);
> > > +
> > > +	if (host->msi_enabled) {
> > > +		pci_disable_msi(pdev);
> > > +		host->msi_enabled = false;
> > > +	}
> > > +}
> > > +
> > > +#else
> > > +
> > > +static int sdhci_pci_enable_msi(struct sdhci_host *host, irq_handler_t handler)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static void sdhci_pci_disable_msi(struct sdhci_host *host)
> > > +{
> > > +}
> > > +#endif /* CONFIG_MMC_SDHCI_PCI_MSI */
> > > +
> > >  static const struct sdhci_ops sdhci_pci_ops = {
> > >  	.enable_dma	= sdhci_pci_enable_dma,
> > >  	.platform_bus_width	= sdhci_pci_bus_width,
> > >  	.hw_reset		= sdhci_pci_hw_reset,
> > > +	.enable_msi		= sdhci_pci_enable_msi,
> > > +	.disable_msi		= sdhci_pci_disable_msi,
> > >  };
> > >  
> > >  /*****************************************************************************\
> > > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > > index 6785fb1..4c2a1ac 100644
> > > --- a/drivers/mmc/host/sdhci.c
> > > +++ b/drivers/mmc/host/sdhci.c
> > > @@ -2554,6 +2554,31 @@ void sdhci_disable_irq_wakeups(struct sdhci_host *host)
> > >  }
> > >  EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
> > >  
> > > +static int sdhci_request_irq(struct sdhci_host *host)
> > > +{
> > > +	int ret = 0;
> > > +
> > > +	/* try to enable MSI */
> > > +	if (host->ops->enable_msi) {
> > > +		ret = host->ops->enable_msi(host, sdhci_irq);
> > > +		if (ret)
> > > +			pr_warn("%s: Fall back to Pin-based Interrupt: %d\n",
> > > +				mmc_hostname(host->mmc), ret);
> > > +	}
> > > +
> > > +	if (!host->msi_enabled) {
> > > +		/* fall back to legacy pin-based interrupt */
> > > +		ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
> > > +				mmc_hostname(host->mmc), host);
> > > +		if (ret) {
> > > +			pr_err("%s: Failed to request IRQ %d: %d\n",
> > > +				 mmc_hostname(host->mmc), host->irq, ret);
> > > +			return ret;
> > > +		}
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > >  int sdhci_suspend_host(struct sdhci_host *host)
> > >  {
> > >  	if (host->ops->platform_suspend)
> > > @@ -2570,6 +2595,8 @@ int sdhci_suspend_host(struct sdhci_host *host)
> > >  	if (!device_may_wakeup(mmc_dev(host->mmc))) {
> > >  		sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
> > >  		free_irq(host->irq, host);
> > > +		if (host->ops->disable_msi)
> > > +			host->ops->disable_msi(host);
> > 
> > What would happen if we do not disable/enable msi in suspend/resume host?
> > We have already masked all irqs with sdhci_mask_irqs anyway.
> > 
> We should also remove request|free_irq at the same time, right?
> I will do some tests.

Hi Aaron,

I did some tests and find system works fine:
1. remove disable/enable_msi in suspend/resume host
2. remove free|request_irq in suspend/resume host

BTY, I find system also works fine if my patch is not used and
item 2 above is adopted.

The IRQ number is reserved in suspend state and re-used in resume state.

Thanks,
Jackey

> 
> Thanks,
> Jackey
> 
> > Thanks,
> > Aaron
> > 
> > >  	} else {
> > >  		sdhci_enable_irq_wakeups(host);
> > >  		enable_irq_wake(host->irq);
> > > @@ -2589,8 +2616,7 @@ int sdhci_resume_host(struct sdhci_host *host)
> > >  	}
> > >  
> > >  	if (!device_may_wakeup(mmc_dev(host->mmc))) {
> > > -		ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
> > > -				  mmc_hostname(host->mmc), host);
> > > +		ret = sdhci_request_irq(host);
> > >  		if (ret)
> > >  			return ret;
> > >  	} else {
> > > @@ -3212,13 +3238,9 @@ int sdhci_add_host(struct sdhci_host *host)
> > >  
> > >  	sdhci_init(host, 0);
> > >  
> > > -	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
> > > -		mmc_hostname(mmc), host);
> > > -	if (ret) {
> > > -		pr_err("%s: Failed to request IRQ %d: %d\n",
> > > -		       mmc_hostname(mmc), host->irq, ret);
> > > +	ret = sdhci_request_irq(host);
> > > +	if (ret)
> > >  		goto untasklet;
> > > -	}
> > >  
> > >  #ifdef CONFIG_MMC_DEBUG
> > >  	sdhci_dumpregs(host);
> > > @@ -3258,6 +3280,8 @@ reset:
> > >  	sdhci_reset(host, SDHCI_RESET_ALL);
> > >  	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
> > >  	free_irq(host->irq, host);
> > > +	if (host->ops->disable_msi)
> > > +		host->ops->disable_msi(host);
> > >  #endif
> > >  untasklet:
> > >  	tasklet_kill(&host->card_tasklet);
> > > @@ -3301,6 +3325,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
> > >  
> > >  	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
> > >  	free_irq(host->irq, host);
> > > +	if (host->ops->disable_msi)
> > > +		host->ops->disable_msi(host);
> > >  
> > >  	del_timer_sync(&host->timer);
> > >  
> > > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > > index 0a3ed01..cbee843 100644
> > > --- a/drivers/mmc/host/sdhci.h
> > > +++ b/drivers/mmc/host/sdhci.h
> > > @@ -296,6 +296,8 @@ struct sdhci_ops {
> > >  	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
> > >  	void	(*platform_init)(struct sdhci_host *host);
> > >  	void    (*card_event)(struct sdhci_host *host);
> > > +	int	(*enable_msi)(struct sdhci_host *host, irq_handler_t handler);
> > > +	void	(*disable_msi)(struct sdhci_host *host);
> > >  };
> > >  
> > >  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> > > diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
> > > index 3e781b8..3812479 100644
> > > --- a/include/linux/mmc/sdhci.h
> > > +++ b/include/linux/mmc/sdhci.h
> > > @@ -99,6 +99,8 @@ struct sdhci_host {
> > >  /* Controller has a non-standard host control register */
> > >  #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL		(1<<5)
> > >  
> > > +	bool msi_enabled;	/* SD host controller with PCI MSI enabled */
> > > +
> > >  	int irq;		/* Device IRQ */
> > >  	void __iomem *ioaddr;	/* Mapped address */
> > >  
> > > 
> > 
> > --
> > 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
> > 
> 
> --
> 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
> 

--
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