MIPS: Netlogic: Fix for quad-XLP boot
authorJayachandran C <jchandra@broadcom.com>
Mon, 14 Jan 2013 15:12:01 +0000 (15:12 +0000)
committerJohn Crispin <blogic@openwrt.org>
Sat, 16 Feb 2013 23:15:22 +0000 (00:15 +0100)
On multi-chip boards, the first core on slave SoCs may take much
more time to wakeup. Add code to wait for the core to come up before
proceeding with the rest of the boot up.

Update xlp_wakeup_core to also skip the boot node and the boot CPU
initialization which is already complete.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
Patchwork: http://patchwork.linux-mips.org/patch/4783/
Signed-off-by: John Crispin <blogic@openwrt.org>
arch/mips/netlogic/xlp/wakeup.c

index cb9010642ac33d8002a7b1034644c98574e384af..abb3e08cc05250498f0d9502e78ef824ec1ebd80 100644 (file)
@@ -51,7 +51,7 @@
 #include <asm/netlogic/xlp-hal/xlp.h>
 #include <asm/netlogic/xlp-hal/sys.h>
 
-static int xlp_wakeup_core(uint64_t sysbase, int core)
+static int xlp_wakeup_core(uint64_t sysbase, int node, int core)
 {
        uint32_t coremask, value;
        int count;
@@ -82,36 +82,51 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
        struct nlm_soc_info *nodep;
        uint64_t syspcibase;
        uint32_t syscoremask;
-       int core, n, cpu;
+       int core, n, cpu, count, val;
 
        for (n = 0; n < NLM_NR_NODES; n++) {
                syspcibase = nlm_get_sys_pcibase(n);
                if (nlm_read_reg(syspcibase, 0) == 0xffffffff)
                        break;
 
-               /* read cores in reset from SYS and account for boot cpu */
-               nlm_node_init(n);
+               /* read cores in reset from SYS */
+               if (n != 0)
+                       nlm_node_init(n);
                nodep = nlm_get_node(n);
                syscoremask = nlm_read_sys_reg(nodep->sysbase, SYS_CPU_RESET);
-               if (n == 0)
+               /* The boot cpu */
+               if (n == 0) {
                        syscoremask |= 1;
+                       nodep->coremask = 1;
+               }
 
                for (core = 0; core < NLM_CORES_PER_NODE; core++) {
+                       /* we will be on node 0 core 0 */
+                       if (n == 0 && core == 0)
+                               continue;
+
                        /* see if the core exists */
                        if ((syscoremask & (1 << core)) == 0)
                                continue;
 
-                       /* see if at least the first thread is enabled */
+                       /* see if at least the first hw thread is enabled */
                        cpu = (n * NLM_CORES_PER_NODE + core)
                                                * NLM_THREADS_PER_CORE;
                        if (!cpumask_test_cpu(cpu, wakeup_mask))
                                continue;
 
                        /* wake up the core */
-                       if (xlp_wakeup_core(nodep->sysbase, core))
-                               nodep->coremask |= 1u << core;
-                       else
-                               pr_err("Failed to enable core %d\n", core);
+                       if (!xlp_wakeup_core(nodep->sysbase, n, core))
+                               continue;
+
+                       /* core is up */
+                       nodep->coremask |= 1u << core;
+
+                       /* spin until the first hw thread sets its ready */
+                       count = 0x20000000;
+                       do {
+                               val = *(volatile int *)&nlm_cpu_ready[cpu];
+                       } while (val == 0 && --count > 0);
                }
        }
 }