x86, cacheinfo: Calculate L3 indices
authorBorislav Petkov <borislav.petkov@amd.com>
Fri, 22 Jan 2010 15:01:07 +0000 (16:01 +0100)
committerH. Peter Anvin <hpa@zytor.com>
Sat, 23 Jan 2010 00:06:31 +0000 (16:06 -0800)
We need to know the valid L3 indices interval when disabling them over
/sysfs. Do that when the core is brought online and add boundary checks
to the sysfs .store attribute.

Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
LKML-Reference: <1264172467-25155-6-git-send-email-bp@amd64.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/kernel/cpu/intel_cacheinfo.c

index 3976ce95095f7b11dbf9f3dde7c16cb702bef31b..589b705e80edd125784e38a763c24adc2d6d116c 100644 (file)
@@ -151,7 +151,8 @@ struct _cpuid4_info {
        union _cpuid4_leaf_ebx ebx;
        union _cpuid4_leaf_ecx ecx;
        unsigned long size;
-       unsigned long can_disable;
+       bool can_disable;
+       unsigned int l3_indices;
        DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
 };
 
@@ -161,7 +162,8 @@ struct _cpuid4_info_regs {
        union _cpuid4_leaf_ebx ebx;
        union _cpuid4_leaf_ecx ecx;
        unsigned long size;
-       unsigned long can_disable;
+       bool can_disable;
+       unsigned int l3_indices;
 };
 
 unsigned short                 num_cache_leaves;
@@ -291,6 +293,29 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                (ebx->split.ways_of_associativity + 1) - 1;
 }
 
+static unsigned int __cpuinit amd_calc_l3_indices(void)
+{
+       /*
+        * We're called over smp_call_function_single() and therefore
+        * are on the correct cpu.
+        */
+       int cpu = smp_processor_id();
+       int node = cpu_to_node(cpu);
+       struct pci_dev *dev = node_to_k8_nb_misc(node);
+       unsigned int sc0, sc1, sc2, sc3;
+       u32 val;
+
+       pci_read_config_dword(dev, 0x1C4, &val);
+
+       /* calculate subcache sizes */
+       sc0 = !(val & BIT(0));
+       sc1 = !(val & BIT(4));
+       sc2 = !(val & BIT(8))  + !(val & BIT(9));
+       sc3 = !(val & BIT(12)) + !(val & BIT(13));
+
+       return (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
+}
+
 static void __cpuinit
 amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 {
@@ -306,7 +331,8 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
             (boot_cpu_data.x86_mask  < 0x1)))
                return;
 
-       this_leaf->can_disable = 1;
+       this_leaf->can_disable = true;
+       this_leaf->l3_indices  = amd_calc_l3_indices();
 }
 
 static int
@@ -765,7 +791,8 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
                return -EINVAL;
 
        /* do not allow writes outside of allowed bits */
-       if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX))
+       if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
+           ((val & SUBCACHE_INDEX) > this_leaf->l3_indices))
                return -EINVAL;
 
        val |= BIT(30);