diff options
Diffstat (limited to 'drivers/irqchip/irq-mips-gic.c')
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 69 |
1 files changed, 52 insertions, 17 deletions
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index f2d269bca789..4400edd1a6c7 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -239,7 +239,7 @@ int gic_get_c0_compare_int(void) int gic_get_c0_perfcount_int(void) { if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) { - /* Is the erformance counter shared with the timer? */ + /* Is the performance counter shared with the timer? */ if (cp0_perfcount_irq < 0) return -1; return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; @@ -248,7 +248,30 @@ int gic_get_c0_perfcount_int(void) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR)); } -static void gic_handle_shared_int(void) +int gic_get_c0_fdc_int(void) +{ + if (!gic_local_irq_is_routable(GIC_LOCAL_INT_FDC)) { + /* Is the FDC IRQ even present? */ + if (cp0_fdc_irq < 0) + return -1; + return MIPS_CPU_IRQ_BASE + cp0_fdc_irq; + } + + /* + * Some cores claim the FDC is routable but it doesn't actually seem to + * be connected. + */ + switch (current_cpu_type()) { + case CPU_INTERAPTIV: + case CPU_PROAPTIV: + return -1; + } + + return irq_create_mapping(gic_irq_domain, + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC)); +} + +static void gic_handle_shared_int(bool chained) { unsigned int i, intr, virq; unsigned long *pcpu_mask; @@ -276,7 +299,10 @@ static void gic_handle_shared_int(void) while (intr != gic_shared_intrs) { virq = irq_linear_revmap(gic_irq_domain, GIC_SHARED_TO_HWIRQ(intr)); - do_IRQ(virq); + if (chained) + generic_handle_irq(virq); + else + do_IRQ(virq); /* go to next pending bit */ bitmap_clear(pending, intr, 1); @@ -366,19 +392,19 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, int i; cpumask_and(&tmp, cpumask, cpu_online_mask); - if (cpus_empty(tmp)) + if (cpumask_empty(&tmp)) return -EINVAL; /* Assumption : cpumask refers to a single CPU */ spin_lock_irqsave(&gic_lock, flags); /* Re-route this IRQ */ - gic_map_to_vpe(irq, first_cpu(tmp)); + gic_map_to_vpe(irq, cpumask_first(&tmp)); /* Update the pcpu_masks */ for (i = 0; i < NR_CPUS; i++) clear_bit(irq, pcpu_masks[i].pcpu_mask); - set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); + set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask); cpumask_copy(d->affinity, cpumask); spin_unlock_irqrestore(&gic_lock, flags); @@ -408,7 +434,7 @@ static struct irq_chip gic_edge_irq_controller = { #endif }; -static void gic_handle_local_int(void) +static void gic_handle_local_int(bool chained) { unsigned long pending, masked; unsigned int intr, virq; @@ -422,7 +448,10 @@ static void gic_handle_local_int(void) while (intr != GIC_NUM_LOCAL_INTRS) { virq = irq_linear_revmap(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(intr)); - do_IRQ(virq); + if (chained) + generic_handle_irq(virq); + else + do_IRQ(virq); /* go to next pending bit */ bitmap_clear(&pending, intr, 1); @@ -486,13 +515,14 @@ static struct irq_chip gic_all_vpes_local_irq_controller = { static void __gic_irq_dispatch(void) { - gic_handle_local_int(); - gic_handle_shared_int(); + gic_handle_local_int(false); + gic_handle_shared_int(false); } static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc) { - __gic_irq_dispatch(); + gic_handle_local_int(true); + gic_handle_shared_int(true); } #ifdef CONFIG_MIPS_GIC_IPI @@ -613,15 +643,20 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, * of the MIPS kernel code does not use the percpu IRQ API for * the CP0 timer and performance counter interrupts. */ - if (intr != GIC_LOCAL_INT_TIMER && intr != GIC_LOCAL_INT_PERFCTR) { + switch (intr) { + case GIC_LOCAL_INT_TIMER: + case GIC_LOCAL_INT_PERFCTR: + case GIC_LOCAL_INT_FDC: + irq_set_chip_and_handler(virq, + &gic_all_vpes_local_irq_controller, + handle_percpu_irq); + break; + default: irq_set_chip_and_handler(virq, &gic_local_irq_controller, handle_percpu_devid_irq); irq_set_percpu_devid(virq); - } else { - irq_set_chip_and_handler(virq, - &gic_all_vpes_local_irq_controller, - handle_percpu_irq); + break; } spin_lock_irqsave(&gic_lock, flags); @@ -711,7 +746,7 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, return 0; } -static struct irq_domain_ops gic_irq_domain_ops = { +static const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, .xlate = gic_irq_domain_xlate, }; |