aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2012-08-02 04:19:12 -0400
committerGregory CLEMENT <gregory.clement@free-electrons.com>2012-11-21 10:49:37 -0500
commit344e873e5657e8dc0631e4d1d42b69f7d625b02c (patch)
tree3df34d2662770a3b65d91911240acb87453bef2c
parent7444dad2409afd94c08875e961ca61c5999cd606 (diff)
arm: mvebu: Add IPI support via doorbells
This patch enhances the IRQ controller driver to add support for Inter-Processor-Interrupts that are needed to enable SMP support. Signed-off-by: Yehuda Yitschak <yehuday@marvell.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
-rw-r--r--Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt12
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi2
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h7
-rw-r--r--arch/arm/mach-mvebu/irq-armada-370-xp.c92
4 files changed, 103 insertions, 10 deletions
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
index 70c0dc5f00ed..61df564c0d23 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
+++ b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
@@ -6,9 +6,15 @@ Required properties:
6- interrupt-controller: Identifies the node as an interrupt controller. 6- interrupt-controller: Identifies the node as an interrupt controller.
7- #interrupt-cells: The number of cells to define the interrupts. Should be 1. 7- #interrupt-cells: The number of cells to define the interrupts. Should be 1.
8 The cell is the IRQ number 8 The cell is the IRQ number
9
9- reg: Should contain PMIC registers location and length. First pair 10- reg: Should contain PMIC registers location and length. First pair
10 for the main interrupt registers, second pair for the per-CPU 11 for the main interrupt registers, second pair for the per-CPU
11 interrupt registers 12 interrupt registers. For this last pair, to be compliant with SMP
13 support, the "virtual" must be use (For the record, these registers
14 automatically map to the interrupt controller registers of the
15 current CPU)
16
17
12 18
13Example: 19Example:
14 20
@@ -18,6 +24,6 @@ Example:
18 #address-cells = <1>; 24 #address-cells = <1>;
19 #size-cells = <1>; 25 #size-cells = <1>;
20 interrupt-controller; 26 interrupt-controller;
21 reg = <0xd0020000 0x1000>, 27 reg = <0xd0020a00 0x1d0>,
22 <0xd0021000 0x1000>; 28 <0xd0021070 0x58>;
23 }; 29 };
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 1f95e227053b..e6db2b7e2925 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -24,7 +24,7 @@
24 24
25 mpic: interrupt-controller@d0020000 { 25 mpic: interrupt-controller@d0020000 {
26 reg = <0xd0020a00 0x1d0>, 26 reg = <0xd0020a00 0x1d0>,
27 <0xd0021870 0x58>; 27 <0xd0021070 0x58>;
28 }; 28 };
29 29
30 armada-370-xp-pmsu@d0022000 { 30 armada-370-xp-pmsu@d0022000 {
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
index aac9bebc6b03..c6a7d74fddfe 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -19,4 +19,11 @@
19#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfeb00000) 19#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfeb00000)
20#define ARMADA_370_XP_REGS_SIZE SZ_1M 20#define ARMADA_370_XP_REGS_SIZE SZ_1M
21 21
22#ifdef CONFIG_SMP
23#include <linux/cpumask.h>
24
25void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
26void armada_xp_mpic_smp_cpu_init(void);
27#endif
28
22#endif /* __MACH_ARMADA_370_XP_H */ 29#endif /* __MACH_ARMADA_370_XP_H */
diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/arch/arm/mach-mvebu/irq-armada-370-xp.c
index 5f5f9394b6b2..549b6846f940 100644
--- a/arch/arm/mach-mvebu/irq-armada-370-xp.c
+++ b/arch/arm/mach-mvebu/irq-armada-370-xp.c
@@ -24,6 +24,7 @@
24#include <linux/irqdomain.h> 24#include <linux/irqdomain.h>
25#include <asm/mach/arch.h> 25#include <asm/mach/arch.h>
26#include <asm/exception.h> 26#include <asm/exception.h>
27#include <asm/smp_plat.h>
27 28
28/* Interrupt Controller Registers Map */ 29/* Interrupt Controller Registers Map */
29#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) 30#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48)
@@ -35,6 +36,12 @@
35 36
36#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) 37#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
37 38
39#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
40#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
41#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
42
43#define ACTIVE_DOORBELLS (8)
44
38static void __iomem *per_cpu_int_base; 45static void __iomem *per_cpu_int_base;
39static void __iomem *main_int_base; 46static void __iomem *main_int_base;
40static struct irq_domain *armada_370_xp_mpic_domain; 47static struct irq_domain *armada_370_xp_mpic_domain;
@@ -51,11 +58,22 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
51 per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 58 per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
52} 59}
53 60
61#ifdef CONFIG_SMP
62static int armada_xp_set_affinity(struct irq_data *d,
63 const struct cpumask *mask_val, bool force)
64{
65 return 0;
66}
67#endif
68
54static struct irq_chip armada_370_xp_irq_chip = { 69static struct irq_chip armada_370_xp_irq_chip = {
55 .name = "armada_370_xp_irq", 70 .name = "armada_370_xp_irq",
56 .irq_mask = armada_370_xp_irq_mask, 71 .irq_mask = armada_370_xp_irq_mask,
57 .irq_mask_ack = armada_370_xp_irq_mask, 72 .irq_mask_ack = armada_370_xp_irq_mask,
58 .irq_unmask = armada_370_xp_irq_unmask, 73 .irq_unmask = armada_370_xp_irq_unmask,
74#ifdef CONFIG_SMP
75 .irq_set_affinity = armada_xp_set_affinity,
76#endif
59}; 77};
60 78
61static int armada_370_xp_mpic_irq_map(struct irq_domain *h, 79static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
@@ -72,6 +90,41 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
72 return 0; 90 return 0;
73} 91}
74 92
93#ifdef CONFIG_SMP
94void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq)
95{
96 int cpu;
97 unsigned long map = 0;
98
99 /* Convert our logical CPU mask into a physical one. */
100 for_each_cpu(cpu, mask)
101 map |= 1 << cpu_logical_map(cpu);
102
103 /*
104 * Ensure that stores to Normal memory are visible to the
105 * other CPUs before issuing the IPI.
106 */
107 dsb();
108
109 /* submit softirq */
110 writel((map << 8) | irq, main_int_base +
111 ARMADA_370_XP_SW_TRIG_INT_OFFS);
112}
113
114void armada_xp_mpic_smp_cpu_init(void)
115{
116 /* Clear pending IPIs */
117 writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
118
119 /* Enable first 8 IPIs */
120 writel((1 << ACTIVE_DOORBELLS) - 1, per_cpu_int_base +
121 ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
122
123 /* Unmask IPI interrupt */
124 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
125}
126#endif /* CONFIG_SMP */
127
75static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { 128static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
76 .map = armada_370_xp_mpic_irq_map, 129 .map = armada_370_xp_mpic_irq_map,
77 .xlate = irq_domain_xlate_onecell, 130 .xlate = irq_domain_xlate_onecell,
@@ -91,13 +144,18 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
91 control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); 144 control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
92 145
93 armada_370_xp_mpic_domain = 146 armada_370_xp_mpic_domain =
94 irq_domain_add_linear(node, (control >> 2) & 0x3ff, 147 irq_domain_add_linear(node, (control >> 2) & 0x3ff,
95 &armada_370_xp_mpic_irq_ops, NULL); 148 &armada_370_xp_mpic_irq_ops, NULL);
96 149
97 if (!armada_370_xp_mpic_domain) 150 if (!armada_370_xp_mpic_domain)
98 panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n"); 151 panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n");
99 152
100 irq_set_default_host(armada_370_xp_mpic_domain); 153 irq_set_default_host(armada_370_xp_mpic_domain);
154
155#ifdef CONFIG_SMP
156 armada_xp_mpic_smp_cpu_init();
157#endif
158
101 return 0; 159 return 0;
102} 160}
103 161
@@ -111,14 +169,36 @@ asmlinkage void __exception_irq_entry armada_370_xp_handle_irq(struct pt_regs
111 ARMADA_370_XP_CPU_INTACK_OFFS); 169 ARMADA_370_XP_CPU_INTACK_OFFS);
112 irqnr = irqstat & 0x3FF; 170 irqnr = irqstat & 0x3FF;
113 171
114 if (irqnr < 1023) { 172 if (irqnr > 1022)
115 irqnr = 173 break;
116 irq_find_mapping(armada_370_xp_mpic_domain, irqnr); 174
175 if (irqnr >= 8) {
176 irqnr = irq_find_mapping(armada_370_xp_mpic_domain,
177 irqnr);
117 handle_IRQ(irqnr, regs); 178 handle_IRQ(irqnr, regs);
118 continue; 179 continue;
119 } 180 }
181#ifdef CONFIG_SMP
182 /* IPI Handling */
183 if (irqnr == 0) {
184 u32 ipimask, ipinr;
185
186 ipimask = readl_relaxed(per_cpu_int_base +
187 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
188 & 0xFF;
189
190 writel(0x0, per_cpu_int_base +
191 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
192
193 /* Handle all pending doorbells */
194 for (ipinr = 0; ipinr < ACTIVE_DOORBELLS; ipinr++) {
195 if (ipimask & (0x1 << ipinr))
196 handle_IPI(ipinr, regs);
197 }
198 continue;
199 }
200#endif
120 201
121 break;
122 } while (1); 202 } while (1);
123} 203}
124 204