Commit 302a2523 authored by Alexander Gordeev's avatar Alexander Gordeev Committed by Bjorn Helgaas

PCI/MSI: Add pci_enable_msi_range() and pci_enable_msix_range()

This adds pci_enable_msi_range(), which supersedes the pci_enable_msi()
and pci_enable_msi_block() MSI interfaces.

It also adds pci_enable_msix_range(), which supersedes the
pci_enable_msix() MSI-X interface.

The old interfaces have three categories of return values:

    negative: failure; caller should not retry
    positive: failure; value indicates number of interrupts that *could*
	have been allocated, and caller may retry with a smaller request
    zero: success; at least as many interrupts allocated as requested

It is error-prone to handle these three cases correctly in drivers.

The new functions return either a negative error code or a number of
successfully allocated MSI/MSI-X interrupts, which is expected to lead to
clearer device driver code.

pci_enable_msi(), pci_enable_msi_block() and pci_enable_msix() still exist
unchanged, but are deprecated and may be removed after callers are updated.

[bhelgaas: tweak changelog]
Suggested-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarAlexander Gordeev <agordeev@redhat.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarTejun Heo <tj@kernel.org>
parent ff1aa430
This diff is collapsed.
...@@ -1102,3 +1102,77 @@ void pci_msi_init_pci_dev(struct pci_dev *dev) ...@@ -1102,3 +1102,77 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
if (dev->msix_cap) if (dev->msix_cap)
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
} }
/**
* pci_enable_msi_range - configure device's MSI capability structure
* @dev: device to configure
* @minvec: minimal number of interrupts to configure
* @maxvec: maximum number of interrupts to configure
*
* This function tries to allocate a maximum possible number of interrupts in a
* range between @minvec and @maxvec. It returns a negative errno if an error
* occurs. If it succeeds, it returns the actual number of interrupts allocated
* and updates the @dev's irq member to the lowest new interrupt number;
* the other interrupt numbers allocated to this device are consecutive.
**/
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
{
int nvec = maxvec;
int rc;
if (maxvec < minvec)
return -ERANGE;
do {
rc = pci_enable_msi_block(dev, nvec);
if (rc < 0) {
return rc;
} else if (rc > 0) {
if (rc < minvec)
return -ENOSPC;
nvec = rc;
}
} while (rc);
return nvec;
}
EXPORT_SYMBOL(pci_enable_msi_range);
/**
* pci_enable_msix_range - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of MSI-X entries
* @minvec: minimum number of MSI-X irqs requested
* @maxvec: maximum number of MSI-X irqs requested
*
* Setup the MSI-X capability structure of device function with a maximum
* possible number of interrupts in the range between @minvec and @maxvec
* upon its software driver call to request for MSI-X mode enabled on its
* hardware device function. It returns a negative errno if an error occurs.
* If it succeeds, it returns the actual number of interrupts allocated and
* indicates the successful configuration of MSI-X capability structure
* with new allocated MSI-X interrupts.
**/
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
int minvec, int maxvec)
{
int nvec = maxvec;
int rc;
if (maxvec < minvec)
return -ERANGE;
do {
rc = pci_enable_msix(dev, entries, nvec);
if (rc < 0) {
return rc;
} else if (rc > 0) {
if (rc < minvec)
return -ENOSPC;
nvec = rc;
}
} while (rc);
return nvec;
}
EXPORT_SYMBOL(pci_enable_msix_range);
...@@ -1193,6 +1193,17 @@ static inline int pci_msi_enabled(void) ...@@ -1193,6 +1193,17 @@ static inline int pci_msi_enabled(void)
{ {
return 0; return 0;
} }
static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
int maxvec)
{
return -ENOSYS;
}
static inline int pci_enable_msix_range(struct pci_dev *dev,
struct msix_entry *entries, int minvec, int maxvec)
{
return -ENOSYS;
}
#else #else
int pci_msi_vec_count(struct pci_dev *dev); int pci_msi_vec_count(struct pci_dev *dev);
int pci_enable_msi_block(struct pci_dev *dev, int nvec); int pci_enable_msi_block(struct pci_dev *dev, int nvec);
...@@ -1205,6 +1216,9 @@ void pci_disable_msix(struct pci_dev *dev); ...@@ -1205,6 +1216,9 @@ void pci_disable_msix(struct pci_dev *dev);
void msi_remove_pci_irq_vectors(struct pci_dev *dev); void msi_remove_pci_irq_vectors(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev); void pci_restore_msi_state(struct pci_dev *dev);
int pci_msi_enabled(void); int pci_msi_enabled(void);
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec);
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
int minvec, int maxvec);
#endif #endif
#ifdef CONFIG_PCIEPORTBUS #ifdef CONFIG_PCIEPORTBUS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment