On Wed, 29 Jul 2015, Jon Hunter wrote: > The gic_init_bases() function initialises an array that stores the mapping > between the GIC and CPUs. This array is a global array that is > unconditionally initialised on every call to gic_init_bases(). Although, > it is not common for there to be more than one GIC instance, there are > some devices that do support nested GIC controllers and gic_init_bases() > can be called more than once. > > A 2nd call to gic_init_bases() will clear the previous CPU mapping and > will only setup the mapping again for CPU0. This is because for child GIC > controllers there is most likely only one recipient of the interrupt. > > Fix this by moving the CPU mapping array to the GIC chip data structure > so that it is initialised for each GIC instance separately. It is assumed > that the bL switcher code is only interested in the root or primary GIC > instance. > > Signed-off-by: Jon Hunter <jonath...@nvidia.com>
Acked-by: Nicolas Pitre <n...@linaro.org> > --- > arch/arm/common/bL_switcher.c | 2 +- > drivers/irqchip/irq-gic.c | 41 > ++++++++++++++++++++++------------------- > include/linux/irqchip/arm-gic.h | 2 +- > 3 files changed, 24 insertions(+), 21 deletions(-) > > diff --git a/arch/arm/common/bL_switcher.c b/arch/arm/common/bL_switcher.c > index 37dc0fe1093f..4111d7b36077 100644 > --- a/arch/arm/common/bL_switcher.c > +++ b/arch/arm/common/bL_switcher.c > @@ -488,7 +488,7 @@ static int bL_switcher_halve_cpus(void) > cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1); > > /* Let's take note of the GIC ID for this CPU */ > - gic_id = gic_get_cpu_id(i); > + gic_id = gic_get_cpu_id(i, 0); > if (gic_id < 0) { > pr_err("%s: bad GIC ID for CPU %d\n", __func__, i); > bL_switcher_restore_cpus(); > diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c > index a530d9a9b810..78a7706c607e 100644 > --- a/drivers/irqchip/irq-gic.c > +++ b/drivers/irqchip/irq-gic.c > @@ -50,6 +50,8 @@ > > #include "irq-gic-common.h" > > +#define NR_GIC_CPU_IF 8 > + > union gic_base { > void __iomem *common_base; > void __percpu * __iomem *percpu_base; > @@ -70,18 +72,16 @@ struct gic_chip_data { > #ifdef CONFIG_GIC_NON_BANKED > void __iomem *(*get_base)(union gic_base *); > #endif > + /* > + * The GIC mapping of CPU interfaces does not necessarily match > + * the logical CPU numbering. Let's use a mapping as returned > + * by the GIC itself. > + */ > + u8 cpu_map[NR_GIC_CPU_IF]; > }; > > static DEFINE_RAW_SPINLOCK(irq_controller_lock); > > -/* > - * The GIC mapping of CPU interfaces does not necessarily match > - * the logical CPU numbering. Let's use a mapping as returned > - * by the GIC itself. > - */ > -#define NR_GIC_CPU_IF 8 > -static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; > - > #ifndef MAX_GIC_NR > #define MAX_GIC_NR 1 > #endif > @@ -237,6 +237,7 @@ static int gic_set_type(struct irq_data *d, unsigned int > type) > static int gic_set_affinity(struct irq_data *d, const struct cpumask > *mask_val, > bool force) > { > + struct gic_chip_data *gic = irq_data_get_irq_chip_data(d); > void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & > ~3); > unsigned int cpu, shift = (gic_irq(d) % 4) * 8; > u32 val, mask, bit; > @@ -252,7 +253,7 @@ static int gic_set_affinity(struct irq_data *d, const > struct cpumask *mask_val, > > raw_spin_lock_irqsave(&irq_controller_lock, flags); > mask = 0xff << shift; > - bit = gic_cpu_map[cpu] << shift; > + bit = gic->cpu_map[cpu] << shift; > val = readl_relaxed(reg) & ~mask; > writel_relaxed(val | bit, reg); > raw_spin_unlock_irqrestore(&irq_controller_lock, flags); > @@ -420,7 +421,7 @@ static void gic_cpu_init(struct gic_chip_data *gic) > */ > BUG_ON(cpu >= NR_GIC_CPU_IF); > cpu_mask = gic_get_cpumask(gic); > - gic_cpu_map[cpu] = cpu_mask; > + gic->cpu_map[cpu] = cpu_mask; > > /* > * Clear our mask from the other map entries in case they're > @@ -428,7 +429,7 @@ static void gic_cpu_init(struct gic_chip_data *gic) > */ > for (i = 0; i < NR_GIC_CPU_IF; i++) > if (i != cpu) > - gic_cpu_map[i] &= ~cpu_mask; > + gic->cpu_map[i] &= ~cpu_mask; > > gic_cpu_config(dist_base, NULL); > > @@ -677,7 +678,7 @@ static void gic_raise_softirq(const struct cpumask *mask, > unsigned int irq) > > /* Convert our logical CPU mask into a physical one. */ > for_each_cpu(cpu, mask) > - map |= gic_cpu_map[cpu]; > + map |= gic->cpu_map[cpu]; > > /* > * Ensure that stores to Normal memory are visible to the > @@ -722,15 +723,17 @@ void gic_send_sgi(unsigned int cpu_id, unsigned int irq) > * or -1 if the CPU number is too large or the interface ID is > * unknown (more than one bit set). > */ > -int gic_get_cpu_id(unsigned int cpu) > +int gic_get_cpu_id(unsigned int cpu, unsigned int gic_nr) > { > unsigned int cpu_bit; > > + if (gic_nr >= MAX_GIC_NR) > + return -EINVAL; > if (cpu >= NR_GIC_CPU_IF) > - return -1; > - cpu_bit = gic_cpu_map[cpu]; > + return -EINVAL; > + cpu_bit = gic_data[gic_nr].cpu_map[cpu]; > if (cpu_bit & (cpu_bit - 1)) > - return -1; > + return -EINVAL; > return __ffs(cpu_bit); > } > > @@ -759,14 +762,14 @@ void gic_migrate_target(unsigned int new_cpu_id) > return; > gic_irqs = gic_data[gic_nr].gic_irqs; > > - cur_cpu_id = __ffs(gic_cpu_map[cpu]); > + cur_cpu_id = __ffs(gic->cpu_map[cpu]); > cur_target_mask = 0x01010101 << cur_cpu_id; > ror_val = (cur_cpu_id - new_cpu_id) & 31; > > raw_spin_lock(&irq_controller_lock); > > /* Update the target interface for this logical CPU */ > - gic_cpu_map[cpu] = 1 << new_cpu_id; > + gic->cpu_map[cpu] = 1 << new_cpu_id; > > /* > * Find all the peripheral interrupts targetting the current > @@ -981,7 +984,7 @@ void __init gic_init_bases(unsigned int gic_nr, int > irq_start, > * It will be refined as each CPU probes its ID. > */ > for (i = 0; i < NR_GIC_CPU_IF; i++) > - gic_cpu_map[i] = 0xff; > + gic->cpu_map[i] = 0xff; > > /* > * Find out how many interrupts are supported. > diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h > index f52a9024be9a..9a4d30564492 100644 > --- a/include/linux/irqchip/arm-gic.h > +++ b/include/linux/irqchip/arm-gic.h > @@ -111,7 +111,7 @@ static inline void gic_init(unsigned int nr, int start, > int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); > > void gic_send_sgi(unsigned int cpu_id, unsigned int irq); > -int gic_get_cpu_id(unsigned int cpu); > +int gic_get_cpu_id(unsigned int cpu, unsigned int gic_nr); > void gic_migrate_target(unsigned int new_cpu_id); > unsigned long gic_get_sgir_physaddr(void); > > -- > 2.1.4 > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/