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

Reply via email to