aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Gordeev <agordeev@redhat.com>2013-12-30 02:28:13 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-01-03 19:17:55 -0500
commitd1ac1d2622e8f0fd2a25127a8649d135b54db8a9 (patch)
tree9b267fa3c5d97fc9c6c65877a9d493d407258abe
parent52179dc9edc3b7a2b3bb01cbb1b6c96f6d05fc73 (diff)
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>
-rw-r--r--Documentation/PCI/MSI-HOWTO.txt15
-rw-r--r--drivers/pci/msi.c41
-rw-r--r--include/linux/pci.h6
3 files changed, 54 insertions, 8 deletions
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt
index a4d174e95413..a8b41788dfde 100644
--- a/Documentation/PCI/MSI-HOWTO.txt
+++ b/Documentation/PCI/MSI-HOWTO.txt
@@ -169,6 +169,21 @@ on any interrupt for which it previously called request_irq().
169Failure to do so results in a BUG_ON(), leaving the device with 169Failure to do so results in a BUG_ON(), leaving the device with
170MSI enabled and thus leaking its vector. 170MSI enabled and thus leaking its vector.
171 171
1724.2.5 pci_msi_vec_count
173
174int pci_msi_vec_count(struct pci_dev *dev)
175
176This function could be used to retrieve the number of MSI vectors the
177device requested (via the Multiple Message Capable register). The MSI
178specification only allows the returned value to be a power of two,
179up to a maximum of 2^5 (32).
180
181If this function returns a negative number, it indicates the device is
182not capable of sending MSIs.
183
184If this function returns a positive number, it indicates the maximum
185number of MSI interrupt vectors that could be allocated.
186
1724.3 Using MSI-X 1874.3 Using MSI-X
173 188
174The MSI-X capability is much more flexible than the MSI capability. 189The MSI-X capability is much more flexible than the MSI capability.
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ce0d4eb91a22..ba6d0a9bdd39 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -843,6 +843,31 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
843} 843}
844 844
845/** 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 **/
855int 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}
868EXPORT_SYMBOL(pci_msi_vec_count);
869
870/**
846 * pci_enable_msi_block - configure device's MSI capability structure 871 * pci_enable_msi_block - configure device's MSI capability structure
847 * @dev: device to configure 872 * @dev: device to configure
848 * @nvec: number of interrupts to configure 873 * @nvec: number of interrupts to configure
@@ -858,13 +883,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
858int pci_enable_msi_block(struct pci_dev *dev, int nvec) 883int pci_enable_msi_block(struct pci_dev *dev, int nvec)
859{ 884{
860 int status, maxvec; 885 int status, maxvec;
861 u16 msgctl;
862 886
863 if (!dev->msi_cap || dev->current_state != PCI_D0) 887 if (dev->current_state != PCI_D0)
864 return -EINVAL; 888 return -EINVAL;
865 889
866 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl); 890 maxvec = pci_msi_vec_count(dev);
867 maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); 891 if (maxvec < 0)
892 return maxvec;
868 if (nvec > maxvec) 893 if (nvec > maxvec)
869 return maxvec; 894 return maxvec;
870 895
@@ -889,13 +914,13 @@ EXPORT_SYMBOL(pci_enable_msi_block);
889int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec) 914int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec)
890{ 915{
891 int ret, nvec; 916 int ret, nvec;
892 u16 msgctl;
893 917
894 if (!dev->msi_cap || dev->current_state != PCI_D0) 918 if (dev->current_state != PCI_D0)
895 return -EINVAL; 919 return -EINVAL;
896 920
897 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl); 921 ret = pci_msi_vec_count(dev);
898 ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); 922 if (ret < 0)
923 return ret;
899 924
900 if (maxvec) 925 if (maxvec)
901 *maxvec = ret; 926 *maxvec = ret;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7c34c3913bcb..6691de093f1c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1154,6 +1154,11 @@ struct msix_entry {
1154 1154
1155 1155
1156#ifndef CONFIG_PCI_MSI 1156#ifndef CONFIG_PCI_MSI
1157static inline int pci_msi_vec_count(struct pci_dev *dev)
1158{
1159 return -ENOSYS;
1160}
1161
1157static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec) 1162static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
1158{ 1163{
1159 return -ENOSYS; 1164 return -ENOSYS;
@@ -1195,6 +1200,7 @@ static inline int pci_msi_enabled(void)
1195 return 0; 1200 return 0;
1196} 1201}
1197#else 1202#else
1203int pci_msi_vec_count(struct pci_dev *dev);
1198int pci_enable_msi_block(struct pci_dev *dev, int nvec); 1204int pci_enable_msi_block(struct pci_dev *dev, int nvec);
1199int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec); 1205int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec);
1200void pci_msi_shutdown(struct pci_dev *dev); 1206void pci_msi_shutdown(struct pci_dev *dev);