From: David Mercado <david.merc...@windriver.com>

Adds ability to dynamically enable or diesable a CPU on a running system.

Signed-off-by: David Mercado <david.merc...@windriver.com>
---
 arch/arm/mach-axxia/axxia-gic.c | 73 ++++++++++++++++++++++-------------------
 arch/arm/mach-axxia/hotplug.c   | 52 ++++++++++++++++++++---------
 arch/arm/mach-axxia/platsmp.c   |  5 +++
 3 files changed, 80 insertions(+), 50 deletions(-)

diff --git a/arch/arm/mach-axxia/axxia-gic.c b/arch/arm/mach-axxia/axxia-gic.c
index 20d04ea..2c2dfba 100644
--- a/arch/arm/mach-axxia/axxia-gic.c
+++ b/arch/arm/mach-axxia/axxia-gic.c
@@ -155,8 +155,12 @@ static void gic_mask_irq(struct irq_data *d)
        if (irqid >= 1020)
                return;
 
+       /* Don't mess with the AXM IPIs. */
+       if ((irqid >= IPI0_CPU0) && (irqid < MAX_AXM_IPI_NUM))
+               return;
+
        /* Deal with PPI interrupts directly. */
-       if (irqid > 16 && irqid < 32) {
+       if ((irqid > 16) && (irqid < 32)) {
                _gic_mask_irq(d);
                return;
        }
@@ -203,8 +207,12 @@ static void gic_unmask_irq(struct irq_data *d)
        if (irqid >= 1020)
                return;
 
+       /* Don't mess with the AXM IPIs. */
+       if ((irqid >= IPI0_CPU0) && (irqid < MAX_AXM_IPI_NUM))
+               return;
+
        /* Deal with PPI interrupts directly. */
-       if (irqid > 15 && irqid < 32) {
+       if ((irqid > 15) && (irqid < 32)) {
                _gic_unmask_irq(d);
                return;
        }
@@ -253,18 +261,6 @@ static int _gic_set_type(struct irq_data *d, unsigned int 
type)
        bool enabled = false;
        u32 val;
 
-       /* Interrupt configuration for SGIs can't be changed. */
-       if (gicirq < 16)
-               return -EINVAL;
-
-       /* Interrupt configuration for the AXM IPIs can't be changed. */
-       if ((gicirq >= IPI0_CPU0) && (gicirq < MAX_AXM_IPI_NUM))
-               return -EINVAL;
-
-       /* We only support two interrupt trigger types. */
-       if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
-               return -EINVAL;
-
        raw_spin_lock(&irq_controller_lock);
 
        val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
@@ -315,9 +311,22 @@ static int gic_set_type(struct irq_data *d, unsigned int 
type)
 {
 #ifdef CONFIG_SMP
        int i, nr_cluster_ids = ((nr_cpu_ids-1) / 4) + 1;
+       unsigned int gicirq = gic_irq(d);
        u32 pcpu = cpu_logical_map(smp_processor_id());
        struct gic_set_type_wrapper_struct data;
 
+       /* Interrupt configuration for SGIs can't be changed. */
+       if (gicirq < 16)
+               return -EINVAL;
+
+       /* Interrupt configuration for the AXM IPIs can't be changed. */
+       if ((gicirq >= IPI0_CPU0) && (gicirq < MAX_AXM_IPI_NUM))
+               return -EINVAL;
+
+       /* We only support two interrupt trigger types. */
+       if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+               return -EINVAL;
+
        /*
         * Duplicate IRQ type settings across all clusters. Run
         * directly for this cluster, use IPI for all others.
@@ -410,15 +419,26 @@ static int gic_set_affinity(struct irq_data *d,
        if (irqid >= 1020)
                return -EINVAL;
 
-       data.d = d;
-       data.mask_val = mask_val;
-       data.disable = false;
+       /* Interrupt affinity for the AXM IPIs can't be changed. */
+       if ((irqid >= IPI0_CPU0) && (irqid < MAX_AXM_IPI_NUM))
+               return IRQ_SET_MASK_OK;
+
+       /*
+        * If the new IRQ affinity is the same as current, then
+        * there's no need to update anything.
+        */
+       if (cpu == irq_cpuid[irqid])
+               return IRQ_SET_MASK_OK;
 
        /*
         * If the new physical cpu assignment falls within the same
         * cluster as the cpu we're currently running on, set the IRQ
         * affinity directly. Otherwise, use the IPI mechanism.
         */
+       data.d = d;
+       data.mask_val = mask_val;
+       data.disable = false;
+
        if ((cpu_logical_map(cpu) / 4) == (pcpu / 4)) {
                _gic_set_affinity(&data);
        } else {
@@ -475,7 +495,6 @@ asmlinkage void __exception_irq_entry 
axxia_gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
        u32 ipinum = 0;
-       u32 mask, offset;
        struct gic_chip_data *gic = &gic_data;
        void __iomem *cpu_base = gic_data_cpu_base(gic);
 
@@ -540,7 +559,7 @@ asmlinkage void __exception_irq_entry 
axxia_gic_handle_irq(struct pt_regs *regs)
                                break;
                        }
 
-                       if (ipinum) {
+                       if (ipinum > 1) { /* Ignore IPI_WAKEUP (1) */
                                /*
                                 * Write the original irq number to the
                                 * EOI register to acknowledge the IRQ.
@@ -548,18 +567,6 @@ asmlinkage void __exception_irq_entry 
axxia_gic_handle_irq(struct pt_regs *regs)
                                 * is really a SPI interrupt, not a SGI.
                                 */
                                writel_relaxed(irqnr, cpu_base + GIC_CPU_EOI);
-
-                               /*
-                                * Unlike the GIC softirqs, the Axxia IPI
-                                * interrupts do not remain enabled after
-                                * firing. Re-enable the interrupt here.
-                                */
-                               mask = 1 << (irqnr % 32);
-                               offset = 4 * (irqnr / 32);
-                               writel_relaxed(mask,
-                                       gic_data_dist_base(&gic_data)
-                                       + GIC_DIST_ENABLE_SET + offset);
-
 #ifdef CONFIG_SMP
                                /* Do the normal IPI handling. */
                                handle_IPI(ipinum, regs);
@@ -668,8 +675,7 @@ static void __cpuinit gic_dist_init(struct gic_chip_data 
*gic)
         */
        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 + (4 * (i / 4)) + i % 4);
+               writeb_relaxed(cpumask_8, base + GIC_DIST_TARGET + i);
        }
 
        /*
@@ -849,7 +855,6 @@ static int _gic_notifier(struct notifier_block *self,
                         unsigned long cmd, void *v)
 {
        int i;
-
        switch (cmd) {
        case CPU_PM_ENTER:
                gic_cpu_save();
diff --git a/arch/arm/mach-axxia/hotplug.c b/arch/arm/mach-axxia/hotplug.c
index 9ecd64d..d919bff 100644
--- a/arch/arm/mach-axxia/hotplug.c
+++ b/arch/arm/mach-axxia/hotplug.c
@@ -18,26 +18,33 @@
 
 extern volatile int pen_release;
 
-static inline void cpu_enter_lowpower(void)
+static inline void cpu_enter_lowpower_a15(void)
 {
        unsigned int v;
 
+       asm volatile(
+       "       mrc     p15, 0, %0, c1, c0, 0\n"
+       "       bic     %0, %0, %1\n"
+       "       mcr     p15, 0, %0, c1, c0, 0\n"
+       : "=&r" (v)
+       : "Ir" (CR_C)
+       : "cc");
+
        flush_cache_all();
+
        asm volatile(
-               "mcr    p15, 0, %1, c7, c5, 0\n"
-       "       mcr     p15, 0, %1, c7, c10, 4\n"
        /*
-        * Turn off coherency
-        */
-       "       mrc     p15, 0, %0, c1, c0, 1\n"
-       "       bic     %0, %0, %3\n"
-       "       mcr     p15, 0, %0, c1, c0, 1\n"
-       "       mrc     p15, 0, %0, c1, c0, 0\n"
-       "       bic     %0, %0, %2\n"
-       "       mcr     p15, 0, %0, c1, c0, 0\n"
-         : "=&r" (v)
-         : "r" (0), "Ir" (CR_C), "Ir" (0x40)
-         : "cc");
+       * Turn off coherency
+       */
+       "       mrc     p15, 0, %0, c1, c0, 1\n"
+       "       bic     %0, %0, %1\n"
+       "       mcr     p15, 0, %0, c1, c0, 1\n"
+       : "=&r" (v)
+       : "Ir" (0x40)
+       : "cc");
+
+       isb();
+       dsb();
 }
 
 static inline void cpu_leave_lowpower(void)
