Commit d7ed36a4 authored by Santosh Shilimkar's avatar Santosh Shilimkar Committed by Russell King

ARM: 6777/1: gic: Add hooks for architecture specific extensions

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: default avatarSantosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: default avatarColin Cross <ccross@android.com>
Tested-by: default avatarColin Cross <ccross@android.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 4bdb1577
...@@ -44,6 +44,19 @@ struct gic_chip_data { ...@@ -44,6 +44,19 @@ struct gic_chip_data {
void __iomem *cpu_base; 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 #ifndef MAX_GIC_NR
#define MAX_GIC_NR 1 #define MAX_GIC_NR 1
#endif #endif
...@@ -74,6 +87,8 @@ static inline unsigned int gic_irq(struct irq_data *d) ...@@ -74,6 +87,8 @@ static inline unsigned int gic_irq(struct irq_data *d)
static void gic_ack_irq(struct irq_data *d) static void gic_ack_irq(struct irq_data *d)
{ {
spin_lock(&irq_controller_lock); 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); writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
} }
...@@ -84,6 +99,8 @@ static void gic_mask_irq(struct irq_data *d) ...@@ -84,6 +99,8 @@ static void gic_mask_irq(struct irq_data *d)
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); 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); spin_unlock(&irq_controller_lock);
} }
...@@ -92,6 +109,8 @@ static void gic_unmask_irq(struct irq_data *d) ...@@ -92,6 +109,8 @@ static void gic_unmask_irq(struct irq_data *d)
u32 mask = 1 << (d->irq % 32); u32 mask = 1 << (d->irq % 32);
spin_lock(&irq_controller_lock); 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); writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
} }
...@@ -116,6 +135,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -116,6 +135,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
spin_lock(&irq_controller_lock); 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); val = readl(base + GIC_DIST_CONFIG + confoff);
if (type == IRQ_TYPE_LEVEL_HIGH) if (type == IRQ_TYPE_LEVEL_HIGH)
val &= ~confmask; val &= ~confmask;
...@@ -141,6 +163,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -141,6 +163,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
return 0; 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 #ifdef CONFIG_SMP
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force) bool force)
...@@ -166,6 +196,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, ...@@ -166,6 +196,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
} }
#endif #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) static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
{ {
struct gic_chip_data *chip_data = get_irq_data(irq); struct gic_chip_data *chip_data = get_irq_data(irq);
...@@ -201,9 +246,11 @@ static struct irq_chip gic_chip = { ...@@ -201,9 +246,11 @@ static struct irq_chip gic_chip = {
.irq_mask = gic_mask_irq, .irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq, .irq_unmask = gic_unmask_irq,
.irq_set_type = gic_set_type, .irq_set_type = gic_set_type,
.irq_retrigger = gic_retrigger,
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
.irq_set_affinity = gic_set_affinity, .irq_set_affinity = gic_set_affinity,
#endif #endif
.irq_set_wake = gic_set_wake,
}; };
void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void __iomem *gic_cpu_base_addr; 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_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
void gic_secondary_init(unsigned int); void gic_secondary_init(unsigned int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment