diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/msi.c | 150 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 7 |
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 | **/ | ||
864 | int 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 | } | ||
877 | EXPORT_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) | |||
867 | int pci_enable_msi_block(struct pci_dev *dev, int nvec) | 892 | int 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 | } |
896 | EXPORT_SYMBOL(pci_enable_msi_block); | 921 | EXPORT_SYMBOL(pci_enable_msi_block); |
897 | 922 | ||
898 | int 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 | } | ||
921 | EXPORT_SYMBOL(pci_enable_msi_block_auto); | ||
922 | |||
923 | void pci_msi_shutdown(struct pci_dev *dev) | 923 | void 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) | |||
957 | EXPORT_SYMBOL(pci_disable_msi); | 957 | EXPORT_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 | |
963 | int 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 | **/ | ||
968 | int 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 | } |
978 | EXPORT_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 | **/ | ||
1127 | int 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 | } | ||
1148 | EXPORT_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 | **/ | ||
1165 | int 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 | } | ||
1187 | EXPORT_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 | ||