aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/msi.c150
-rw-r--r--drivers/pci/pcie/portdrv_core.c7
2 files changed, 120 insertions, 37 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 22957aa51edc..7a0fec6ce571 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -852,6 +852,31 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
852} 852}
853 853
854/** 854/**
855 * pci_msi_vec_count - Return the number of MSI vectors a device can send
856 * @dev: device to report about
857 *
858 * This function returns the number of MSI vectors a device requested via
859 * Multiple Message Capable register. It returns a negative errno if the
860 * device is not capable sending MSI interrupts. Otherwise, the call succeeds
861 * and returns a power of two, up to a maximum of 2^5 (32), according to the
862 * MSI specification.
863 **/
864int pci_msi_vec_count(struct pci_dev *dev)
865{
866 int ret;
867 u16 msgctl;
868
869 if (!dev->msi_cap)
870 return -EINVAL;
871
872 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
873 ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
874
875 return ret;
876}
877EXPORT_SYMBOL(pci_msi_vec_count);
878
879/**
855 * pci_enable_msi_block - configure device's MSI capability structure 880 * pci_enable_msi_block - configure device's MSI capability structure
856 * @dev: device to configure 881 * @dev: device to configure
857 * @nvec: number of interrupts to configure 882 * @nvec: number of interrupts to configure
@@ -867,13 +892,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
867int pci_enable_msi_block(struct pci_dev *dev, int nvec) 892int pci_enable_msi_block(struct pci_dev *dev, int nvec)
868{ 893{
869 int status, maxvec; 894 int status, maxvec;
870 u16 msgctl;
871 895
872 if (!dev->msi_cap || dev->current_state != PCI_D0) 896 if (dev->current_state != PCI_D0)
873 return -EINVAL; 897 return -EINVAL;
874 898
875 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl); 899 maxvec = pci_msi_vec_count(dev);
876 maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); 900 if (maxvec < 0)
901 return maxvec;
877 if (nvec > maxvec) 902 if (nvec > maxvec)
878 return maxvec; 903 return maxvec;
879 904
@@ -895,31 +920,6 @@ int pci_enable_msi_block(struct pci_dev *dev, int nvec)
895} 920}
896EXPORT_SYMBOL(pci_enable_msi_block); 921EXPORT_SYMBOL(pci_enable_msi_block);
897 922
898int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec)
899{
900 int ret, nvec;
901 u16 msgctl;
902
903 if (!dev->msi_cap || dev->current_state != PCI_D0)
904 return -EINVAL;
905
906 pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
907 ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
908
909 if (maxvec)
910 *maxvec = ret;
911
912 do {
913 nvec = ret;
914 ret = pci_enable_msi_block(dev, nvec);
915 } while (ret > 0);
916
917 if (ret < 0)
918 return ret;
919 return nvec;
920}
921EXPORT_SYMBOL(pci_enable_msi_block_auto);
922
923void pci_msi_shutdown(struct pci_dev *dev) 923void pci_msi_shutdown(struct pci_dev *dev)
924{ 924{
925 struct msi_desc *desc; 925 struct msi_desc *desc;
@@ -957,19 +957,25 @@ void pci_disable_msi(struct pci_dev *dev)
957EXPORT_SYMBOL(pci_disable_msi); 957EXPORT_SYMBOL(pci_disable_msi);
958 958
959/** 959/**
960 * pci_msix_table_size - return the number of device's MSI-X table entries 960 * pci_msix_vec_count - return the number of device's MSI-X table entries
961 * @dev: pointer to the pci_dev data structure of MSI-X device function 961 * @dev: pointer to the pci_dev data structure of MSI-X device function
962 */ 962
963int pci_msix_table_size(struct pci_dev *dev) 963 * This function returns the number of device's MSI-X table entries and
964 * therefore the number of MSI-X vectors device is capable of sending.
965 * It returns a negative errno if the device is not capable of sending MSI-X
966 * interrupts.
967 **/
968int pci_msix_vec_count(struct pci_dev *dev)
964{ 969{
965 u16 control; 970 u16 control;
966 971
967 if (!dev->msix_cap) 972 if (!dev->msix_cap)
968 return 0; 973 return -EINVAL;
969 974
970 pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control); 975 pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
971 return msix_table_size(control); 976 return msix_table_size(control);
972} 977}
978EXPORT_SYMBOL(pci_msix_vec_count);
973 979
974/** 980/**
975 * pci_enable_msix - configure device's MSI-X capability structure 981 * 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)
998 if (status) 1004 if (status)
999 return status; 1005 return status;
1000 1006
1001 nr_entries = pci_msix_table_size(dev); 1007 nr_entries = pci_msix_vec_count(dev);
1008 if (nr_entries < 0)
1009 return nr_entries;
1002 if (nvec > nr_entries) 1010 if (nvec > nr_entries)
1003 return nr_entries; 1011 return nr_entries;
1004 1012
@@ -1103,3 +1111,77 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
1103 if (dev->msix_cap) 1111 if (dev->msix_cap)
1104 msix_set_enable(dev, 0); 1112 msix_set_enable(dev, 0);
1105} 1113}
1114
1115/**
1116 * pci_enable_msi_range - configure device's MSI capability structure
1117 * @dev: device to configure
1118 * @minvec: minimal number of interrupts to configure
1119 * @maxvec: maximum number of interrupts to configure
1120 *
1121 * This function tries to allocate a maximum possible number of interrupts in a
1122 * range between @minvec and @maxvec. It returns a negative errno if an error
1123 * occurs. If it succeeds, it returns the actual number of interrupts allocated
1124 * and updates the @dev's irq member to the lowest new interrupt number;
1125 * the other interrupt numbers allocated to this device are consecutive.
1126 **/
1127int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
1128{
1129 int nvec = maxvec;
1130 int rc;
1131
1132 if (maxvec < minvec)
1133 return -ERANGE;
1134
1135 do {
1136 rc = pci_enable_msi_block(dev, nvec);
1137 if (rc < 0) {
1138 return rc;
1139 } else if (rc > 0) {
1140 if (rc < minvec)
1141 return -ENOSPC;
1142 nvec = rc;
1143 }
1144 } while (rc);
1145
1146 return nvec;
1147}
1148EXPORT_SYMBOL(pci_enable_msi_range);
1149
1150/**
1151 * pci_enable_msix_range - configure device's MSI-X capability structure
1152 * @dev: pointer to the pci_dev data structure of MSI-X device function
1153 * @entries: pointer to an array of MSI-X entries
1154 * @minvec: minimum number of MSI-X irqs requested
1155 * @maxvec: maximum number of MSI-X irqs requested
1156 *
1157 * Setup the MSI-X capability structure of device function with a maximum
1158 * possible number of interrupts in the range between @minvec and @maxvec
1159 * upon its software driver call to request for MSI-X mode enabled on its
1160 * hardware device function. It returns a negative errno if an error occurs.
1161 * If it succeeds, it returns the actual number of interrupts allocated and
1162 * indicates the successful configuration of MSI-X capability structure
1163 * with new allocated MSI-X interrupts.
1164 **/
1165int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
1166 int minvec, int maxvec)
1167{
1168 int nvec = maxvec;
1169 int rc;
1170
1171 if (maxvec < minvec)
1172 return -ERANGE;
1173
1174 do {
1175 rc = pci_enable_msix(dev, entries, nvec);
1176 if (rc < 0) {
1177 return rc;
1178 } else if (rc > 0) {
1179 if (rc < minvec)
1180 return -ENOSPC;
1181 nvec = rc;
1182 }
1183 } while (rc);
1184
1185 return nvec;
1186}
1187EXPORT_SYMBOL(pci_enable_msix_range);
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 16a1ce4f6b18..986f8eadfd39 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -79,9 +79,10 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
79 u16 reg16; 79 u16 reg16;
80 u32 reg32; 80 u32 reg32;
81 81
82 nr_entries = pci_msix_table_size(dev); 82 nr_entries = pci_msix_vec_count(dev);
83 if (!nr_entries) 83 if (nr_entries < 0)
84 return -EINVAL; 84 return nr_entries;
85 BUG_ON(!nr_entries);
85 if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES) 86 if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES)
86 nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES; 87 nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES;
87 88