i386: move video
[firefly-linux-kernel-4.4.55.git] / arch / i386 / kernel / cpu / intel_cacheinfo.c
index 80b4c5d421b1366915028b2002af39cdae851c95..db6c25aa57768f67f7cdb4a794ece94aece18fa0 100644 (file)
@@ -4,7 +4,7 @@
  *      Changes:
  *      Venkatesh Pallipadi    : Adding cache identification through cpuid(4)
  *             Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
- *     Andi Kleen              : CPUID4 emulation on AMD.
+ *     Andi Kleen / Andreas Herrmann   : CPUID4 emulation on AMD.
  */
 
 #include <linux/init.h>
@@ -135,7 +135,7 @@ unsigned short                      num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
    information to the user.  This makes some assumptions about the machine:
-   No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs.
+   L2 not shared, no SMT etc. that is currently true on AMD CPUs.
 
    In theory the TLBs could be reported as fake type (they are in "dummy").
    Maybe later */
@@ -159,13 +159,26 @@ union l2_cache {
        unsigned val;
 };
 
+union l3_cache {
+       struct {
+               unsigned line_size : 8;
+               unsigned lines_per_tag : 4;
+               unsigned assoc : 4;
+               unsigned res : 2;
+               unsigned size_encoded : 14;
+       };
+       unsigned val;
+};
+
 static const unsigned short assocs[] = {
        [1] = 1, [2] = 2, [4] = 4, [6] = 8,
-       [8] = 16,
+       [8] = 16, [0xa] = 32, [0xb] = 48,
+       [0xc] = 64,
        [0xf] = 0xffff // ??
-       };
-static const unsigned char levels[] = { 1, 1, 2 };
-static const unsigned char types[] = { 1, 2, 3 };
+};
+
+static const unsigned char levels[] = { 1, 1, 2, 3 };
+static const unsigned char types[] = { 1, 2, 3, 3 };
 
 static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                       union _cpuid4_leaf_ebx *ebx,
@@ -175,37 +188,58 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
        unsigned line_size, lines_per_tag, assoc, size_in_kb;
        union l1_cache l1i, l1d;
        union l2_cache l2;
+       union l3_cache l3;
+       union l1_cache *l1 = &l1d;
 
        eax->full = 0;
        ebx->full = 0;
        ecx->full = 0;
 
        cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
-       cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy);
-
-       if (leaf > 2 || !l1d.val || !l1i.val || !l2.val)
-               return;
-
-       eax->split.is_self_initializing = 1;
-       eax->split.type = types[leaf];
-       eax->split.level = levels[leaf];
-       eax->split.num_threads_sharing = 0;
-       eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
-
-       if (leaf <= 1) {
-               union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
+       cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
+
+       switch (leaf) {
+       case 1:
+               l1 = &l1i;
+       case 0:
+               if (!l1->val)
+                       return;
                assoc = l1->assoc;
                line_size = l1->line_size;
                lines_per_tag = l1->lines_per_tag;
                size_in_kb = l1->size_in_kb;
-       } else {
+               break;
+       case 2:
+               if (!l2.val)
+                       return;
                assoc = l2.assoc;
                line_size = l2.line_size;
                lines_per_tag = l2.lines_per_tag;
                /* cpu_data has errata corrections for K7 applied */
                size_in_kb = current_cpu_data.x86_cache_size;
+               break;
+       case 3:
+               if (!l3.val)
+                       return;
+               assoc = l3.assoc;
+               line_size = l3.line_size;
+               lines_per_tag = l3.lines_per_tag;
+               size_in_kb = l3.size_encoded * 512;
+               break;
+       default:
+               return;
        }
 
+       eax->split.is_self_initializing = 1;
+       eax->split.type = types[leaf];
+       eax->split.level = levels[leaf];
+       if (leaf == 3)
+               eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
+       else
+               eax->split.num_threads_sharing = 0;
+       eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
+
+
        if (assoc == 0xf)
                eax->split.is_fully_associative = 1;
        ebx->split.coherency_line_size = line_size - 1;
@@ -239,8 +273,7 @@ static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_le
        return 0;
 }
 
-/* will only be called once; __init is safe here */
-static int __init find_num_cache_leaves(void)
+static int __cpuinit find_num_cache_leaves(void)
 {
        unsigned int            eax, ebx, ecx, edx;
        union _cpuid4_leaf_eax  cache_eax;
@@ -482,7 +515,7 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu)
 
        cpuid4_info[cpu] = kzalloc(
            sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
-       if (unlikely(cpuid4_info[cpu] == NULL))
+       if (cpuid4_info[cpu] == NULL)
                return -ENOMEM;
 
        oldmask = current->cpus_allowed;
@@ -710,11 +743,13 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
        return retval;
 }
 
-static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
+static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        unsigned long i;
 
+       if (cpuid4_info[cpu] == NULL)
+               return;
        for (i = 0; i < num_cache_leaves; i++) {
                cache_remove_shared_cpu_map(cpu, i);
                kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
@@ -733,9 +768,11 @@ static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
        sys_dev = get_cpu_sysdev(cpu);
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cache_add_dev(sys_dev);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                cache_remove_dev(sys_dev);
                break;
        }