mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
irqchip: gic: Allow interrupt level to be set for PPIs
During a recent cleanup of the arm64 DTs it has become clear that the handling of PPIs in xxxx_set_type() is incorrect. The ARM TRMs for GICv2 and later allow for "implementation defined" support for setting the edge or level type of the PPI interrupts and don't restrict the activation level of the signal. Current ARM implementations do restrict the PPI level type to IRQ_TYPE_LEVEL_LOW, but licensees of the IP can decide to shoot themselves in the foot at any time. Signed-off-by: Liviu Dudau <[email protected]> Acked-by: Marc Zyngier <[email protected]> Cc: LAKML <[email protected]> Cc: Russell King <[email protected]> Cc: Rob Herring <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Ian Campbell <[email protected]> Cc: Jason Cooper <[email protected]> Cc: Haojian Zhuang <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
This commit is contained in:
parent
d7eb4f2ecc
commit
fb7e7deb7f
6 changed files with 35 additions and 19 deletions
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "irq-gic-common.h"
|
||||
|
||||
void gic_configure_irq(unsigned int irq, unsigned int type,
|
||||
int gic_configure_irq(unsigned int irq, unsigned int type,
|
||||
void __iomem *base, void (*sync_access)(void))
|
||||
{
|
||||
u32 enablemask = 1 << (irq % 32);
|
||||
|
|
@ -29,16 +29,17 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
|
|||
u32 confmask = 0x2 << ((irq % 16) * 2);
|
||||
u32 confoff = (irq / 16) * 4;
|
||||
bool enabled = false;
|
||||
u32 val;
|
||||
u32 val, oldval;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Read current configuration register, and insert the config
|
||||
* for "irq", depending on "type".
|
||||
*/
|
||||
val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
|
||||
if (type == IRQ_TYPE_LEVEL_HIGH)
|
||||
val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
val &= ~confmask;
|
||||
else if (type == IRQ_TYPE_EDGE_RISING)
|
||||
else if (type & IRQ_TYPE_EDGE_BOTH)
|
||||
val |= confmask;
|
||||
|
||||
/*
|
||||
|
|
@ -54,15 +55,20 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
|
|||
|
||||
/*
|
||||
* Write back the new configuration, and possibly re-enable
|
||||
* the interrupt.
|
||||
* the interrupt. If we tried to write a new configuration and failed,
|
||||
* return an error.
|
||||
*/
|
||||
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
|
||||
if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
|
||||
ret = -EINVAL;
|
||||
|
||||
if (enabled)
|
||||
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
|
||||
|
||||
if (sync_access)
|
||||
sync_access();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __init gic_dist_config(void __iomem *base, int gic_irqs,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
void gic_configure_irq(unsigned int irq, unsigned int type,
|
||||
int gic_configure_irq(unsigned int irq, unsigned int type,
|
||||
void __iomem *base, void (*sync_access)(void));
|
||||
void gic_dist_config(void __iomem *base, int gic_irqs,
|
||||
void (*sync_access)(void));
|
||||
|
|
|
|||
|
|
@ -238,7 +238,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
|||
if (irq < 16)
|
||||
return -EINVAL;
|
||||
|
||||
if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
|
||||
/* SPIs have restrictions on the supported types */
|
||||
if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
|
||||
type != IRQ_TYPE_EDGE_RISING)
|
||||
return -EINVAL;
|
||||
|
||||
if (gic_irq_in_rdist(d)) {
|
||||
|
|
@ -249,9 +251,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
|||
rwp_wait = gic_dist_wait_for_rwp;
|
||||
}
|
||||
|
||||
gic_configure_irq(irq, type, base, rwp_wait);
|
||||
|
||||
return 0;
|
||||
return gic_configure_irq(irq, type, base, rwp_wait);
|
||||
}
|
||||
|
||||
static u64 gic_mpidr_to_affinity(u64 mpidr)
|
||||
|
|
|
|||
|
|
@ -188,12 +188,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
|||
{
|
||||
void __iomem *base = gic_dist_base(d);
|
||||
unsigned int gicirq = gic_irq(d);
|
||||
int ret;
|
||||
|
||||
/* Interrupt configuration for SGIs can't be changed */
|
||||
if (gicirq < 16)
|
||||
return -EINVAL;
|
||||
|
||||
if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
|
||||
/* SPIs have restrictions on the supported types */
|
||||
if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
|
||||
type != IRQ_TYPE_EDGE_RISING)
|
||||
return -EINVAL;
|
||||
|
||||
raw_spin_lock(&irq_controller_lock);
|
||||
|
|
@ -201,11 +204,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
|||
if (gic_arch_extn.irq_set_type)
|
||||
gic_arch_extn.irq_set_type(d, type);
|
||||
|
||||
gic_configure_irq(gicirq, type, base, NULL);
|
||||
ret = gic_configure_irq(gicirq, type, base, NULL);
|
||||
|
||||
raw_spin_unlock(&irq_controller_lock);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gic_retrigger(struct irq_data *d)
|
||||
|
|
|
|||
|
|
@ -120,21 +120,24 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
{
|
||||
void __iomem *base = hip04_dist_base(d);
|
||||
unsigned int irq = hip04_irq(d);
|
||||
int ret;
|
||||
|
||||
/* Interrupt configuration for SGIs can't be changed */
|
||||
if (irq < 16)
|
||||
return -EINVAL;
|
||||
|
||||
if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
|
||||
/* SPIs have restrictions on the supported types */
|
||||
if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
|
||||
type != IRQ_TYPE_EDGE_RISING)
|
||||
return -EINVAL;
|
||||
|
||||
raw_spin_lock(&irq_controller_lock);
|
||||
|
||||
gic_configure_irq(irq, type, base, NULL);
|
||||
ret = gic_configure_irq(irq, type, base, NULL);
|
||||
|
||||
raw_spin_unlock(&irq_controller_lock);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
|
|
|||
Loading…
Reference in a new issue