Skip to content

Commit

Permalink
irqchip/mips-gic: Fix local interrupts
Browse files Browse the repository at this point in the history
Some local interrupts are not initialised properly at the moment and
cannot be used since the domain's alloc method is never called for them.

This has been observed earlier and partially fixed in commit
e875bd6 ("irqchip/mips-gic: Fix local interrupts"), but that change
still relied on the interrupt to be requested by an external driver (eg.
drivers/clocksource/mips-gic-timer.c).

This does however not solve the issue for interrupts that are not
referenced by any driver through the device tree and results in
request_irq() calls returning -ENOSYS. It can be observed when attempting
to use perf tool to access hardware performance counters.

Fix this by explicitly calling irq_create_fwspec_mapping() for local
interrupts.

Fixes: e875bd6 ("irqchip/mips-gic: Fix local interrupts")
Signed-off-by: Marcin Nowakowski <marcin.nowakowski@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: linux-mips@linux-mips.org
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
  • Loading branch information
MJNowakowski authored and Marc Zyngier committed Feb 8, 2017
1 parent b4d3053 commit 4cfffcf
Showing 1 changed file with 29 additions and 0 deletions.
29 changes: 29 additions & 0 deletions drivers/irqchip/irq-mips-gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,34 @@ static struct irq_domain_ops gic_ipi_domain_ops = {
.match = gic_ipi_domain_match,
};

static void __init gic_map_single_int(struct device_node *node,
unsigned int irq)
{
unsigned int linux_irq;
struct irq_fwspec local_int_fwspec = {
.fwnode = &node->fwnode,
.param_count = 3,
.param = {
[0] = GIC_LOCAL,
[1] = irq,
[2] = IRQ_TYPE_NONE,
},
};

if (!gic_local_irq_is_routable(irq))
return;

linux_irq = irq_create_fwspec_mapping(&local_int_fwspec);
WARN_ON(!linux_irq);
}

static void __init gic_map_interrupts(struct device_node *node)
{
gic_map_single_int(node, GIC_LOCAL_INT_TIMER);
gic_map_single_int(node, GIC_LOCAL_INT_PERFCTR);
gic_map_single_int(node, GIC_LOCAL_INT_FDC);
}

static void __init __gic_init(unsigned long gic_base_addr,
unsigned long gic_addrspace_size,
unsigned int cpu_vec, unsigned int irqbase,
Expand Down Expand Up @@ -1067,6 +1095,7 @@ static void __init __gic_init(unsigned long gic_base_addr,
}

gic_basic_init();
gic_map_interrupts(node);
}

void __init gic_init(unsigned long gic_base_addr,
Expand Down

0 comments on commit 4cfffcf

Please sign in to comment.