diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-03-05 16:12:37 -0500 |
---|---|---|
committer | Michael Ellerman <michael@ellerman.id.au> | 2013-04-17 23:03:59 -0400 |
commit | fb1b55d654a7038ca6337fbf55839a308c9bc1a7 (patch) | |
tree | 00d57b0dedb5aac0c6ef7c4e5ebc69fb4c43f17c /arch/powerpc/platforms/powernv/pci.c | |
parent | 2a3563b023e5f99e1ec48b66b4caeac94584e7c7 (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.c | 59 |
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 | |||
53 | static 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; | ||
69 | out: | ||
70 | spin_unlock_irqrestore(&phb->lock, flags); | ||
71 | return rc; | ||
72 | } | ||
73 | |||
74 | static 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 | ||
89 | static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 54 | static 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 | } |