diff options
-rw-r--r-- | drivers/pci/msi.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a83c1f5735d6..008235947aa4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -901,6 +901,33 @@ static int msix_capability_init(struct pci_dev *dev, | |||
901 | } | 901 | } |
902 | 902 | ||
903 | /** | 903 | /** |
904 | * pci_msi_supported - check whether MSI may be enabled on device | ||
905 | * @dev: pointer to the pci_dev data structure of MSI device function | ||
906 | * | ||
907 | * MSI must be globally enabled and supported by the device and its root | ||
908 | * bus. But, the root bus is not easy to find since some architectures | ||
909 | * have virtual busses on top of the PCI hierarchy (for instance the | ||
910 | * hypertransport bus), while the actual bus where MSI must be supported | ||
911 | * is below. So we test the MSI flag on all parent busses and assume | ||
912 | * that no quirk will ever set the NO_MSI flag on a non-root bus. | ||
913 | **/ | ||
914 | static | ||
915 | int pci_msi_supported(struct pci_dev * dev) | ||
916 | { | ||
917 | struct pci_bus *bus; | ||
918 | |||
919 | if (!pci_msi_enable || !dev || dev->no_msi) | ||
920 | return -EINVAL; | ||
921 | |||
922 | /* check MSI flags of all parent busses */ | ||
923 | for (bus = dev->bus; bus; bus = bus->parent) | ||
924 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
925 | return -EINVAL; | ||
926 | |||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | /** | ||
904 | * pci_enable_msi - configure device's MSI capability structure | 931 | * pci_enable_msi - configure device's MSI capability structure |
905 | * @dev: pointer to the pci_dev data structure of MSI device function | 932 | * @dev: pointer to the pci_dev data structure of MSI device function |
906 | * | 933 | * |
@@ -912,19 +939,11 @@ static int msix_capability_init(struct pci_dev *dev, | |||
912 | **/ | 939 | **/ |
913 | int pci_enable_msi(struct pci_dev* dev) | 940 | int pci_enable_msi(struct pci_dev* dev) |
914 | { | 941 | { |
915 | struct pci_bus *bus; | 942 | int pos, temp, status; |
916 | int pos, temp, status = -EINVAL; | ||
917 | u16 control; | 943 | u16 control; |
918 | 944 | ||
919 | if (!pci_msi_enable || !dev) | 945 | if (pci_msi_supported(dev) < 0) |
920 | return status; | 946 | return -EINVAL; |
921 | |||
922 | if (dev->no_msi) | ||
923 | return status; | ||
924 | |||
925 | for (bus = dev->bus; bus; bus = bus->parent) | ||
926 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
927 | return -EINVAL; | ||
928 | 947 | ||
929 | temp = dev->irq; | 948 | temp = dev->irq; |
930 | 949 | ||
@@ -1134,22 +1153,14 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | |||
1134 | **/ | 1153 | **/ |
1135 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 1154 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
1136 | { | 1155 | { |
1137 | struct pci_bus *bus; | ||
1138 | int status, pos, nr_entries, free_vectors; | 1156 | int status, pos, nr_entries, free_vectors; |
1139 | int i, j, temp; | 1157 | int i, j, temp; |
1140 | u16 control; | 1158 | u16 control; |
1141 | unsigned long flags; | 1159 | unsigned long flags; |
1142 | 1160 | ||
1143 | if (!pci_msi_enable || !dev || !entries) | 1161 | if (!entries || pci_msi_supported(dev) < 0) |
1144 | return -EINVAL; | 1162 | return -EINVAL; |
1145 | 1163 | ||
1146 | if (dev->no_msi) | ||
1147 | return -EINVAL; | ||
1148 | |||
1149 | for (bus = dev->bus; bus; bus = bus->parent) | ||
1150 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
1151 | return -EINVAL; | ||
1152 | |||
1153 | status = msi_init(); | 1164 | status = msi_init(); |
1154 | if (status < 0) | 1165 | if (status < 0) |
1155 | return status; | 1166 | return status; |