diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 426 |
1 files changed, 212 insertions, 214 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index baba2eb5367d..6f2e6295e773 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -27,48 +27,53 @@ static int pci_msi_enable = 1; | |||
27 | 27 | ||
28 | /* Arch hooks */ | 28 | /* Arch hooks */ |
29 | 29 | ||
30 | int __attribute__ ((weak)) | 30 | #ifndef arch_msi_check_device |
31 | arch_msi_check_device(struct pci_dev *dev, int nvec, int type) | 31 | int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) |
32 | { | 32 | { |
33 | return 0; | 33 | return 0; |
34 | } | 34 | } |
35 | #endif | ||
35 | 36 | ||
36 | int __attribute__ ((weak)) | 37 | #ifndef arch_setup_msi_irqs |
37 | arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) | 38 | int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
38 | { | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | int __attribute__ ((weak)) | ||
43 | arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
44 | { | 39 | { |
45 | struct msi_desc *entry; | 40 | struct msi_desc *entry; |
46 | int ret; | 41 | int ret; |
47 | 42 | ||
43 | /* | ||
44 | * If an architecture wants to support multiple MSI, it needs to | ||
45 | * override arch_setup_msi_irqs() | ||
46 | */ | ||
47 | if (type == PCI_CAP_ID_MSI && nvec > 1) | ||
48 | return 1; | ||
49 | |||
48 | list_for_each_entry(entry, &dev->msi_list, list) { | 50 | list_for_each_entry(entry, &dev->msi_list, list) { |
49 | ret = arch_setup_msi_irq(dev, entry); | 51 | ret = arch_setup_msi_irq(dev, entry); |
50 | if (ret) | 52 | if (ret < 0) |
51 | return ret; | 53 | return ret; |
54 | if (ret > 0) | ||
55 | return -ENOSPC; | ||
52 | } | 56 | } |
53 | 57 | ||
54 | return 0; | 58 | return 0; |
55 | } | 59 | } |
60 | #endif | ||
56 | 61 | ||
57 | void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) | 62 | #ifndef arch_teardown_msi_irqs |
58 | { | 63 | void arch_teardown_msi_irqs(struct pci_dev *dev) |
59 | return; | ||
60 | } | ||
61 | |||
62 | void __attribute__ ((weak)) | ||
63 | arch_teardown_msi_irqs(struct pci_dev *dev) | ||
64 | { | 64 | { |
65 | struct msi_desc *entry; | 65 | struct msi_desc *entry; |
66 | 66 | ||
67 | list_for_each_entry(entry, &dev->msi_list, list) { | 67 | list_for_each_entry(entry, &dev->msi_list, list) { |
68 | if (entry->irq != 0) | 68 | int i, nvec; |
69 | arch_teardown_msi_irq(entry->irq); | 69 | if (entry->irq == 0) |
70 | continue; | ||
71 | nvec = 1 << entry->msi_attrib.multiple; | ||
72 | for (i = 0; i < nvec; i++) | ||
73 | arch_teardown_msi_irq(entry->irq + i); | ||
70 | } | 74 | } |
71 | } | 75 | } |
76 | #endif | ||
72 | 77 | ||
73 | static void __msi_set_enable(struct pci_dev *dev, int pos, int enable) | 78 | static void __msi_set_enable(struct pci_dev *dev, int pos, int enable) |
74 | { | 79 | { |
@@ -111,27 +116,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x) | |||
111 | return (1 << (1 << x)) - 1; | 116 | return (1 << (1 << x)) - 1; |
112 | } | 117 | } |
113 | 118 | ||
114 | static void msix_flush_writes(struct irq_desc *desc) | 119 | static inline __attribute_const__ u32 msi_capable_mask(u16 control) |
115 | { | 120 | { |
116 | struct msi_desc *entry; | 121 | return msi_mask((control >> 1) & 7); |
122 | } | ||
117 | 123 | ||
118 | entry = get_irq_desc_msi(desc); | 124 | static inline __attribute_const__ u32 msi_enabled_mask(u16 control) |
119 | BUG_ON(!entry || !entry->dev); | 125 | { |
120 | switch (entry->msi_attrib.type) { | 126 | return msi_mask((control >> 4) & 7); |
121 | case PCI_CAP_ID_MSI: | ||
122 | /* nothing to do */ | ||
123 | break; | ||
124 | case PCI_CAP_ID_MSIX: | ||
125 | { | ||
126 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | ||
127 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; | ||
128 | readl(entry->mask_base + offset); | ||
129 | break; | ||
130 | } | ||
131 | default: | ||
132 | BUG(); | ||
133 | break; | ||
134 | } | ||
135 | } | 127 | } |
136 | 128 | ||
137 | /* | 129 | /* |
@@ -143,49 +135,71 @@ static void msix_flush_writes(struct irq_desc *desc) | |||
143 | * Returns 1 if it succeeded in masking the interrupt and 0 if the device | 135 | * Returns 1 if it succeeded in masking the interrupt and 0 if the device |
144 | * doesn't support MSI masking. | 136 | * doesn't support MSI masking. |
145 | */ | 137 | */ |
146 | static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag) | 138 | static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) |
147 | { | 139 | { |
148 | struct msi_desc *entry; | 140 | u32 mask_bits = desc->masked; |
149 | 141 | ||
150 | entry = get_irq_desc_msi(desc); | 142 | if (!desc->msi_attrib.maskbit) |
151 | BUG_ON(!entry || !entry->dev); | 143 | return; |
152 | switch (entry->msi_attrib.type) { | 144 | |
153 | case PCI_CAP_ID_MSI: | 145 | mask_bits &= ~mask; |
154 | if (entry->msi_attrib.maskbit) { | 146 | mask_bits |= flag; |
155 | int pos; | 147 | pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits); |
156 | u32 mask_bits; | 148 | desc->masked = mask_bits; |
157 | 149 | } | |
158 | pos = (long)entry->mask_base; | 150 | |
159 | pci_read_config_dword(entry->dev, pos, &mask_bits); | 151 | /* |
160 | mask_bits &= ~(mask); | 152 | * This internal function does not flush PCI writes to the device. |
161 | mask_bits |= flag & mask; | 153 | * All users must ensure that they read from the device before either |
162 | pci_write_config_dword(entry->dev, pos, mask_bits); | 154 | * assuming that the device state is up to date, or returning out of this |
163 | } else { | 155 | * file. This saves a few milliseconds when initialising devices with lots |
164 | return 0; | 156 | * of MSI-X interrupts. |
165 | } | 157 | */ |
166 | break; | 158 | static void msix_mask_irq(struct msi_desc *desc, u32 flag) |
167 | case PCI_CAP_ID_MSIX: | 159 | { |
168 | { | 160 | u32 mask_bits = desc->masked; |
169 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 161 | unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
170 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; | 162 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; |
171 | writel(flag, entry->mask_base + offset); | 163 | mask_bits &= ~1; |
172 | readl(entry->mask_base + offset); | 164 | mask_bits |= flag; |
173 | break; | 165 | writel(mask_bits, desc->mask_base + offset); |
174 | } | 166 | desc->masked = mask_bits; |
175 | default: | 167 | } |
176 | BUG(); | 168 | |
177 | break; | 169 | static void msi_set_mask_bit(unsigned irq, u32 flag) |
170 | { | ||
171 | struct msi_desc *desc = get_irq_msi(irq); | ||
172 | |||
173 | if (desc->msi_attrib.is_msix) { | ||
174 | msix_mask_irq(desc, flag); | ||
175 | readl(desc->mask_base); /* Flush write to device */ | ||
176 | } else { | ||
177 | unsigned offset = irq - desc->dev->irq; | ||
178 | msi_mask_irq(desc, 1 << offset, flag << offset); | ||
178 | } | 179 | } |
179 | entry->msi_attrib.masked = !!flag; | 180 | } |
180 | return 1; | 181 | |
182 | void mask_msi_irq(unsigned int irq) | ||
183 | { | ||
184 | msi_set_mask_bit(irq, 1); | ||
185 | } | ||
186 | |||
187 | void unmask_msi_irq(unsigned int irq) | ||
188 | { | ||
189 | msi_set_mask_bit(irq, 0); | ||
181 | } | 190 | } |
182 | 191 | ||
183 | void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | 192 | void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) |
184 | { | 193 | { |
185 | struct msi_desc *entry = get_irq_desc_msi(desc); | 194 | struct msi_desc *entry = get_irq_desc_msi(desc); |
186 | switch(entry->msi_attrib.type) { | 195 | if (entry->msi_attrib.is_msix) { |
187 | case PCI_CAP_ID_MSI: | 196 | void __iomem *base = entry->mask_base + |
188 | { | 197 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; |
198 | |||
199 | msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
200 | msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
201 | msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); | ||
202 | } else { | ||
189 | struct pci_dev *dev = entry->dev; | 203 | struct pci_dev *dev = entry->dev; |
190 | int pos = entry->msi_attrib.pos; | 204 | int pos = entry->msi_attrib.pos; |
191 | u16 data; | 205 | u16 data; |
@@ -201,21 +215,6 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | |||
201 | pci_read_config_word(dev, msi_data_reg(pos, 0), &data); | 215 | pci_read_config_word(dev, msi_data_reg(pos, 0), &data); |
202 | } | 216 | } |
203 | msg->data = data; | 217 | msg->data = data; |
204 | break; | ||
205 | } | ||
206 | case PCI_CAP_ID_MSIX: | ||
207 | { | ||
208 | void __iomem *base; | ||
209 | base = entry->mask_base + | ||
210 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; | ||
211 | |||
212 | msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
213 | msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
214 | msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); | ||
215 | break; | ||
216 | } | ||
217 | default: | ||
218 | BUG(); | ||
219 | } | 218 | } |
220 | } | 219 | } |
221 | 220 | ||
@@ -229,11 +228,25 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) | |||
229 | void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | 228 | void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) |
230 | { | 229 | { |
231 | struct msi_desc *entry = get_irq_desc_msi(desc); | 230 | struct msi_desc *entry = get_irq_desc_msi(desc); |
232 | switch (entry->msi_attrib.type) { | 231 | if (entry->msi_attrib.is_msix) { |
233 | case PCI_CAP_ID_MSI: | 232 | void __iomem *base; |
234 | { | 233 | base = entry->mask_base + |
234 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; | ||
235 | |||
236 | writel(msg->address_lo, | ||
237 | base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
238 | writel(msg->address_hi, | ||
239 | base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
240 | writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); | ||
241 | } else { | ||
235 | struct pci_dev *dev = entry->dev; | 242 | struct pci_dev *dev = entry->dev; |
236 | int pos = entry->msi_attrib.pos; | 243 | int pos = entry->msi_attrib.pos; |
244 | u16 msgctl; | ||
245 | |||
246 | pci_read_config_word(dev, msi_control_reg(pos), &msgctl); | ||
247 | msgctl &= ~PCI_MSI_FLAGS_QSIZE; | ||
248 | msgctl |= entry->msi_attrib.multiple << 4; | ||
249 | pci_write_config_word(dev, msi_control_reg(pos), msgctl); | ||
237 | 250 | ||
238 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | 251 | pci_write_config_dword(dev, msi_lower_address_reg(pos), |
239 | msg->address_lo); | 252 | msg->address_lo); |
@@ -246,23 +259,6 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) | |||
246 | pci_write_config_word(dev, msi_data_reg(pos, 0), | 259 | pci_write_config_word(dev, msi_data_reg(pos, 0), |
247 | msg->data); | 260 | msg->data); |
248 | } | 261 | } |
249 | break; | ||
250 | } | ||
251 | case PCI_CAP_ID_MSIX: | ||
252 | { | ||
253 | void __iomem *base; | ||
254 | base = entry->mask_base + | ||
255 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; | ||
256 | |||
257 | writel(msg->address_lo, | ||
258 | base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
259 | writel(msg->address_hi, | ||
260 | base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
261 | writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); | ||
262 | break; | ||
263 | } | ||
264 | default: | ||
265 | BUG(); | ||
266 | } | 262 | } |
267 | entry->msg = *msg; | 263 | entry->msg = *msg; |
268 | } | 264 | } |
@@ -274,37 +270,18 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) | |||
274 | write_msi_msg_desc(desc, msg); | 270 | write_msi_msg_desc(desc, msg); |
275 | } | 271 | } |
276 | 272 | ||
277 | void mask_msi_irq(unsigned int irq) | ||
278 | { | ||
279 | struct irq_desc *desc = irq_to_desc(irq); | ||
280 | |||
281 | msi_set_mask_bits(desc, 1, 1); | ||
282 | msix_flush_writes(desc); | ||
283 | } | ||
284 | |||
285 | void unmask_msi_irq(unsigned int irq) | ||
286 | { | ||
287 | struct irq_desc *desc = irq_to_desc(irq); | ||
288 | |||
289 | msi_set_mask_bits(desc, 1, 0); | ||
290 | msix_flush_writes(desc); | ||
291 | } | ||
292 | |||
293 | static int msi_free_irqs(struct pci_dev* dev); | 273 | static int msi_free_irqs(struct pci_dev* dev); |
294 | 274 | ||
295 | static struct msi_desc* alloc_msi_entry(void) | 275 | static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) |
296 | { | 276 | { |
297 | struct msi_desc *entry; | 277 | struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); |
298 | 278 | if (!desc) | |
299 | entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL); | ||
300 | if (!entry) | ||
301 | return NULL; | 279 | return NULL; |
302 | 280 | ||
303 | INIT_LIST_HEAD(&entry->list); | 281 | INIT_LIST_HEAD(&desc->list); |
304 | entry->irq = 0; | 282 | desc->dev = dev; |
305 | entry->dev = NULL; | ||
306 | 283 | ||
307 | return entry; | 284 | return desc; |
308 | } | 285 | } |
309 | 286 | ||
310 | static void pci_intx_for_msi(struct pci_dev *dev, int enable) | 287 | static void pci_intx_for_msi(struct pci_dev *dev, int enable) |
@@ -328,15 +305,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev) | |||
328 | pci_intx_for_msi(dev, 0); | 305 | pci_intx_for_msi(dev, 0); |
329 | msi_set_enable(dev, 0); | 306 | msi_set_enable(dev, 0); |
330 | write_msi_msg(dev->irq, &entry->msg); | 307 | write_msi_msg(dev->irq, &entry->msg); |
331 | if (entry->msi_attrib.maskbit) { | ||
332 | struct irq_desc *desc = irq_to_desc(dev->irq); | ||
333 | msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask, | ||
334 | entry->msi_attrib.masked); | ||
335 | } | ||
336 | 308 | ||
337 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); | 309 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); |
310 | msi_mask_irq(entry, msi_capable_mask(control), entry->masked); | ||
338 | control &= ~PCI_MSI_FLAGS_QSIZE; | 311 | control &= ~PCI_MSI_FLAGS_QSIZE; |
339 | control |= PCI_MSI_FLAGS_ENABLE; | 312 | control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE; |
340 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | 313 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); |
341 | } | 314 | } |
342 | 315 | ||
@@ -354,9 +327,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) | |||
354 | msix_set_enable(dev, 0); | 327 | msix_set_enable(dev, 0); |
355 | 328 | ||
356 | list_for_each_entry(entry, &dev->msi_list, list) { | 329 | list_for_each_entry(entry, &dev->msi_list, list) { |
357 | struct irq_desc *desc = irq_to_desc(entry->irq); | ||
358 | write_msi_msg(entry->irq, &entry->msg); | 330 | write_msi_msg(entry->irq, &entry->msg); |
359 | msi_set_mask_bits(desc, 1, entry->msi_attrib.masked); | 331 | msix_mask_irq(entry, entry->masked); |
360 | } | 332 | } |
361 | 333 | ||
362 | BUG_ON(list_empty(&dev->msi_list)); | 334 | BUG_ON(list_empty(&dev->msi_list)); |
@@ -378,52 +350,48 @@ EXPORT_SYMBOL_GPL(pci_restore_msi_state); | |||
378 | /** | 350 | /** |
379 | * msi_capability_init - configure device's MSI capability structure | 351 | * msi_capability_init - configure device's MSI capability structure |
380 | * @dev: pointer to the pci_dev data structure of MSI device function | 352 | * @dev: pointer to the pci_dev data structure of MSI device function |
353 | * @nvec: number of interrupts to allocate | ||
381 | * | 354 | * |
382 | * Setup the MSI capability structure of device function with a single | 355 | * Setup the MSI capability structure of the device with the requested |
383 | * MSI irq, regardless of device function is capable of handling | 356 | * number of interrupts. A return value of zero indicates the successful |
384 | * multiple messages. A return of zero indicates the successful setup | 357 | * setup of an entry with the new MSI irq. A negative return value indicates |
385 | * of an entry zero with the new MSI irq or non-zero for otherwise. | 358 | * an error, and a positive return value indicates the number of interrupts |
386 | **/ | 359 | * which could have been allocated. |
387 | static int msi_capability_init(struct pci_dev *dev) | 360 | */ |
361 | static int msi_capability_init(struct pci_dev *dev, int nvec) | ||
388 | { | 362 | { |
389 | struct msi_desc *entry; | 363 | struct msi_desc *entry; |
390 | int pos, ret; | 364 | int pos, ret; |
391 | u16 control; | 365 | u16 control; |
366 | unsigned mask; | ||
392 | 367 | ||
393 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ | 368 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ |
394 | 369 | ||
395 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 370 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
396 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 371 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
397 | /* MSI Entry Initialization */ | 372 | /* MSI Entry Initialization */ |
398 | entry = alloc_msi_entry(); | 373 | entry = alloc_msi_entry(dev); |
399 | if (!entry) | 374 | if (!entry) |
400 | return -ENOMEM; | 375 | return -ENOMEM; |
401 | 376 | ||
402 | entry->msi_attrib.type = PCI_CAP_ID_MSI; | 377 | entry->msi_attrib.is_msix = 0; |
403 | entry->msi_attrib.is_64 = is_64bit_address(control); | 378 | entry->msi_attrib.is_64 = is_64bit_address(control); |
404 | entry->msi_attrib.entry_nr = 0; | 379 | entry->msi_attrib.entry_nr = 0; |
405 | entry->msi_attrib.maskbit = is_mask_bit_support(control); | 380 | entry->msi_attrib.maskbit = is_mask_bit_support(control); |
406 | entry->msi_attrib.masked = 1; | ||
407 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ | 381 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ |
408 | entry->msi_attrib.pos = pos; | 382 | entry->msi_attrib.pos = pos; |
409 | entry->dev = dev; | 383 | |
410 | if (entry->msi_attrib.maskbit) { | 384 | entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); |
411 | unsigned int base, maskbits, temp; | 385 | /* All MSIs are unmasked by default, Mask them all */ |
412 | 386 | if (entry->msi_attrib.maskbit) | |
413 | base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); | 387 | pci_read_config_dword(dev, entry->mask_pos, &entry->masked); |
414 | entry->mask_base = (void __iomem *)(long)base; | 388 | mask = msi_capable_mask(control); |
415 | 389 | msi_mask_irq(entry, mask, mask); | |
416 | /* All MSIs are unmasked by default, Mask them all */ | 390 | |
417 | pci_read_config_dword(dev, base, &maskbits); | ||
418 | temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1); | ||
419 | maskbits |= temp; | ||
420 | pci_write_config_dword(dev, base, maskbits); | ||
421 | entry->msi_attrib.maskbits_mask = temp; | ||
422 | } | ||
423 | list_add_tail(&entry->list, &dev->msi_list); | 391 | list_add_tail(&entry->list, &dev->msi_list); |
424 | 392 | ||
425 | /* Configure MSI capability structure */ | 393 | /* Configure MSI capability structure */ |
426 | ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); | 394 | ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); |
427 | if (ret) { | 395 | if (ret) { |
428 | msi_free_irqs(dev); | 396 | msi_free_irqs(dev); |
429 | return ret; | 397 | return ret; |
@@ -476,26 +444,28 @@ static int msix_capability_init(struct pci_dev *dev, | |||
476 | 444 | ||
477 | /* MSI-X Table Initialization */ | 445 | /* MSI-X Table Initialization */ |
478 | for (i = 0; i < nvec; i++) { | 446 | for (i = 0; i < nvec; i++) { |
479 | entry = alloc_msi_entry(); | 447 | entry = alloc_msi_entry(dev); |
480 | if (!entry) | 448 | if (!entry) |
481 | break; | 449 | break; |
482 | 450 | ||
483 | j = entries[i].entry; | 451 | j = entries[i].entry; |
484 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; | 452 | entry->msi_attrib.is_msix = 1; |
485 | entry->msi_attrib.is_64 = 1; | 453 | entry->msi_attrib.is_64 = 1; |
486 | entry->msi_attrib.entry_nr = j; | 454 | entry->msi_attrib.entry_nr = j; |
487 | entry->msi_attrib.maskbit = 1; | ||
488 | entry->msi_attrib.masked = 1; | ||
489 | entry->msi_attrib.default_irq = dev->irq; | 455 | entry->msi_attrib.default_irq = dev->irq; |
490 | entry->msi_attrib.pos = pos; | 456 | entry->msi_attrib.pos = pos; |
491 | entry->dev = dev; | ||
492 | entry->mask_base = base; | 457 | entry->mask_base = base; |
458 | entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
459 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | ||
460 | msix_mask_irq(entry, 1); | ||
493 | 461 | ||
494 | list_add_tail(&entry->list, &dev->msi_list); | 462 | list_add_tail(&entry->list, &dev->msi_list); |
495 | } | 463 | } |
496 | 464 | ||
497 | ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); | 465 | ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); |
498 | if (ret) { | 466 | if (ret < 0) { |
467 | /* If we had some success report the number of irqs | ||
468 | * we succeeded in setting up. */ | ||
499 | int avail = 0; | 469 | int avail = 0; |
500 | list_for_each_entry(entry, &dev->msi_list, list) { | 470 | list_for_each_entry(entry, &dev->msi_list, list) { |
501 | if (entry->irq != 0) { | 471 | if (entry->irq != 0) { |
@@ -503,14 +473,13 @@ static int msix_capability_init(struct pci_dev *dev, | |||
503 | } | 473 | } |
504 | } | 474 | } |
505 | 475 | ||
506 | msi_free_irqs(dev); | 476 | if (avail != 0) |
477 | ret = avail; | ||
478 | } | ||
507 | 479 | ||
508 | /* If we had some success report the number of irqs | 480 | if (ret) { |
509 | * we succeeded in setting up. | 481 | msi_free_irqs(dev); |
510 | */ | 482 | return ret; |
511 | if (avail == 0) | ||
512 | avail = ret; | ||
513 | return avail; | ||
514 | } | 483 | } |
515 | 484 | ||
516 | i = 0; | 485 | i = 0; |
@@ -575,39 +544,54 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) | |||
575 | } | 544 | } |
576 | 545 | ||
577 | /** | 546 | /** |
578 | * pci_enable_msi - configure device's MSI capability structure | 547 | * pci_enable_msi_block - configure device's MSI capability structure |
579 | * @dev: pointer to the pci_dev data structure of MSI device function | 548 | * @dev: device to configure |
549 | * @nvec: number of interrupts to configure | ||
580 | * | 550 | * |
581 | * Setup the MSI capability structure of device function with | 551 | * Allocate IRQs for a device with the MSI capability. |
582 | * a single MSI irq upon its software driver call to request for | 552 | * This function returns a negative errno if an error occurs. If it |
583 | * MSI mode enabled on its hardware device function. A return of zero | 553 | * is unable to allocate the number of interrupts requested, it returns |
584 | * indicates the successful setup of an entry zero with the new MSI | 554 | * the number of interrupts it might be able to allocate. If it successfully |
585 | * irq or non-zero for otherwise. | 555 | * allocates at least the number of interrupts requested, it returns 0 and |
586 | **/ | 556 | * updates the @dev's irq member to the lowest new interrupt number; the |
587 | int pci_enable_msi(struct pci_dev* dev) | 557 | * other interrupt numbers allocated to this device are consecutive. |
558 | */ | ||
559 | int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) | ||
588 | { | 560 | { |
589 | int status; | 561 | int status, pos, maxvec; |
562 | u16 msgctl; | ||
590 | 563 | ||
591 | status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); | 564 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
565 | if (!pos) | ||
566 | return -EINVAL; | ||
567 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl); | ||
568 | maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); | ||
569 | if (nvec > maxvec) | ||
570 | return maxvec; | ||
571 | |||
572 | status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI); | ||
592 | if (status) | 573 | if (status) |
593 | return status; | 574 | return status; |
594 | 575 | ||
595 | WARN_ON(!!dev->msi_enabled); | 576 | WARN_ON(!!dev->msi_enabled); |
596 | 577 | ||
597 | /* Check whether driver already requested for MSI-X irqs */ | 578 | /* Check whether driver already requested MSI-X irqs */ |
598 | if (dev->msix_enabled) { | 579 | if (dev->msix_enabled) { |
599 | dev_info(&dev->dev, "can't enable MSI " | 580 | dev_info(&dev->dev, "can't enable MSI " |
600 | "(MSI-X already enabled)\n"); | 581 | "(MSI-X already enabled)\n"); |
601 | return -EINVAL; | 582 | return -EINVAL; |
602 | } | 583 | } |
603 | status = msi_capability_init(dev); | 584 | |
585 | status = msi_capability_init(dev, nvec); | ||
604 | return status; | 586 | return status; |
605 | } | 587 | } |
606 | EXPORT_SYMBOL(pci_enable_msi); | 588 | EXPORT_SYMBOL(pci_enable_msi_block); |
607 | 589 | ||
608 | void pci_msi_shutdown(struct pci_dev* dev) | 590 | void pci_msi_shutdown(struct pci_dev *dev) |
609 | { | 591 | { |
610 | struct msi_desc *entry; | 592 | struct msi_desc *desc; |
593 | u32 mask; | ||
594 | u16 ctrl; | ||
611 | 595 | ||
612 | if (!pci_msi_enable || !dev || !dev->msi_enabled) | 596 | if (!pci_msi_enable || !dev || !dev->msi_enabled) |
613 | return; | 597 | return; |
@@ -617,19 +601,15 @@ void pci_msi_shutdown(struct pci_dev* dev) | |||
617 | dev->msi_enabled = 0; | 601 | dev->msi_enabled = 0; |
618 | 602 | ||
619 | BUG_ON(list_empty(&dev->msi_list)); | 603 | BUG_ON(list_empty(&dev->msi_list)); |
620 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | 604 | desc = list_first_entry(&dev->msi_list, struct msi_desc, list); |
621 | /* Return the the pci reset with msi irqs unmasked */ | 605 | pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl); |
622 | if (entry->msi_attrib.maskbit) { | 606 | mask = msi_capable_mask(ctrl); |
623 | u32 mask = entry->msi_attrib.maskbits_mask; | 607 | msi_mask_irq(desc, mask, ~mask); |
624 | struct irq_desc *desc = irq_to_desc(dev->irq); | ||
625 | msi_set_mask_bits(desc, mask, ~mask); | ||
626 | } | ||
627 | if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) | ||
628 | return; | ||
629 | 608 | ||
630 | /* Restore dev->irq to its default pin-assertion irq */ | 609 | /* Restore dev->irq to its default pin-assertion irq */ |
631 | dev->irq = entry->msi_attrib.default_irq; | 610 | dev->irq = desc->msi_attrib.default_irq; |
632 | } | 611 | } |
612 | |||
633 | void pci_disable_msi(struct pci_dev* dev) | 613 | void pci_disable_msi(struct pci_dev* dev) |
634 | { | 614 | { |
635 | struct msi_desc *entry; | 615 | struct msi_desc *entry; |
@@ -640,7 +620,7 @@ void pci_disable_msi(struct pci_dev* dev) | |||
640 | pci_msi_shutdown(dev); | 620 | pci_msi_shutdown(dev); |
641 | 621 | ||
642 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | 622 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); |
643 | if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) | 623 | if (entry->msi_attrib.is_msix) |
644 | return; | 624 | return; |
645 | 625 | ||
646 | msi_free_irqs(dev); | 626 | msi_free_irqs(dev); |
@@ -652,14 +632,18 @@ static int msi_free_irqs(struct pci_dev* dev) | |||
652 | struct msi_desc *entry, *tmp; | 632 | struct msi_desc *entry, *tmp; |
653 | 633 | ||
654 | list_for_each_entry(entry, &dev->msi_list, list) { | 634 | list_for_each_entry(entry, &dev->msi_list, list) { |
655 | if (entry->irq) | 635 | int i, nvec; |
656 | BUG_ON(irq_has_action(entry->irq)); | 636 | if (!entry->irq) |
637 | continue; | ||
638 | nvec = 1 << entry->msi_attrib.multiple; | ||
639 | for (i = 0; i < nvec; i++) | ||
640 | BUG_ON(irq_has_action(entry->irq + i)); | ||
657 | } | 641 | } |
658 | 642 | ||
659 | arch_teardown_msi_irqs(dev); | 643 | arch_teardown_msi_irqs(dev); |
660 | 644 | ||
661 | list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { | 645 | list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { |
662 | if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) { | 646 | if (entry->msi_attrib.is_msix) { |
663 | writel(1, entry->mask_base + entry->msi_attrib.entry_nr | 647 | writel(1, entry->mask_base + entry->msi_attrib.entry_nr |
664 | * PCI_MSIX_ENTRY_SIZE | 648 | * PCI_MSIX_ENTRY_SIZE |
665 | + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 649 | + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
@@ -675,6 +659,23 @@ static int msi_free_irqs(struct pci_dev* dev) | |||
675 | } | 659 | } |
676 | 660 | ||
677 | /** | 661 | /** |
662 | * pci_msix_table_size - return the number of device's MSI-X table entries | ||
663 | * @dev: pointer to the pci_dev data structure of MSI-X device function | ||
664 | */ | ||
665 | int pci_msix_table_size(struct pci_dev *dev) | ||
666 | { | ||
667 | int pos; | ||
668 | u16 control; | ||
669 | |||
670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
671 | if (!pos) | ||
672 | return 0; | ||
673 | |||
674 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
675 | return multi_msix_capable(control); | ||
676 | } | ||
677 | |||
678 | /** | ||
678 | * pci_enable_msix - configure device's MSI-X capability structure | 679 | * pci_enable_msix - configure device's MSI-X capability structure |
679 | * @dev: pointer to the pci_dev data structure of MSI-X device function | 680 | * @dev: pointer to the pci_dev data structure of MSI-X device function |
680 | * @entries: pointer to an array of MSI-X entries | 681 | * @entries: pointer to an array of MSI-X entries |
@@ -691,9 +692,8 @@ static int msi_free_irqs(struct pci_dev* dev) | |||
691 | **/ | 692 | **/ |
692 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 693 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
693 | { | 694 | { |
694 | int status, pos, nr_entries; | 695 | int status, nr_entries; |
695 | int i, j; | 696 | int i, j; |
696 | u16 control; | ||
697 | 697 | ||
698 | if (!entries) | 698 | if (!entries) |
699 | return -EINVAL; | 699 | return -EINVAL; |
@@ -702,9 +702,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
702 | if (status) | 702 | if (status) |
703 | return status; | 703 | return status; |
704 | 704 | ||
705 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 705 | nr_entries = pci_msix_table_size(dev); |
706 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
707 | nr_entries = multi_msix_capable(control); | ||
708 | if (nvec > nr_entries) | 706 | if (nvec > nr_entries) |
709 | return -EINVAL; | 707 | return -EINVAL; |
710 | 708 | ||