diff options
Diffstat (limited to 'arch/arm/common/gic.c')
| -rw-r--r-- | arch/arm/common/gic.c | 64 | 
1 files changed, 46 insertions, 18 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index ada6359160e..e6388dcd8cf 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -146,9 +146,15 @@ static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)  	unsigned int shift = (irq % 4) * 8;  	unsigned int cpu = cpumask_first(mask_val);  	u32 val; +	struct irq_desc *desc;  	spin_lock(&irq_controller_lock); -	irq_desc[irq].node = cpu; +	desc = irq_to_desc(irq); +	if (desc == NULL) { +		spin_unlock(&irq_controller_lock); +		return -EINVAL; +	} +	desc->node = cpu;  	val = readl(reg) & ~(0xff << shift);  	val |= 1 << (cpu + shift);  	writel(val, reg); @@ -210,7 +216,7 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)  void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,  			  unsigned int irq_start)  { -	unsigned int max_irq, i; +	unsigned int gic_irqs, irq_limit, i;  	u32 cpumask = 1 << smp_processor_id();  	if (gic_nr >= MAX_GIC_NR) @@ -226,46 +232,49 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,  	/*  	 * Find out how many interrupts are supported. -	 */ -	max_irq = readl(base + GIC_DIST_CTR) & 0x1f; -	max_irq = (max_irq + 1) * 32; - -	/*  	 * The GIC only supports up to 1020 interrupt sources. -	 * Limit this to either the architected maximum, or the -	 * platform maximum.  	 */ -	if (max_irq > max(1020, NR_IRQS)) -		max_irq = max(1020, NR_IRQS); +	gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f; +	gic_irqs = (gic_irqs + 1) * 32; +	if (gic_irqs > 1020) +		gic_irqs = 1020;  	/*  	 * Set all global interrupts to be level triggered, active low.  	 */ -	for (i = 32; i < max_irq; i += 16) +	for (i = 32; i < gic_irqs; i += 16)  		writel(0, base + GIC_DIST_CONFIG + i * 4 / 16);  	/*  	 * Set all global interrupts to this CPU only.  	 */ -	for (i = 32; i < max_irq; i += 4) +	for (i = 32; i < gic_irqs; i += 4)  		writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);  	/* -	 * Set priority on all interrupts. +	 * Set priority on all global interrupts.  	 */ -	for (i = 0; i < max_irq; i += 4) +	for (i = 32; i < gic_irqs; i += 4)  		writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);  	/* -	 * Disable all interrupts. +	 * Disable all interrupts.  Leave the PPI and SGIs alone +	 * as these enables are banked registers.  	 */ -	for (i = 0; i < max_irq; i += 32) +	for (i = 32; i < gic_irqs; i += 32)  		writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);  	/* +	 * Limit number of interrupts registered to the platform maximum +	 */ +	irq_limit = gic_data[gic_nr].irq_offset + gic_irqs; +	if (WARN_ON(irq_limit > NR_IRQS)) +		irq_limit = NR_IRQS; + +	/*  	 * Setup the Linux IRQ subsystem.  	 */ -	for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) { +	for (i = irq_start; i < irq_limit; i++) {  		set_irq_chip(i, &gic_chip);  		set_irq_chip_data(i, &gic_data[gic_nr]);  		set_irq_handler(i, handle_level_irq); @@ -277,11 +286,30 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,  void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)  { +	void __iomem *dist_base; +	int i; +  	if (gic_nr >= MAX_GIC_NR)  		BUG(); +	dist_base = gic_data[gic_nr].dist_base; +	BUG_ON(!dist_base); +  	gic_data[gic_nr].cpu_base = base; +	/* +	 * Deal with the banked PPI and SGI interrupts - disable all +	 * PPI interrupts, ensure all SGI interrupts are enabled. +	 */ +	writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); +	writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); + +	/* +	 * Set priority on PPI and SGI interrupts +	 */ +	for (i = 0; i < 32; i += 4) +		writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); +  	writel(0xf0, base + GIC_CPU_PRIMASK);  	writel(1, base + GIC_CPU_CTRL);  }  |