Merge branch 'pci/msi' into next
* pci/msi: PCI/MSI: Add pci_enable_msi_range() and pci_enable_msix_range() PCI/MSI: Add pci_msix_vec_count() PCI/MSI: Remove pci_enable_msi_block_auto() PCI/MSI: Add pci_msi_vec_count()
This commit is contained in:
@@ -851,6 +851,31 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
|
||||
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
|
||||
* @dev: device to configure
|
||||
@@ -867,13 +892,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 status, maxvec;
|
||||
u16 msgctl;
|
||||
|
||||
if (!dev->msi_cap || dev->current_state != PCI_D0)
|
||||
if (dev->current_state != PCI_D0)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
|
||||
maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
|
||||
maxvec = pci_msi_vec_count(dev);
|
||||
if (maxvec < 0)
|
||||
return maxvec;
|
||||
if (nvec > maxvec)
|
||||
return maxvec;
|
||||
|
||||
@@ -895,31 +920,6 @@ int pci_enable_msi_block(struct pci_dev *dev, int nvec)
|
||||
}
|
||||
EXPORT_SYMBOL(pci_enable_msi_block);
|
||||
|
||||
int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec)
|
||||
{
|
||||
int ret, nvec;
|
||||
u16 msgctl;
|
||||
|
||||
if (!dev->msi_cap || dev->current_state != PCI_D0)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
|
||||
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
|
||||
|
||||
if (maxvec)
|
||||
*maxvec = ret;
|
||||
|
||||
do {
|
||||
nvec = ret;
|
||||
ret = pci_enable_msi_block(dev, nvec);
|
||||
} while (ret > 0);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return nvec;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_enable_msi_block_auto);
|
||||
|
||||
void pci_msi_shutdown(struct pci_dev *dev)
|
||||
{
|
||||
struct msi_desc *desc;
|
||||
@@ -957,19 +957,25 @@ void pci_disable_msi(struct pci_dev *dev)
|
||||
EXPORT_SYMBOL(pci_disable_msi);
|
||||
|
||||
/**
|
||||
* pci_msix_table_size - return the number of device's MSI-X table entries
|
||||
* pci_msix_vec_count - return the number of device's MSI-X table entries
|
||||
* @dev: pointer to the pci_dev data structure of MSI-X device function
|
||||
*/
|
||||
int pci_msix_table_size(struct pci_dev *dev)
|
||||
|
||||
* This function returns the number of device's MSI-X table entries and
|
||||
* therefore the number of MSI-X vectors device is capable of sending.
|
||||
* It returns a negative errno if the device is not capable of sending MSI-X
|
||||
* interrupts.
|
||||
**/
|
||||
int pci_msix_vec_count(struct pci_dev *dev)
|
||||
{
|
||||
u16 control;
|
||||
|
||||
if (!dev->msix_cap)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
|
||||
return msix_table_size(control);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_msix_vec_count);
|
||||
|
||||
/**
|
||||
* pci_enable_msix - configure device's MSI-X capability structure
|
||||
@@ -998,7 +1004,9 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
nr_entries = pci_msix_table_size(dev);
|
||||
nr_entries = pci_msix_vec_count(dev);
|
||||
if (nr_entries < 0)
|
||||
return nr_entries;
|
||||
if (nvec > nr_entries)
|
||||
return nr_entries;
|
||||
|
||||
@@ -1103,3 +1111,77 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
|
||||
if (dev->msix_cap)
|
||||
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);
|
||||
|
Reference in New Issue
Block a user