Skip to content

Commit d1ac1d2

Browse files
Alexander Gordeevbjorn-helgaas
authored andcommitted
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>
1 parent 52179dc commit d1ac1d2

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

Documentation/PCI/MSI-HOWTO.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,21 @@ on any interrupt for which it previously called request_irq().
169169
Failure to do so results in a BUG_ON(), leaving the device with
170170
MSI enabled and thus leaking its vector.
171171

172+
4.2.5 pci_msi_vec_count
173+
174+
int pci_msi_vec_count(struct pci_dev *dev)
175+
176+
This function could be used to retrieve the number of MSI vectors the
177+
device requested (via the Multiple Message Capable register). The MSI
178+
specification only allows the returned value to be a power of two,
179+
up to a maximum of 2^5 (32).
180+
181+
If this function returns a negative number, it indicates the device is
182+
not capable of sending MSIs.
183+
184+
If this function returns a positive number, it indicates the maximum
185+
number of MSI interrupt vectors that could be allocated.
186+
172187
4.3 Using MSI-X
173188

174189
The MSI-X capability is much more flexible than the MSI capability.

drivers/pci/msi.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,31 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
842842
return 0;
843843
}
844844

845+
/**
846+
* pci_msi_vec_count - Return the number of MSI vectors a device can send
847+
* @dev: device to report about
848+
*
849+
* This function returns the number of MSI vectors a device requested via
850+
* Multiple Message Capable register. It returns a negative errno if the
851+
* device is not capable sending MSI interrupts. Otherwise, the call succeeds
852+
* and returns a power of two, up to a maximum of 2^5 (32), according to the
853+
* MSI specification.
854+
**/
855+
int pci_msi_vec_count(struct pci_dev *dev)
856+
{
857+
int ret;
858+
u16 msgctl;
859+
860+
if (!dev->msi_cap)
861+
return -EINVAL;
862+
863+
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
864+
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
865+
866+
return ret;
867+
}
868+
EXPORT_SYMBOL(pci_msi_vec_count);
869+
845870
/**
846871
* pci_enable_msi_block - configure device's MSI capability structure
847872
* @dev: device to configure
@@ -858,13 +883,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
858883
int pci_enable_msi_block(struct pci_dev *dev, int nvec)
859884
{
860885
int status, maxvec;
861-
u16 msgctl;
862886

863-
if (!dev->msi_cap || dev->current_state != PCI_D0)
887+
if (dev->current_state != PCI_D0)
864888
return -EINVAL;
865889

866-
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
867-
maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
890+
maxvec = pci_msi_vec_count(dev);
891+
if (maxvec < 0)
892+
return maxvec;
868893
if (nvec > maxvec)
869894
return maxvec;
870895

@@ -889,13 +914,13 @@ EXPORT_SYMBOL(pci_enable_msi_block);
889914
int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec)
890915
{
891916
int ret, nvec;
892-
u16 msgctl;
893917

894-
if (!dev->msi_cap || dev->current_state != PCI_D0)
918+
if (dev->current_state != PCI_D0)
895919
return -EINVAL;
896920

897-
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
898-
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
921+
ret = pci_msi_vec_count(dev);
922+
if (ret < 0)
923+
return ret;
899924

900925
if (maxvec)
901926
*maxvec = ret;

include/linux/pci.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,11 @@ struct msix_entry {
11541154

11551155

11561156
#ifndef CONFIG_PCI_MSI
1157+
static inline int pci_msi_vec_count(struct pci_dev *dev)
1158+
{
1159+
return -ENOSYS;
1160+
}
1161+
11571162
static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
11581163
{
11591164
return -ENOSYS;
@@ -1195,6 +1200,7 @@ static inline int pci_msi_enabled(void)
11951200
return 0;
11961201
}
11971202
#else
1203+
int pci_msi_vec_count(struct pci_dev *dev);
11981204
int pci_enable_msi_block(struct pci_dev *dev, int nvec);
11991205
int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec);
12001206
void pci_msi_shutdown(struct pci_dev *dev);

0 commit comments

Comments
 (0)