Skip to content

Commit

Permalink
ARM: 6777/1: gic: Add hooks for architecture specific extensions
Browse files Browse the repository at this point in the history
Few architectures combine the GIC with an external interrupt
controller. On such systems it may be necessary to update both
the GIC registers and the external controller's registers to control
IRQ behavior.

This can be addressed in couple of possible methods.
 1. Export common GIC routines along with 'struct irq_chip gic_chip'
    and allow architectures to have custom function by override.
 2. Provide architecture specific function pointer hooks
    within GIC library and leave platforms to add the necessary
    code as part of these hooks.

First one might be non-intrusive but have few shortcomings like arch
needs to have there own custom gic library. Locks used should be
common since it caters to same IRQs etc. Maintenance point of view
also it leads to multiple file fixes.

The second probably is cleaner and portable. It ensures that all the
common GIC infrastructure is not touched and also provides archs to
address their specific issue.

Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Colin Cross <ccross@android.com>
Tested-by: Colin Cross <ccross@android.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Santosh Shilimkar authored and Russell King committed Mar 9, 2011
1 parent 4bdb157 commit d7ed36a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
47 changes: 47 additions & 0 deletions arch/arm/common/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ struct gic_chip_data {
void __iomem *cpu_base;
};

/*
* Supported arch specific GIC irq extension.
* Default make them NULL.
*/
struct irq_chip gic_arch_extn = {
.irq_ack = NULL,
.irq_mask = NULL,
.irq_unmask = NULL,
.irq_retrigger = NULL,
.irq_set_type = NULL,
.irq_set_wake = NULL,
};

#ifndef MAX_GIC_NR
#define MAX_GIC_NR 1
#endif
Expand Down Expand Up @@ -74,6 +87,8 @@ static inline unsigned int gic_irq(struct irq_data *d)
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);
}
Expand All @@ -84,6 +99,8 @@ static void gic_mask_irq(struct irq_data *d)

spin_lock(&irq_controller_lock);
writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
if (gic_arch_extn.irq_mask)
gic_arch_extn.irq_mask(d);
spin_unlock(&irq_controller_lock);
}

Expand All @@ -92,6 +109,8 @@ static void gic_unmask_irq(struct irq_data *d)
u32 mask = 1 << (d->irq % 32);

spin_lock(&irq_controller_lock);
if (gic_arch_extn.irq_unmask)
gic_arch_extn.irq_unmask(d);
writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
spin_unlock(&irq_controller_lock);
}
Expand All @@ -116,6 +135,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)

spin_lock(&irq_controller_lock);

if (gic_arch_extn.irq_set_type)
gic_arch_extn.irq_set_type(d, type);

val = readl(base + GIC_DIST_CONFIG + confoff);
if (type == IRQ_TYPE_LEVEL_HIGH)
val &= ~confmask;
Expand All @@ -141,6 +163,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
return 0;
}

static int gic_retrigger(struct irq_data *d)
{
if (gic_arch_extn.irq_retrigger)
return gic_arch_extn.irq_retrigger(d);

return -ENXIO;
}

#ifdef CONFIG_SMP
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force)
Expand All @@ -166,6 +196,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
}
#endif

#ifdef CONFIG_PM
static int gic_set_wake(struct irq_data *d, unsigned int on)
{
int ret = -ENXIO;

if (gic_arch_extn.irq_set_wake)
ret = gic_arch_extn.irq_set_wake(d, on);

return ret;
}

#else
#define gic_set_wake NULL
#endif

static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
{
struct gic_chip_data *chip_data = get_irq_data(irq);
Expand Down Expand Up @@ -201,9 +246,11 @@ static struct irq_chip gic_chip = {
.irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq,
.irq_set_type = gic_set_type,
.irq_retrigger = gic_retrigger,
#ifdef CONFIG_SMP
.irq_set_affinity = gic_set_affinity,
#endif
.irq_set_wake = gic_set_wake,
};

void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
Expand Down
1 change: 1 addition & 0 deletions arch/arm/include/asm/hardware/gic.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#ifndef __ASSEMBLY__
extern void __iomem *gic_cpu_base_addr;
extern struct irq_chip gic_arch_extn;

void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
void gic_secondary_init(unsigned int);
Expand Down

0 comments on commit d7ed36a

Please sign in to comment.