aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/pci.c
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/powernv/pci.c
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/powernv/pci.c')
-rw-r--r--arch/powerpc/platforms/powernv/pci.c59
1 files changed, 13 insertions, 46 deletions
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}