aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/fsl_msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/fsl_msi.c')
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c109
1 files changed, 16 insertions, 93 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 2c5187cc8a24..f25ce818d40a 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -14,7 +14,6 @@
14 */ 14 */
15#include <linux/irq.h> 15#include <linux/irq.h>
16#include <linux/bootmem.h> 16#include <linux/bootmem.h>
17#include <linux/bitmap.h>
18#include <linux/msi.h> 17#include <linux/msi.h>
19#include <linux/pci.h> 18#include <linux/pci.h>
20#include <linux/of_platform.h> 19#include <linux/of_platform.h>
@@ -67,95 +66,22 @@ static struct irq_host_ops fsl_msi_host_ops = {
67 .map = fsl_msi_host_map, 66 .map = fsl_msi_host_map,
68}; 67};
69 68
70static irq_hw_number_t fsl_msi_alloc_hwirqs(struct fsl_msi *msi, int num)
71{
72 unsigned long flags;
73 int order = get_count_order(num);
74 int offset;
75
76 spin_lock_irqsave(&msi->bitmap_lock, flags);
77
78 offset = bitmap_find_free_region(msi->fsl_msi_bitmap,
79 NR_MSI_IRQS, order);
80
81 spin_unlock_irqrestore(&msi->bitmap_lock, flags);
82
83 pr_debug("%s: allocated 0x%x (2^%d) at offset 0x%x\n",
84 __func__, num, order, offset);
85
86 return offset;
87}
88
89static void fsl_msi_free_hwirqs(struct fsl_msi *msi, int offset, int num)
90{
91 unsigned long flags;
92 int order = get_count_order(num);
93
94 pr_debug("%s: freeing 0x%x (2^%d) at offset 0x%x\n",
95 __func__, num, order, offset);
96
97 spin_lock_irqsave(&msi->bitmap_lock, flags);
98 bitmap_release_region(msi->fsl_msi_bitmap, offset, order);
99 spin_unlock_irqrestore(&msi->bitmap_lock, flags);
100}
101
102static int fsl_msi_free_dt_hwirqs(struct fsl_msi *msi)
103{
104 int i;
105 int len;
106 const u32 *p;
107
108 bitmap_allocate_region(msi->fsl_msi_bitmap, 0,
109 get_count_order(NR_MSI_IRQS));
110
111 p = of_get_property(msi->of_node, "msi-available-ranges", &len);
112
113 if (!p) {
114 /* No msi-available-ranges property,
115 * All the 256 MSI interrupts can be used
116 */
117 fsl_msi_free_hwirqs(msi, 0, 0x100);
118 return 0;
119 }
120
121 if ((len % (2 * sizeof(u32))) != 0) {
122 printk(KERN_WARNING "fsl_msi: Malformed msi-available-ranges "
123 "property on %s\n", msi->of_node->full_name);
124 return -EINVAL;
125 }
126
127 /* Format is: (<u32 start> <u32 count>)+ */
128 len /= 2 * sizeof(u32);
129 for (i = 0; i < len; i++, p += 2)
130 fsl_msi_free_hwirqs(msi, *p, *(p + 1));
131
132 return 0;
133}
134
135static int fsl_msi_init_allocator(struct fsl_msi *msi_data) 69static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
136{ 70{
137 int rc; 71 int rc;
138 int size = BITS_TO_LONGS(NR_MSI_IRQS) * sizeof(u32);
139 72
140 msi_data->fsl_msi_bitmap = kzalloc(size, GFP_KERNEL); 73 rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
74 msi_data->irqhost->of_node);
75 if (rc)
76 return rc;
141 77
142 if (msi_data->fsl_msi_bitmap == NULL) { 78 rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
143 pr_debug("%s: ENOMEM allocating allocator bitmap!\n", 79 if (rc < 0) {
144 __func__); 80 msi_bitmap_free(&msi_data->bitmap);
145 return -ENOMEM; 81 return rc;
146 } 82 }
147 83
148 rc = fsl_msi_free_dt_hwirqs(msi_data);
149 if (rc)
150 goto out_free;
151
152 return 0; 84 return 0;
153out_free:
154 kfree(msi_data->fsl_msi_bitmap);
155
156 msi_data->fsl_msi_bitmap = NULL;
157 return rc;
158
159} 85}
160 86
161static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) 87static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
@@ -175,7 +101,8 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
175 if (entry->irq == NO_IRQ) 101 if (entry->irq == NO_IRQ)
176 continue; 102 continue;
177 set_irq_msi(entry->irq, NULL); 103 set_irq_msi(entry->irq, NULL);
178 fsl_msi_free_hwirqs(msi_data, virq_to_hw(entry->irq), 1); 104 msi_bitmap_free_hwirqs(&msi_data->bitmap,
105 virq_to_hw(entry->irq), 1);
179 irq_dispose_mapping(entry->irq); 106 irq_dispose_mapping(entry->irq);
180 } 107 }
181 108
@@ -197,15 +124,14 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
197 124
198static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 125static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
199{ 126{
200 irq_hw_number_t hwirq; 127 int rc, hwirq;
201 int rc;
202 unsigned int virq; 128 unsigned int virq;
203 struct msi_desc *entry; 129 struct msi_desc *entry;
204 struct msi_msg msg; 130 struct msi_msg msg;
205 struct fsl_msi *msi_data = fsl_msi; 131 struct fsl_msi *msi_data = fsl_msi;
206 132
207 list_for_each_entry(entry, &pdev->msi_list, list) { 133 list_for_each_entry(entry, &pdev->msi_list, list) {
208 hwirq = fsl_msi_alloc_hwirqs(msi_data, 1); 134 hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
209 if (hwirq < 0) { 135 if (hwirq < 0) {
210 rc = hwirq; 136 rc = hwirq;
211 pr_debug("%s: fail allocating msi interrupt\n", 137 pr_debug("%s: fail allocating msi interrupt\n",
@@ -216,9 +142,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
216 virq = irq_create_mapping(msi_data->irqhost, hwirq); 142 virq = irq_create_mapping(msi_data->irqhost, hwirq);
217 143
218 if (virq == NO_IRQ) { 144 if (virq == NO_IRQ) {
219 pr_debug("%s: fail mapping hwirq 0x%lx\n", 145 pr_debug("%s: fail mapping hwirq 0x%x\n",
220 __func__, hwirq); 146 __func__, hwirq);
221 fsl_msi_free_hwirqs(msi_data, hwirq, 1); 147 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
222 rc = -ENOSPC; 148 rc = -ENOSPC;
223 goto out_free; 149 goto out_free;
224 } 150 }
@@ -317,14 +243,11 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
317 goto error_out; 243 goto error_out;
318 } 244 }
319 245
320 msi->of_node = of_node_get(dev->node); 246 msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
247 NR_MSI_IRQS, &fsl_msi_host_ops, 0);
321 248
322 msi->irqhost = irq_alloc_host(of_node_get(dev->node),
323 IRQ_HOST_MAP_LINEAR,
324 NR_MSI_IRQS, &fsl_msi_host_ops, 0);
325 if (msi->irqhost == NULL) { 249 if (msi->irqhost == NULL) {
326 dev_err(&dev->dev, "No memory for MSI irqhost\n"); 250 dev_err(&dev->dev, "No memory for MSI irqhost\n");
327 of_node_put(dev->node);
328 err = -ENOMEM; 251 err = -ENOMEM;
329 goto error_out; 252 goto error_out;
330 } 253 }