ARM: hwcap: disable HWCAP_SWP if the CPU advertises it has exclusives
[firefly-linux-kernel-4.4.55.git] / arch / arm / kernel / setup.c
index 8a16ee5d8a953f6c54ed6c14ed394d7ceae1fc37..84db893dedc27c9b79edb3d3a8845f3c39e0c859 100644 (file)
@@ -393,19 +393,34 @@ static void __init cpuid_init_hwcaps(void)
                elf_hwcap |= HWCAP_LPAE;
 }
 
-static void __init feat_v6_fixup(void)
+static void __init elf_hwcap_fixup(void)
 {
-       int id = read_cpuid_id();
-
-       if ((id & 0xff0f0000) != 0x41070000)
-               return;
+       unsigned id = read_cpuid_id();
+       unsigned sync_prim;
 
        /*
         * HWCAP_TLS is available only on 1136 r1p0 and later,
         * see also kuser_get_tls_init.
         */
-       if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
+       if (read_cpuid_part() == ARM_CPU_PART_ARM1136 &&
+           ((id >> 20) & 3) == 0) {
                elf_hwcap &= ~HWCAP_TLS;
+               return;
+       }
+
+       /* Verify if CPUID scheme is implemented */
+       if ((id & 0x000f0000) != 0x000f0000)
+               return;
+
+       /*
+        * If the CPU supports LDREX/STREX and LDREXB/STREXB,
+        * avoid advertising SWP; it may not be atomic with
+        * multiprocessing cores.
+        */
+       sync_prim = ((read_cpuid_ext(CPUID_EXT_ISAR3) >> 8) & 0xf0) |
+                   ((read_cpuid_ext(CPUID_EXT_ISAR4) >> 20) & 0x0f);
+       if (sync_prim >= 0x13)
+               elf_hwcap &= ~HWCAP_SWP;
 }
 
 /*
@@ -609,7 +624,7 @@ static void __init setup_processor(void)
 #endif
        erratum_a15_798181_init();
 
-       feat_v6_fixup();
+       elf_hwcap_fixup();
 
        cacheid_init();
        cpu_init();