@@ -58,6 +65,8 @@ static inline void cpu_leave_lowpower(void)
 
 static void __ref platform_do_lowpower(unsigned int cpu, int *spurious)
 {
+       int phys_cpu, cluster;
+
        /*
         * there is no power-control hardware on this platform, so all
         * we can do is put the core into WFI; this is safe as the calling
@@ -66,7 +75,18 @@ static void __ref platform_do_lowpower(unsigned int cpu, int 
*spurious)
        for (;;) {
                wfi();
 
-               if (pen_release == cpu_logical_map(cpu)) {
+               /*
+                * Convert the "cpu" variable to be compatible with the
+                * ARM MPIDR register format (CLUSTERID and CPUID):
+                *
+                * Bits:   |11 10 9 8|7 6 5 4 3 2|1 0
+                *         | CLUSTER | Reserved  |CPU
+                */
+               phys_cpu = cpu_logical_map(cpu);
+               cluster = (phys_cpu / 4) << 8;
+               phys_cpu = cluster + (phys_cpu % 4);
+
+               if (pen_release == phys_cpu) {
                        /*
                         * OK, proper wakeup, we're done
                         */
@@ -101,7 +121,7 @@ void platform_cpu_die(unsigned int cpu)
        /*
         * we're ready for shutdown now, so do it
         */
-       cpu_enter_lowpower();
+       cpu_enter_lowpower_a15();
        platform_do_lowpower(cpu, &spurious);
 
        /*
diff --git a/arch/arm/mach-axxia/platsmp.c b/arch/arm/mach-axxia/platsmp.c
index 3b202b9..4ba2e7a 100644
--- a/arch/arm/mach-axxia/platsmp.c
+++ b/arch/arm/mach-axxia/platsmp.c
@@ -107,6 +107,11 @@ int __cpuinit boot_secondary(unsigned int cpu, struct 
task_struct *idle)
        /* Release the specified core */
        write_pen_release(phys_cpu);
 
+#ifdef CONFIG_HOTPLUG_CPU
+       /* Send a wakeup IPI to get the idled cpu out of WFI state */
+       axxia_gic_raise_softirq(cpumask_of(cpu), 1);
+#endif
+
        /* Wait for so long, then give up if nothing happens ... */
        timeout = jiffies + (1 * HZ);
        while (time_before(jiffies, timeout)) {
-- 
1.8.3.4

_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to