Skip to content

Commit

Permalink
ARM: gic: use handle_fasteoi_irq for SPIs
Browse files Browse the repository at this point in the history
Currently, the gic uses handle_level_irq for handling SPIs (Shared
Peripheral Interrupts), requiring active interrupts to be masked at
the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in
hardware. Accesses to the distributor must be trapped by the
hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling
interrupts, which only requires us to signal EOI to the CPU interface
when handling is complete. Cascaded IRQ handling is also updated to use
the chained IRQ enter/exit functions to honour the flow control of the
parent chip.

Note that commit 846afbd ("GIC: Dont disable INT in ack callback")
broke cascading interrupts by forgetting to add IRQ masking. This is
no longer an issue because the unmask call is now unnecessary.

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Tested-and-reviewed-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Tested-and-acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
  • Loading branch information
Will Deacon committed May 11, 2011
1 parent 4bd66cf commit 1a01753
Showing 1 changed file with 16 additions and 16 deletions.
32 changes: 16 additions & 16 deletions arch/arm/common/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct gic_chip_data {
* Default make them NULL.
*/
struct irq_chip gic_arch_extn = {
.irq_ack = NULL,
.irq_eoi = NULL,
.irq_mask = NULL,
.irq_unmask = NULL,
.irq_retrigger = NULL,
Expand Down Expand Up @@ -84,15 +84,6 @@ static inline unsigned int gic_irq(struct irq_data *d)
/*
* Routines to acknowledge, disable and enable interrupts
*/
static void gic_ack_irq(struct irq_data *d)
{
spin_lock(&irq_controller_lock);
if (gic_arch_extn.irq_ack)
gic_arch_extn.irq_ack(d);
writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
spin_unlock(&irq_controller_lock);
}

static void gic_mask_irq(struct irq_data *d)
{
u32 mask = 1 << (d->irq % 32);
Expand All @@ -115,6 +106,17 @@ static void gic_unmask_irq(struct irq_data *d)
spin_unlock(&irq_controller_lock);
}

static void gic_eoi_irq(struct irq_data *d)
{
if (gic_arch_extn.irq_eoi) {
spin_lock(&irq_controller_lock);
gic_arch_extn.irq_eoi(d);
spin_unlock(&irq_controller_lock);
}

writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
}

static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
Expand Down Expand Up @@ -218,8 +220,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
unsigned int cascade_irq, gic_irq;
unsigned long status;

/* primary controller ack'ing */
chip->irq_ack(&desc->irq_data);
chained_irq_enter(chip, desc);

spin_lock(&irq_controller_lock);
status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
Expand All @@ -236,15 +237,14 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(cascade_irq);

out:
/* primary controller unmasking */
chip->irq_unmask(&desc->irq_data);
chained_irq_exit(chip, desc);
}

static struct irq_chip gic_chip = {
.name = "GIC",
.irq_ack = gic_ack_irq,
.irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq,
.irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
.irq_retrigger = gic_retrigger,
#ifdef CONFIG_SMP
Expand Down Expand Up @@ -319,7 +319,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
* Setup the Linux IRQ subsystem.
*/
for (i = irq_start; i < irq_limit; i++) {
irq_set_chip_and_handler(i, &gic_chip, handle_level_irq);
irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
irq_set_chip_data(i, gic);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
Expand Down

0 comments on commit 1a01753

Please sign in to comment.