aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-10-04 05:16:31 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 10:55:26 -0400
commit7bd007e480672c99d8656c7b7b12ef0549432c37 (patch)
treebd8ab1fa9914532b075c7f026e209d2a03a6b050
parent0be6652f1e61b647f738eb25af057bf9551a9841 (diff)
[PATCH] genirq: msi: simplify msi enable and disable
The problem. Because the disable routines leave the msi interrupts in all sorts of half enabled states the enable routines become impossible to implement correctly, and almost impossible to understand. Simplifing this allows me to simply kill the buggy reroute_msix_table, and generally makes the code more maintainable. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Rajesh Shah <rajesh.shah@intel.com> Cc: Andi Kleen <ak@muc.de> Cc: "Protasevich, Natalie" <Natalie.Protasevich@UNISYS.com> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Rajesh Shah <rajesh.shah@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/pci/msi.c122
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)
933int pci_enable_msi(struct pci_dev* dev) 933int 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
1081static 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}