import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm64 / kernel / setup.c
index add6ea616843139ff81a65f26c344ed9e69fd66d..268f504664fb2143601e2414435c7084a0d7c592 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/cputype.h>
 #include <asm/elf.h>
 #include <asm/cputable.h>
+#include <asm/cpu_ops.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/smp_plat.h>
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
 
-unsigned int elf_hwcap __read_mostly;
+unsigned long elf_hwcap __read_mostly;
 EXPORT_SYMBOL_GPL(elf_hwcap);
 
+#ifdef CONFIG_COMPAT
+#define COMPAT_ELF_HWCAP_DEFAULT       \
+                               (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
+                                COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
+                                COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
+                                COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
+                                COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
+unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
+unsigned int compat_elf_hwcap2 __read_mostly;
+#endif
+
 static const char *cpu_name;
 static const char *machine_name;
 phys_addr_t __fdt_pointer __initdata;
@@ -97,15 +109,95 @@ void __init early_print(const char *str, ...)
        printk("%s", buf);
 }
 
-static void __init setup_processor(void)
+void __init smp_setup_processor_id(void)
 {
-       struct cpu_info *cpu_info;
+       /*
+        * clear __my_cpu_offset on boot CPU to avoid hang caused by
+        * using percpu variable early, for example, lockdep will
+        * access percpu variable inside lock_release
+        */
+       set_my_cpu_offset(0);
+}
+
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+       return phys_id == cpu_logical_map(cpu);
+}
 
+struct mpidr_hash mpidr_hash;
+#ifdef CONFIG_SMP
+/**
+ * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
+ *                       level in order to build a linear index from an
+ *                       MPIDR value. Resulting algorithm is a collision
+ *                       free hash carried out through shifting and ORing
+ */
+static void __init smp_build_mpidr_hash(void)
+{
+       u32 i, affinity, fs[4], bits[4], ls;
+       u64 mask = 0;
+       /*
+        * Pre-scan the list of MPIDRS and filter out bits that do
+        * not contribute to affinity levels, ie they never toggle.
+        */
+       for_each_possible_cpu(i)
+               mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
+       pr_debug("mask of set bits %#llx\n", mask);
+       /*
+        * Find and stash the last and first bit set at all affinity levels to
+        * check how many bits are required to represent them.
+        */
+       for (i = 0; i < 4; i++) {
+               affinity = MPIDR_AFFINITY_LEVEL(mask, i);
+               /*
+                * Find the MSB bit and LSB bits position
+                * to determine how many bits are required
+                * to express the affinity level.
+                */
+               ls = fls(affinity);
+               fs[i] = affinity ? ffs(affinity) - 1 : 0;
+               bits[i] = ls - fs[i];
+       }
        /*
-        * locate processor in the list of supported processor
-        * types.  The linker builds this table for us from the
-        * entries in arch/arm/mm/proc.S
+        * An index can be created from the MPIDR_EL1 by isolating the
+        * significant bits at each affinity level and by shifting
+        * them in order to compress the 32 bits values space to a
+        * compressed set of values. This is equivalent to hashing
+        * the MPIDR_EL1 through shifting and ORing. It is a collision free
+        * hash though not minimal since some levels might contain a number
+        * of CPUs that is not an exact power of 2 and their bit
+        * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}.
         */
+       mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0];
+       mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0];
+       mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] -
+                                               (bits[1] + bits[0]);
+       mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) +
+                                 fs[3] - (bits[2] + bits[1] + bits[0]);
+       mpidr_hash.mask = mask;
+       mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0];
+       pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n",
+               mpidr_hash.shift_aff[0],
+               mpidr_hash.shift_aff[1],
+               mpidr_hash.shift_aff[2],
+               mpidr_hash.shift_aff[3],
+               mpidr_hash.mask,
+               mpidr_hash.bits);
+       /*
+        * 4x is an arbitrary value used to warn on a hash table much bigger
+        * than expected on most systems.
+        */
+       if (mpidr_hash_size() > 4 * num_possible_cpus())
+               pr_warn("Large number of MPIDR hash buckets detected\n");
+       __flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash));
+}
+#endif
+
+static void __init setup_processor(void)
+{
+       struct cpu_info *cpu_info;
+       u64 features, block;
+
        cpu_info = lookup_processor_type(read_cpuid_id());
        if (!cpu_info) {
                printk("CPU configuration botched (ID %08x), unable to continue.\n",
@@ -120,6 +212,37 @@ static void __init setup_processor(void)
 
        sprintf(init_utsname()->machine, "aarch64");
        elf_hwcap = 0;
+
+       /*
+        * ID_AA64ISAR0_EL1 contains 4-bit wide signed feature blocks.
+        * The blocks we test below represent incremental functionality
+        * for non-negative values. Negative values are reserved.
+        */
+       features = read_cpuid(ID_AA64ISAR0_EL1);
+       block = (features >> 4) & 0xf;
+       if (!(block & 0x8)) {
+               switch (block) {
+               default:
+               case 2:
+                       elf_hwcap |= HWCAP_PMULL;
+               case 1:
+                       elf_hwcap |= HWCAP_AES;
+               case 0:
+                       break;
+               }
+       }
+
+       block = (features >> 8) & 0xf;
+       if (block && !(block & 0x8))
+               elf_hwcap |= HWCAP_SHA1;
+
+       block = (features >> 12) & 0xf;
+       if (block && !(block & 0x8))
+               elf_hwcap |= HWCAP_SHA2;
+
+       block = (features >> 16) & 0xf;
+       if (block && !(block & 0x8))
+               elf_hwcap |= HWCAP_CRC32;
 }
 
 static void __init setup_machine_fdt(phys_addr_t dt_phys)
@@ -269,8 +392,10 @@ void __init setup_arch(char **cmdline_p)
        psci_init();
 
        cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+       cpu_read_bootcpu_ops();
 #ifdef CONFIG_SMP
        smp_init_cpus();
+       smp_build_mpidr_hash();
 #endif
 
 #ifdef CONFIG_VT
@@ -280,6 +405,7 @@ void __init setup_arch(char **cmdline_p)
        conswitchp = &dummy_con;
 #endif
 #endif
+
 }
 
 static int __init arm64_device_init(void)
@@ -288,7 +414,7 @@ static int __init arm64_device_init(void)
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
        return 0;
 }
-arch_initcall(arm64_device_init);
+arch_initcall_sync(arm64_device_init);
 
 static DEFINE_PER_CPU(struct cpu, cpu_data);
 
@@ -309,6 +435,12 @@ subsys_initcall(topology_init);
 static const char *hwcap_str[] = {
        "fp",
        "asimd",
+       "evtstrm",
+       "aes",
+       "pmull",
+       "sha1",
+       "sha2",
+       "crc32",
        NULL
 };
 
@@ -339,9 +471,20 @@ static int c_show(struct seq_file *m, void *v)
        for (i = 0; hwcap_str[i]; i++)
                if (elf_hwcap & (1 << i))
                        seq_printf(m, "%s ", hwcap_str[i]);
+#ifdef CONFIG_ARMV7_COMPAT_CPUINFO
+       if (is_compat_task()) {
+               /* Print out the non-optional ARMv8 HW capabilities */
+               seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi ");
+               seq_printf(m, "vfpv4 idiva idivt ");
+       }
+#endif
 
        seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
-       seq_printf(m, "CPU architecture: AArch64\n");
+       seq_printf(m, "CPU architecture: %s\n",
+#if IS_ENABLED(CONFIG_ARMV7_COMPAT_CPUINFO)
+                       is_compat_task() ? "8" :
+#endif
+                       "AArch64");
        seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
        seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
        seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);