diff options
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/gic.c | 72 |
1 files changed, 59 insertions, 13 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 224377211151..cb6b041c39d2 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -44,6 +44,19 @@ struct gic_chip_data { | |||
44 | void __iomem *cpu_base; | 44 | void __iomem *cpu_base; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | /* | ||
48 | * Supported arch specific GIC irq extension. | ||
49 | * Default make them NULL. | ||
50 | */ | ||
51 | struct irq_chip gic_arch_extn = { | ||
52 | .irq_ack = NULL, | ||
53 | .irq_mask = NULL, | ||
54 | .irq_unmask = NULL, | ||
55 | .irq_retrigger = NULL, | ||
56 | .irq_set_type = NULL, | ||
57 | .irq_set_wake = NULL, | ||
58 | }; | ||
59 | |||
47 | #ifndef MAX_GIC_NR | 60 | #ifndef MAX_GIC_NR |
48 | #define MAX_GIC_NR 1 | 61 | #define MAX_GIC_NR 1 |
49 | #endif | 62 | #endif |
@@ -74,6 +87,8 @@ static inline unsigned int gic_irq(struct irq_data *d) | |||
74 | static void gic_ack_irq(struct irq_data *d) | 87 | static void gic_ack_irq(struct irq_data *d) |
75 | { | 88 | { |
76 | spin_lock(&irq_controller_lock); | 89 | spin_lock(&irq_controller_lock); |
90 | if (gic_arch_extn.irq_ack) | ||
91 | gic_arch_extn.irq_ack(d); | ||
77 | writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); | 92 | writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); |
78 | spin_unlock(&irq_controller_lock); | 93 | spin_unlock(&irq_controller_lock); |
79 | } | 94 | } |
@@ -84,6 +99,8 @@ static void gic_mask_irq(struct irq_data *d) | |||
84 | 99 | ||
85 | spin_lock(&irq_controller_lock); | 100 | spin_lock(&irq_controller_lock); |
86 | writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); | 101 | writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); |
102 | if (gic_arch_extn.irq_mask) | ||
103 | gic_arch_extn.irq_mask(d); | ||
87 | spin_unlock(&irq_controller_lock); | 104 | spin_unlock(&irq_controller_lock); |
88 | } | 105 | } |
89 | 106 | ||
@@ -92,6 +109,8 @@ static void gic_unmask_irq(struct irq_data *d) | |||
92 | u32 mask = 1 << (d->irq % 32); | 109 | u32 mask = 1 << (d->irq % 32); |
93 | 110 | ||
94 | spin_lock(&irq_controller_lock); | 111 | spin_lock(&irq_controller_lock); |
112 | if (gic_arch_extn.irq_unmask) | ||
113 | gic_arch_extn.irq_unmask(d); | ||
95 | writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); | 114 | writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); |
96 | spin_unlock(&irq_controller_lock); | 115 | spin_unlock(&irq_controller_lock); |
97 | } | 116 | } |
@@ -116,6 +135,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type) | |||
116 | 135 | ||
117 | spin_lock(&irq_controller_lock); | 136 | spin_lock(&irq_controller_lock); |
118 | 137 | ||
138 | if (gic_arch_extn.irq_set_type) | ||
139 | gic_arch_extn.irq_set_type(d, type); | ||
140 | |||
119 | val = readl(base + GIC_DIST_CONFIG + confoff); | 141 | val = readl(base + GIC_DIST_CONFIG + confoff); |
120 | if (type == IRQ_TYPE_LEVEL_HIGH) | 142 | if (type == IRQ_TYPE_LEVEL_HIGH) |
121 | val &= ~confmask; | 143 | val &= ~confmask; |
@@ -141,32 +163,54 @@ static int gic_set_type(struct irq_data *d, unsigned int type) | |||
141 | return 0; | 163 | return 0; |
142 | } | 164 | } |
143 | 165 | ||
166 | static int gic_retrigger(struct irq_data *d) | ||
167 | { | ||
168 | if (gic_arch_extn.irq_retrigger) | ||
169 | return gic_arch_extn.irq_retrigger(d); | ||
170 | |||
171 | return -ENXIO; | ||
172 | } | ||
173 | |||
144 | #ifdef CONFIG_SMP | 174 | #ifdef CONFIG_SMP |
145 | static int | 175 | static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, |
146 | gic_set_cpu(struct irq_data *d, const struct cpumask *mask_val, bool force) | 176 | bool force) |
147 | { | 177 | { |
148 | void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); | 178 | void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); |
149 | unsigned int shift = (d->irq % 4) * 8; | 179 | unsigned int shift = (d->irq % 4) * 8; |
150 | unsigned int cpu = cpumask_first(mask_val); | 180 | unsigned int cpu = cpumask_first(mask_val); |
151 | u32 val; | 181 | u32 val, mask, bit; |
152 | struct irq_desc *desc; | ||
153 | 182 | ||
154 | spin_lock(&irq_controller_lock); | 183 | if (cpu >= 8) |
155 | desc = irq_to_desc(d->irq); | ||
156 | if (desc == NULL) { | ||
157 | spin_unlock(&irq_controller_lock); | ||
158 | return -EINVAL; | 184 | return -EINVAL; |
159 | } | 185 | |
186 | mask = 0xff << shift; | ||
187 | bit = 1 << (cpu + shift); | ||
188 | |||
189 | spin_lock(&irq_controller_lock); | ||
160 | d->node = cpu; | 190 | d->node = cpu; |
161 | val = readl(reg) & ~(0xff << shift); | 191 | val = readl(reg) & ~mask; |
162 | val |= 1 << (cpu + shift); | 192 | writel(val | bit, reg); |
163 | writel(val, reg); | ||
164 | spin_unlock(&irq_controller_lock); | 193 | spin_unlock(&irq_controller_lock); |
165 | 194 | ||
166 | return 0; | 195 | return 0; |
167 | } | 196 | } |
168 | #endif | 197 | #endif |
169 | 198 | ||
199 | #ifdef CONFIG_PM | ||
200 | static int gic_set_wake(struct irq_data *d, unsigned int on) | ||
201 | { | ||
202 | int ret = -ENXIO; | ||
203 | |||
204 | if (gic_arch_extn.irq_set_wake) | ||
205 | ret = gic_arch_extn.irq_set_wake(d, on); | ||
206 | |||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | #else | ||
211 | #define gic_set_wake NULL | ||
212 | #endif | ||
213 | |||
170 | static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) | 214 | static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) |
171 | { | 215 | { |
172 | struct gic_chip_data *chip_data = get_irq_data(irq); | 216 | struct gic_chip_data *chip_data = get_irq_data(irq); |
@@ -202,9 +246,11 @@ static struct irq_chip gic_chip = { | |||
202 | .irq_mask = gic_mask_irq, | 246 | .irq_mask = gic_mask_irq, |
203 | .irq_unmask = gic_unmask_irq, | 247 | .irq_unmask = gic_unmask_irq, |
204 | .irq_set_type = gic_set_type, | 248 | .irq_set_type = gic_set_type, |
249 | .irq_retrigger = gic_retrigger, | ||
205 | #ifdef CONFIG_SMP | 250 | #ifdef CONFIG_SMP |
206 | .irq_set_affinity = gic_set_cpu, | 251 | .irq_set_affinity = gic_set_affinity, |
207 | #endif | 252 | #endif |
253 | .irq_set_wake = gic_set_wake, | ||
208 | }; | 254 | }; |
209 | 255 | ||
210 | void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) | 256 | void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) |