aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/msi.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2007-04-18 05:39:22 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-05-02 22:02:38 -0400
commit032de8e2fe3c0eec5fb0ffe4d38aa602dad397dc (patch)
treeb9ad28ab3642c2dfba8e059fc72bd8e86c667449 /drivers/pci/msi.c
parent9c8313343c83c0ca731ceb8d2a4ab1e022ed9c94 (diff)
MSI: Give archs the option to free all MSI/Xs at once.
This patch introduces an optional function, arch_teardown_msi_irqs(), which gives an arch the opportunity to do per-device teardown for MSI/X. If that's not required, the default version simply calls arch_teardown_msi_irq() for each msi irq required. arch_teardown_msi_irqs() is simply passed a pdev, attached to the pdev is a list of msi_descs, it is up to the arch to free the irq associated with each of these as appropriate. For archs that _don't_ implement arch_teardown_msi_irqs(), all msi_descs with irq == 0 are considered unallocated, and the arch teardown routine is not called on them. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r--drivers/pci/msi.c75
1 files changed, 39 insertions, 36 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index c71e8e4c7168..9e1321d0d5e6 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -207,7 +207,7 @@ void unmask_msi_irq(unsigned int irq)
207 msix_flush_writes(irq); 207 msix_flush_writes(irq);
208} 208}
209 209
210static int msi_free_irq(struct pci_dev* dev, int irq); 210static int msi_free_irqs(struct pci_dev* dev);
211 211
212 212
213static struct msi_desc* alloc_msi_entry(void) 213static struct msi_desc* alloc_msi_entry(void)
@@ -339,8 +339,7 @@ static int msi_capability_init(struct pci_dev *dev)
339 /* Configure MSI capability structure */ 339 /* Configure MSI capability structure */
340 ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); 340 ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
341 if (ret) { 341 if (ret) {
342 list_del(&entry->list); 342 msi_free_irqs(dev);
343 kfree(entry);
344 return ret; 343 return ret;
345 } 344 }
346 345
@@ -415,10 +414,11 @@ static int msix_capability_init(struct pci_dev *dev,
415 list_for_each_entry(entry, &dev->msi_list, list) { 414 list_for_each_entry(entry, &dev->msi_list, list) {
416 if (entry->irq != 0) { 415 if (entry->irq != 0) {
417 avail++; 416 avail++;
418 msi_free_irq(dev, entry->irq);
419 } 417 }
420 } 418 }
421 419
420 msi_free_irqs(dev);
421
422 /* If we had some success report the number of irqs 422 /* If we had some success report the number of irqs
423 * we succeeded in setting up. 423 * we succeeded in setting up.
424 */ 424 */
@@ -539,39 +539,33 @@ void pci_disable_msi(struct pci_dev* dev)
539 } 539 }
540 540
541 default_irq = entry->msi_attrib.default_irq; 541 default_irq = entry->msi_attrib.default_irq;
542 msi_free_irq(dev, entry->irq); 542 msi_free_irqs(dev);
543 543
544 /* Restore dev->irq to its default pin-assertion irq */ 544 /* Restore dev->irq to its default pin-assertion irq */
545 dev->irq = default_irq; 545 dev->irq = default_irq;
546} 546}
547EXPORT_SYMBOL(pci_disable_msi); 547EXPORT_SYMBOL(pci_disable_msi);
548 548
549static int msi_free_irq(struct pci_dev* dev, int irq) 549static int msi_free_irqs(struct pci_dev* dev)
550{ 550{
551 struct msi_desc *entry; 551 struct msi_desc *entry, *tmp;
552 int entry_nr, type;
553 void __iomem *base;
554
555 BUG_ON(irq_has_action(irq));
556 552
557 entry = get_irq_msi(irq); 553 list_for_each_entry(entry, &dev->msi_list, list)
558 if (!entry || entry->dev != dev) { 554 BUG_ON(irq_has_action(entry->irq));
559 return -EINVAL;
560 }
561 type = entry->msi_attrib.type;
562 entry_nr = entry->msi_attrib.entry_nr;
563 base = entry->mask_base;
564 list_del(&entry->list);
565 555
566 arch_teardown_msi_irq(irq); 556 arch_teardown_msi_irqs(dev);
567 kfree(entry);
568 557
569 if (type == PCI_CAP_ID_MSIX) { 558 list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
570 writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + 559 if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) {
571 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); 560 if (list_is_last(&entry->list, &dev->msi_list))
561 iounmap(entry->mask_base);
572 562
573 if (list_empty(&dev->msi_list)) 563 writel(1, entry->mask_base + entry->msi_attrib.entry_nr
574 iounmap(base); 564 * PCI_MSIX_ENTRY_SIZE
565 + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
566 }
567 list_del(&entry->list);
568 kfree(entry);
575 } 569 }
576 570
577 return 0; 571 return 0;
@@ -636,10 +630,7 @@ EXPORT_SYMBOL(pci_enable_msix);
636 630
637static void msix_free_all_irqs(struct pci_dev *dev) 631static void msix_free_all_irqs(struct pci_dev *dev)
638{ 632{
639 struct msi_desc *entry; 633 msi_free_irqs(dev);
640
641 list_for_each_entry(entry, &dev->msi_list, list)
642 msi_free_irq(dev, entry->irq);
643} 634}
644 635
645void pci_disable_msix(struct pci_dev* dev) 636void pci_disable_msix(struct pci_dev* dev)
@@ -669,12 +660,8 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
669 if (!pci_msi_enable || !dev) 660 if (!pci_msi_enable || !dev)
670 return; 661 return;
671 662
672 if (dev->msi_enabled) { 663 if (dev->msi_enabled)
673 struct msi_desc *entry; 664 msi_free_irqs(dev);
674 BUG_ON(list_empty(&dev->msi_list));
675 entry = list_entry(dev->msi_list.next, struct msi_desc, list);
676 msi_free_irq(dev, entry->irq);
677 }
678 665
679 if (dev->msix_enabled) 666 if (dev->msix_enabled)
680 msix_free_all_irqs(dev); 667 msix_free_all_irqs(dev);
@@ -719,3 +706,19 @@ arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
719 706
720 return 0; 707 return 0;
721} 708}
709
710void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
711{
712 return;
713}
714
715void __attribute__ ((weak))
716arch_teardown_msi_irqs(struct pci_dev *dev)
717{
718 struct msi_desc *entry;
719
720 list_for_each_entry(entry, &dev->msi_list, list) {
721 if (entry->irq != 0)
722 arch_teardown_msi_irq(entry->irq);
723 }
724}