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);
 };
 
        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;
                (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)
 {
             (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
                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);