aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2012-12-05 15:43:23 -0500
committerArnd Bergmann <arnd@arndb.de>2013-02-28 12:57:06 -0500
commit3202bf0157ccbf8f1f89051d60ba9ca3aa4d424f (patch)
tree5e3befeee8793e85e6ad7af63f2ebdbc5c127e5c /arch/arm/mach-mvebu
parent48be9ac930086f7605fb4959936f568e865b2cff (diff)
arm: mvebu: Improve the SMP support of the interrupt controller
This patch makes the interrupt controller driver more SMP aware for the Armada XP SoCs. It adds the support for the per-CPU irq. It also adds the implementation for the set_affinity hook. Patch initialy wrote by Yehuda Yitschak and reworked by Gregory CLEMENT. Signed-off-by: Yehuda Yitschak <yehuday@marvell.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r--arch/arm/mach-mvebu/irq-armada-370-xp.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/arch/arm/mach-mvebu/irq-armada-370-xp.c
index 8e3fb082c3c6..f99a4a2a250d 100644
--- a/arch/arm/mach-mvebu/irq-armada-370-xp.c
+++ b/arch/arm/mach-mvebu/irq-armada-370-xp.c
@@ -34,6 +34,7 @@
34#define ARMADA_370_XP_INT_CONTROL (0x00) 34#define ARMADA_370_XP_INT_CONTROL (0x00)
35#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) 35#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30)
36#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34) 36#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34)
37#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
37 38
38#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) 39#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
39 40
@@ -41,28 +42,90 @@
41#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc) 42#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
42#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8) 43#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
43 44
45#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28)
46
44#define ACTIVE_DOORBELLS (8) 47#define ACTIVE_DOORBELLS (8)
45 48
49static DEFINE_RAW_SPINLOCK(irq_controller_lock);
50
46static void __iomem *per_cpu_int_base; 51static void __iomem *per_cpu_int_base;
47static void __iomem *main_int_base; 52static void __iomem *main_int_base;
48static struct irq_domain *armada_370_xp_mpic_domain; 53static struct irq_domain *armada_370_xp_mpic_domain;
49 54
55/*
56 * In SMP mode:
57 * For shared global interrupts, mask/unmask global enable bit
58 * For CPU interrtups, mask/unmask the calling CPU's bit
59 */
50static void armada_370_xp_irq_mask(struct irq_data *d) 60static void armada_370_xp_irq_mask(struct irq_data *d)
51{ 61{
62#ifdef CONFIG_SMP
63 irq_hw_number_t hwirq = irqd_to_hwirq(d);
64
65 if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
66 writel(hwirq, main_int_base +
67 ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
68 else
69 writel(hwirq, per_cpu_int_base +
70 ARMADA_370_XP_INT_SET_MASK_OFFS);
71#else
52 writel(irqd_to_hwirq(d), 72 writel(irqd_to_hwirq(d),
53 per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); 73 per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
74#endif
54} 75}
55 76
56static void armada_370_xp_irq_unmask(struct irq_data *d) 77static void armada_370_xp_irq_unmask(struct irq_data *d)
57{ 78{
79#ifdef CONFIG_SMP
80 irq_hw_number_t hwirq = irqd_to_hwirq(d);
81
82 if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
83 writel(hwirq, main_int_base +
84 ARMADA_370_XP_INT_SET_ENABLE_OFFS);
85 else
86 writel(hwirq, per_cpu_int_base +
87 ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
88#else
58 writel(irqd_to_hwirq(d), 89 writel(irqd_to_hwirq(d),
59 per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 90 per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
91#endif
60} 92}
61 93
62#ifdef CONFIG_SMP 94#ifdef CONFIG_SMP
63static int armada_xp_set_affinity(struct irq_data *d, 95static int armada_xp_set_affinity(struct irq_data *d,
64 const struct cpumask *mask_val, bool force) 96 const struct cpumask *mask_val, bool force)
65{ 97{
98 unsigned long reg;
99 unsigned long new_mask = 0;
100 unsigned long online_mask = 0;
101 unsigned long count = 0;
102 irq_hw_number_t hwirq = irqd_to_hwirq(d);
103 int cpu;
104
105 for_each_cpu(cpu, mask_val) {
106 new_mask |= 1 << cpu_logical_map(cpu);
107 count++;
108 }
109
110 /*
111 * Forbid mutlicore interrupt affinity
112 * This is required since the MPIC HW doesn't limit
113 * several CPUs from acknowledging the same interrupt.
114 */
115 if (count > 1)
116 return -EINVAL;
117
118 for_each_cpu(cpu, cpu_online_mask)
119 online_mask |= 1 << cpu_logical_map(cpu);
120
121 raw_spin_lock(&irq_controller_lock);
122
123 reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
124 reg = (reg & (~online_mask)) | new_mask;
125 writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
126
127 raw_spin_unlock(&irq_controller_lock);
128
66 return 0; 129 return 0;
67} 130}
68#endif 131#endif
@@ -155,6 +218,15 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
155 218
156#ifdef CONFIG_SMP 219#ifdef CONFIG_SMP
157 armada_xp_mpic_smp_cpu_init(); 220 armada_xp_mpic_smp_cpu_init();
221
222 /*
223 * Set the default affinity from all CPUs to the boot cpu.
224 * This is required since the MPIC doesn't limit several CPUs
225 * from acknowledging the same interrupt.
226 */
227 cpumask_clear(irq_default_affinity);
228 cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
229
158#endif 230#endif
159 231
160 return 0; 232 return 0;