MIPS: smp-cps: prevent multi-core SMP with unsuitable CCA
authorPaul Burton <paul.burton@imgtec.com>
Mon, 14 Apr 2014 14:21:25 +0000 (15:21 +0100)
committerPaul Burton <paul.burton@imgtec.com>
Wed, 28 May 2014 15:20:32 +0000 (16:20 +0100)
If the user or bootloader sets the CCA to a value which is not suited
for multi-core SMP (ie. anything non-coherent) then limit the system to
using only a single core and warn the user.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
arch/mips/kernel/smp-cps.c

index 3c30891fc7890f1a2d0590de7bd50be5d928ce90..e2f78b34ff93550c6016dd17ceac66eb9eeaad81 100644 (file)
@@ -88,11 +88,38 @@ static void __init cps_smp_setup(void)
 
 static void __init cps_prepare_cpus(unsigned int max_cpus)
 {
-       unsigned ncores, core_vpes, c;
+       unsigned ncores, core_vpes, c, cca;
+       bool cca_unsuitable;
        u32 *entry_code;
 
        mips_mt_set_cpuoptions();
 
+       /* Detect whether the CCA is unsuited to multi-core SMP */
+       cca = read_c0_config() & CONF_CM_CMASK;
+       switch (cca) {
+       case 0x4: /* CWBE */
+       case 0x5: /* CWB */
+               /* The CCA is coherent, multi-core is fine */
+               cca_unsuitable = false;
+               break;
+
+       default:
+               /* CCA is not coherent, multi-core is not usable */
+               cca_unsuitable = true;
+       }
+
+       /* Warn the user if the CCA prevents multi-core */
+       ncores = mips_cm_numcores();
+       if (cca_unsuitable && ncores > 1) {
+               pr_warn("Using only one core due to unsuitable CCA 0x%x\n",
+                       cca);
+
+               for_each_present_cpu(c) {
+                       if (cpu_data[c].core)
+                               set_cpu_present(c, false);
+               }
+       }
+
        /* Patch the start of mips_cps_core_entry to provide the CM base */
        entry_code = (u32 *)&mips_cps_core_entry;
        UASM_i_LA(&entry_code, 3, (long)mips_cm_base);
@@ -100,7 +127,6 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
                            (void *)entry_code - (void *)&mips_cps_core_entry);
 
        /* Allocate core boot configuration structs */
-       ncores = mips_cm_numcores();
        mips_cps_core_bootcfg = kcalloc(ncores, sizeof(*mips_cps_core_bootcfg),
                                        GFP_KERNEL);
        if (!mips_cps_core_bootcfg) {