aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2013-03-05 16:12:37 -0500
committerMichael Ellerman <michael@ellerman.id.au>2013-04-17 23:03:59 -0400
commitfb1b55d654a7038ca6337fbf55839a308c9bc1a7 (patch)
tree00d57b0dedb5aac0c6ef7c4e5ebc69fb4c43f17c /arch/powerpc/platforms
parent2a3563b023e5f99e1ec48b66b4caeac94584e7c7 (diff)
powerpc/powernv: Use MSI bitmap to manage IRQs
As Michael Ellerman mentioned, arch/powerpc/sysdev/msi_bitmap.c already implemented bitmap to manage (alloc/free) MSI interrupts. The patch intends to use that mechanism to manage MSI interrupts for PowerNV platform. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c12
-rw-r--r--arch/powerpc/platforms/powernv/pci-p5ioc2.c11
-rw-r--r--arch/powerpc/platforms/powernv/pci.c59
-rw-r--r--arch/powerpc/platforms/powernv/pci.h4
4 files changed, 25 insertions, 61 deletions
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 8e90e8906df3..a5c5f15242ba 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -26,6 +26,7 @@
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/pci-bridge.h> 27#include <asm/pci-bridge.h>
28#include <asm/machdep.h> 28#include <asm/machdep.h>
29#include <asm/msi_bitmap.h>
29#include <asm/ppc-pci.h> 30#include <asm/ppc-pci.h>
30#include <asm/opal.h> 31#include <asm/opal.h>
31#include <asm/iommu.h> 32#include <asm/iommu.h>
@@ -647,7 +648,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
647 648
648static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) 649static void pnv_pci_init_ioda_msis(struct pnv_phb *phb)
649{ 650{
650 unsigned int bmap_size; 651 unsigned int count;
651 const __be32 *prop = of_get_property(phb->hose->dn, 652 const __be32 *prop = of_get_property(phb->hose->dn,
652 "ibm,opal-msi-ranges", NULL); 653 "ibm,opal-msi-ranges", NULL);
653 if (!prop) { 654 if (!prop) {
@@ -658,18 +659,17 @@ static void pnv_pci_init_ioda_msis(struct pnv_phb *phb)
658 return; 659 return;
659 660
660 phb->msi_base = be32_to_cpup(prop); 661 phb->msi_base = be32_to_cpup(prop);
661 phb->msi_count = be32_to_cpup(prop + 1); 662 count = be32_to_cpup(prop + 1);
662 bmap_size = BITS_TO_LONGS(phb->msi_count) * sizeof(unsigned long); 663 if (msi_bitmap_alloc(&phb->msi_bmp, count, phb->hose->dn)) {
663 phb->msi_map = zalloc_maybe_bootmem(bmap_size, GFP_KERNEL);
664 if (!phb->msi_map) {
665 pr_err("PCI %d: Failed to allocate MSI bitmap !\n", 664 pr_err("PCI %d: Failed to allocate MSI bitmap !\n",
666 phb->hose->global_number); 665 phb->hose->global_number);
667 return; 666 return;
668 } 667 }
668
669 phb->msi_setup = pnv_pci_ioda_msi_setup; 669 phb->msi_setup = pnv_pci_ioda_msi_setup;
670 phb->msi32_support = 1; 670 phb->msi32_support = 1;
671 pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", 671 pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n",
672 phb->msi_count, phb->msi_base); 672 count, phb->msi_base);
673} 673}
674#else 674#else
675static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { } 675static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { }
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
index 7db8771a40f5..d5c066ea7d1f 100644
--- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c
+++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
@@ -26,6 +26,7 @@
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/pci-bridge.h> 27#include <asm/pci-bridge.h>
28#include <asm/machdep.h> 28#include <asm/machdep.h>
29#include <asm/msi_bitmap.h>
29#include <asm/ppc-pci.h> 30#include <asm/ppc-pci.h>
30#include <asm/opal.h> 31#include <asm/opal.h>
31#include <asm/iommu.h> 32#include <asm/iommu.h>
@@ -55,7 +56,7 @@ static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
55 56
56static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) 57static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb)
57{ 58{
58 unsigned int bmap_size; 59 unsigned int count;
59 const __be32 *prop = of_get_property(phb->hose->dn, 60 const __be32 *prop = of_get_property(phb->hose->dn,
60 "ibm,opal-msi-ranges", NULL); 61 "ibm,opal-msi-ranges", NULL);
61 if (!prop) 62 if (!prop)
@@ -67,10 +68,8 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb)
67 if (of_device_is_compatible(phb->hose->dn, "ibm,p5ioc2-pcix")) 68 if (of_device_is_compatible(phb->hose->dn, "ibm,p5ioc2-pcix"))
68 return; 69 return;
69 phb->msi_base = be32_to_cpup(prop); 70 phb->msi_base = be32_to_cpup(prop);
70 phb->msi_count = be32_to_cpup(prop + 1); 71 count = be32_to_cpup(prop + 1);
71 bmap_size = BITS_TO_LONGS(phb->msi_count) * sizeof(unsigned long); 72 if (msi_bitmap_alloc(&phb->msi_bmp, count, phb->hose->dn)) {
72 phb->msi_map = zalloc_maybe_bootmem(bmap_size, GFP_KERNEL);
73 if (!phb->msi_map) {
74 pr_err("PCI %d: Failed to allocate MSI bitmap !\n", 73 pr_err("PCI %d: Failed to allocate MSI bitmap !\n",
75 phb->hose->global_number); 74 phb->hose->global_number);
76 return; 75 return;
@@ -78,7 +77,7 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb)
78 phb->msi_setup = pnv_pci_p5ioc2_msi_setup; 77 phb->msi_setup = pnv_pci_p5ioc2_msi_setup;
79 phb->msi32_support = 0; 78 phb->msi32_support = 0;
80 pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", 79 pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n",
81 phb->msi_count, phb->msi_base); 80 count, phb->msi_base);
82} 81}
83#else 82#else
84static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { } 83static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { }
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index b8b8e0bd9897..42eee93ca9c3 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -26,6 +26,7 @@
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/pci-bridge.h> 27#include <asm/pci-bridge.h>
28#include <asm/machdep.h> 28#include <asm/machdep.h>
29#include <asm/msi_bitmap.h>
29#include <asm/ppc-pci.h> 30#include <asm/ppc-pci.h>
30#include <asm/opal.h> 31#include <asm/opal.h>
31#include <asm/iommu.h> 32#include <asm/iommu.h>
@@ -47,43 +48,7 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type)
47 struct pci_controller *hose = pci_bus_to_host(pdev->bus); 48 struct pci_controller *hose = pci_bus_to_host(pdev->bus);
48 struct pnv_phb *phb = hose->private_data; 49 struct pnv_phb *phb = hose->private_data;
49 50
50 return (phb && phb->msi_map) ? 0 : -ENODEV; 51 return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV;
51}
52
53static unsigned int pnv_get_one_msi(struct pnv_phb *phb)
54{
55 unsigned long flags;
56 unsigned int id, rc;
57
58 spin_lock_irqsave(&phb->lock, flags);
59
60 id = find_next_zero_bit(phb->msi_map, phb->msi_count, phb->msi_next);
61 if (id >= phb->msi_count && phb->msi_next)
62 id = find_next_zero_bit(phb->msi_map, phb->msi_count, 0);
63 if (id >= phb->msi_count) {
64 rc = 0;
65 goto out;
66 }
67 __set_bit(id, phb->msi_map);
68 rc = id + phb->msi_base;
69out:
70 spin_unlock_irqrestore(&phb->lock, flags);
71 return rc;
72}
73
74static void pnv_put_msi(struct pnv_phb *phb, unsigned int hwirq)
75{
76 unsigned long flags;
77 unsigned int id;
78
79 if (WARN_ON(hwirq < phb->msi_base ||
80 hwirq >= (phb->msi_base + phb->msi_count)))
81 return;
82 id = hwirq - phb->msi_base;
83
84 spin_lock_irqsave(&phb->lock, flags);
85 __clear_bit(id, phb->msi_map);
86 spin_unlock_irqrestore(&phb->lock, flags);
87} 52}
88 53
89static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 54static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
@@ -92,7 +57,8 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
92 struct pnv_phb *phb = hose->private_data; 57 struct pnv_phb *phb = hose->private_data;
93 struct msi_desc *entry; 58 struct msi_desc *entry;
94 struct msi_msg msg; 59 struct msi_msg msg;
95 unsigned int hwirq, virq; 60 int hwirq;
61 unsigned int virq;
96 int rc; 62 int rc;
97 63
98 if (WARN_ON(!phb)) 64 if (WARN_ON(!phb))
@@ -104,25 +70,25 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
104 pci_name(pdev)); 70 pci_name(pdev));
105 return -ENXIO; 71 return -ENXIO;
106 } 72 }
107 hwirq = pnv_get_one_msi(phb); 73 hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, 1);
108 if (!hwirq) { 74 if (hwirq < 0) {
109 pr_warn("%s: Failed to find a free MSI\n", 75 pr_warn("%s: Failed to find a free MSI\n",
110 pci_name(pdev)); 76 pci_name(pdev));
111 return -ENOSPC; 77 return -ENOSPC;
112 } 78 }
113 virq = irq_create_mapping(NULL, hwirq); 79 virq = irq_create_mapping(NULL, phb->msi_base + hwirq);
114 if (virq == NO_IRQ) { 80 if (virq == NO_IRQ) {
115 pr_warn("%s: Failed to map MSI to linux irq\n", 81 pr_warn("%s: Failed to map MSI to linux irq\n",
116 pci_name(pdev)); 82 pci_name(pdev));
117 pnv_put_msi(phb, hwirq); 83 msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 1);
118 return -ENOMEM; 84 return -ENOMEM;
119 } 85 }
120 rc = phb->msi_setup(phb, pdev, hwirq, entry->msi_attrib.is_64, 86 rc = phb->msi_setup(phb, pdev, phb->msi_base + hwirq,
121 &msg); 87 entry->msi_attrib.is_64, &msg);
122 if (rc) { 88 if (rc) {
123 pr_warn("%s: Failed to setup MSI\n", pci_name(pdev)); 89 pr_warn("%s: Failed to setup MSI\n", pci_name(pdev));
124 irq_dispose_mapping(virq); 90 irq_dispose_mapping(virq);
125 pnv_put_msi(phb, hwirq); 91 msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 1);
126 return rc; 92 return rc;
127 } 93 }
128 irq_set_msi_desc(virq, entry); 94 irq_set_msi_desc(virq, entry);
@@ -144,7 +110,8 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev)
144 if (entry->irq == NO_IRQ) 110 if (entry->irq == NO_IRQ)
145 continue; 111 continue;
146 irq_set_msi_desc(entry->irq, NULL); 112 irq_set_msi_desc(entry->irq, NULL);
147 pnv_put_msi(phb, virq_to_hw(entry->irq)); 113 msi_bitmap_free_hwirqs(&phb->msi_bmp,
114 virq_to_hw(entry->irq) - phb->msi_base, 1);
148 irq_dispose_mapping(entry->irq); 115 irq_dispose_mapping(entry->irq);
149 } 116 }
150} 117}
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 7cfb7c883deb..42ddfba79651 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -73,11 +73,9 @@ struct pnv_phb {
73 spinlock_t lock; 73 spinlock_t lock;
74 74
75#ifdef CONFIG_PCI_MSI 75#ifdef CONFIG_PCI_MSI
76 unsigned long *msi_map;
77 unsigned int msi_base; 76 unsigned int msi_base;
78 unsigned int msi_count;
79 unsigned int msi_next;
80 unsigned int msi32_support; 77 unsigned int msi32_support;
78 struct msi_bitmap msi_bmp;
81#endif 79#endif
82 int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev, 80 int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev,
83 unsigned int hwirq, unsigned int is_64, 81 unsigned int hwirq, unsigned int is_64,