diff options
author | Andrew Bresticker <abrestic@chromium.org> | 2014-09-18 17:47:24 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-11-24 01:44:56 -0500 |
commit | 18743d2781d01d34d132f952a2e16353ccb4c3de (patch) | |
tree | 42df699518d3b44c08ef49fa3d893dc38d8ddc5e /drivers/irqchip | |
parent | c49581a4dfaade3a483f3db85581a2cdb6bb85a0 (diff) |
irqchip: mips-gic: Stop using per-platform mapping tables
Now that the GIC properly uses IRQ domains, kill off the per-platform
routing tables that were used to make the GIC appear transparent.
This includes:
- removing the mapping tables and the support for applying them,
- moving GIC IPI support to the GIC driver,
- properly routing the i8259 through the GIC on Malta, and
- updating IRQ assignments on SEAD-3 when the GIC is present.
Platforms no longer will pass an interrupt mapping table to gic_init.
Instead, they will pass the CPU interrupt vector (2 - 7) that they
expect the GIC to route interrupts to. Note that in EIC mode this
value is ignored and all GIC interrupts are routed to EIC vector 1.
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Reviewed-by: Qais Yousef <qais.yousef@imgtec.com>
Tested-by: Qais Yousef <qais.yousef@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jeffrey Deans <jeffrey.deans@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Jonas Gorski <jogo@openwrt.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7816/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 201 |
1 files changed, 105 insertions, 96 deletions
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 79ab99781534..633a34639388 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c | |||
@@ -8,6 +8,8 @@ | |||
8 | */ | 8 | */ |
9 | #include <linux/bitmap.h> | 9 | #include <linux/bitmap.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/sched.h> | ||
11 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
12 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
13 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
@@ -22,11 +24,8 @@ | |||
22 | unsigned int gic_frequency; | 24 | unsigned int gic_frequency; |
23 | unsigned int gic_present; | 25 | unsigned int gic_present; |
24 | unsigned long _gic_base; | 26 | unsigned long _gic_base; |
25 | unsigned int gic_irq_base; | ||
26 | unsigned int gic_irq_flags[GIC_NUM_INTRS]; | 27 | unsigned int gic_irq_flags[GIC_NUM_INTRS]; |
27 | 28 | unsigned int gic_cpu_pin; | |
28 | /* The index into this array is the vector # of the interrupt. */ | ||
29 | struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS]; | ||
30 | 29 | ||
31 | struct gic_pcpu_mask { | 30 | struct gic_pcpu_mask { |
32 | DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); | 31 | DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); |
@@ -46,6 +45,8 @@ static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; | |||
46 | static DEFINE_SPINLOCK(gic_lock); | 45 | static DEFINE_SPINLOCK(gic_lock); |
47 | static struct irq_domain *gic_irq_domain; | 46 | static struct irq_domain *gic_irq_domain; |
48 | 47 | ||
48 | static void __gic_irq_dispatch(void); | ||
49 | |||
49 | #if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC) | 50 | #if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC) |
50 | cycle_t gic_read_count(void) | 51 | cycle_t gic_read_count(void) |
51 | { | 52 | { |
@@ -117,21 +118,6 @@ void gic_send_ipi(unsigned int intr) | |||
117 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); | 118 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); |
118 | } | 119 | } |
119 | 120 | ||
120 | static void gic_eic_irq_dispatch(void) | ||
121 | { | ||
122 | unsigned int cause = read_c0_cause(); | ||
123 | int irq; | ||
124 | |||
125 | irq = (cause & ST0_IM) >> STATUSB_IP2; | ||
126 | if (irq == 0) | ||
127 | irq = -1; | ||
128 | |||
129 | if (irq >= 0) | ||
130 | do_IRQ(gic_irq_base + irq); | ||
131 | else | ||
132 | spurious_interrupt(); | ||
133 | } | ||
134 | |||
135 | static void __init vpe_local_setup(unsigned int numvpes) | 121 | static void __init vpe_local_setup(unsigned int numvpes) |
136 | { | 122 | { |
137 | unsigned long timer_intr = GIC_INT_TMR; | 123 | unsigned long timer_intr = GIC_INT_TMR; |
@@ -166,16 +152,15 @@ static void __init vpe_local_setup(unsigned int numvpes) | |||
166 | GIC_MAP_TO_PIN_MSK | timer_intr); | 152 | GIC_MAP_TO_PIN_MSK | timer_intr); |
167 | if (cpu_has_veic) { | 153 | if (cpu_has_veic) { |
168 | set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET, | 154 | set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET, |
169 | gic_eic_irq_dispatch); | 155 | __gic_irq_dispatch); |
170 | gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK; | ||
171 | } | 156 | } |
172 | 157 | ||
173 | if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) | 158 | if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) |
174 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), | 159 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), |
175 | GIC_MAP_TO_PIN_MSK | perf_intr); | 160 | GIC_MAP_TO_PIN_MSK | perf_intr); |
176 | if (cpu_has_veic) { | 161 | if (cpu_has_veic) { |
177 | set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch); | 162 | set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, |
178 | gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK; | 163 | __gic_irq_dispatch); |
179 | } | 164 | } |
180 | } | 165 | } |
181 | } | 166 | } |
@@ -343,64 +328,100 @@ static struct irq_chip gic_irq_controller = { | |||
343 | #endif | 328 | #endif |
344 | }; | 329 | }; |
345 | 330 | ||
346 | static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, | 331 | static void __gic_irq_dispatch(void) |
347 | unsigned int pin, unsigned int polarity, unsigned int trigtype, | ||
348 | unsigned int flags) | ||
349 | { | 332 | { |
350 | struct gic_shared_intr_map *map_ptr; | 333 | unsigned int intr, virq; |
351 | int i; | ||
352 | |||
353 | /* Setup Intr to Pin mapping */ | ||
354 | if (pin & GIC_MAP_TO_NMI_MSK) { | ||
355 | int i; | ||
356 | 334 | ||
357 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); | 335 | while ((intr = gic_get_int()) != GIC_NUM_INTRS) { |
358 | /* FIXME: hack to route NMI to all cpu's */ | 336 | virq = irq_linear_revmap(gic_irq_domain, intr); |
359 | for (i = 0; i < NR_CPUS; i += 32) { | 337 | do_IRQ(virq); |
360 | GICWRITE(GIC_REG_ADDR(SHARED, | ||
361 | GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)), | ||
362 | 0xffffffff); | ||
363 | } | ||
364 | } else { | ||
365 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), | ||
366 | GIC_MAP_TO_PIN_MSK | pin); | ||
367 | /* Setup Intr to CPU mapping */ | ||
368 | GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); | ||
369 | if (cpu_has_veic) { | ||
370 | set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET, | ||
371 | gic_eic_irq_dispatch); | ||
372 | map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET]; | ||
373 | if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR) | ||
374 | BUG(); | ||
375 | map_ptr->intr_list[map_ptr->num_shared_intr++] = intr; | ||
376 | } | ||
377 | } | 338 | } |
339 | } | ||
378 | 340 | ||
379 | /* Setup Intr Polarity */ | 341 | static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc) |
380 | GIC_SET_POLARITY(intr, polarity); | 342 | { |
343 | __gic_irq_dispatch(); | ||
344 | } | ||
345 | |||
346 | #ifdef CONFIG_MIPS_GIC_IPI | ||
347 | static int gic_resched_int_base; | ||
348 | static int gic_call_int_base; | ||
349 | |||
350 | unsigned int plat_ipi_resched_int_xlate(unsigned int cpu) | ||
351 | { | ||
352 | return gic_resched_int_base + cpu; | ||
353 | } | ||
381 | 354 | ||
382 | /* Setup Intr Trigger Type */ | 355 | unsigned int plat_ipi_call_int_xlate(unsigned int cpu) |
383 | GIC_SET_TRIGGER(intr, trigtype); | 356 | { |
357 | return gic_call_int_base + cpu; | ||
358 | } | ||
384 | 359 | ||
385 | /* Init Intr Masks */ | 360 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) |
386 | GIC_CLR_INTR_MASK(intr); | 361 | { |
362 | scheduler_ipi(); | ||
363 | |||
364 | return IRQ_HANDLED; | ||
365 | } | ||
366 | |||
367 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
368 | { | ||
369 | smp_call_function_interrupt(); | ||
370 | |||
371 | return IRQ_HANDLED; | ||
372 | } | ||
387 | 373 | ||
388 | /* Initialise per-cpu Interrupt software masks */ | 374 | static struct irqaction irq_resched = { |
375 | .handler = ipi_resched_interrupt, | ||
376 | .flags = IRQF_PERCPU, | ||
377 | .name = "IPI resched" | ||
378 | }; | ||
379 | |||
380 | static struct irqaction irq_call = { | ||
381 | .handler = ipi_call_interrupt, | ||
382 | .flags = IRQF_PERCPU, | ||
383 | .name = "IPI call" | ||
384 | }; | ||
385 | |||
386 | static __init void gic_ipi_init_one(unsigned int intr, int cpu, | ||
387 | struct irqaction *action) | ||
388 | { | ||
389 | int virq = irq_create_mapping(gic_irq_domain, intr); | ||
390 | int i; | ||
391 | |||
392 | GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); | ||
389 | for (i = 0; i < NR_CPUS; i++) | 393 | for (i = 0; i < NR_CPUS; i++) |
390 | clear_bit(intr, pcpu_masks[i].pcpu_mask); | 394 | clear_bit(intr, pcpu_masks[i].pcpu_mask); |
391 | set_bit(intr, pcpu_masks[cpu].pcpu_mask); | 395 | set_bit(intr, pcpu_masks[cpu].pcpu_mask); |
392 | 396 | ||
393 | if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0)) | 397 | irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING); |
394 | GIC_SET_INTR_MASK(intr); | 398 | |
395 | if (trigtype == GIC_TRIG_EDGE) | 399 | irq_set_handler(virq, handle_percpu_irq); |
396 | gic_irq_flags[intr] |= GIC_TRIG_EDGE; | 400 | setup_irq(virq, action); |
397 | } | 401 | } |
398 | 402 | ||
399 | static void __init gic_basic_init(int numintrs, int numvpes, | 403 | static __init void gic_ipi_init(void) |
400 | struct gic_intr_map *intrmap, int mapsize) | ||
401 | { | 404 | { |
402 | unsigned int i, cpu; | 405 | int i; |
403 | unsigned int pin_offset = 0; | 406 | |
407 | /* Use last 2 * NR_CPUS interrupts as IPIs */ | ||
408 | gic_resched_int_base = GIC_NUM_INTRS - nr_cpu_ids; | ||
409 | gic_call_int_base = gic_resched_int_base - nr_cpu_ids; | ||
410 | |||
411 | for (i = 0; i < nr_cpu_ids; i++) { | ||
412 | gic_ipi_init_one(gic_call_int_base + i, i, &irq_call); | ||
413 | gic_ipi_init_one(gic_resched_int_base + i, i, &irq_resched); | ||
414 | } | ||
415 | } | ||
416 | #else | ||
417 | static inline void gic_ipi_init(void) | ||
418 | { | ||
419 | } | ||
420 | #endif | ||
421 | |||
422 | static void __init gic_basic_init(int numintrs, int numvpes) | ||
423 | { | ||
424 | unsigned int i; | ||
404 | 425 | ||
405 | board_bind_eic_interrupt = &gic_bind_eic_interrupt; | 426 | board_bind_eic_interrupt = &gic_bind_eic_interrupt; |
406 | 427 | ||
@@ -409,31 +430,8 @@ static void __init gic_basic_init(int numintrs, int numvpes, | |||
409 | GIC_SET_POLARITY(i, GIC_POL_POS); | 430 | GIC_SET_POLARITY(i, GIC_POL_POS); |
410 | GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); | 431 | GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); |
411 | GIC_CLR_INTR_MASK(i); | 432 | GIC_CLR_INTR_MASK(i); |
412 | if (i < GIC_NUM_INTRS) { | 433 | if (i < GIC_NUM_INTRS) |
413 | gic_irq_flags[i] = 0; | 434 | gic_irq_flags[i] = 0; |
414 | gic_shared_intr_map[i].num_shared_intr = 0; | ||
415 | gic_shared_intr_map[i].local_intr_mask = 0; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract | ||
421 | * one because the GIC will add one (since 0=no intr). | ||
422 | */ | ||
423 | if (cpu_has_veic) | ||
424 | pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); | ||
425 | |||
426 | /* Setup specifics */ | ||
427 | for (i = 0; i < mapsize; i++) { | ||
428 | cpu = intrmap[i].cpunum; | ||
429 | if (cpu == GIC_UNUSED) | ||
430 | continue; | ||
431 | gic_setup_intr(i, | ||
432 | intrmap[i].cpunum, | ||
433 | intrmap[i].pin + pin_offset, | ||
434 | intrmap[i].polarity, | ||
435 | intrmap[i].trigtype, | ||
436 | intrmap[i].flags); | ||
437 | } | 435 | } |
438 | 436 | ||
439 | vpe_local_setup(numvpes); | 437 | vpe_local_setup(numvpes); |
@@ -448,7 +446,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, | |||
448 | 446 | ||
449 | spin_lock_irqsave(&gic_lock, flags); | 447 | spin_lock_irqsave(&gic_lock, flags); |
450 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)), | 448 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)), |
451 | GIC_MAP_TO_PIN_MSK | 0); | 449 | GIC_MAP_TO_PIN_MSK | gic_cpu_pin); |
452 | /* Map to VPE 0 by default */ | 450 | /* Map to VPE 0 by default */ |
453 | GIC_SH_MAP_TO_VPE_SMASK(hw, 0); | 451 | GIC_SH_MAP_TO_VPE_SMASK(hw, 0); |
454 | set_bit(hw, pcpu_masks[0].pcpu_mask); | 452 | set_bit(hw, pcpu_masks[0].pcpu_mask); |
@@ -463,8 +461,7 @@ static struct irq_domain_ops gic_irq_domain_ops = { | |||
463 | }; | 461 | }; |
464 | 462 | ||
465 | void __init gic_init(unsigned long gic_base_addr, | 463 | void __init gic_init(unsigned long gic_base_addr, |
466 | unsigned long gic_addrspace_size, | 464 | unsigned long gic_addrspace_size, unsigned int cpu_vec, |
467 | struct gic_intr_map *intr_map, unsigned int intr_map_size, | ||
468 | unsigned int irqbase) | 465 | unsigned int irqbase) |
469 | { | 466 | { |
470 | unsigned int gicconfig; | 467 | unsigned int gicconfig; |
@@ -472,7 +469,6 @@ void __init gic_init(unsigned long gic_base_addr, | |||
472 | 469 | ||
473 | _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, | 470 | _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, |
474 | gic_addrspace_size); | 471 | gic_addrspace_size); |
475 | gic_irq_base = irqbase; | ||
476 | 472 | ||
477 | GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); | 473 | GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); |
478 | numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> | 474 | numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> |
@@ -483,10 +479,23 @@ void __init gic_init(unsigned long gic_base_addr, | |||
483 | GIC_SH_CONFIG_NUMVPES_SHF; | 479 | GIC_SH_CONFIG_NUMVPES_SHF; |
484 | numvpes = numvpes + 1; | 480 | numvpes = numvpes + 1; |
485 | 481 | ||
482 | if (cpu_has_veic) { | ||
483 | /* Always use vector 1 in EIC mode */ | ||
484 | gic_cpu_pin = 0; | ||
485 | set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, | ||
486 | __gic_irq_dispatch); | ||
487 | } else { | ||
488 | gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; | ||
489 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, | ||
490 | gic_irq_dispatch); | ||
491 | } | ||
492 | |||
486 | gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_INTRS, irqbase, | 493 | gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_INTRS, irqbase, |
487 | &gic_irq_domain_ops, NULL); | 494 | &gic_irq_domain_ops, NULL); |
488 | if (!gic_irq_domain) | 495 | if (!gic_irq_domain) |
489 | panic("Failed to add GIC IRQ domain"); | 496 | panic("Failed to add GIC IRQ domain"); |
490 | 497 | ||
491 | gic_basic_init(numintrs, numvpes, intr_map, intr_map_size); | 498 | gic_basic_init(numintrs, numvpes); |
499 | |||
500 | gic_ipi_init(); | ||
492 | } | 501 | } |