MIPS: smp-cps: Clear Status IPL field when using EIC
[linux-2.6-block.git] / arch / mips / kernel / smp-cps.c
index 253e1409338c146706ffb730952fb880c30e5b5d..4ed36f288d64600610bca35e30e96be472d08e8f 100644 (file)
 #include <asm/time.h>
 #include <asm/uasm.h>
 
+static bool threads_disabled;
 static DECLARE_BITMAP(core_power, NR_CPUS);
 
 struct core_boot_config *mips_cps_core_bootcfg;
 
+static int __init setup_nothreads(char *s)
+{
+       threads_disabled = true;
+       return 0;
+}
+early_param("nothreads", setup_nothreads);
+
 static unsigned core_vpe_count(unsigned core)
 {
        unsigned cfg;
 
-       if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
+       if (threads_disabled)
+               return 1;
+
+       if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
+               && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
                return 1;
 
        mips_cm_lock_other(core, 0);
@@ -47,11 +59,12 @@ static unsigned core_vpe_count(unsigned core)
 static void __init cps_smp_setup(void)
 {
        unsigned int ncores, nvpes, core_vpes;
+       unsigned long core_entry;
        int c, v;
 
        /* Detect & record VPE topology */
        ncores = mips_cm_numcores();
-       pr_info("VPE topology ");
+       pr_info("%s topology ", cpu_has_mips_r6 ? "VP" : "VPE");
        for (c = nvpes = 0; c < ncores; c++) {
                core_vpes = core_vpe_count(c);
                pr_cont("%c%u", c ? ',' : '{', core_vpes);
@@ -62,7 +75,7 @@ static void __init cps_smp_setup(void)
 
                for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) {
                        cpu_data[nvpes + v].core = c;
-#ifdef CONFIG_MIPS_MT_SMP
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6)
                        cpu_data[nvpes + v].vpe_id = v;
 #endif
                }
@@ -91,6 +104,11 @@ static void __init cps_smp_setup(void)
        /* Make core 0 coherent with everything */
        write_gcr_cl_coherence(0xff);
 
+       if (mips_cm_revision() >= CM_REV_CM3) {
+               core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
+               write_gcr_bev_base(core_entry);
+       }
+
 #ifdef CONFIG_MIPS_MT_FPAFF
        /* If we have an FPU, enroll ourselves in the FPU-full mask */
        if (cpu_has_fpu)
@@ -213,6 +231,18 @@ static void boot_core(unsigned core)
        if (mips_cpc_present()) {
                /* Reset the core */
                mips_cpc_lock_other(core);
+
+               if (mips_cm_revision() >= CM_REV_CM3) {
+                       /* Run VP0 following the reset */
+                       write_cpc_co_vp_run(0x1);
+
+                       /*
+                        * Ensure that the VP_RUN register is written before the
+                        * core leaves reset.
+                        */
+                       wmb();
+               }
+
                write_cpc_co_cmd(CPC_Cx_CMD_RESET);
 
                timeout = 100;
@@ -250,7 +280,10 @@ static void boot_core(unsigned core)
 
 static void remote_vpe_boot(void *dummy)
 {
-       mips_cps_boot_vpes();
+       unsigned core = current_cpu_data.core;
+       struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
+
+       mips_cps_boot_vpes(core_cfg, cpu_vpe_id(&current_cpu_data));
 }
 
 static void cps_boot_secondary(int cpu, struct task_struct *idle)
@@ -259,6 +292,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
        unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
        struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
        struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
+       unsigned long core_entry;
        unsigned int remote;
        int err;
 
@@ -276,6 +310,13 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
                goto out;
        }
 
+       if (cpu_has_vp) {
+               mips_cm_lock_other(core, vpe_id);
+               core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
+               write_gcr_co_reset_base(core_entry);
+               mips_cm_unlock_other();
+       }
+
        if (core != current_cpu_data.core) {
                /* Boot a VPE on another powered up core */
                for (remote = 0; remote < NR_CPUS; remote++) {
@@ -293,10 +334,10 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
                goto out;
        }
 
-       BUG_ON(!cpu_has_mipsmt);
+       BUG_ON(!cpu_has_mipsmt && !cpu_has_vp);
 
        /* Boot a VPE on this core */
-       mips_cps_boot_vpes();
+       mips_cps_boot_vpes(core_cfg, vpe_id);
 out:
        preempt_enable();
 }
@@ -307,8 +348,23 @@ static void cps_init_secondary(void)
        if (cpu_has_mipsmt)
                dmt();
 
-       change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 |
-                                STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7);
+       if (mips_cm_revision() >= CM_REV_CM3) {
+               unsigned ident = gic_read_local_vp_id();
+
+               /*
+                * Ensure that our calculation of the VP ID matches up with
+                * what the GIC reports, otherwise we'll have configured
+                * interrupts incorrectly.
+                */
+               BUG_ON(ident != mips_cm_vp_id(smp_processor_id()));
+       }
+
+       if (cpu_has_veic)
+               clear_c0_status(ST0_IM);
+       else
+               change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 |
+                                        STATUSF_IP4 | STATUSF_IP5 |
+                                        STATUSF_IP6 | STATUSF_IP7);
 }
 
 static void cps_smp_finish(void)