diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2015-03-18 07:01:24 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-04-08 17:28:28 -0400 |
commit | b594c6e20c7ff65e0f0775cb1866e97501c96846 (patch) | |
tree | d8f16e08f6611fd36c156156ec1160301f28c73d | |
parent | 567178077c369ae6a32f90926fb4172f7cf1f87f (diff) |
irqchip: GICv3: Add support for irq_[get, set]_irqchip_state()
Add the required hooks for the internal state of an interrupt
to be exposed to other subsystems.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Phong Vo <pvo@apm.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Tin Huynh <tnhuynh@apm.com>
Cc: Y Vo <yvo@apm.com>
Cc: Toan Le <toanle@apm.com>
Cc: Bjorn Andersson <bjorn@kryo.se>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Arnd Bergmann <arnd@arndb.de>
Link: http://lkml.kernel.org/r/1426676484-21812-4-git-send-email-marc.zyngier@arm.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd8850def1b8..4f2fb62e6f37 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c | |||
@@ -195,6 +195,19 @@ static void gic_enable_redist(bool enable) | |||
195 | /* | 195 | /* |
196 | * Routines to disable, enable, EOI and route interrupts | 196 | * Routines to disable, enable, EOI and route interrupts |
197 | */ | 197 | */ |
198 | static int gic_peek_irq(struct irq_data *d, u32 offset) | ||
199 | { | ||
200 | u32 mask = 1 << (gic_irq(d) % 32); | ||
201 | void __iomem *base; | ||
202 | |||
203 | if (gic_irq_in_rdist(d)) | ||
204 | base = gic_data_rdist_sgi_base(); | ||
205 | else | ||
206 | base = gic_data.dist_base; | ||
207 | |||
208 | return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); | ||
209 | } | ||
210 | |||
198 | static void gic_poke_irq(struct irq_data *d, u32 offset) | 211 | static void gic_poke_irq(struct irq_data *d, u32 offset) |
199 | { | 212 | { |
200 | u32 mask = 1 << (gic_irq(d) % 32); | 213 | u32 mask = 1 << (gic_irq(d) % 32); |
@@ -223,6 +236,61 @@ static void gic_unmask_irq(struct irq_data *d) | |||
223 | gic_poke_irq(d, GICD_ISENABLER); | 236 | gic_poke_irq(d, GICD_ISENABLER); |
224 | } | 237 | } |
225 | 238 | ||
239 | static int gic_irq_set_irqchip_state(struct irq_data *d, | ||
240 | enum irqchip_irq_state which, bool val) | ||
241 | { | ||
242 | u32 reg; | ||
243 | |||
244 | if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ | ||
245 | return -EINVAL; | ||
246 | |||
247 | switch (which) { | ||
248 | case IRQCHIP_STATE_PENDING: | ||
249 | reg = val ? GICD_ISPENDR : GICD_ICPENDR; | ||
250 | break; | ||
251 | |||
252 | case IRQCHIP_STATE_ACTIVE: | ||
253 | reg = val ? GICD_ISACTIVER : GICD_ICACTIVER; | ||
254 | break; | ||
255 | |||
256 | case IRQCHIP_STATE_MASKED: | ||
257 | reg = val ? GICD_ICENABLER : GICD_ISENABLER; | ||
258 | break; | ||
259 | |||
260 | default: | ||
261 | return -EINVAL; | ||
262 | } | ||
263 | |||
264 | gic_poke_irq(d, reg); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int gic_irq_get_irqchip_state(struct irq_data *d, | ||
269 | enum irqchip_irq_state which, bool *val) | ||
270 | { | ||
271 | if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ | ||
272 | return -EINVAL; | ||
273 | |||
274 | switch (which) { | ||
275 | case IRQCHIP_STATE_PENDING: | ||
276 | *val = gic_peek_irq(d, GICD_ISPENDR); | ||
277 | break; | ||
278 | |||
279 | case IRQCHIP_STATE_ACTIVE: | ||
280 | *val = gic_peek_irq(d, GICD_ISACTIVER); | ||
281 | break; | ||
282 | |||
283 | case IRQCHIP_STATE_MASKED: | ||
284 | *val = !gic_peek_irq(d, GICD_ISENABLER); | ||
285 | break; | ||
286 | |||
287 | default: | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
226 | static void gic_eoi_irq(struct irq_data *d) | 294 | static void gic_eoi_irq(struct irq_data *d) |
227 | { | 295 | { |
228 | gic_write_eoir(gic_irq(d)); | 296 | gic_write_eoir(gic_irq(d)); |
@@ -418,19 +486,6 @@ static void gic_cpu_init(void) | |||
418 | } | 486 | } |
419 | 487 | ||
420 | #ifdef CONFIG_SMP | 488 | #ifdef CONFIG_SMP |
421 | static int gic_peek_irq(struct irq_data *d, u32 offset) | ||
422 | { | ||
423 | u32 mask = 1 << (gic_irq(d) % 32); | ||
424 | void __iomem *base; | ||
425 | |||
426 | if (gic_irq_in_rdist(d)) | ||
427 | base = gic_data_rdist_sgi_base(); | ||
428 | else | ||
429 | base = gic_data.dist_base; | ||
430 | |||
431 | return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); | ||
432 | } | ||
433 | |||
434 | static int gic_secondary_init(struct notifier_block *nfb, | 489 | static int gic_secondary_init(struct notifier_block *nfb, |
435 | unsigned long action, void *hcpu) | 490 | unsigned long action, void *hcpu) |
436 | { | 491 | { |
@@ -601,6 +656,8 @@ static struct irq_chip gic_chip = { | |||
601 | .irq_eoi = gic_eoi_irq, | 656 | .irq_eoi = gic_eoi_irq, |
602 | .irq_set_type = gic_set_type, | 657 | .irq_set_type = gic_set_type, |
603 | .irq_set_affinity = gic_set_affinity, | 658 | .irq_set_affinity = gic_set_affinity, |
659 | .irq_get_irqchip_state = gic_irq_get_irqchip_state, | ||
660 | .irq_set_irqchip_state = gic_irq_set_irqchip_state, | ||
604 | }; | 661 | }; |
605 | 662 | ||
606 | #define GIC_ID_NR (1U << gic_data.rdists.id_bits) | 663 | #define GIC_ID_NR (1U << gic_data.rdists.id_bits) |