[linux-yocto] [PATCH 35/35] arch/arm/mach-axxia: fixed hang in preempt kernel
Bruce Ashfield
bruce.ashfield at windriver.com
Sun Nov 16 20:48:38 PST 2014
On 2014-11-13, 12:20 PM, Daniel Dragomir wrote:
> From: John Jacques <john.jacques at 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.
This should be one patch.
>
> Fixed the intermittent failure to power up the cluster by
> setting the L2CTLR, L2ACTLR and ACTLR2 registers. Also updated
> the power on GIC process to only power on the current cpu when
> powering up a GIC cluster
.. and this in another.
Bruce
>
> Signed-off-by: John Jacques <john.jacques at lsi.com>
> ---
> arch/arm/mach-axxia/axxia-gic.c | 242 ++++++++++++++++-------------
> arch/arm/mach-axxia/hotplug.c | 30 ++--
> arch/arm/mach-axxia/lsi_power_management.c | 189 +++++++++++++---------
> arch/arm/mach-axxia/lsi_power_management.h | 9 +-
> arch/arm/mach-axxia/platsmp.c | 36 ++---
> 5 files changed, 282 insertions(+), 224 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;
>
> diff --git a/arch/arm/mach-axxia/hotplug.c b/arch/arm/mach-axxia/hotplug.c
> index d44fbb3..5def7c3 100644
> --- a/arch/arm/mach-axxia/hotplug.c
> +++ b/arch/arm/mach-axxia/hotplug.c
> @@ -85,13 +85,19 @@ static inline void pm_L2_logical_shutdown(u32 cpu)
> : "Ir" (0x400)
> : "cc");
>
> + asm volatile(
> + " mrc p15, 1, %0, c15, c0, 4\n"
> + " orr %0, %0, %1\n"
> + " mcr p15, 1, %0, c15, c0, 4\n"
> + : "=&r" (val)
> + : "Ir" (0x1)
> + : "cc");
> +
> isb();
> dsb();
>
> - /* Clear and invalidate all L1 and L2 data cache */
> flush_cache_all();
>
> -
> /* Turn the DBG Double Lock quiet */
> asm volatile(
> /*
> @@ -163,6 +169,8 @@ static inline void cpu_leave_lowpower(void)
> : "=&r" (v)
> : "Ir" (CR_C), "Ir" (0x40)
> : "cc");
> + isb();
> + dsb();
> }
>
> static void __ref platform_do_lowpower(unsigned int cpu, int *spurious)
> @@ -211,7 +219,9 @@ int axxia_platform_cpu_kill(unsigned int cpu)
> {
>
> #ifdef CONFIG_HOTPLUG_CPU_COMPLETE_POWER_DOWN
> + get_cpu();
> pm_cpu_shutdown(cpu);
> + put_cpu();
> #endif
> return 1;
> }
> @@ -227,21 +237,6 @@ void axxia_platform_cpu_die(unsigned int cpu)
> #ifdef CONFIG_HOTPLUG_CPU_COMPLETE_POWER_DOWN
> bool last_cpu;
>
> - int timeout;
> - timeout = 30;
> -
> - /* make sure no migrations are happening */
> - while (!axxia_is_empty(&axxia_circ_q)) {
> -
> - if (timeout-- == 0)
> - break;
> -
> - mdelay(1);
> - }
> -
> - if (timeout == 0)
> - pr_err("ERROR: tried to shut down and Q was still full\n");
> -
> last_cpu = pm_cpu_last_of_cluster(cpu);
> if (last_cpu)
> pm_L2_logical_shutdown(cpu);
> @@ -251,7 +246,6 @@ void axxia_platform_cpu_die(unsigned int cpu)
> for (;;)
> wfi();
>
> -
> #else /* CPU low power mode */
>
> int spurious = 0;
> diff --git a/arch/arm/mach-axxia/lsi_power_management.c b/arch/arm/mach-axxia/lsi_power_management.c
> index 3ae4afc..6deea07 100644
> --- a/arch/arm/mach-axxia/lsi_power_management.c
> +++ b/arch/arm/mach-axxia/lsi_power_management.c
> @@ -53,6 +53,13 @@ PORESET_CLUSTER1,
> PORESET_CLUSTER2,
> PORESET_CLUSTER3 };
>
> +static const u32 cluster_to_mask[MAX_CLUSTER] = {
> + IPI0_MASK,
> + IPI1_MASK,
> + IPI2_MASK,
> + IPI3_MASK
> +};
> +
> static const u32 ipi_register[MAX_IPI] = {
> NCP_SYSCON_MASK_IPI0,
> NCP_SYSCON_MASK_IPI1,
> @@ -92,6 +99,7 @@ u32 pm_cpu_powered_down;
>
> /*======================= LOCAL FUNCTIONS ==============================*/
> static void pm_set_bits_syscon_register(u32 reg, u32 data);
> +static void pm_or_bits_syscon_register(u32 reg, u32 data);
> static void pm_clear_bits_syscon_register(u32 reg, u32 data);
> static bool pm_test_for_bit_with_timeout(u32 reg, u32 bit);
> static bool pm_wait_for_bit_clear_with_timeout(u32 reg,
> @@ -237,6 +245,11 @@ bool pm_cpu_last_of_cluster(u32 cpu)
>
> static void pm_set_bits_syscon_register(u32 reg, u32 data)
> {
> + writel(data, syscon + reg);
> +}
> +
> +static void pm_or_bits_syscon_register(u32 reg, u32 data)
> +{
> u32 tmp;
>
> tmp = readl(syscon + reg);
> @@ -244,6 +257,7 @@ static void pm_set_bits_syscon_register(u32 reg, u32 data)
> writel(tmp, syscon + reg);
> }
>
> +
> static void pm_clear_bits_syscon_register(u32 reg, u32 data)
> {
> u32 tmp;
> @@ -419,23 +433,25 @@ dickens_power_up:
> return rval;
> }
>
> -static int pm_enable_ipi_interrupts(u32 cpu)
> +static void pm_disable_ipi_interrupts(u32 cpu)
> +{
> + pm_clear_bits_syscon_register(ipi_register[cpu], IPI_IRQ_MASK);
> +}
> +
> +static void pm_enable_ipi_interrupts(u32 cpu)
> {
>
> u32 i;
> - u32 cpumask = 1 << cpu;
> u32 powered_on_cpu = (~(pm_cpu_powered_down) & IPI_IRQ_MASK);
>
> - /* Enable the CPU IPI */
> pm_set_bits_syscon_register(ipi_register[cpu], powered_on_cpu);
>
> - for (i = 0; i < MAX_IPI; i++) {
> + for (i = 0; i < MAX_CPUS; i++) {
> if ((1 << i) & powered_on_cpu)
> - pm_set_bits_syscon_register(ipi_register[i], cpumask);
> + pm_or_bits_syscon_register(ipi_register[i], (1 << cpu));
> }
>
> - return 0;
> -
> + return;
> }
>
> void pm_init_syscon(void)
> @@ -483,7 +499,7 @@ void pm_cpu_shutdown(u32 cpu)
> if (last_cpu) {
>
> /* Disable all the interrupts to the cluster gic */
> - pm_set_bits_syscon_register(NCP_SYSCON_GIC_DISABLE, cluster_mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_GIC_DISABLE, cluster_mask);
>
> /* Remove the cluster from the Dickens coherency domain */
> pm_dickens_logical_shutdown(cluster);
> @@ -501,7 +517,7 @@ void pm_cpu_shutdown(u32 cpu)
> }
>
> /* Turn off the ACE */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_ACEPWRDNRQ, cluster_mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_ACEPWRDNRQ, cluster_mask);
>
> /* Wait for ACE to complete power off */
> success = pm_wait_for_bit_clear_with_timeout(NCP_SYSCON_PWR_NACEPWRDNACK, cluster);
> @@ -512,7 +528,7 @@ void pm_cpu_shutdown(u32 cpu)
> }
>
> /* Isolate the cluster */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_ISOLATEL2MISC, cluster_mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_ISOLATEL2MISC, cluster_mask);
>
> /* Wait for WFI L2 to go to standby */
> success = pm_test_for_bit_with_timeout(NCP_SYSCON_PWR_STANDBYWFIL2, cluster);
> @@ -555,21 +571,10 @@ int pm_cpu_powerup(u32 cpu)
> u32 reqcpu = cpu_logical_map(cpu);
> u32 cluster = reqcpu / CORES_PER_CLUSTER;
> u32 cluster_mask = (0x01 << cluster);
> - u32 timeout;
>
> pm_init_syscon();
>
> /*
> - * The key value has to be written before the CPU RST can be written.
> - */
> - pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> - pm_set_bits_syscon_register(NCP_SYSCON_PWRUP_CPU_RST, cpu_mask);
> -
> - /* Hold the CPU in reset */
> - pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> - pm_set_bits_syscon_register(NCP_SYSCON_HOLD_CPU, cpu_mask);
> -
> - /*
> * Is this the first cpu of a cluster to come back on?
> * Then power up the L2 cache.
> */
> @@ -581,11 +586,18 @@ int pm_cpu_powerup(u32 cpu)
> pr_err("CPU: Failed the logical L2 power up\n");
> goto pm_power_up;
> }
> - pm_clear_bits_syscon_register(NCP_SYSCON_GIC_DISABLE, cluster_mask);
> cluster_power_up[cluster] = true;
> + pm_clear_bits_syscon_register(NCP_SYSCON_GIC_DISABLE, cluster_mask);
> +
> +
> + } else {
> + /* Set the CPU into reset */
> + pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWRUP_CPU_RST, cpu_mask);
>
> }
>
> +
> /*
> * Power up the CPU
> */
> @@ -595,22 +607,6 @@ int pm_cpu_powerup(u32 cpu)
> goto pm_power_up;
> }
>
> - timeout = 30;
> -
> - /* wait max 10 ms until cpuX is on */
> - while (!pm_cpu_active(cpu)) {
> -
> - if (timeout-- == 0)
> - break;
> -
> - mdelay(1);
> - }
> -
> - if (timeout == 0) {
> - rval = -ETIMEDOUT;
> - goto pm_power_up;
> - }
> -
> /*
> * The key value must be written before the CPU RST can be written.
> */
> @@ -618,12 +614,6 @@ int pm_cpu_powerup(u32 cpu)
> pm_clear_bits_syscon_register(NCP_SYSCON_PWRUP_CPU_RST, cpu_mask);
>
> /*
> - * The key value must be written before HOLD CPU can be written.
> - */
> - pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> - pm_clear_bits_syscon_register(NCP_SYSCON_HOLD_CPU, cpu_mask);
> -
> - /*
> * Clear the powered down mask
> */
> pm_cpu_powered_down &= ~(1 << cpu);
> @@ -631,8 +621,9 @@ int pm_cpu_powerup(u32 cpu)
> /* Enable the CPU IPI */
> pm_enable_ipi_interrupts(cpu);
>
> -pm_power_up:
>
> +
> +pm_power_up:
> iounmap(syscon);
> return rval;
> }
> @@ -654,19 +645,61 @@ inline void pm_cpu_logical_powerup(void)
> " mrc p15, 0, %0, c1, c0, 0\n"
> " orr %0, %0, %2\n"
> " mcr p15, 0, %0, c1, c0, 0\n"
> - " mrc p15, 0, %0, c1, c0, 1\n"
> - " orr %0, %0, %3\n"
> - " mcr p15, 0, %0, c1, c0, 1\n"
> : "=&r" (v)
> - : "Ir" (CR_C), "Ir" (CR_I), "Ir" (0x40)
> + : "Ir" (CR_C), "Ir" (CR_I)
> : "cc");
>
> + /*
> + * Iniitalize the ACTLR2 register (all cores).
> + */
> +
> asm volatile(
> - " mrc p15, 1, %0, c9, c0, 2\n"
> + " mrc p15, 1, %0, c15, c0, 4\n"
> + " bic %0, %0, %1\n"
> + " mcr p15, 1, %0, c15, c0, 4\n"
> : "=&r" (v)
> : "Ir" (0x1)
> : "cc");
>
> + isb();
> + dsb();
> +}
> +
> +inline void pm_cluster_logical_powerup(void)
> +{
> + unsigned int v;
> +
> + /*
> + * Initialize the L2CTLR register (primary core in each cluster).
> + */
> + asm volatile(
> + " mrc p15, 1, %0, c9, c0, 2\n"
> + " orr %0, %0, %1\n"
> + " orr %0, %0, %2\n"
> + " mcr p15, 1, %0, c9, c0, 2"
> + : "=&r" (v)
> + : "Ir" (0x01), "Ir" (0x1 << 21)
> + : "cc");
> + isb();
> + dsb();
> +
> + /*
> + * Initialize the L2ACTLR register (primary core in each cluster).
> + */
> + asm volatile(
> + " mrc p15, 1, r0, c15, c0, 0\n"
> + " orr %0, %0, %1\n"
> + " orr %0, %0, %2\n"
> + " orr %0, %0, %3\n"
> + " orr %0, %0, %4\n"
> + " orr %0, %0, %5\n"
> + " mcr p15, 1, %0, c15, c0, 0"
> + : "=&r" (v)
> + : "Ir" (0x1 << 3), "Ir" (0x1 << 7), "Ir" (0x1 << 12), "Ir" (0x1 << 13), "Ir" (0x1 << 14)
> + : "cc");
> + isb();
> + dsb();
> +
> }
>
> static int pm_cpu_physical_isolation_and_power_down(int cpu)
> @@ -678,7 +711,7 @@ static int pm_cpu_physical_isolation_and_power_down(int cpu)
> u32 mask = (0x01 << cpu);
>
> /* Disable the CPU IPI */
> - pm_clear_bits_syscon_register(ipi_register[cpu], IPI_IRQ_MASK);
> + pm_disable_ipi_interrupts(cpu);
>
> /* Initiate power down of the CPU's HS Rams */
> pm_clear_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPURAM, mask);
> @@ -692,12 +725,12 @@ static int pm_cpu_physical_isolation_and_power_down(int cpu)
> }
>
> /* Activate the CPU's isolation clamps */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_ISOLATECPU, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_ISOLATECPU, mask);
>
> /* Initiate power down of the CPU logic */
> pm_clear_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPUSTG2, mask);
>
> - udelay(10);
> + udelay(16);
>
> /* Continue power down of the CPU logic */
> pm_clear_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPUSTG1, mask);
> @@ -722,7 +755,7 @@ static int pm_cpu_physical_connection_and_power_up(int cpu)
> u32 mask = (0x01 << cpu);
>
> /* Initiate power up of the CPU */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPUSTG1, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPUSTG1, mask);
>
> /* Wait until CPU logic power is compete */
> success = pm_wait_for_bit_clear_with_timeout(NCP_SYSCON_PWR_NPWRUPCPUSTG1_ACK, cpu);
> @@ -733,12 +766,12 @@ static int pm_cpu_physical_connection_and_power_up(int cpu)
> }
>
> /* Continue stage 2 power up of the CPU*/
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPUSTG2, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPUSTG2, mask);
>
> - udelay(20);
> + udelay(16);
>
> /* Initiate power up of HS Rams */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPURAM, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_PWRUPCPURAM, mask);
>
> /* Wait until the RAM power up is complete */
> success = pm_wait_for_bit_clear_with_timeout(NCP_SYSCON_PWR_NPWRUPCPURAM_ACK, cpu);
> @@ -751,6 +784,8 @@ static int pm_cpu_physical_connection_and_power_up(int cpu)
> /* Release the CPU's isolation clamps */
> pm_clear_bits_syscon_register(NCP_SYSCON_PWR_ISOLATECPU, mask);
>
> + udelay(16);
> +
> power_up_cleanup:
>
>
> @@ -765,7 +800,7 @@ static void pm_L2_isolation_and_power_down(int cluster)
> u32 mask = (0x1 << cluster);
>
> /* Enable the chip select for the cluster */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_CHIPSELECTEN, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_CHIPSELECTEN, mask);
>
> /* Disable the hsram */
> pm_clear_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2HSRAM, mask);
> @@ -900,7 +935,7 @@ static int pm_L2_physical_connection_and_power_up(u32 cluster)
> int rval = 0;
>
> /* Power up stage 1 */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2LGCSTG1, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2LGCSTG1, mask);
>
> /* Wait for the stage 1 power up to complete */
> success = pm_wait_for_bit_clear_with_timeout(NCP_SYSCON_PWR_NPWRUPL2LGCSTG1_ACK, cluster);
> @@ -911,13 +946,13 @@ static int pm_L2_physical_connection_and_power_up(u32 cluster)
> }
>
> /* Power on stage 2 */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2LGCSTG2, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2LGCSTG2, mask);
>
> /* Set the chip select */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_CHIPSELECTEN, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_CHIPSELECTEN, mask);
>
> /* Power up the snoop ram */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2HSRAM, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_PWRUPL2HSRAM, mask);
>
> /* Wait for the stage 1 power up to complete */
> success = pm_wait_for_bit_clear_with_timeout(NCP_SYSCON_PWR_NPWRUPL2HSRAM_ACK, cluster);
> @@ -961,7 +996,7 @@ static int pm_L2_physical_connection_and_power_up(u32 cluster)
>
> pm_set_bits_syscon_register(syscon,
> NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> - udelay(20);
> + udelay(20);
> pm_set_bits_syscon_register(syscon,
> NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> pm_set_bits_syscon_register(syscon,
> @@ -1059,28 +1094,37 @@ static int pm_L2_logical_powerup(u32 cluster, u32 cpu)
>
> u32 mask = (0x1 << cluster);
> int rval = 0;
> + u32 cluster_mask;
> +
> + if (cluster == 0)
> + cluster_mask = 0xe;
> + else
> + cluster_mask = 0xf << (cluster * 4);
>
> /* put the cluster into a cpu hold */
> - pm_set_bits_syscon_register(NCP_SYSCON_RESET_AXIS,
> + pm_or_bits_syscon_register(NCP_SYSCON_RESET_AXIS,
> cluster_to_poreset[cluster]);
>
> - /* Allow the L2 to be reset */
> - pm_clear_bits_syscon_register(NCP_SYSCON_LRSTDISABLE, mask);
> + /*
> + * The key value has to be written before the CPU RST can be written.
> + */
> + pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWRUP_CPU_RST, cluster_mask);
>
> /* Hold the chip debug cluster */
> pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> - pm_set_bits_syscon_register(NCP_SYSCON_HOLD_DBG, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_HOLD_DBG, mask);
>
> /* Hold the L2 cluster */
> pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> - pm_set_bits_syscon_register(NCP_SYSCON_HOLD_L2, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_HOLD_L2, mask);
> +
>
> /* Cluster physical power up */
> rval = pm_L2_physical_connection_and_power_up(cluster);
> if (rval)
> goto exit_pm_L2_logical_powerup;
>
> -
> udelay(16);
>
> /* take the cluster out of a cpu hold */
> @@ -1090,7 +1134,7 @@ static int pm_L2_logical_powerup(u32 cluster, u32 cpu)
> udelay(64);
>
> /* Enable the system counter */
> - pm_set_bits_syscon_register(NCP_SYSCON_PWR_CSYSREQ_CNT, mask);
> + pm_or_bits_syscon_register(NCP_SYSCON_PWR_CSYSREQ_CNT, mask);
>
> /* Release the L2 cluster */
> pm_set_bits_syscon_register(NCP_SYSCON_KEY, VALID_KEY_VALUE);
> @@ -1108,11 +1152,6 @@ static int pm_L2_logical_powerup(u32 cluster, u32 cpu)
> /* start L2 */
> pm_clear_bits_syscon_register(NCP_SYSCON_PWR_ACINACTM, mask);
>
> - /* Disable the L2 reset */
> - pm_set_bits_syscon_register(NCP_SYSCON_LRSTDISABLE, mask);
> -
> - udelay(64);
> -
> exit_pm_L2_logical_powerup:
>
> return rval;
> diff --git a/arch/arm/mach-axxia/lsi_power_management.h b/arch/arm/mach-axxia/lsi_power_management.h
> index 4de6bd7..ef70af3 100644
> --- a/arch/arm/mach-axxia/lsi_power_management.h
> +++ b/arch/arm/mach-axxia/lsi_power_management.h
> @@ -150,12 +150,19 @@
> #define PORESET_CLUSTER2 (0x40000)
> #define PORESET_CLUSTER3 (0x80000)
>
> +/* IPI Masks */
> +#define IPI0_MASK (0x1111)
> +#define IPI1_MASK (0x2222)
> +#define IPI2_MASK (0x4444)
> +#define IPI3_MASK (0x8888)
> +
> /* SYSCON KEY Value */
> #define VALID_KEY_VALUE (0xAB)
>
> #define MAX_NUM_CLUSTERS (4)
> #define CORES_PER_CLUSTER (4)
> #define MAX_IPI (19)
> +#define MAX_CPUS (MAX_NUM_CLUSTERS * CORES_PER_CLUSTER)
>
> typedef struct {
> u32 cpu;
> @@ -174,9 +181,9 @@ bool pm_cpu_last_of_cluster(u32 cpu);
> void pm_dump_dickens(void);
> void pm_init_cpu(u32 cpu);
> void pm_cpu_logical_powerup(void);
> +void pm_cluster_logical_powerup(void);
> bool pm_cpu_active(u32 cpu);
> void pm_init_syscon(void);
> -
> extern bool pm_in_progress[];
> extern bool cluster_power_up[];
> extern u32 pm_cpu_powered_down;
> diff --git a/arch/arm/mach-axxia/platsmp.c b/arch/arm/mach-axxia/platsmp.c
> index 5781a3c..2804fce 100644
> --- a/arch/arm/mach-axxia/platsmp.c
> +++ b/arch/arm/mach-axxia/platsmp.c
> @@ -24,11 +24,13 @@
>
> #include "axxia.h"
> #include "lsi_power_management.h"
> +#include "axxia_circular_queue.h"
> #include <mach/axxia-gic.h>
>
> extern void axxia_secondary_startup(void);
> extern void axxia_cpu_power_management_gic_control(u32 cpu, bool enable);
> extern void axxia_dist_power_management_gic_control(bool enable);
> +extern struct circular_queue_t axxia_circ_q;
>
> #define SYSCON_PHYS_ADDR 0x002010030000ULL
>
> @@ -62,7 +64,7 @@ static void __init check_fixup_sev(void __iomem *syscon)
> pr_info("axxia: Cross-cluster SEV fixup: %s\n", wfe_fixup ? "yes" : "no");
> }
>
> -static void __cpuinit do_fixup_sev(void)
> +static void do_fixup_sev(void)
> {
> u32 tmp;
>
> @@ -79,7 +81,7 @@ static void __cpuinit do_fixup_sev(void)
> * observers, irrespective of whether they're taking part in coherency
> * or not. This is necessary for the hotplug code to work reliably.
> */
> -static void __cpuinit write_pen_release(int val)
> +static void write_pen_release(int val)
> {
> pen_release = val;
> smp_wmb();
> @@ -89,7 +91,7 @@ static void __cpuinit write_pen_release(int val)
>
> static DEFINE_RAW_SPINLOCK(boot_lock);
>
> -void __cpuinit axxia_secondary_init(unsigned int cpu)
> +void axxia_secondary_init(unsigned int cpu)
> {
> int phys_cpu;
> int phys_cluster;
> @@ -100,7 +102,7 @@ void __cpuinit axxia_secondary_init(unsigned int cpu)
> /*
> * Only execute this when powering up a cpu for hotplug.
> */
> - if (!pm_in_progress[cpu]) {
> + if (!pm_in_progress[phys_cpu]) {
> /* Fixup for cross-cluster SEV */
> do_fixup_sev();
>
> @@ -108,16 +110,16 @@ void __cpuinit axxia_secondary_init(unsigned int cpu)
> } else {
>
> #ifdef CONFIG_HOTPLUG_CPU_COMPLETE_POWER_DOWN
> + if (cluster_power_up[phys_cluster])
> + pm_cluster_logical_powerup();
> pm_cpu_logical_powerup();
> - mdelay(16);
> #endif
> -
> + get_cpu();
> axxia_gic_secondary_init();
> + put_cpu();
>
> #ifdef CONFIG_HOTPLUG_CPU_COMPLETE_POWER_DOWN
> - pm_cpu_logical_powerup();
> - if (cluster_power_up[phys_cluster])
> - cluster_power_up[phys_cluster] = false;
> + cluster_power_up[phys_cluster] = false;
> pm_in_progress[phys_cpu] = false;
> #endif
> }
> @@ -135,13 +137,14 @@ void __cpuinit axxia_secondary_init(unsigned int cpu)
> _raw_spin_unlock(&boot_lock);
> }
>
> -int __cpuinit axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
> +int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
> {
>
> int phys_cpu, cluster;
> unsigned long timeout;
> unsigned long powered_down_cpu;
> - int rVal = 0;
> + u32 i;
> + u32 dummy;
>
>
> /*
> @@ -156,12 +159,7 @@ int __cpuinit axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
>
> if (powered_down_cpu & (1 << phys_cpu)) {
> pm_in_progress[phys_cpu] = true;
> -
> - rVal = pm_cpu_powerup(phys_cpu);
> - if (rVal) {
> - _raw_spin_unlock(&boot_lock);
> - return rVal;
> - }
> + pm_cpu_powerup(phys_cpu);
> }
>
> /*
> @@ -200,7 +198,9 @@ int __cpuinit axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
> if (pen_release == -1)
> break;
>
> - udelay(10);
> + /* Wait 10 cycles */
> + for (i = 0; i < 10; i++)
> + dummy = i;
> }
>
> /*
>
More information about the linux-yocto
mailing list