public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Michael Ellerman <michael@ellerman.id.au>
To: Matthew Wilcox <matthew@wil.cx>
Cc: linux-pci@vger.kernel.org, kaneshige.kenji@jp.fujitsu.com,
	mingo@elte.hu, tglx@linutronix.de, davem@davemloft.net,
	dan.j.williams@intel.com, Martine.Silbermann@hp.com,
	benh@kernel.crashing.org, linux-kernel@vger.kernel.org,
	Matthew Wilcox <willy@linux.intel.com>
Subject: Re: [PATCH 2/4] PCI: Support multiple MSI
Date: Mon, 07 Jul 2008 12:05:25 +1000	[thread overview]
Message-ID: <1215396326.19157.15.camel@localhost> (raw)
In-Reply-To: <1215264855-4372-2-git-send-email-matthew@wil.cx>

[-- Attachment #1: Type: text/plain, Size: 9758 bytes --]

On Sat, 2008-07-05 at 09:34 -0400, Matthew Wilcox wrote:
> Add the new API pci_enable_msi_block() to allow drivers to
> request multiple MSIs.  Reimplement pci_enable_msi in terms
> of pci_enable_msi_block.  Add a default implementation of
> arch_setup_msi_block() that only allows one MSI to be requested.

I don't think you need arch_setup_msi_block() at all.

We already have an arch hook that takes a number of irqs, it's
arch_setup_msi_irqs(), plural. It also has the type passed to it (MSI or
MSI-X), so it can decide if it needs to allocate the irq numbers
contiguously.

Or am I missing something?

cheers

> diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
> index c62d101..317c7c8 100644
> --- a/arch/powerpc/kernel/msi.c
> +++ b/arch/powerpc/kernel/msi.c
> @@ -32,7 +32,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>  	return ppc_md.setup_msi_irqs(dev, nvec, type);
>  }
>  
> -void arch_teardown_msi_irqs(struct pci_dev *dev)
> +void arch_teardown_msi_irqs(struct pci_dev *dev, int nvec)
>  {
>  	return ppc_md.teardown_msi_irqs(dev);
>  }
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 92992a8..6cbdf11 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -40,18 +40,31 @@ arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
>  }
>  
>  int __attribute__ ((weak))
> +arch_setup_msi_block(struct pci_dev *pdev, struct msi_desc *desc, int nvec)
> +{
> +	if (nvec > 1)
> +		return 1;
> +	return arch_setup_msi_irq(pdev, desc);
> +}
> +
> +int __attribute__ ((weak))
>  arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>  {
> -	struct msi_desc *entry;
> +	struct msi_desc *desc;
>  	int ret;
>  
> -	list_for_each_entry(entry, &dev->msi_list, list) {
> -		ret = arch_setup_msi_irq(dev, entry);
> -		if (ret)
> -			return ret;
> +	if (type == PCI_CAP_ID_MSI) {
> +		desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
> +		ret = arch_setup_msi_block(dev, desc, nvec);
> +	} else {
> +		list_for_each_entry(desc, &dev->msi_list, list) {
> +			ret = arch_setup_msi_irq(dev, desc);
> +			if (ret)
> +				break;
> +		}
>  	}
>  
> -	return 0;
> +	return ret;
>  }
>  
>  void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
> @@ -60,13 +73,16 @@ void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
>  }
>  
>  void __attribute__ ((weak))
> -arch_teardown_msi_irqs(struct pci_dev *dev)
> +arch_teardown_msi_irqs(struct pci_dev *dev, int nvec)
>  {
>  	struct msi_desc *entry;
>  
>  	list_for_each_entry(entry, &dev->msi_list, list) {
> -		if (entry->irq != 0)
> -			arch_teardown_msi_irq(entry->irq);
> +		int i;
> +		if (entry->irq == 0)
> +			continue;
> +		for (i = 0; i < nvec; i++)
> +			arch_teardown_msi_irq(entry->irq + i);
>  	}
>  }
>  
> @@ -350,7 +366,7 @@ EXPORT_SYMBOL_GPL(pci_restore_msi_state);
>   * multiple messages. A return of zero indicates the successful setup
>   * of an entry zero with the new MSI irq or non-zero for otherwise.
>   **/
> -static int msi_capability_init(struct pci_dev *dev)
> +static int msi_capability_init(struct pci_dev *dev, int nr_irqs)
>  {
>  	struct msi_desc *entry;
>  	int pos, ret;
> @@ -394,7 +410,7 @@ static int msi_capability_init(struct pci_dev *dev)
>  	list_add_tail(&entry->list, &dev->msi_list);
>  
>  	/* Configure MSI capability structure */
> -	ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
> +	ret = arch_setup_msi_irqs(dev, nr_irqs, PCI_CAP_ID_MSI);
>  	if (ret) {
>  		msi_free_irqs(dev);
>  		return ret;
> @@ -546,36 +562,47 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
>  }
>  
>  /**
> - * pci_enable_msi - configure device's MSI capability structure
> - * @dev: pointer to the pci_dev data structure of MSI device function
> + * pci_enable_msi_block - configure device's MSI capability structure
> + * @pdev: Device to configure
> + * @nr_irqs: Number of IRQs requested
> + *
> + * Allocate IRQs for a device with the MSI capability.
> + * This function returns a negative errno if an error occurs.  On success,
> + * this function returns the number of IRQs actually allocated.  Since
> + * MSIs are required to be a power of two, the number of IRQs allocated
> + * may be rounded up to the next power of two (if the number requested is
> + * not a power of two).  Fewer IRQs than requested may be allocated if the
> + * system does not have the resources for the full number.
>   *
> - * Setup the MSI capability structure of device function with
> - * a single MSI irq upon its software driver call to request for
> - * MSI mode enabled on its hardware device function. A return of zero
> - * indicates the successful setup of an entry zero with the new MSI
> - * irq or non-zero for otherwise.
> + * If successful, the @pdev's irq member will be updated to the lowest new
> + * IRQ allocated; the other IRQs allocated to this device will be consecutive.
>   **/
> -int pci_enable_msi(struct pci_dev* dev)
> +int pci_enable_msi_block(struct pci_dev *pdev, unsigned int nr_irqs)
>  {
>  	int status;
>  
> -	status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
> +	/* MSI only supports up to 32 interrupts */
> +	if (nr_irqs > 32)
> +		return 32;
> +
> +	status = pci_msi_check_device(pdev, nr_irqs, PCI_CAP_ID_MSI);
>  	if (status)
>  		return status;
>  
> -	WARN_ON(!!dev->msi_enabled);
> +	WARN_ON(!!pdev->msi_enabled);
>  
> -	/* Check whether driver already requested for MSI-X irqs */
> -	if (dev->msix_enabled) {
> +	/* Check whether driver already requested MSI-X irqs */
> +	if (pdev->msix_enabled) {
>  		printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
>  			"Device already has MSI-X enabled\n",
> -			pci_name(dev));
> +			pci_name(pdev));
>  		return -EINVAL;
>  	}
> -	status = msi_capability_init(dev);
> +
> +	status = msi_capability_init(pdev, nr_irqs);
>  	return status;
>  }
> -EXPORT_SYMBOL(pci_enable_msi);
> +EXPORT_SYMBOL(pci_enable_msi_block);
>  
>  void pci_msi_shutdown(struct pci_dev* dev)
>  {
> @@ -621,26 +648,30 @@ EXPORT_SYMBOL(pci_disable_msi);
>  
>  static int msi_free_irqs(struct pci_dev* dev)
>  {
> -	struct msi_desc *entry, *tmp;
> +	int i, nvec = 1;
> +	struct msi_desc *desc, *tmp;
>  
> -	list_for_each_entry(entry, &dev->msi_list, list) {
> -		if (entry->irq)
> -			BUG_ON(irq_has_action(entry->irq));
> +	list_for_each_entry(desc, &dev->msi_list, list) {
> +		nvec = 1 << desc->msi_attrib.multiple;
> +		if (!desc->irq)
> +			continue;
> +		for (i = 0; i < nvec; i++)
> +			BUG_ON(irq_has_action(desc->irq + i));
>  	}
>  
> -	arch_teardown_msi_irqs(dev);
> +	arch_teardown_msi_irqs(dev, nvec);
>  
> -	list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
> -		if (entry->msi_attrib._type == MSIX_ATTRIB) {
> -			writel(1, entry->mask_base + entry->msi_attrib.entry_nr
> +	list_for_each_entry_safe(desc, tmp, &dev->msi_list, list) {
> +		if (desc->msi_attrib._type == MSIX_ATTRIB) {
> +			writel(1, desc->mask_base + desc->msi_attrib.entry_nr
>  				  * PCI_MSIX_ENTRY_SIZE
>  				  + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
>  
> -			if (list_is_last(&entry->list, &dev->msi_list))
> -				iounmap(entry->mask_base);
> +			if (list_is_last(&desc->list, &dev->msi_list))
> +				iounmap(desc->mask_base);
>  		}
> -		list_del(&entry->list);
> -		kfree(entry);
> +		list_del(&desc->list);
> +		kfree(desc);
>  	}
>  
>  	return 0;
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index d322148..4731fe7 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -45,9 +45,10 @@ struct msi_desc {
>   * The arch hook for setup up msi irqs
>   */
>  int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
> +int arch_setup_msi_block(struct pci_dev *dev, struct msi_desc *desc, int nvec);
>  void arch_teardown_msi_irq(unsigned int irq);
>  extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
> -extern void arch_teardown_msi_irqs(struct pci_dev *dev);
> +extern void arch_teardown_msi_irqs(struct pci_dev *dev, int nvec);
>  extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
>  
> 
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index d18b1dd..f7ca7f8 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -699,7 +699,7 @@ struct msix_entry {
>  
> 
>  #ifndef CONFIG_PCI_MSI
> -static inline int pci_enable_msi(struct pci_dev *dev)
> +static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int count)
>  {
>  	return -1;
>  }
> @@ -726,7 +726,7 @@ static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev)
>  static inline void pci_restore_msi_state(struct pci_dev *dev)
>  { }
>  #else
> -extern int pci_enable_msi(struct pci_dev *dev);
> +extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int count);
>  extern void pci_msi_shutdown(struct pci_dev *dev);
>  extern void pci_disable_msi(struct pci_dev *dev);
>  extern int pci_enable_msix(struct pci_dev *dev,
> @@ -737,6 +737,8 @@ extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
>  extern void pci_restore_msi_state(struct pci_dev *dev);
>  #endif
>  
> +#define pci_enable_msi(pdev)	pci_enable_msi_block(pdev, 1)
> +
>  #ifdef CONFIG_HT_IRQ
>  /* The functions a driver should call */
>  int  ht_create_irq(struct pci_dev *dev, int idx);
-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

  reply	other threads:[~2008-07-07  2:05 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-03  2:44 Multiple MSI Matthew Wilcox
2008-07-03  3:24 ` Benjamin Herrenschmidt
2008-07-03  3:59   ` Matthew Wilcox
2008-07-03  4:41     ` Benjamin Herrenschmidt
2008-07-03  6:44       ` Michael Ellerman
2008-07-03  9:10         ` Arnd Bergmann
2008-07-03  9:17           ` Benjamin Herrenschmidt
2008-07-03 11:31             ` Matthew Wilcox
2008-07-03 11:41               ` Benjamin Herrenschmidt
2008-07-04  1:52                 ` Michael Ellerman
2008-07-04  8:08                   ` Alan Cox
2008-07-03 11:34       ` Matthew Wilcox
2008-07-07 16:17   ` Grant Grundler
2008-07-07 16:39     ` Matthew Wilcox
2008-07-07 16:51       ` Grant Grundler
2008-07-07 23:06     ` Benjamin Herrenschmidt
2008-07-10  0:55     ` Michael Ellerman
2008-07-05 13:27 ` Matthew Wilcox
2008-07-05 13:34   ` [PATCH 1/4] PCI MSI: Store the number of messages in the msi_desc Matthew Wilcox
2008-07-07  2:05     ` Michael Ellerman
2008-07-07  2:41       ` Matthew Wilcox
2008-07-07  3:26         ` Benjamin Herrenschmidt
2008-07-07  3:48         ` Michael Ellerman
2008-07-07 12:04           ` Matthew Wilcox
2008-07-07 16:02             ` Grant Grundler
2008-07-07 16:19               ` Matthew Wilcox
2008-07-10  1:32             ` Michael Ellerman
2008-07-10  1:35               ` Matthew Wilcox
2008-07-05 13:34   ` [PATCH 2/4] PCI: Support multiple MSI Matthew Wilcox
2008-07-07  2:05     ` Michael Ellerman [this message]
2008-07-07  2:45       ` Matthew Wilcox
2008-07-07  3:56         ` Michael Ellerman
2008-07-07 11:31           ` Matthew Wilcox
2008-07-10  1:32             ` Michael Ellerman
2008-07-10  1:43               ` Matthew Wilcox
2008-07-10  4:00                 ` Michael Ellerman
2008-07-05 13:34   ` [PATCH 3/4] AHCI: Request multiple MSIs Matthew Wilcox
2008-07-07 16:45     ` Grant Grundler
2008-07-07 17:48       ` Matthew Wilcox
2008-07-20  7:49         ` Grant Grundler
2008-07-05 13:34   ` [PATCH 4/4] x86-64: Support for " Matthew Wilcox
2008-07-05 13:43   ` Multiple MSI Matthew Wilcox
2008-07-05 22:38     ` Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1215396326.19157.15.camel@localhost \
    --to=michael@ellerman.id.au \
    --cc=Martine.Silbermann@hp.com \
    --cc=benh@kernel.crashing.org \
    --cc=dan.j.williams@intel.com \
    --cc=davem@davemloft.net \
    --cc=kaneshige.kenji@jp.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=matthew@wil.cx \
    --cc=mingo@elte.hu \
    --cc=tglx@linutronix.de \
    --cc=willy@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox