diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2012-12-05 15:43:23 -0500 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2013-02-28 12:57:06 -0500 |
commit | 3202bf0157ccbf8f1f89051d60ba9ca3aa4d424f (patch) | |
tree | 5e3befeee8793e85e6ad7af63f2ebdbc5c127e5c /arch/arm/mach-mvebu | |
parent | 48be9ac930086f7605fb4959936f568e865b2cff (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.c | 72 |
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 | ||
49 | static DEFINE_RAW_SPINLOCK(irq_controller_lock); | ||
50 | |||
46 | static void __iomem *per_cpu_int_base; | 51 | static void __iomem *per_cpu_int_base; |
47 | static void __iomem *main_int_base; | 52 | static void __iomem *main_int_base; |
48 | static struct irq_domain *armada_370_xp_mpic_domain; | 53 | static 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 | */ | ||
50 | static void armada_370_xp_irq_mask(struct irq_data *d) | 60 | static 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 | ||
56 | static void armada_370_xp_irq_unmask(struct irq_data *d) | 77 | static 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 |
63 | static int armada_xp_set_affinity(struct irq_data *d, | 95 | static 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; |