aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu/irq-armada-370-xp.c
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 /arch/arm/mach-mvebu/irq-armada-370-xp.c
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>
Diffstat (limited to 'arch/arm/mach-mvebu/irq-armada-370-xp.c')
-rw-r--r--arch/arm/mach-mvebu/irq-armada-370-xp.c92
1 files changed, 86 insertions, 6 deletions
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