From: John Jacques <john.jacq...@lsi.com> Fixed the hang in the affinity code. The selection of a cpu on a clear affinity did not have the right mask, causing the affinity to be moved to a cpu that was not powered up.
Signed-off-by: John Jacques <john.jacq...@lsi.com> --- arch/arm/mach-axxia/axxia-gic.c | 242 +++++++++++++++++++++------------------- 1 file changed, 130 insertions(+), 112 deletions(-) diff --git a/arch/arm/mach-axxia/axxia-gic.c b/arch/arm/mach-axxia/axxia-gic.c index 6345a99..34764b0 100644 --- a/arch/arm/mach-axxia/axxia-gic.c +++ b/arch/arm/mach-axxia/axxia-gic.c @@ -228,22 +228,23 @@ static void axxia_gic_flush_affinity_queue(struct work_struct *dummy) void *qdata; struct gic_rpc_data *rpc_data; - while (axxia_get_item(&axxia_circ_q, &qdata) != -1) { + rpc_data = (struct gic_rpc_data *) qdata; if (rpc_data->func_mask == SET_AFFINITY) { - smp_call_function_single(rpc_data->cpu, - gic_set_affinity_remote, - qdata, 1); - + if (cpu_online(rpc_data->cpu)) { + smp_call_function_single(rpc_data->cpu, gic_set_affinity_remote, + qdata, 1); + } } else if (rpc_data->func_mask == CLR_AFFINITY) { - - smp_call_function_single(rpc_data->cpu, - gic_clr_affinity_remote, - qdata, 1); + if (cpu_online(rpc_data->cpu)) { + smp_call_function_single(rpc_data->cpu, gic_clr_affinity_remote, + qdata, 1); + } } kfree(qdata); } + } /* @@ -482,35 +483,45 @@ static int gic_retrigger(struct irq_data *d) return -ENXIO; } -static int _gic_clear_affinity(struct irq_data *d, u32 cpu, bool update_enable) +static void gic_set_irq_target(void __iomem *dist_base, + u32 irqid, u32 cpu, bool set) { - - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); - unsigned int shift = (gic_irq(d) % 4) * 8; + void __iomem *reg; + unsigned int shift; u32 val; u32 mask = 0; - u32 enable_mask, enable_offset; + u32 bit; + reg = dist_base + GIC_DIST_TARGET + (irqid & ~3); + shift = (irqid % 4) * 8; mask = 0xff << shift; - enable_mask = 1 << (gic_irq(d) % 32); - enable_offset = 4 * (gic_irq(d) / 32); + val = readl_relaxed(reg) & ~mask; + + if (!set) + /* Clear affinity, mask IRQ. */ + writel_relaxed(val, reg); + else { + bit = 1 << ((cpu_logical_map(cpu) % CORES_PER_CLUSTER) + shift); + writel_relaxed(val | bit, reg); + } + +} + +static int _gic_clear_affinity(struct irq_data *d, u32 cpu, bool update_enable) +{ + + u32 enable_mask, enable_offset; raw_spin_lock(&irq_controller_lock); - val = readl_relaxed(reg) & ~mask; - /* Clear affinity, mask IRQ. */ - writel_relaxed(val, reg); + gic_set_irq_target(gic_dist_base(d), gic_irq(d), cpu, false); if (update_enable) { - - writel_relaxed(enable_mask, - gic_data_dist_base(&gic_data) + GIC_DIST_PENDING_CLEAR + enable_offset); - writel_relaxed(enable_mask, - gic_data_dist_base(&gic_data) + GIC_DIST_ACTIVE_CLEAR + enable_offset); + enable_mask = 1 << (gic_irq(d) % 32); + enable_offset = 4 * (gic_irq(d) / 32); writel_relaxed(enable_mask, gic_data_dist_base(&gic_data) + GIC_DIST_ENABLE_CLEAR + enable_offset); - } raw_spin_unlock(&irq_controller_lock); @@ -523,33 +534,17 @@ static int _gic_set_affinity(struct irq_data *d, u32 cpu, bool update_enable) { - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); - unsigned int shift = (gic_irq(d) % 4) * 8; - u32 val; - u32 mask = 0; - u32 bit; u32 enable_mask, enable_offset; - /* - * Normalize the cpu number as seen by Linux (0-15) to a - * number as seen by a cluster (0-3). - */ - bit = 1 << ((cpu_logical_map(cpu) % CORES_PER_CLUSTER) + shift); - mask = 0xff << shift; - - enable_mask = 1 << (gic_irq(d) % 32); - enable_offset = 4 * (gic_irq(d) / 32); - raw_spin_lock(&irq_controller_lock); - val = readl_relaxed(reg) & ~mask; - /* Set affinity, mask IRQ. */ - writel_relaxed(val | bit, reg); + gic_set_irq_target(gic_dist_base(d), gic_irq(d), cpu, true); if (update_enable) { + enable_mask = 1 << (gic_irq(d) % 32); + enable_offset = 4 * (gic_irq(d) / 32); writel_relaxed(enable_mask, - gic_data_dist_base(&gic_data) + GIC_DIST_ENABLE_SET - + enable_offset); + gic_data_dist_base(&gic_data) + GIC_DIST_ENABLE_SET + enable_offset); } raw_spin_unlock(&irq_controller_lock); @@ -580,11 +575,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { - u32 pcpu = cpu_logical_map(smp_processor_id()); - unsigned int irqid = gic_irq(d); - struct cpumask *affinity_mask = (struct cpumask *)mask_val; + u32 pcpu; + unsigned int irqid; + struct cpumask *affinity_mask; u32 mask; - u32 oldcpu = irq_cpuid[irqid]; + u32 oldcpu; struct gic_rpc_data *gic_rpc_ptr; int rval; bool new_same_core = false; @@ -597,6 +592,12 @@ static int gic_set_affinity(struct irq_data *d, BUG_ON(!irqs_disabled()); + + pcpu = cpu_logical_map(smp_processor_id()); + irqid = gic_irq(d); + affinity_mask = (struct cpumask *)mask_val; + oldcpu = irq_cpuid[irqid]; + if (irqid >= MAX_GIC_INTERRUPTS) return -EINVAL; @@ -604,7 +605,6 @@ static int gic_set_affinity(struct irq_data *d, if ((irqid >= IPI0_CPU0) && (irqid < MAX_AXM_IPI_NUM)) return IRQ_SET_MASK_OK; - if (force) add_cpu = cpumask_any(cpu_online_mask); else @@ -650,25 +650,21 @@ static int gic_set_affinity(struct irq_data *d, } } - mutex_lock(&affinity_lock); - - /* Update Axxia IRQ affinity table with the new physical CPU number. */ - irq_cpuid[irqid] = cpu_logical_map(add_cpu); /* * We clear first to make sure the affinity mask always has a bit set, * especially when the two cpus are in the same cluster. */ if (irqid != IRQ_PMU) { - if (clear_needed == AFFINITY_CLEAR_LOCAL) { _gic_clear_affinity(d, del_cpu, update_enable); } else if (clear_needed == AFFINITY_CLEAR_OTHER_CLUSTER) { - mask = 0xf << (oldcpu / CORES_PER_CLUSTER); - del_cpu = cpumask_any_and((struct cpumask *)&mask, cpu_online_mask); + mask = 0xf << ((oldcpu / CORES_PER_CLUSTER) * 4); + del_cpu = cpumask_any_and((struct cpumask *)&mask, + cpu_online_mask); if (del_cpu < nr_cpu_ids) { @@ -685,19 +681,23 @@ static int gic_set_affinity(struct irq_data *d, gic_rpc_ptr->oldcpu = oldcpu; gic_rpc_ptr->d = d; gic_rpc_ptr->update_enable = update_enable; + get_cpu(); rval = axxia_put_item(&axxia_circ_q, (void *) gic_rpc_ptr); + put_cpu(); if (rval) { pr_err( "ERROR: failed to add CLR_AFFINITY request for cpu: %d\n", del_cpu); kfree((void *) gic_rpc_ptr); + mutex_unlock(&affinity_lock); + return rval; } schedule_work_on(0, &axxia_gic_affinity_work); - } + } else + pr_err("ERROR: no CPUs left\n"); } } - if (set_needed == AFFINITY_SET_LOCAL) { _gic_set_affinity(d, add_cpu, update_enable); @@ -716,19 +716,22 @@ static int gic_set_affinity(struct irq_data *d, gic_rpc_ptr->cpu = add_cpu; gic_rpc_ptr->update_enable = update_enable; gic_rpc_ptr->d = d; + get_cpu(); rval = axxia_put_item(&axxia_circ_q, (void *) gic_rpc_ptr); + put_cpu(); if (rval) { pr_err("ERROR: failed to add SET_AFFINITY request for cpu: %d\n", add_cpu); kfree((void *) gic_rpc_ptr); + mutex_unlock(&affinity_lock); + return rval; } schedule_work_on(0, &axxia_gic_affinity_work); } - - mutex_unlock(&affinity_lock); - + /* Update Axxia IRQ affinity table with the new physical CPU number. */ + irq_cpuid[irqid] = cpu_logical_map(add_cpu); return IRQ_SET_MASK_OK; } @@ -1206,10 +1209,9 @@ static void __init gic_axxia_init(struct gic_chip_data *gic) writel_relaxed(cpumask, ipi_mask_reg_base + 0x40 + i * 4); } -static void __cpuinit gic_dist_init(struct gic_chip_data *gic) +static void gic_dist_init(struct gic_chip_data *gic) { unsigned int i; - u32 cpumask; unsigned int gic_irqs = gic->gic_irqs; void __iomem *base = gic_data_dist_base(gic); u32 cpu = cpu_logical_map(smp_processor_id()); @@ -1220,17 +1222,17 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic) u32 enableoff; u32 val; u32 this_cluster = get_cluster_id(); + u32 powered_on; + u32 ccpu; /* Initialize the distributor interface once per CPU cluster */ if ((test_and_set_bit(get_cluster_id(), &gic->dist_init_done)) && (!cluster_power_up[this_cluster])) return; - cpumask = 1 << cpu; - cpumask |= cpumask << 8; - cpumask |= cpumask << 16; - writel_relaxed(0, base + GIC_DIST_CTRL); + /*################################# CONFIG IRQS ####################################*/ + /* * Set all global interrupts to be level triggered, active low. */ @@ -1238,13 +1240,23 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic) writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16); /* - * Set all global interrupts to this CPU only. - * (Only do this for the first core on cluster 0). + * Set Axxia IPI interrupts to be edge triggered. */ - if (cpu == 0) - for (i = 32; i < gic_irqs; i += 4) - writel_relaxed(cpumask, - base + GIC_DIST_TARGET + i * 4 / 4); + for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) { + confmask = 0x2 << ((i % 16) * 2); + confoff = (i / 16) * 4; + val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); + val |= confmask; + writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); + } + + /*################################# PRIORITY ####################################*/ + /* + * Set priority on PPI and SGI interrupts + */ + for (i = 0; i < 32; i += 4) + writel_relaxed(0xa0a0a0a0, + base + GIC_DIST_PRI + i * 4 / 4); /* * Set priority on all global interrupts. @@ -1252,52 +1264,43 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic) for (i = 32; i < gic_irqs; i += 4) writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); + + /*################################# TARGET ####################################*/ /* - * Disable all interrupts. Leave the PPI and SGIs alone - * as these enables are banked registers. + * Set all global interrupts to this CPU only. + * (Only do this for the first core on cluster 0). */ - for (i = 32; i < gic_irqs; i += 32) { - writel_relaxed(0xffffffff, - base + GIC_DIST_ACTIVE_CLEAR + i * 4 / 32); - writel_relaxed(0xffffffff, - base + GIC_DIST_PENDING_CLEAR + i * 4 / 32); - writel_relaxed(0xffffffff, - base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); - } + if (cpu == 0) + for (i = 32; i < gic_irqs; i += 4) + writel_relaxed(0x01010101, base + GIC_DIST_TARGET + i * 4 / 4); /* * Set Axxia IPI interrupts for all CPUs in this cluster. */ + powered_on = (~pm_cpu_powered_down) & 0xFFFF; for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) { cpumask_8 = 1 << ((i - IPI0_CPU0) % 4); - writeb_relaxed(cpumask_8, base + GIC_DIST_TARGET + i); - } - - /* - * Set the PMU IRQ to the first cpu in this cluster. - */ - writeb_relaxed(0x01, base + GIC_DIST_TARGET + IRQ_PMU); - - /* - * Set Axxia IPI interrupts to be edge triggered. - */ - for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) { - confmask = 0x2 << ((i % 16) * 2); - confoff = (i / 16) * 4; - val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); - val |= confmask; - writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); + ccpu = (this_cluster * 4) + ((i - IPI0_CPU0) % CORES_PER_CLUSTER); + if ((1 << ccpu) & powered_on) + writeb_relaxed(cpumask_8, base + GIC_DIST_TARGET + i); + else + writeb_relaxed(0x00, base + GIC_DIST_TARGET + i); } + /*################################# ENABLE IRQS ####################################*/ /* * Do the initial enable of the Axxia IPI interrupts here. * NOTE: Writing a 0 to this register has no effect, so * no need to read and OR in bits, just writing is OK. */ + + powered_on = (~pm_cpu_powered_down) & 0xFFFF; for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) { enablemask = 1 << (i % 32); enableoff = (i / 32) * 4; - writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); + ccpu = (this_cluster * 4) + ((i - IPI0_CPU0) % CORES_PER_CLUSTER); + if ((1 << ccpu) & powered_on) + writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); } /* @@ -1307,32 +1310,47 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic) enableoff = (IRQ_PMU / 32) * 4; writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); + writel_relaxed(1, base + GIC_DIST_CTRL); + } -static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) +static void gic_cpu_init(struct gic_chip_data *gic) { void __iomem *dist_base = gic_data_dist_base(gic); void __iomem *base = gic_data_cpu_base(gic); int i; - + u32 enablemask; + u32 enableoff; + u32 ccpu; + u32 cpu = smp_processor_id(); + u32 cluster = cpu / CORES_PER_CLUSTER; + u32 cpumask_8; /* * Deal with the banked PPI and SGI interrupts - disable all * PPI interrupts, and also all SGI interrupts (we don't use * SGIs in the Axxia). */ - writel_relaxed(0xffffffff, dist_base + GIC_DIST_ENABLE_CLEAR); - /* - * Set priority on PPI and SGI interrupts - */ - for (i = 0; i < 32; i += 4) - writel_relaxed(0xa0a0a0a0, - dist_base + GIC_DIST_PRI + i * 4 / 4); + if (!cluster_power_up[cluster]) { + writel_relaxed(0, dist_base + GIC_DIST_CTRL); + for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) { + cpumask_8 = 1 << ((i - IPI0_CPU0) % 4); + enablemask = 1 << (i % 32); + enableoff = (i / 32) * 4; + ccpu = (cluster * 4) + ((i - IPI0_CPU0) % CORES_PER_CLUSTER); + if (ccpu == cpu) { + writeb_relaxed(cpumask_8, dist_base + GIC_DIST_TARGET + i); + writel_relaxed(enablemask, dist_base + GIC_DIST_ENABLE_SET + enableoff); + } + } + writel_relaxed(1, dist_base + GIC_DIST_CTRL); + } writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); + writel_relaxed(1, base + GIC_CPU_CTRL); } @@ -1526,7 +1544,7 @@ void __init axxia_gic_init_bases(int irq_start, } -void __cpuinit axxia_gic_secondary_init(void) +void axxia_gic_secondary_init(void) { struct gic_chip_data *gic = &gic_data; -- 1.8.1.4 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto