Merge tag 'v3.10.69' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm64 / kernel / setup.c
index add6ea616843139ff81a65f26c344ed9e69fd66d..21ad76b0495f99895e3f111022f2e52dba373121 100644 (file)
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
+#include <linux/personality.h>
 
 #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 +110,108 @@ void __init early_print(const char *str, ...)
        printk("%s", buf);
 }
 
+struct cpuinfo_arm64 {
+       struct cpu      cpu;
+       u32             reg_midr;
+};
+
+static DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
+
+void cpuinfo_store_cpu(void)
+{
+       struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
+       info->reg_midr = read_cpuid_id();
+}
+
 static void __init setup_processor(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 +226,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)
@@ -127,6 +264,8 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
        struct boot_param_header *devtree;
        unsigned long dt_root;
 
+       cpuinfo_store_cpu();
+
        /* Check we have a non-NULL DT pointer */
        if (!dt_phys) {
                early_print("\n"
@@ -269,8 +408,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 +421,7 @@ void __init setup_arch(char **cmdline_p)
        conswitchp = &dummy_con;
 #endif
 #endif
+
 }
 
 static int __init arm64_device_init(void)
@@ -288,16 +430,14 @@ 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);
-
-static DEFINE_PER_CPU(struct cpu, cpu_data);
+arch_initcall_sync(arm64_device_init);
 
 static int __init topology_init(void)
 {
        int i;
 
        for_each_possible_cpu(i) {
-               struct cpu *cpu = &per_cpu(cpu_data, i);
+               struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
                cpu->hotpluggable = 1;
                register_cpu(cpu, i);
        }
@@ -309,17 +449,50 @@ subsys_initcall(topology_init);
 static const char *hwcap_str[] = {
        "fp",
        "asimd",
+       "evtstrm",
+       "aes",
+       "pmull",
+       "sha1",
+       "sha2",
+       "crc32",
        NULL
 };
 
+#ifdef CONFIG_COMPAT
+static const char *compat_hwcap_str[] = {
+       "swp",
+       "half",
+       "thumb",
+       "26bit",
+       "fastmult",
+       "fpa",
+       "vfp",
+       "edsp",
+       "java",
+       "iwmmxt",
+       "crunch",
+       "thumbee",
+       "neon",
+       "vfpv3",
+       "vfpv3d16",
+       "tls",
+       "vfpv4",
+       "idiva",
+       "idivt",
+       "vfpd32",
+       "lpae",
+       "evtstrm"
+};
+#endif /* CONFIG_COMPAT */
+
 static int c_show(struct seq_file *m, void *v)
 {
-       int i;
-
-       seq_printf(m, "Processor\t: %s rev %d (%s)\n",
-                  cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
+       int i, j;
 
        for_each_online_cpu(i) {
+               struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
+               u32 midr = cpuinfo->reg_midr;
+
                /*
                 * glibc reads /proc/cpuinfo to determine the number of
                 * online processors, looking for lines beginning with
@@ -328,27 +501,36 @@ static int c_show(struct seq_file *m, void *v)
 #ifdef CONFIG_SMP
                seq_printf(m, "processor\t: %d\n", i);
 #endif
-               seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
+               seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
                           loops_per_jiffy / (500000UL/HZ),
                           loops_per_jiffy / (5000UL/HZ) % 100);
-       }
 
-       /* dump out the processor features */
-       seq_puts(m, "Features\t: ");
-
-       for (i = 0; hwcap_str[i]; i++)
-               if (elf_hwcap & (1 << i))
-                       seq_printf(m, "%s ", hwcap_str[i]);
-
-       seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
-       seq_printf(m, "CPU architecture: AArch64\n");
-       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);
-
-       seq_puts(m, "\n");
-
-       seq_printf(m, "Hardware\t: %s\n", machine_name);
+               /*
+                * Dump out the common processor features in a single line.
+                * Userspace should read the hwcaps with getauxval(AT_HWCAP)
+                * rather than attempting to parse this, but there's a body of
+                * software which does already (at least for 32-bit).
+                */
+               seq_puts(m, "Features\t:");
+               if (personality(current->personality) == PER_LINUX32) {
+#ifdef CONFIG_COMPAT
+                       for (j = 0; compat_hwcap_str[j]; j++)
+                               if (COMPAT_ELF_HWCAP & (1 << j))
+                                       seq_printf(m, " %s", compat_hwcap_str[j]);
+#endif /* CONFIG_COMPAT */
+               } else {
+                       for (j = 0; hwcap_str[j]; j++)
+                               if (elf_hwcap & (1 << j))
+                                       seq_printf(m, " %s", hwcap_str[j]);
+               }
+               seq_puts(m, "\n");
+
+               seq_printf(m, "CPU implementer\t: 0x%02x\n", (midr >> 24));
+               seq_printf(m, "CPU architecture: 8\n");
+               seq_printf(m, "CPU variant\t: 0x%x\n", ((midr >> 20) & 0xf));
+               seq_printf(m, "CPU part\t: 0x%03x\n", ((midr >> 4) & 0xfff));
+               seq_printf(m, "CPU revision\t: %d\n\n", (midr & 0xf));
+       }
 
        return 0;
 }