diff options
Diffstat (limited to 'arch/powerpc/sysdev/fsl_msi.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 109 |
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 | ||
70 | static 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 | |||
89 | static 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 | |||
102 | static 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 | |||
135 | static int fsl_msi_init_allocator(struct fsl_msi *msi_data) | 69 | static 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; |
153 | out_free: | ||
154 | kfree(msi_data->fsl_msi_bitmap); | ||
155 | |||
156 | msi_data->fsl_msi_bitmap = NULL; | ||
157 | return rc; | ||
158 | |||
159 | } | 85 | } |
160 | 86 | ||
161 | static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) | 87 | static 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 | ||
198 | static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 125 | static 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 | } |