diff options
-rw-r--r-- | drivers/pci/msi.c | 122 |
1 files changed, 16 insertions, 106 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 27a057409eca..75d1c0dacffa 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -933,7 +933,6 @@ int pci_msi_supported(struct pci_dev * dev) | |||
933 | int pci_enable_msi(struct pci_dev* dev) | 933 | int pci_enable_msi(struct pci_dev* dev) |
934 | { | 934 | { |
935 | int pos, temp, status; | 935 | int pos, temp, status; |
936 | u16 control; | ||
937 | 936 | ||
938 | if (pci_msi_supported(dev) < 0) | 937 | if (pci_msi_supported(dev) < 0) |
939 | return -EINVAL; | 938 | return -EINVAL; |
@@ -948,27 +947,8 @@ int pci_enable_msi(struct pci_dev* dev) | |||
948 | if (!pos) | 947 | if (!pos) |
949 | return -EINVAL; | 948 | return -EINVAL; |
950 | 949 | ||
951 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 950 | WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI)); |
952 | /* Lookup Sucess */ | ||
953 | unsigned long flags; | ||
954 | 951 | ||
955 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
956 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
957 | return 0; /* Already in MSI mode */ | ||
958 | spin_lock_irqsave(&msi_lock, flags); | ||
959 | if (!vector_irq[dev->irq]) { | ||
960 | msi_desc[dev->irq]->msi_attrib.state = 0; | ||
961 | vector_irq[dev->irq] = -1; | ||
962 | nr_released_vectors--; | ||
963 | spin_unlock_irqrestore(&msi_lock, flags); | ||
964 | status = msi_register_init(dev, msi_desc[dev->irq]); | ||
965 | if (status == 0) | ||
966 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
967 | return status; | ||
968 | } | ||
969 | spin_unlock_irqrestore(&msi_lock, flags); | ||
970 | dev->irq = temp; | ||
971 | } | ||
972 | /* Check whether driver already requested for MSI-X vectors */ | 952 | /* Check whether driver already requested for MSI-X vectors */ |
973 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 953 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); |
974 | if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | 954 | if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { |
@@ -1010,6 +990,8 @@ void pci_disable_msi(struct pci_dev* dev) | |||
1010 | if (!(control & PCI_MSI_FLAGS_ENABLE)) | 990 | if (!(control & PCI_MSI_FLAGS_ENABLE)) |
1011 | return; | 991 | return; |
1012 | 992 | ||
993 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
994 | |||
1013 | spin_lock_irqsave(&msi_lock, flags); | 995 | spin_lock_irqsave(&msi_lock, flags); |
1014 | entry = msi_desc[dev->irq]; | 996 | entry = msi_desc[dev->irq]; |
1015 | if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { | 997 | if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { |
@@ -1023,14 +1005,12 @@ void pci_disable_msi(struct pci_dev* dev) | |||
1023 | pci_name(dev), dev->irq); | 1005 | pci_name(dev), dev->irq); |
1024 | BUG_ON(entry->msi_attrib.state > 0); | 1006 | BUG_ON(entry->msi_attrib.state > 0); |
1025 | } else { | 1007 | } else { |
1026 | vector_irq[dev->irq] = 0; /* free it */ | ||
1027 | nr_released_vectors++; | ||
1028 | default_vector = entry->msi_attrib.default_vector; | 1008 | default_vector = entry->msi_attrib.default_vector; |
1029 | spin_unlock_irqrestore(&msi_lock, flags); | 1009 | spin_unlock_irqrestore(&msi_lock, flags); |
1010 | msi_free_vector(dev, dev->irq, 0); | ||
1011 | |||
1030 | /* Restore dev->irq to its default pin-assertion vector */ | 1012 | /* Restore dev->irq to its default pin-assertion vector */ |
1031 | dev->irq = default_vector; | 1013 | dev->irq = default_vector; |
1032 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
1033 | PCI_CAP_ID_MSI); | ||
1034 | } | 1014 | } |
1035 | } | 1015 | } |
1036 | 1016 | ||
@@ -1078,57 +1058,6 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
1078 | return 0; | 1058 | return 0; |
1079 | } | 1059 | } |
1080 | 1060 | ||
1081 | static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | ||
1082 | { | ||
1083 | int vector = head, tail = 0; | ||
1084 | int i, j = 0, nr_entries = 0; | ||
1085 | void __iomem *base; | ||
1086 | unsigned long flags; | ||
1087 | |||
1088 | spin_lock_irqsave(&msi_lock, flags); | ||
1089 | while (head != tail) { | ||
1090 | nr_entries++; | ||
1091 | tail = msi_desc[vector]->link.tail; | ||
1092 | if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr) | ||
1093 | j = vector; | ||
1094 | vector = tail; | ||
1095 | } | ||
1096 | if (*nvec > nr_entries) { | ||
1097 | spin_unlock_irqrestore(&msi_lock, flags); | ||
1098 | *nvec = nr_entries; | ||
1099 | return -EINVAL; | ||
1100 | } | ||
1101 | vector = ((j > 0) ? j : head); | ||
1102 | for (i = 0; i < *nvec; i++) { | ||
1103 | j = msi_desc[vector]->msi_attrib.entry_nr; | ||
1104 | msi_desc[vector]->msi_attrib.state = 0; /* Mark it not active */ | ||
1105 | vector_irq[vector] = -1; /* Mark it busy */ | ||
1106 | nr_released_vectors--; | ||
1107 | entries[i].vector = vector; | ||
1108 | if (j != (entries + i)->entry) { | ||
1109 | base = msi_desc[vector]->mask_base; | ||
1110 | msi_desc[vector]->msi_attrib.entry_nr = | ||
1111 | (entries + i)->entry; | ||
1112 | writel( readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
1113 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base + | ||
1114 | (entries + i)->entry * PCI_MSIX_ENTRY_SIZE + | ||
1115 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
1116 | writel( readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
1117 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base + | ||
1118 | (entries + i)->entry * PCI_MSIX_ENTRY_SIZE + | ||
1119 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
1120 | writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
1121 | PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector, | ||
1122 | base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE + | ||
1123 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
1124 | } | ||
1125 | vector = msi_desc[vector]->link.tail; | ||
1126 | } | ||
1127 | spin_unlock_irqrestore(&msi_lock, flags); | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | /** | 1061 | /** |
1133 | * pci_enable_msix - configure device's MSI-X capability structure | 1062 | * pci_enable_msix - configure device's MSI-X capability structure |
1134 | * @dev: pointer to the pci_dev data structure of MSI-X device function | 1063 | * @dev: pointer to the pci_dev data structure of MSI-X device function |
@@ -1163,9 +1092,6 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
1163 | return -EINVAL; | 1092 | return -EINVAL; |
1164 | 1093 | ||
1165 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 1094 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
1166 | if (control & PCI_MSIX_FLAGS_ENABLE) | ||
1167 | return -EINVAL; /* Already in MSI-X mode */ | ||
1168 | |||
1169 | nr_entries = multi_msix_capable(control); | 1095 | nr_entries = multi_msix_capable(control); |
1170 | if (nvec > nr_entries) | 1096 | if (nvec > nr_entries) |
1171 | return -EINVAL; | 1097 | return -EINVAL; |
@@ -1180,19 +1106,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
1180 | } | 1106 | } |
1181 | } | 1107 | } |
1182 | temp = dev->irq; | 1108 | temp = dev->irq; |
1183 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | 1109 | WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)); |
1184 | /* Lookup Sucess */ | 1110 | |
1185 | nr_entries = nvec; | ||
1186 | /* Reroute MSI-X table */ | ||
1187 | if (reroute_msix_table(dev->irq, entries, &nr_entries)) { | ||
1188 | /* #requested > #previous-assigned */ | ||
1189 | dev->irq = temp; | ||
1190 | return nr_entries; | ||
1191 | } | ||
1192 | dev->irq = temp; | ||
1193 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | ||
1194 | return 0; | ||
1195 | } | ||
1196 | /* Check whether driver already requested for MSI vector */ | 1111 | /* Check whether driver already requested for MSI vector */ |
1197 | if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && | 1112 | if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && |
1198 | !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 1113 | !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { |
@@ -1251,37 +1166,32 @@ void pci_disable_msix(struct pci_dev* dev) | |||
1251 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | 1166 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) |
1252 | return; | 1167 | return; |
1253 | 1168 | ||
1169 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | ||
1170 | |||
1254 | temp = dev->irq; | 1171 | temp = dev->irq; |
1255 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | 1172 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { |
1256 | int state, vector, head, tail = 0, warning = 0; | 1173 | int state, vector, head, tail = 0, warning = 0; |
1257 | unsigned long flags; | 1174 | unsigned long flags; |
1258 | 1175 | ||
1259 | vector = head = dev->irq; | 1176 | vector = head = dev->irq; |
1260 | spin_lock_irqsave(&msi_lock, flags); | 1177 | dev->irq = temp; /* Restore pin IRQ */ |
1261 | while (head != tail) { | 1178 | while (head != tail) { |
1179 | spin_lock_irqsave(&msi_lock, flags); | ||
1262 | state = msi_desc[vector]->msi_attrib.state; | 1180 | state = msi_desc[vector]->msi_attrib.state; |
1181 | tail = msi_desc[vector]->link.tail; | ||
1182 | spin_unlock_irqrestore(&msi_lock, flags); | ||
1263 | if (state) | 1183 | if (state) |
1264 | warning = 1; | 1184 | warning = 1; |
1265 | else { | 1185 | else if (vector != head) /* Release MSI-X vector */ |
1266 | vector_irq[vector] = 0; /* free it */ | 1186 | msi_free_vector(dev, vector, 0); |
1267 | nr_released_vectors++; | ||
1268 | } | ||
1269 | tail = msi_desc[vector]->link.tail; | ||
1270 | vector = tail; | 1187 | vector = tail; |
1271 | } | 1188 | } |
1272 | spin_unlock_irqrestore(&msi_lock, flags); | 1189 | msi_free_vector(dev, vector, 0); |
1273 | if (warning) { | 1190 | if (warning) { |
1274 | dev->irq = temp; | ||
1275 | printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " | 1191 | printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " |
1276 | "free_irq() on all MSI-X vectors\n", | 1192 | "free_irq() on all MSI-X vectors\n", |
1277 | pci_name(dev)); | 1193 | pci_name(dev)); |
1278 | BUG_ON(warning > 0); | 1194 | BUG_ON(warning > 0); |
1279 | } else { | ||
1280 | dev->irq = temp; | ||
1281 | disable_msi_mode(dev, | ||
1282 | pci_find_capability(dev, PCI_CAP_ID_MSIX), | ||
1283 | PCI_CAP_ID_MSIX); | ||
1284 | |||
1285 | } | 1195 | } |
1286 | } | 1196 | } |
1287 | } | 1197 | } |