PCI/MSI: Add pci_msi_vec_count()

Device drivers can use this interface to obtain the maximum number of MSI
interrupts the device supports and use that number, e.g., in a subsequent
call to pci_enable_msi_block().

Signed-off-by: Alexander Gordeev <agordeev@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Alexander Gordeev 2013-12-30 08:28:13 +01:00 committed by Bjorn Helgaas
parent 52179dc9ed
commit d1ac1d2622
3 changed files with 54 additions and 8 deletions

View File

@ -169,6 +169,21 @@ on any interrupt for which it previously called request_irq().
Failure to do so results in a BUG_ON(), leaving the device with Failure to do so results in a BUG_ON(), leaving the device with
MSI enabled and thus leaking its vector. MSI enabled and thus leaking its vector.
4.2.5 pci_msi_vec_count
int pci_msi_vec_count(struct pci_dev *dev)
This function could be used to retrieve the number of MSI vectors the
device requested (via the Multiple Message Capable register). The MSI
specification only allows the returned value to be a power of two,
up to a maximum of 2^5 (32).
If this function returns a negative number, it indicates the device is
not capable of sending MSIs.
If this function returns a positive number, it indicates the maximum
number of MSI interrupt vectors that could be allocated.
4.3 Using MSI-X 4.3 Using MSI-X
The MSI-X capability is much more flexible than the MSI capability. The MSI-X capability is much more flexible than the MSI capability.

View File

@ -842,6 +842,31 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
return 0; return 0;
} }
/**
* pci_msi_vec_count - Return the number of MSI vectors a device can send
* @dev: device to report about
*
* This function returns the number of MSI vectors a device requested via
* Multiple Message Capable register. It returns a negative errno if the
* device is not capable sending MSI interrupts. Otherwise, the call succeeds
* and returns a power of two, up to a maximum of 2^5 (32), according to the
* MSI specification.
**/
int pci_msi_vec_count(struct pci_dev *dev)
{
int ret;
u16 msgctl;
if (!dev->msi_cap)
return -EINVAL;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
return ret;
}
EXPORT_SYMBOL(pci_msi_vec_count);
/** /**
* pci_enable_msi_block - configure device's MSI capability structure * pci_enable_msi_block - configure device's MSI capability structure
* @dev: device to configure * @dev: device to configure
@ -858,13 +883,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
int pci_enable_msi_block(struct pci_dev *dev, int nvec) int pci_enable_msi_block(struct pci_dev *dev, int nvec)
{ {
int status, maxvec; int status, maxvec;
u16 msgctl;
if (!dev->msi_cap || dev->current_state != PCI_D0) if (dev->current_state != PCI_D0)
return -EINVAL; return -EINVAL;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl); maxvec = pci_msi_vec_count(dev);
maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); if (maxvec < 0)
return maxvec;
if (nvec > maxvec) if (nvec > maxvec)
return maxvec; return maxvec;
@ -889,13 +914,13 @@ EXPORT_SYMBOL(pci_enable_msi_block);
int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec) int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec)
{ {
int ret, nvec; int ret, nvec;
u16 msgctl;
if (!dev->msi_cap || dev->current_state != PCI_D0) if (dev->current_state != PCI_D0)
return -EINVAL; return -EINVAL;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl); ret = pci_msi_vec_count(dev);
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); if (ret < 0)
return ret;
if (maxvec) if (maxvec)
*maxvec = ret; *maxvec = ret;

View File

@ -1154,6 +1154,11 @@ struct msix_entry {
#ifndef CONFIG_PCI_MSI #ifndef CONFIG_PCI_MSI
static inline int pci_msi_vec_count(struct pci_dev *dev)
{
return -ENOSYS;
}
static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec) static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
{ {
return -ENOSYS; return -ENOSYS;
@ -1195,6 +1200,7 @@ static inline int pci_msi_enabled(void)
return 0; return 0;
} }
#else #else
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);
int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec); int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec);
void pci_msi_shutdown(struct pci_dev *dev); void pci_msi_shutdown(struct pci_dev *dev);