diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-10-04 05:16:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:26 -0400 |
commit | 7bd007e480672c99d8656c7b7b12ef0549432c37 (patch) | |
tree | bd8ab1fa9914532b075c7f026e209d2a03a6b050 /drivers/pci/msi.c | |
parent | 0be6652f1e61b647f738eb25af057bf9551a9841 (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>
Diffstat (limited to 'drivers/pci/msi.c')
-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 | } |