diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 325 |
1 files changed, 117 insertions, 208 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ed3f7e1a563c..68555c11f556 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -24,8 +24,6 @@ | |||
24 | #include "pci.h" | 24 | #include "pci.h" |
25 | #include "msi.h" | 25 | #include "msi.h" |
26 | 26 | ||
27 | static DEFINE_SPINLOCK(msi_lock); | ||
28 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; | ||
29 | static struct kmem_cache* msi_cachep; | 27 | static struct kmem_cache* msi_cachep; |
30 | 28 | ||
31 | static int pci_msi_enable = 1; | 29 | static int pci_msi_enable = 1; |
@@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned int irq, int flag) | |||
44 | { | 42 | { |
45 | struct msi_desc *entry; | 43 | struct msi_desc *entry; |
46 | 44 | ||
47 | entry = msi_desc[irq]; | 45 | entry = get_irq_msi(irq); |
48 | BUG_ON(!entry || !entry->dev); | 46 | BUG_ON(!entry || !entry->dev); |
49 | switch (entry->msi_attrib.type) { | 47 | switch (entry->msi_attrib.type) { |
50 | case PCI_CAP_ID_MSI: | 48 | case PCI_CAP_ID_MSI: |
51 | if (entry->msi_attrib.maskbit) { | 49 | if (entry->msi_attrib.maskbit) { |
52 | int pos; | 50 | int pos; |
53 | u32 mask_bits; | 51 | u32 mask_bits; |
54 | 52 | ||
55 | pos = (long)entry->mask_base; | 53 | pos = (long)entry->mask_base; |
56 | pci_read_config_dword(entry->dev, pos, &mask_bits); | 54 | pci_read_config_dword(entry->dev, pos, &mask_bits); |
@@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag) | |||
74 | 72 | ||
75 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) | 73 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) |
76 | { | 74 | { |
77 | struct msi_desc *entry = get_irq_data(irq); | 75 | struct msi_desc *entry = get_irq_msi(irq); |
78 | switch(entry->msi_attrib.type) { | 76 | switch(entry->msi_attrib.type) { |
79 | case PCI_CAP_ID_MSI: | 77 | case PCI_CAP_ID_MSI: |
80 | { | 78 | { |
@@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) | |||
113 | 111 | ||
114 | void write_msi_msg(unsigned int irq, struct msi_msg *msg) | 112 | void write_msi_msg(unsigned int irq, struct msi_msg *msg) |
115 | { | 113 | { |
116 | struct msi_desc *entry = get_irq_data(irq); | 114 | struct msi_desc *entry = get_irq_msi(irq); |
117 | switch (entry->msi_attrib.type) { | 115 | switch (entry->msi_attrib.type) { |
118 | case PCI_CAP_ID_MSI: | 116 | case PCI_CAP_ID_MSI: |
119 | { | 117 | { |
@@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq) | |||
162 | } | 160 | } |
163 | 161 | ||
164 | static int msi_free_irq(struct pci_dev* dev, int irq); | 162 | static int msi_free_irq(struct pci_dev* dev, int irq); |
163 | |||
165 | static int msi_init(void) | 164 | static int msi_init(void) |
166 | { | 165 | { |
167 | static int status = -ENOMEM; | 166 | static int status = -ENOMEM; |
@@ -169,13 +168,6 @@ static int msi_init(void) | |||
169 | if (!status) | 168 | if (!status) |
170 | return status; | 169 | return status; |
171 | 170 | ||
172 | if (pci_msi_quirk) { | ||
173 | pci_msi_enable = 0; | ||
174 | printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n"); | ||
175 | status = -EINVAL; | ||
176 | return status; | ||
177 | } | ||
178 | |||
179 | status = msi_cache_init(); | 171 | status = msi_cache_init(); |
180 | if (status < 0) { | 172 | if (status < 0) { |
181 | pci_msi_enable = 0; | 173 | pci_msi_enable = 0; |
@@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void) | |||
200 | return entry; | 192 | return entry; |
201 | } | 193 | } |
202 | 194 | ||
203 | static void attach_msi_entry(struct msi_desc *entry, int irq) | ||
204 | { | ||
205 | unsigned long flags; | ||
206 | |||
207 | spin_lock_irqsave(&msi_lock, flags); | ||
208 | msi_desc[irq] = entry; | ||
209 | spin_unlock_irqrestore(&msi_lock, flags); | ||
210 | } | ||
211 | |||
212 | static int create_msi_irq(void) | ||
213 | { | ||
214 | struct msi_desc *entry; | ||
215 | int irq; | ||
216 | |||
217 | entry = alloc_msi_entry(); | ||
218 | if (!entry) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | irq = create_irq(); | ||
222 | if (irq < 0) { | ||
223 | kmem_cache_free(msi_cachep, entry); | ||
224 | return -EBUSY; | ||
225 | } | ||
226 | |||
227 | set_irq_data(irq, entry); | ||
228 | |||
229 | return irq; | ||
230 | } | ||
231 | |||
232 | static void destroy_msi_irq(unsigned int irq) | ||
233 | { | ||
234 | struct msi_desc *entry; | ||
235 | |||
236 | entry = get_irq_data(irq); | ||
237 | set_irq_chip(irq, NULL); | ||
238 | set_irq_data(irq, NULL); | ||
239 | destroy_irq(irq); | ||
240 | kmem_cache_free(msi_cachep, entry); | ||
241 | } | ||
242 | |||
243 | static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | 195 | static void enable_msi_mode(struct pci_dev *dev, int pos, int type) |
244 | { | 196 | { |
245 | u16 control; | 197 | u16 control; |
@@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
278 | pci_intx(dev, 1); /* enable intx */ | 230 | pci_intx(dev, 1); /* enable intx */ |
279 | } | 231 | } |
280 | 232 | ||
281 | static int msi_lookup_irq(struct pci_dev *dev, int type) | ||
282 | { | ||
283 | int irq; | ||
284 | unsigned long flags; | ||
285 | |||
286 | spin_lock_irqsave(&msi_lock, flags); | ||
287 | for (irq = 0; irq < NR_IRQS; irq++) { | ||
288 | if (!msi_desc[irq] || msi_desc[irq]->dev != dev || | ||
289 | msi_desc[irq]->msi_attrib.type != type || | ||
290 | msi_desc[irq]->msi_attrib.default_irq != dev->irq) | ||
291 | continue; | ||
292 | spin_unlock_irqrestore(&msi_lock, flags); | ||
293 | /* This pre-assigned MSI irq for this device | ||
294 | already exits. Override dev->irq with this irq */ | ||
295 | dev->irq = irq; | ||
296 | return 0; | ||
297 | } | ||
298 | spin_unlock_irqrestore(&msi_lock, flags); | ||
299 | |||
300 | return -EACCES; | ||
301 | } | ||
302 | |||
303 | void pci_scan_msi_device(struct pci_dev *dev) | ||
304 | { | ||
305 | if (!dev) | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | #ifdef CONFIG_PM | 233 | #ifdef CONFIG_PM |
310 | int pci_save_msi_state(struct pci_dev *dev) | 234 | static int __pci_save_msi_state(struct pci_dev *dev) |
311 | { | 235 | { |
312 | int pos, i = 0; | 236 | int pos, i = 0; |
313 | u16 control; | 237 | u16 control; |
@@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev) | |||
345 | return 0; | 269 | return 0; |
346 | } | 270 | } |
347 | 271 | ||
348 | void pci_restore_msi_state(struct pci_dev *dev) | 272 | static void __pci_restore_msi_state(struct pci_dev *dev) |
349 | { | 273 | { |
350 | int i = 0, pos; | 274 | int i = 0, pos; |
351 | u16 control; | 275 | u16 control; |
@@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
373 | kfree(save_state); | 297 | kfree(save_state); |
374 | } | 298 | } |
375 | 299 | ||
376 | int pci_save_msix_state(struct pci_dev *dev) | 300 | static int __pci_save_msix_state(struct pci_dev *dev) |
377 | { | 301 | { |
378 | int pos; | 302 | int pos; |
379 | int temp; | ||
380 | int irq, head, tail = 0; | 303 | int irq, head, tail = 0; |
381 | u16 control; | 304 | u16 control; |
382 | struct pci_cap_saved_state *save_state; | 305 | struct pci_cap_saved_state *save_state; |
383 | 306 | ||
307 | if (!dev->msix_enabled) | ||
308 | return 0; | ||
309 | |||
384 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 310 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); |
385 | if (pos <= 0 || dev->no_msi) | 311 | if (pos <= 0 || dev->no_msi) |
386 | return 0; | 312 | return 0; |
@@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
398 | *((u16 *)&save_state->data[0]) = control; | 324 | *((u16 *)&save_state->data[0]) = control; |
399 | 325 | ||
400 | /* save the table */ | 326 | /* save the table */ |
401 | temp = dev->irq; | 327 | irq = head = dev->first_msi_irq; |
402 | if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { | ||
403 | kfree(save_state); | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | irq = head = dev->irq; | ||
408 | while (head != tail) { | 328 | while (head != tail) { |
409 | struct msi_desc *entry; | 329 | struct msi_desc *entry; |
410 | 330 | ||
411 | entry = msi_desc[irq]; | 331 | entry = get_irq_msi(irq); |
412 | read_msi_msg(irq, &entry->msg_save); | 332 | read_msi_msg(irq, &entry->msg_save); |
413 | 333 | ||
414 | tail = msi_desc[irq]->link.tail; | 334 | tail = entry->link.tail; |
415 | irq = tail; | 335 | irq = tail; |
416 | } | 336 | } |
417 | dev->irq = temp; | ||
418 | 337 | ||
419 | save_state->cap_nr = PCI_CAP_ID_MSIX; | 338 | save_state->cap_nr = PCI_CAP_ID_MSIX; |
420 | pci_add_saved_cap(dev, save_state); | 339 | pci_add_saved_cap(dev, save_state); |
421 | return 0; | 340 | return 0; |
422 | } | 341 | } |
423 | 342 | ||
424 | void pci_restore_msix_state(struct pci_dev *dev) | 343 | int pci_save_msi_state(struct pci_dev *dev) |
344 | { | ||
345 | int rc; | ||
346 | |||
347 | rc = __pci_save_msi_state(dev); | ||
348 | if (rc) | ||
349 | return rc; | ||
350 | |||
351 | rc = __pci_save_msix_state(dev); | ||
352 | |||
353 | return rc; | ||
354 | } | ||
355 | |||
356 | static void __pci_restore_msix_state(struct pci_dev *dev) | ||
425 | { | 357 | { |
426 | u16 save; | 358 | u16 save; |
427 | int pos; | 359 | int pos; |
428 | int irq, head, tail = 0; | 360 | int irq, head, tail = 0; |
429 | struct msi_desc *entry; | 361 | struct msi_desc *entry; |
430 | int temp; | ||
431 | struct pci_cap_saved_state *save_state; | 362 | struct pci_cap_saved_state *save_state; |
432 | 363 | ||
364 | if (!dev->msix_enabled) | ||
365 | return; | ||
366 | |||
433 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); | 367 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); |
434 | if (!save_state) | 368 | if (!save_state) |
435 | return; | 369 | return; |
@@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
442 | return; | 376 | return; |
443 | 377 | ||
444 | /* route the table */ | 378 | /* route the table */ |
445 | temp = dev->irq; | 379 | irq = head = dev->first_msi_irq; |
446 | if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) | ||
447 | return; | ||
448 | irq = head = dev->irq; | ||
449 | while (head != tail) { | 380 | while (head != tail) { |
450 | entry = msi_desc[irq]; | 381 | entry = get_irq_msi(irq); |
451 | write_msi_msg(irq, &entry->msg_save); | 382 | write_msi_msg(irq, &entry->msg_save); |
452 | 383 | ||
453 | tail = msi_desc[irq]->link.tail; | 384 | tail = entry->link.tail; |
454 | irq = tail; | 385 | irq = tail; |
455 | } | 386 | } |
456 | dev->irq = temp; | ||
457 | 387 | ||
458 | pci_write_config_word(dev, msi_control_reg(pos), save); | 388 | pci_write_config_word(dev, msi_control_reg(pos), save); |
459 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 389 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); |
460 | } | 390 | } |
461 | #endif | 391 | |
392 | void pci_restore_msi_state(struct pci_dev *dev) | ||
393 | { | ||
394 | __pci_restore_msi_state(dev); | ||
395 | __pci_restore_msix_state(dev); | ||
396 | } | ||
397 | #endif /* CONFIG_PM */ | ||
462 | 398 | ||
463 | /** | 399 | /** |
464 | * msi_capability_init - configure device's MSI capability structure | 400 | * msi_capability_init - configure device's MSI capability structure |
@@ -471,7 +407,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
471 | **/ | 407 | **/ |
472 | static int msi_capability_init(struct pci_dev *dev) | 408 | static int msi_capability_init(struct pci_dev *dev) |
473 | { | 409 | { |
474 | int status; | ||
475 | struct msi_desc *entry; | 410 | struct msi_desc *entry; |
476 | int pos, irq; | 411 | int pos, irq; |
477 | u16 control; | 412 | u16 control; |
@@ -479,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev) | |||
479 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 414 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
480 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 415 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
481 | /* MSI Entry Initialization */ | 416 | /* MSI Entry Initialization */ |
482 | irq = create_msi_irq(); | 417 | entry = alloc_msi_entry(); |
483 | if (irq < 0) | 418 | if (!entry) |
484 | return irq; | 419 | return -ENOMEM; |
485 | 420 | ||
486 | entry = get_irq_data(irq); | ||
487 | entry->link.head = irq; | ||
488 | entry->link.tail = irq; | ||
489 | entry->msi_attrib.type = PCI_CAP_ID_MSI; | 421 | entry->msi_attrib.type = PCI_CAP_ID_MSI; |
490 | entry->msi_attrib.is_64 = is_64bit_address(control); | 422 | entry->msi_attrib.is_64 = is_64bit_address(control); |
491 | entry->msi_attrib.entry_nr = 0; | 423 | entry->msi_attrib.entry_nr = 0; |
@@ -511,13 +443,16 @@ static int msi_capability_init(struct pci_dev *dev) | |||
511 | maskbits); | 443 | maskbits); |
512 | } | 444 | } |
513 | /* Configure MSI capability structure */ | 445 | /* Configure MSI capability structure */ |
514 | status = arch_setup_msi_irq(irq, dev); | 446 | irq = arch_setup_msi_irq(dev, entry); |
515 | if (status < 0) { | 447 | if (irq < 0) { |
516 | destroy_msi_irq(irq); | 448 | kmem_cache_free(msi_cachep, entry); |
517 | return status; | 449 | return irq; |
518 | } | 450 | } |
451 | entry->link.head = irq; | ||
452 | entry->link.tail = irq; | ||
453 | dev->first_msi_irq = irq; | ||
454 | set_irq_msi(irq, entry); | ||
519 | 455 | ||
520 | attach_msi_entry(entry, irq); | ||
521 | /* Set MSI enabled bits */ | 456 | /* Set MSI enabled bits */ |
522 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 457 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
523 | 458 | ||
@@ -539,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
539 | struct msix_entry *entries, int nvec) | 474 | struct msix_entry *entries, int nvec) |
540 | { | 475 | { |
541 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 476 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
542 | int status; | ||
543 | int irq, pos, i, j, nr_entries, temp = 0; | 477 | int irq, pos, i, j, nr_entries, temp = 0; |
544 | unsigned long phys_addr; | 478 | unsigned long phys_addr; |
545 | u32 table_offset; | 479 | u32 table_offset; |
@@ -562,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev, | |||
562 | 496 | ||
563 | /* MSI-X Table Initialization */ | 497 | /* MSI-X Table Initialization */ |
564 | for (i = 0; i < nvec; i++) { | 498 | for (i = 0; i < nvec; i++) { |
565 | irq = create_msi_irq(); | 499 | entry = alloc_msi_entry(); |
566 | if (irq < 0) | 500 | if (!entry) |
567 | break; | 501 | break; |
568 | 502 | ||
569 | entry = get_irq_data(irq); | ||
570 | j = entries[i].entry; | 503 | j = entries[i].entry; |
571 | entries[i].vector = irq; | ||
572 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; | 504 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; |
573 | entry->msi_attrib.is_64 = 1; | 505 | entry->msi_attrib.is_64 = 1; |
574 | entry->msi_attrib.entry_nr = j; | 506 | entry->msi_attrib.entry_nr = j; |
@@ -577,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev, | |||
577 | entry->msi_attrib.pos = pos; | 509 | entry->msi_attrib.pos = pos; |
578 | entry->dev = dev; | 510 | entry->dev = dev; |
579 | entry->mask_base = base; | 511 | entry->mask_base = base; |
512 | |||
513 | /* Configure MSI-X capability structure */ | ||
514 | irq = arch_setup_msi_irq(dev, entry); | ||
515 | if (irq < 0) { | ||
516 | kmem_cache_free(msi_cachep, entry); | ||
517 | break; | ||
518 | } | ||
519 | entries[i].vector = irq; | ||
580 | if (!head) { | 520 | if (!head) { |
581 | entry->link.head = irq; | 521 | entry->link.head = irq; |
582 | entry->link.tail = irq; | 522 | entry->link.tail = irq; |
@@ -589,14 +529,8 @@ static int msix_capability_init(struct pci_dev *dev, | |||
589 | } | 529 | } |
590 | temp = irq; | 530 | temp = irq; |
591 | tail = entry; | 531 | tail = entry; |
592 | /* Configure MSI-X capability structure */ | ||
593 | status = arch_setup_msi_irq(irq, dev); | ||
594 | if (status < 0) { | ||
595 | destroy_msi_irq(irq); | ||
596 | break; | ||
597 | } | ||
598 | 532 | ||
599 | attach_msi_entry(entry, irq); | 533 | set_irq_msi(irq, entry); |
600 | } | 534 | } |
601 | if (i != nvec) { | 535 | if (i != nvec) { |
602 | int avail = i - 1; | 536 | int avail = i - 1; |
@@ -613,6 +547,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
613 | avail = -EBUSY; | 547 | avail = -EBUSY; |
614 | return avail; | 548 | return avail; |
615 | } | 549 | } |
550 | dev->first_msi_irq = entries[0].vector; | ||
616 | /* Set MSI-X enabled bits */ | 551 | /* Set MSI-X enabled bits */ |
617 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 552 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); |
618 | 553 | ||
@@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * dev) | |||
660 | **/ | 595 | **/ |
661 | int pci_enable_msi(struct pci_dev* dev) | 596 | int pci_enable_msi(struct pci_dev* dev) |
662 | { | 597 | { |
663 | int pos, temp, status; | 598 | int pos, status; |
664 | 599 | ||
665 | if (pci_msi_supported(dev) < 0) | 600 | if (pci_msi_supported(dev) < 0) |
666 | return -EINVAL; | 601 | return -EINVAL; |
667 | 602 | ||
668 | temp = dev->irq; | ||
669 | |||
670 | status = msi_init(); | 603 | status = msi_init(); |
671 | if (status < 0) | 604 | if (status < 0) |
672 | return status; | 605 | return status; |
@@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev) | |||
675 | if (!pos) | 608 | if (!pos) |
676 | return -EINVAL; | 609 | return -EINVAL; |
677 | 610 | ||
678 | WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); | 611 | WARN_ON(!!dev->msi_enabled); |
679 | 612 | ||
680 | /* Check whether driver already requested for MSI-X irqs */ | 613 | /* Check whether driver already requested for MSI-X irqs */ |
681 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 614 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); |
682 | if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { | 615 | if (pos > 0 && dev->msix_enabled) { |
683 | printk(KERN_INFO "PCI: %s: Can't enable MSI. " | 616 | printk(KERN_INFO "PCI: %s: Can't enable MSI. " |
684 | "Device already has MSI-X irq assigned\n", | 617 | "Device already has MSI-X enabled\n", |
685 | pci_name(dev)); | 618 | pci_name(dev)); |
686 | dev->irq = temp; | ||
687 | return -EINVAL; | 619 | return -EINVAL; |
688 | } | 620 | } |
689 | status = msi_capability_init(dev); | 621 | status = msi_capability_init(dev); |
@@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev) | |||
695 | struct msi_desc *entry; | 627 | struct msi_desc *entry; |
696 | int pos, default_irq; | 628 | int pos, default_irq; |
697 | u16 control; | 629 | u16 control; |
698 | unsigned long flags; | ||
699 | 630 | ||
700 | if (!pci_msi_enable) | 631 | if (!pci_msi_enable) |
701 | return; | 632 | return; |
702 | if (!dev) | 633 | if (!dev) |
703 | return; | 634 | return; |
704 | 635 | ||
636 | if (!dev->msi_enabled) | ||
637 | return; | ||
638 | |||
705 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 639 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
706 | if (!pos) | 640 | if (!pos) |
707 | return; | 641 | return; |
@@ -710,28 +644,26 @@ void pci_disable_msi(struct pci_dev* dev) | |||
710 | if (!(control & PCI_MSI_FLAGS_ENABLE)) | 644 | if (!(control & PCI_MSI_FLAGS_ENABLE)) |
711 | return; | 645 | return; |
712 | 646 | ||
647 | |||
713 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 648 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
714 | 649 | ||
715 | spin_lock_irqsave(&msi_lock, flags); | 650 | entry = get_irq_msi(dev->first_msi_irq); |
716 | entry = msi_desc[dev->irq]; | ||
717 | if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { | 651 | if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { |
718 | spin_unlock_irqrestore(&msi_lock, flags); | ||
719 | return; | 652 | return; |
720 | } | 653 | } |
721 | if (irq_has_action(dev->irq)) { | 654 | if (irq_has_action(dev->first_msi_irq)) { |
722 | spin_unlock_irqrestore(&msi_lock, flags); | ||
723 | printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " | 655 | printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " |
724 | "free_irq() on MSI irq %d\n", | 656 | "free_irq() on MSI irq %d\n", |
725 | pci_name(dev), dev->irq); | 657 | pci_name(dev), dev->first_msi_irq); |
726 | BUG_ON(irq_has_action(dev->irq)); | 658 | BUG_ON(irq_has_action(dev->first_msi_irq)); |
727 | } else { | 659 | } else { |
728 | default_irq = entry->msi_attrib.default_irq; | 660 | default_irq = entry->msi_attrib.default_irq; |
729 | spin_unlock_irqrestore(&msi_lock, flags); | 661 | msi_free_irq(dev, dev->first_msi_irq); |
730 | msi_free_irq(dev, dev->irq); | ||
731 | 662 | ||
732 | /* Restore dev->irq to its default pin-assertion irq */ | 663 | /* Restore dev->irq to its default pin-assertion irq */ |
733 | dev->irq = default_irq; | 664 | dev->irq = default_irq; |
734 | } | 665 | } |
666 | dev->first_msi_irq = 0; | ||
735 | } | 667 | } |
736 | 668 | ||
737 | static int msi_free_irq(struct pci_dev* dev, int irq) | 669 | static int msi_free_irq(struct pci_dev* dev, int irq) |
@@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
739 | struct msi_desc *entry; | 671 | struct msi_desc *entry; |
740 | int head, entry_nr, type; | 672 | int head, entry_nr, type; |
741 | void __iomem *base; | 673 | void __iomem *base; |
742 | unsigned long flags; | ||
743 | 674 | ||
744 | arch_teardown_msi_irq(irq); | 675 | entry = get_irq_msi(irq); |
745 | |||
746 | spin_lock_irqsave(&msi_lock, flags); | ||
747 | entry = msi_desc[irq]; | ||
748 | if (!entry || entry->dev != dev) { | 676 | if (!entry || entry->dev != dev) { |
749 | spin_unlock_irqrestore(&msi_lock, flags); | ||
750 | return -EINVAL; | 677 | return -EINVAL; |
751 | } | 678 | } |
752 | type = entry->msi_attrib.type; | 679 | type = entry->msi_attrib.type; |
753 | entry_nr = entry->msi_attrib.entry_nr; | 680 | entry_nr = entry->msi_attrib.entry_nr; |
754 | head = entry->link.head; | 681 | head = entry->link.head; |
755 | base = entry->mask_base; | 682 | base = entry->mask_base; |
756 | msi_desc[entry->link.head]->link.tail = entry->link.tail; | 683 | get_irq_msi(entry->link.head)->link.tail = entry->link.tail; |
757 | msi_desc[entry->link.tail]->link.head = entry->link.head; | 684 | get_irq_msi(entry->link.tail)->link.head = entry->link.head; |
758 | entry->dev = NULL; | ||
759 | msi_desc[irq] = NULL; | ||
760 | spin_unlock_irqrestore(&msi_lock, flags); | ||
761 | 685 | ||
762 | destroy_msi_irq(irq); | 686 | arch_teardown_msi_irq(irq); |
687 | kmem_cache_free(msi_cachep, entry); | ||
763 | 688 | ||
764 | if (type == PCI_CAP_ID_MSIX) { | 689 | if (type == PCI_CAP_ID_MSIX) { |
765 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + | 690 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + |
@@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
790 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 715 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
791 | { | 716 | { |
792 | int status, pos, nr_entries; | 717 | int status, pos, nr_entries; |
793 | int i, j, temp; | 718 | int i, j; |
794 | u16 control; | 719 | u16 control; |
795 | 720 | ||
796 | if (!entries || pci_msi_supported(dev) < 0) | 721 | if (!entries || pci_msi_supported(dev) < 0) |
@@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
818 | return -EINVAL; /* duplicate entry */ | 743 | return -EINVAL; /* duplicate entry */ |
819 | } | 744 | } |
820 | } | 745 | } |
821 | temp = dev->irq; | 746 | WARN_ON(!!dev->msix_enabled); |
822 | WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)); | ||
823 | 747 | ||
824 | /* Check whether driver already requested for MSI irq */ | 748 | /* Check whether driver already requested for MSI irq */ |
825 | if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && | 749 | if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && |
826 | !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { | 750 | dev->msi_enabled) { |
827 | printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " | 751 | printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " |
828 | "Device already has an MSI irq assigned\n", | 752 | "Device already has an MSI irq assigned\n", |
829 | pci_name(dev)); | 753 | pci_name(dev)); |
830 | dev->irq = temp; | ||
831 | return -EINVAL; | 754 | return -EINVAL; |
832 | } | 755 | } |
833 | status = msix_capability_init(dev, entries, nvec); | 756 | status = msix_capability_init(dev, entries, nvec); |
@@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
836 | 759 | ||
837 | void pci_disable_msix(struct pci_dev* dev) | 760 | void pci_disable_msix(struct pci_dev* dev) |
838 | { | 761 | { |
839 | int pos, temp; | 762 | int irq, head, tail = 0, warning = 0; |
763 | int pos; | ||
840 | u16 control; | 764 | u16 control; |
841 | 765 | ||
842 | if (!pci_msi_enable) | 766 | if (!pci_msi_enable) |
@@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* dev) | |||
844 | if (!dev) | 768 | if (!dev) |
845 | return; | 769 | return; |
846 | 770 | ||
771 | if (!dev->msix_enabled) | ||
772 | return; | ||
773 | |||
847 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 774 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); |
848 | if (!pos) | 775 | if (!pos) |
849 | return; | 776 | return; |
@@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* dev) | |||
854 | 781 | ||
855 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 782 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); |
856 | 783 | ||
857 | temp = dev->irq; | 784 | irq = head = dev->first_msi_irq; |
858 | if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { | 785 | while (head != tail) { |
859 | int irq, head, tail = 0, warning = 0; | 786 | tail = get_irq_msi(irq)->link.tail; |
860 | unsigned long flags; | 787 | if (irq_has_action(irq)) |
861 | 788 | warning = 1; | |
862 | irq = head = dev->irq; | 789 | else if (irq != head) /* Release MSI-X irq */ |
863 | dev->irq = temp; /* Restore pin IRQ */ | 790 | msi_free_irq(dev, irq); |
864 | while (head != tail) { | 791 | irq = tail; |
865 | spin_lock_irqsave(&msi_lock, flags); | 792 | } |
866 | tail = msi_desc[irq]->link.tail; | 793 | msi_free_irq(dev, irq); |
867 | spin_unlock_irqrestore(&msi_lock, flags); | 794 | if (warning) { |
868 | if (irq_has_action(irq)) | 795 | printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " |
869 | warning = 1; | 796 | "free_irq() on all MSI-X irqs\n", |
870 | else if (irq != head) /* Release MSI-X irq */ | 797 | pci_name(dev)); |
871 | msi_free_irq(dev, irq); | 798 | BUG_ON(warning > 0); |
872 | irq = tail; | ||
873 | } | ||
874 | msi_free_irq(dev, irq); | ||
875 | if (warning) { | ||
876 | printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " | ||
877 | "free_irq() on all MSI-X irqs\n", | ||
878 | pci_name(dev)); | ||
879 | BUG_ON(warning > 0); | ||
880 | } | ||
881 | } | 799 | } |
800 | dev->first_msi_irq = 0; | ||
882 | } | 801 | } |
883 | 802 | ||
884 | /** | 803 | /** |
@@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev) | |||
892 | **/ | 811 | **/ |
893 | void msi_remove_pci_irq_vectors(struct pci_dev* dev) | 812 | void msi_remove_pci_irq_vectors(struct pci_dev* dev) |
894 | { | 813 | { |
895 | int pos, temp; | ||
896 | unsigned long flags; | ||
897 | |||
898 | if (!pci_msi_enable || !dev) | 814 | if (!pci_msi_enable || !dev) |
899 | return; | 815 | return; |
900 | 816 | ||
901 | temp = dev->irq; /* Save IOAPIC IRQ */ | 817 | if (dev->msi_enabled) { |
902 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 818 | if (irq_has_action(dev->first_msi_irq)) { |
903 | if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { | ||
904 | if (irq_has_action(dev->irq)) { | ||
905 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 819 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " |
906 | "called without free_irq() on MSI irq %d\n", | 820 | "called without free_irq() on MSI irq %d\n", |
907 | pci_name(dev), dev->irq); | 821 | pci_name(dev), dev->first_msi_irq); |
908 | BUG_ON(irq_has_action(dev->irq)); | 822 | BUG_ON(irq_has_action(dev->first_msi_irq)); |
909 | } else /* Release MSI irq assigned to this device */ | 823 | } else /* Release MSI irq assigned to this device */ |
910 | msi_free_irq(dev, dev->irq); | 824 | msi_free_irq(dev, dev->first_msi_irq); |
911 | dev->irq = temp; /* Restore IOAPIC IRQ */ | ||
912 | } | 825 | } |
913 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 826 | if (dev->msix_enabled) { |
914 | if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { | ||
915 | int irq, head, tail = 0, warning = 0; | 827 | int irq, head, tail = 0, warning = 0; |
916 | void __iomem *base = NULL; | 828 | void __iomem *base = NULL; |
917 | 829 | ||
918 | irq = head = dev->irq; | 830 | irq = head = dev->first_msi_irq; |
919 | while (head != tail) { | 831 | while (head != tail) { |
920 | spin_lock_irqsave(&msi_lock, flags); | 832 | tail = get_irq_msi(irq)->link.tail; |
921 | tail = msi_desc[irq]->link.tail; | 833 | base = get_irq_msi(irq)->mask_base; |
922 | base = msi_desc[irq]->mask_base; | ||
923 | spin_unlock_irqrestore(&msi_lock, flags); | ||
924 | if (irq_has_action(irq)) | 834 | if (irq_has_action(irq)) |
925 | warning = 1; | 835 | warning = 1; |
926 | else if (irq != head) /* Release MSI-X irq */ | 836 | else if (irq != head) /* Release MSI-X irq */ |
@@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
935 | pci_name(dev)); | 845 | pci_name(dev)); |
936 | BUG_ON(warning > 0); | 846 | BUG_ON(warning > 0); |
937 | } | 847 | } |
938 | dev->irq = temp; /* Restore IOAPIC IRQ */ | ||
939 | } | 848 | } |
940 | } | 849 | } |
941 | 850 | ||