aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/wsp/msi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-06 20:12:03 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-06 20:12:03 -0500
commit1197ab2942f920f261952de0c392ac749a35796b (patch)
tree4922ccc8a6061e5ece6ac7420001f3bf4524ea92 /arch/powerpc/platforms/wsp/msi.c
parentec773e99ab4abce07b1ae23117179c2861831964 (diff)
parent96cc017c5b7ec095ef047d3c1952b6b6bbf98943 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (106 commits) powerpc/p3060qds: Add support for P3060QDS board powerpc/83xx: Add shutdown request support to MCU handling on MPC8349 MITX powerpc/85xx: Make kexec to interate over online cpus powerpc/fsl_booke: Fix comment in head_fsl_booke.S powerpc/85xx: issue 15 EOI after core reset for FSL CoreNet devices powerpc/8xxx: Fix interrupt handling in MPC8xxx GPIO driver powerpc/85xx: Add 'fsl,pq3-gpio' compatiable for GPIO driver powerpc/86xx: Correct Gianfar support for GE boards powerpc/cpm: Clear muram before it is in use. drivers/virt: add ioctl for 32-bit compat on 64-bit to fsl-hv-manager powerpc/fsl_msi: add support for "msi-address-64" property powerpc/85xx: Setup secondary cores PIR with hard SMP id powerpc/fsl-booke: Fix settlbcam for 64-bit powerpc/85xx: Adding DCSR node to dtsi device trees powerpc/85xx: clean up FPGA device tree nodes for Freecsale QorIQ boards powerpc/85xx: fix PHYS_64BIT selection for P1022DS powerpc/fsl-booke: Fix setup_initial_memory_limit to not blindly map powerpc: respect mem= setting for early memory limit setup powerpc: Update corenet64_smp_defconfig powerpc: Update mpc85xx/corenet 32-bit defconfigs ... Fix up trivial conflicts in: - arch/powerpc/configs/40x/hcu4_defconfig removed stale file, edited elsewhere - arch/powerpc/include/asm/udbg.h, arch/powerpc/kernel/udbg.c: added opal and gelic drivers vs added ePAPR driver - drivers/tty/serial/8250.c moved UPIO_TSI to powerpc vs removed UPIO_DWAPB support
Diffstat (limited to 'arch/powerpc/platforms/wsp/msi.c')
-rw-r--r--arch/powerpc/platforms/wsp/msi.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/wsp/msi.c b/arch/powerpc/platforms/wsp/msi.c
new file mode 100644
index 00000000000..380882f27ad
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/msi.c
@@ -0,0 +1,102 @@
1/*
2 * Copyright 2011 Michael Ellerman, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/pci.h>
12#include <linux/msi.h>
13#include <linux/irq.h>
14#include <linux/interrupt.h>
15
16#include "msi.h"
17#include "ics.h"
18#include "wsp_pci.h"
19
20/* Magic addresses for 32 & 64-bit MSIs with hardcoded MVE 0 */
21#define MSI_ADDR_32 0xFFFF0000ul
22#define MSI_ADDR_64 0x1000000000000000ul
23
24int wsp_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
25{
26 struct pci_controller *phb;
27 struct msi_desc *entry;
28 struct msi_msg msg;
29 unsigned int virq;
30 int hwirq;
31
32 phb = pci_bus_to_host(dev->bus);
33 if (!phb)
34 return -ENOENT;
35
36 entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
37 if (entry->msi_attrib.is_64) {
38 msg.address_lo = 0;
39 msg.address_hi = MSI_ADDR_64 >> 32;
40 } else {
41 msg.address_lo = MSI_ADDR_32;
42 msg.address_hi = 0;
43 }
44
45 list_for_each_entry(entry, &dev->msi_list, list) {
46 hwirq = wsp_ics_alloc_irq(phb->dn, 1);
47 if (hwirq < 0) {
48 dev_warn(&dev->dev, "wsp_msi: hwirq alloc failed!\n");
49 return hwirq;
50 }
51
52 virq = irq_create_mapping(NULL, hwirq);
53 if (virq == NO_IRQ) {
54 dev_warn(&dev->dev, "wsp_msi: virq alloc failed!\n");
55 return -1;
56 }
57
58 dev_dbg(&dev->dev, "wsp_msi: allocated irq %#x/%#x\n",
59 hwirq, virq);
60
61 wsp_ics_set_msi_chip(virq);
62 irq_set_msi_desc(virq, entry);
63 msg.data = hwirq & XIVE_ADDR_MASK;
64 write_msi_msg(virq, &msg);
65 }
66
67 return 0;
68}
69
70void wsp_teardown_msi_irqs(struct pci_dev *dev)
71{
72 struct pci_controller *phb;
73 struct msi_desc *entry;
74 int hwirq;
75
76 phb = pci_bus_to_host(dev->bus);
77
78 dev_dbg(&dev->dev, "wsp_msi: tearing down msi irqs\n");
79
80 list_for_each_entry(entry, &dev->msi_list, list) {
81 if (entry->irq == NO_IRQ)
82 continue;
83
84 irq_set_msi_desc(entry->irq, NULL);
85 wsp_ics_set_std_chip(entry->irq);
86
87 hwirq = virq_to_hw(entry->irq);
88 /* In this order to avoid racing with irq_create_mapping() */
89 irq_dispose_mapping(entry->irq);
90 wsp_ics_free_irq(phb->dn, hwirq);
91 }
92}
93
94void wsp_setup_phb_msi(struct pci_controller *phb)
95{
96 /* Create a single MVE at offset 0 that matches everything */
97 out_be64(phb->cfg_data + PCIE_REG_IODA_ADDR, PCIE_REG_IODA_AD_TBL_MVT);
98 out_be64(phb->cfg_data + PCIE_REG_IODA_DATA0, 1ull << 63);
99
100 ppc_md.setup_msi_irqs = wsp_setup_msi_irqs;
101 ppc_md.teardown_msi_irqs = wsp_teardown_msi_irqs;
102}