diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-11 20:34:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-11 20:34:00 -0400 |
commit | fd9879b9bb3258ebc27a4cc6d2d29f528f71901f (patch) | |
tree | 48b68994f5e8083aafe116533e8143cb2bf30c85 /arch/powerpc/sysdev/fsl_msi.c | |
parent | 81ae31d78239318610d7c2acb3e2610d622a5aa4 (diff) | |
parent | d53ba6b3bba33432cc37b7101a86f8f3392c46e7 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux
Pull powerpc updates from Michael Ellerman:
"Here's a first pull request for powerpc updates for 3.18.
The bulk of the additions are for the "cxl" driver, for IBM's Coherent
Accelerator Processor Interface (CAPI). Most of it's in drivers/misc,
which Greg & Arnd maintain, Greg said he was happy for us to take it
through our tree.
There's the usual minor cleanups and fixes, including a bit of noise
in drivers from some of those. A bunch of updates to our EEH code,
which has been getting more testing. Several nice speedups from
Anton, including 20% in clear_page().
And a bunch of updates for freescale from Scott"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux: (130 commits)
cxl: Fix afu_read() not doing finish_wait() on signal or non-blocking
cxl: Add documentation for userspace APIs
cxl: Add driver to Kbuild and Makefiles
cxl: Add userspace header file
cxl: Driver code for powernv PCIe based cards for userspace access
cxl: Add base builtin support
powerpc/mm: Add hooks for cxl
powerpc/opal: Add PHB to cxl mode call
powerpc/mm: Add new hash_page_mm()
powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
cxl: Add new header for call backs and structs
powerpc/powernv: Split out set MSI IRQ chip code
powerpc/mm: Export mmu_kernel_ssize and mmu_linear_psize
powerpc/msi: Improve IRQ bitmap allocator
powerpc/cell: Make spu_flush_all_slbs() generic
powerpc/cell: Move data segment faulting code out of cell platform
powerpc/cell: Move spu_handle_mm_fault() out of cell platform
powerpc/pseries: Use new defines when calling H_SET_MODE
powerpc: Update contact info in Documentation files
powerpc/perf/hv-24x7: Simplify catalog_read()
...
Diffstat (limited to 'arch/powerpc/sysdev/fsl_msi.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 95 |
1 files changed, 50 insertions, 45 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index b32e79dbef4f..de40b48b460e 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/of_platform.h> | 20 | #include <linux/of_platform.h> |
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/seq_file.h> | ||
21 | #include <sysdev/fsl_soc.h> | 23 | #include <sysdev/fsl_soc.h> |
22 | #include <asm/prom.h> | 24 | #include <asm/prom.h> |
23 | #include <asm/hw_irq.h> | 25 | #include <asm/hw_irq.h> |
@@ -50,6 +52,7 @@ struct fsl_msi_feature { | |||
50 | struct fsl_msi_cascade_data { | 52 | struct fsl_msi_cascade_data { |
51 | struct fsl_msi *msi_data; | 53 | struct fsl_msi *msi_data; |
52 | int index; | 54 | int index; |
55 | int virq; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) | 58 | static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) |
@@ -65,11 +68,24 @@ static void fsl_msi_end_irq(struct irq_data *d) | |||
65 | { | 68 | { |
66 | } | 69 | } |
67 | 70 | ||
71 | static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p) | ||
72 | { | ||
73 | struct fsl_msi *msi_data = irqd->domain->host_data; | ||
74 | irq_hw_number_t hwirq = irqd_to_hwirq(irqd); | ||
75 | int cascade_virq, srs; | ||
76 | |||
77 | srs = (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK; | ||
78 | cascade_virq = msi_data->cascade_array[srs]->virq; | ||
79 | |||
80 | seq_printf(p, " fsl-msi-%d", cascade_virq); | ||
81 | } | ||
82 | |||
83 | |||
68 | static struct irq_chip fsl_msi_chip = { | 84 | static struct irq_chip fsl_msi_chip = { |
69 | .irq_mask = mask_msi_irq, | 85 | .irq_mask = mask_msi_irq, |
70 | .irq_unmask = unmask_msi_irq, | 86 | .irq_unmask = unmask_msi_irq, |
71 | .irq_ack = fsl_msi_end_irq, | 87 | .irq_ack = fsl_msi_end_irq, |
72 | .name = "FSL-MSI", | 88 | .irq_print_chip = fsl_msi_print_chip, |
73 | }; | 89 | }; |
74 | 90 | ||
75 | static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq, | 91 | static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq, |
@@ -175,7 +191,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
175 | np = of_parse_phandle(hose->dn, "fsl,msi", 0); | 191 | np = of_parse_phandle(hose->dn, "fsl,msi", 0); |
176 | if (np) { | 192 | if (np) { |
177 | if (of_device_is_compatible(np, "fsl,mpic-msi") || | 193 | if (of_device_is_compatible(np, "fsl,mpic-msi") || |
178 | of_device_is_compatible(np, "fsl,vmpic-msi")) | 194 | of_device_is_compatible(np, "fsl,vmpic-msi") || |
195 | of_device_is_compatible(np, "fsl,vmpic-msi-v4.3")) | ||
179 | phandle = np->phandle; | 196 | phandle = np->phandle; |
180 | else { | 197 | else { |
181 | dev_err(&pdev->dev, | 198 | dev_err(&pdev->dev, |
@@ -234,40 +251,24 @@ out_free: | |||
234 | return rc; | 251 | return rc; |
235 | } | 252 | } |
236 | 253 | ||
237 | static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | 254 | static irqreturn_t fsl_msi_cascade(int irq, void *data) |
238 | { | 255 | { |
239 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
240 | struct irq_data *idata = irq_desc_get_irq_data(desc); | ||
241 | unsigned int cascade_irq; | 256 | unsigned int cascade_irq; |
242 | struct fsl_msi *msi_data; | 257 | struct fsl_msi *msi_data; |
243 | int msir_index = -1; | 258 | int msir_index = -1; |
244 | u32 msir_value = 0; | 259 | u32 msir_value = 0; |
245 | u32 intr_index; | 260 | u32 intr_index; |
246 | u32 have_shift = 0; | 261 | u32 have_shift = 0; |
247 | struct fsl_msi_cascade_data *cascade_data; | 262 | struct fsl_msi_cascade_data *cascade_data = data; |
263 | irqreturn_t ret = IRQ_NONE; | ||
248 | 264 | ||
249 | cascade_data = irq_get_handler_data(irq); | ||
250 | msi_data = cascade_data->msi_data; | 265 | msi_data = cascade_data->msi_data; |
251 | 266 | ||
252 | raw_spin_lock(&desc->lock); | ||
253 | if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { | ||
254 | if (chip->irq_mask_ack) | ||
255 | chip->irq_mask_ack(idata); | ||
256 | else { | ||
257 | chip->irq_mask(idata); | ||
258 | chip->irq_ack(idata); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | if (unlikely(irqd_irq_inprogress(idata))) | ||
263 | goto unlock; | ||
264 | |||
265 | msir_index = cascade_data->index; | 267 | msir_index = cascade_data->index; |
266 | 268 | ||
267 | if (msir_index >= NR_MSI_REG_MAX) | 269 | if (msir_index >= NR_MSI_REG_MAX) |
268 | cascade_irq = NO_IRQ; | 270 | cascade_irq = NO_IRQ; |
269 | 271 | ||
270 | irqd_set_chained_irq_inprogress(idata); | ||
271 | switch (msi_data->feature & FSL_PIC_IP_MASK) { | 272 | switch (msi_data->feature & FSL_PIC_IP_MASK) { |
272 | case FSL_PIC_IP_MPIC: | 273 | case FSL_PIC_IP_MPIC: |
273 | msir_value = fsl_msi_read(msi_data->msi_regs, | 274 | msir_value = fsl_msi_read(msi_data->msi_regs, |
@@ -296,40 +297,32 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | |||
296 | cascade_irq = irq_linear_revmap(msi_data->irqhost, | 297 | cascade_irq = irq_linear_revmap(msi_data->irqhost, |
297 | msi_hwirq(msi_data, msir_index, | 298 | msi_hwirq(msi_data, msir_index, |
298 | intr_index + have_shift)); | 299 | intr_index + have_shift)); |
299 | if (cascade_irq != NO_IRQ) | 300 | if (cascade_irq != NO_IRQ) { |
300 | generic_handle_irq(cascade_irq); | 301 | generic_handle_irq(cascade_irq); |
302 | ret = IRQ_HANDLED; | ||
303 | } | ||
301 | have_shift += intr_index + 1; | 304 | have_shift += intr_index + 1; |
302 | msir_value = msir_value >> (intr_index + 1); | 305 | msir_value = msir_value >> (intr_index + 1); |
303 | } | 306 | } |
304 | irqd_clr_chained_irq_inprogress(idata); | ||
305 | 307 | ||
306 | switch (msi_data->feature & FSL_PIC_IP_MASK) { | 308 | return ret; |
307 | case FSL_PIC_IP_MPIC: | ||
308 | case FSL_PIC_IP_VMPIC: | ||
309 | chip->irq_eoi(idata); | ||
310 | break; | ||
311 | case FSL_PIC_IP_IPIC: | ||
312 | if (!irqd_irq_disabled(idata) && chip->irq_unmask) | ||
313 | chip->irq_unmask(idata); | ||
314 | break; | ||
315 | } | ||
316 | unlock: | ||
317 | raw_spin_unlock(&desc->lock); | ||
318 | } | 309 | } |
319 | 310 | ||
320 | static int fsl_of_msi_remove(struct platform_device *ofdev) | 311 | static int fsl_of_msi_remove(struct platform_device *ofdev) |
321 | { | 312 | { |
322 | struct fsl_msi *msi = platform_get_drvdata(ofdev); | 313 | struct fsl_msi *msi = platform_get_drvdata(ofdev); |
323 | int virq, i; | 314 | int virq, i; |
324 | struct fsl_msi_cascade_data *cascade_data; | ||
325 | 315 | ||
326 | if (msi->list.prev != NULL) | 316 | if (msi->list.prev != NULL) |
327 | list_del(&msi->list); | 317 | list_del(&msi->list); |
328 | for (i = 0; i < NR_MSI_REG_MAX; i++) { | 318 | for (i = 0; i < NR_MSI_REG_MAX; i++) { |
329 | virq = msi->msi_virqs[i]; | 319 | if (msi->cascade_array[i]) { |
330 | if (virq != NO_IRQ) { | 320 | virq = msi->cascade_array[i]->virq; |
331 | cascade_data = irq_get_handler_data(virq); | 321 | |
332 | kfree(cascade_data); | 322 | BUG_ON(virq == NO_IRQ); |
323 | |||
324 | free_irq(virq, msi->cascade_array[i]); | ||
325 | kfree(msi->cascade_array[i]); | ||
333 | irq_dispose_mapping(virq); | 326 | irq_dispose_mapping(virq); |
334 | } | 327 | } |
335 | } | 328 | } |
@@ -348,7 +341,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, | |||
348 | int offset, int irq_index) | 341 | int offset, int irq_index) |
349 | { | 342 | { |
350 | struct fsl_msi_cascade_data *cascade_data = NULL; | 343 | struct fsl_msi_cascade_data *cascade_data = NULL; |
351 | int virt_msir, i; | 344 | int virt_msir, i, ret; |
352 | 345 | ||
353 | virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); | 346 | virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); |
354 | if (virt_msir == NO_IRQ) { | 347 | if (virt_msir == NO_IRQ) { |
@@ -363,11 +356,18 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, | |||
363 | return -ENOMEM; | 356 | return -ENOMEM; |
364 | } | 357 | } |
365 | irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class); | 358 | irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class); |
366 | msi->msi_virqs[irq_index] = virt_msir; | ||
367 | cascade_data->index = offset; | 359 | cascade_data->index = offset; |
368 | cascade_data->msi_data = msi; | 360 | cascade_data->msi_data = msi; |
369 | irq_set_handler_data(virt_msir, cascade_data); | 361 | cascade_data->virq = virt_msir; |
370 | irq_set_chained_handler(virt_msir, fsl_msi_cascade); | 362 | msi->cascade_array[irq_index] = cascade_data; |
363 | |||
364 | ret = request_irq(virt_msir, fsl_msi_cascade, 0, | ||
365 | "fsl-msi-cascade", cascade_data); | ||
366 | if (ret) { | ||
367 | dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n", | ||
368 | virt_msir, ret); | ||
369 | return ret; | ||
370 | } | ||
371 | 371 | ||
372 | /* Release the hwirqs corresponding to this MSI register */ | 372 | /* Release the hwirqs corresponding to this MSI register */ |
373 | for (i = 0; i < IRQS_PER_MSI_REG; i++) | 373 | for (i = 0; i < IRQS_PER_MSI_REG; i++) |
@@ -461,7 +461,8 @@ static int fsl_of_msi_probe(struct platform_device *dev) | |||
461 | 461 | ||
462 | p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); | 462 | p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); |
463 | 463 | ||
464 | if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3")) { | 464 | if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") || |
465 | of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) { | ||
465 | msi->srs_shift = MSIIR1_SRS_SHIFT; | 466 | msi->srs_shift = MSIIR1_SRS_SHIFT; |
466 | msi->ibs_shift = MSIIR1_IBS_SHIFT; | 467 | msi->ibs_shift = MSIIR1_IBS_SHIFT; |
467 | if (p) | 468 | if (p) |
@@ -566,6 +567,10 @@ static const struct of_device_id fsl_of_msi_ids[] = { | |||
566 | .compatible = "fsl,vmpic-msi", | 567 | .compatible = "fsl,vmpic-msi", |
567 | .data = &vmpic_msi_feature, | 568 | .data = &vmpic_msi_feature, |
568 | }, | 569 | }, |
570 | { | ||
571 | .compatible = "fsl,vmpic-msi-v4.3", | ||
572 | .data = &vmpic_msi_feature, | ||
573 | }, | ||
569 | #endif | 574 | #endif |
570 | {} | 575 | {} |
571 | }; | 576 | }; |