diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2012-08-02 04:19:12 -0400 |
---|---|---|
committer | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2012-11-21 10:49:37 -0500 |
commit | 344e873e5657e8dc0631e4d1d42b69f7d625b02c (patch) | |
tree | 3df34d2662770a3b65d91911240acb87453bef2c /arch/arm/mach-mvebu/irq-armada-370-xp.c | |
parent | 7444dad2409afd94c08875e961ca61c5999cd606 (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.c | 92 |
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 | |||
38 | static void __iomem *per_cpu_int_base; | 45 | static void __iomem *per_cpu_int_base; |
39 | static void __iomem *main_int_base; | 46 | static void __iomem *main_int_base; |
40 | static struct irq_domain *armada_370_xp_mpic_domain; | 47 | static 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 | ||
62 | static 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 | |||
54 | static struct irq_chip armada_370_xp_irq_chip = { | 69 | static 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 | ||
61 | static int armada_370_xp_mpic_irq_map(struct irq_domain *h, | 79 | static 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 | ||
94 | void 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 | |||
114 | void 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 | |||
75 | static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { | 128 | static 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 | ||