All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
@ 2015-01-08  7:50 Sudeep Holla
  2015-01-23 13:55 ` Thomas Gleixner
  2015-02-23 18:14 ` [PATCH RFT v2] " Sudeep Holla
  0 siblings, 2 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-01-08  7:50 UTC (permalink / raw)
  To: linux-kernel, x86
  Cc: Sudeep Holla, Thomas Gleixner, Ingo Molnar, H. Peter Anvin

This patch removes the redundant sysfs cacheinfo code by reusing
the newly introduced generic cacheinfo infrastructure through the
commit 246246cbde5e ("drivers: base: support cpu cache information
interface to userspace via sysfs")

The private pointer provided by the cacheinfo is used to implement
the AMD L3 cache specific attributes.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com> 
Cc: x86@kernel.org
---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 709 +++++++++-------------------------
 1 file changed, 189 insertions(+), 520 deletions(-)

Hi,

Since I don't have access to any AMD machines, I would appreciate
any testing on it. I have tested this on system with ntel Core i7-2600
CPUs.

Regards,
Sudeep

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index c7035073dfc1..5746aea7e9b8 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -7,16 +7,14 @@
  *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/compiler.h>
+#include <linux/cacheinfo.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/sysfs.h>
 #include <linux/pci.h>
 
 #include <asm/processor.h>
-#include <linux/smp.h>
 #include <asm/amd_nb.h>
 #include <asm/smp.h>
 
@@ -116,10 +114,10 @@ static const struct _cache_table cache_table[] =
 
 
 enum _cache_type {
-	CACHE_TYPE_NULL	= 0,
-	CACHE_TYPE_DATA = 1,
-	CACHE_TYPE_INST = 2,
-	CACHE_TYPE_UNIFIED = 3
+	CTYPE_NULL = 0,
+	CTYPE_DATA = 1,
+	CTYPE_INST = 2,
+	CTYPE_UNIFIED = 3
 };
 
 union _cpuid4_leaf_eax {
@@ -159,11 +157,6 @@ struct _cpuid4_info_regs {
 	struct amd_northbridge *nb;
 };
 
-struct _cpuid4_info {
-	struct _cpuid4_info_regs base;
-	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
-};
-
 unsigned short			num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -220,6 +213,13 @@ static const unsigned short assocs[] = {
 static const unsigned char levels[] = { 1, 1, 2, 3 };
 static const unsigned char types[] = { 1, 2, 3, 3 };
 
+static const enum cache_type cache_type_map[] = {
+	[CTYPE_NULL] = CACHE_TYPE_NOCACHE,
+	[CTYPE_DATA] = CACHE_TYPE_DATA,
+	[CTYPE_INST] = CACHE_TYPE_INST,
+	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
+};
+
 static void
 amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		     union _cpuid4_leaf_ebx *ebx,
@@ -291,14 +291,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
-struct _cache_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);
-	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,
-			 unsigned int);
-};
-
 #if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
+
 /*
  * L3 cache descriptors
  */
@@ -325,20 +319,6 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb)
 	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
-static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
-{
-	int node;
-
-	/* only for L3, and not in virtualized environments */
-	if (index < 3)
-		return;
-
-	node = amd_get_nb_id(smp_processor_id());
-	this_leaf->nb = node_to_amd_nb(node);
-	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
-		amd_calc_l3_indices(this_leaf->nb);
-}
-
 /*
  * check whether a slot used for disabling an L3 index is occupied.
  * @l3: L3 cache descriptor
@@ -359,15 +339,13 @@ int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot)
 	return -1;
 }
 
-static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
+static ssize_t show_cache_disable(struct cacheinfo *this_leaf, char *buf,
 				  unsigned int slot)
 {
 	int index;
+	struct amd_northbridge *nb = this_leaf->priv;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	index = amd_get_l3_disable_slot(this_leaf->base.nb, slot);
+	index = amd_get_l3_disable_slot(nb, slot);
 	if (index >= 0)
 		return sprintf(buf, "%d\n", index);
 
@@ -376,9 +354,10 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 
 #define SHOW_CACHE_DISABLE(slot)					\
 static ssize_t								\
-show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf,	\
-			  unsigned int cpu)				\
+cache_disable_##slot##_show(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return show_cache_disable(this_leaf, buf, slot);		\
 }
 SHOW_CACHE_DISABLE(0)
@@ -446,25 +425,23 @@ int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot,
 	return 0;
 }
 
-static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
-				  const char *buf, size_t count,
-				  unsigned int slot)
+static ssize_t store_cache_disable(struct cacheinfo *this_leaf,
+				   const char *buf, size_t count,
+				   unsigned int slot)
 {
 	unsigned long val = 0;
 	int cpu, err = 0;
+	struct amd_northbridge *nb = this_leaf->priv;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
+	cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	if (kstrtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	err = amd_set_l3_disable_slot(this_leaf->base.nb, cpu, slot, val);
+	err = amd_set_l3_disable_slot(nb, cpu, slot, val);
 	if (err) {
 		if (err == -EEXIST)
 			pr_warning("L3 slot %d in use/index already disabled!\n",
@@ -476,41 +453,36 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 
 #define STORE_CACHE_DISABLE(slot)					\
 static ssize_t								\
-store_cache_disable_##slot(struct _cpuid4_info *this_leaf,		\
-			   const char *buf, size_t count,		\
-			   unsigned int cpu)				\
+cache_disable_##slot##_store(struct device *dev,			\
+			     struct device_attribute *attr,		\
+			     const char *buf, size_t count)		\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return store_cache_disable(this_leaf, buf, count, slot);	\
 }
 STORE_CACHE_DISABLE(0)
 STORE_CACHE_DISABLE(1)
 
-static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
-		show_cache_disable_0, store_cache_disable_0);
-static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
-		show_cache_disable_1, store_cache_disable_1);
-
-static ssize_t
-show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)
+static ssize_t subcaches_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
 }
 
-static ssize_t
-store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
-		unsigned int cpu)
+static ssize_t subcaches_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
 {
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 	unsigned long val;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
-
 	if (kstrtoul(buf, 16, &val) < 0)
 		return -EINVAL;
 
@@ -520,9 +492,88 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
 	return count;
 }
 
-static struct _cache_attr subcaches =
-	__ATTR(subcaches, 0644, show_subcaches, store_subcaches);
+static DEVICE_ATTR_RW(cache_disable_0);
+static DEVICE_ATTR_RW(cache_disable_1);
+static DEVICE_ATTR_RW(subcaches);
+
+static umode_t
+cache_private_attrs_is_visible(struct kobject *kobj,
+			       struct attribute *attr, int unused)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	umode_t mode = attr->mode;
+
+	if (!this_leaf->priv)
+		return 0;
+
+	if ((attr == &dev_attr_subcaches.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		return mode;
+
+	if ((attr == &dev_attr_cache_disable_0.attr ||
+	     attr == &dev_attr_cache_disable_1.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		return mode;
+
+	return 0;
+}
+
+static struct attribute_group cache_private_group = {
+	.is_visible = cache_private_attrs_is_visible,
+};
+
+static void init_amd_l3_attrs(void)
+{
+	int n = 1;
+	static struct attribute **amd_l3_attrs;
+
+	if (amd_l3_attrs) /* already initialized */
+		return;
+
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		n += 2;
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		n += 1;
+
+	amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
+	if (!amd_l3_attrs)
+		return;
+
+	n = 0;
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
+	}
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
+
+	cache_private_group.attrs = amd_l3_attrs;
+}
+
+const struct attribute_group *
+cache_get_priv_group(struct cacheinfo *this_leaf)
+{
+	if (!this_leaf->priv || !cache_private_group.attrs)
+		return NULL;
+	return &cache_private_group;
+}
+
+static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
+{
+	int node;
+
+	/* only for L3, and not in virtualized environments */
+	if (index < 3)
+		return;
 
+	node = amd_get_nb_id(smp_processor_id());
+	this_leaf->nb = node_to_amd_nb(node);
+	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices) {
+		amd_calc_l3_indices(this_leaf->nb);
+		init_amd_l3_attrs();
+	}
+}
 #else
 #define amd_init_l3_cache(x, y)
 #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
@@ -546,7 +597,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
 		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
 	}
 
-	if (eax.split.type == CACHE_TYPE_NULL)
+	if (eax.split.type == CTYPE_NULL)
 		return -EIO; /* better error ? */
 
 	this_leaf->eax = eax;
@@ -575,7 +626,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
 		/* Do cpuid(op) loop to find out num_cache_leaves */
 		cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
 		cache_eax.full = eax;
-	} while (cache_eax.split.type != CACHE_TYPE_NULL);
+	} while (cache_eax.split.type != CTYPE_NULL);
 	return i;
 }
 
@@ -626,9 +677,9 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
 			switch (this_leaf.eax.split.level) {
 			case 1:
-				if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
+				if (this_leaf.eax.split.type == CTYPE_DATA)
 					new_l1d = this_leaf.size/1024;
-				else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
+				else if (this_leaf.eax.split.type == CTYPE_INST)
 					new_l1i = this_leaf.size/1024;
 				break;
 			case 2:
@@ -747,55 +798,46 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 	return l2;
 }
 
-#ifdef CONFIG_SYSFS
-
-/* pointer to _cpuid4_info array (for each cache leaf) */
-static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(ici_cpuid4_info, x))[y]))
-
-#ifdef CONFIG_SMP
-
-static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
+static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
+				    struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf;
 	int i, sibling;
 
 	if (cpu_has_topoext) {
 		unsigned int apicid, nshared, first, last;
 
-		if (!per_cpu(ici_cpuid4_info, cpu))
-			return 0;
-
-		this_leaf = CPUID4_INFO_IDX(cpu, index);
-		nshared = this_leaf->base.eax.split.num_threads_sharing + 1;
+		this_leaf = this_cpu_ci->info_list + index;
+		nshared = base->eax.split.num_threads_sharing + 1;
 		apicid = cpu_data(cpu).apicid;
 		first = apicid - (apicid % nshared);
 		last = first + nshared - 1;
 
 		for_each_online_cpu(i) {
+			this_cpu_ci = get_cpu_cacheinfo(i);
 			apicid = cpu_data(i).apicid;
 			if ((apicid < first) || (apicid > last))
 				continue;
-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_leaf = this_cpu_ci->info_list + index;
 
 			for_each_online_cpu(sibling) {
 				apicid = cpu_data(sibling).apicid;
 				if ((apicid < first) || (apicid > last))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else if (index == 3) {
 		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_cpu_ci = get_cpu_cacheinfo(i);
+			this_leaf = this_cpu_ci->info_list + index;
 			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
 				if (!cpu_online(sibling))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else
@@ -804,459 +846,86 @@ static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
 	return 1;
 }
 
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
+static void __cache_cpumap_setup(unsigned int cpu, int index,
+				 struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf, *sibling_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf, *sibling_leaf;
 	unsigned long num_threads_sharing;
 	int index_msb, i;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 
 	if (c->x86_vendor == X86_VENDOR_AMD) {
-		if (cache_shared_amd_cpu_map_setup(cpu, index))
+		if (__cache_amd_cpumap_setup(cpu, index, base))
 			return;
 	}
 
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	num_threads_sharing = 1 + this_leaf->base.eax.split.num_threads_sharing;
+	this_leaf = this_cpu_ci->info_list + index;
+	num_threads_sharing = 1 + base->eax.split.num_threads_sharing;
 
+	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
 	if (num_threads_sharing == 1)
-		cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
-	else {
-		index_msb = get_count_order(num_threads_sharing);
-
-		for_each_online_cpu(i) {
-			if (cpu_data(i).apicid >> index_msb ==
-			    c->apicid >> index_msb) {
-				cpumask_set_cpu(i,
-					to_cpumask(this_leaf->shared_cpu_map));
-				if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
-					sibling_leaf =
-						CPUID4_INFO_IDX(i, index);
-					cpumask_set_cpu(cpu, to_cpumask(
-						sibling_leaf->shared_cpu_map));
-				}
-			}
-		}
-	}
-}
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-	struct _cpuid4_info	*this_leaf, *sibling_leaf;
-	int sibling;
-
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
-		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
-		cpumask_clear_cpu(cpu,
-				  to_cpumask(sibling_leaf->shared_cpu_map));
-	}
-}
-#else
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
-{
-}
-
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-}
-#endif
-
-static void free_cache_attributes(unsigned int cpu)
-{
-	int i;
-
-	for (i = 0; i < num_cache_leaves; i++)
-		cache_remove_shared_cpu_map(cpu, i);
-
-	kfree(per_cpu(ici_cpuid4_info, cpu));
-	per_cpu(ici_cpuid4_info, cpu) = NULL;
-}
-
-static void get_cpu_leaves(void *_retval)
-{
-	int j, *retval = _retval, cpu = smp_processor_id();
+		return;
 
-	/* Do cpuid and store the results */
-	for (j = 0; j < num_cache_leaves; j++) {
-		struct _cpuid4_info *this_leaf = CPUID4_INFO_IDX(cpu, j);
+	index_msb = get_count_order(num_threads_sharing);
 
-		*retval = cpuid4_cache_lookup_regs(j, &this_leaf->base);
-		if (unlikely(*retval < 0)) {
-			int i;
+	for_each_online_cpu(i)
+		if (cpu_data(i).apicid >> index_msb == c->apicid >> index_msb) {
+			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
 
-			for (i = 0; i < j; i++)
-				cache_remove_shared_cpu_map(cpu, i);
-			break;
+			if (i == cpu || !sib_cpu_ci->info_list)
+				continue;/* skip if itself or no cacheinfo */
+			sibling_leaf = sib_cpu_ci->info_list + index;
+			cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+			cpumask_set_cpu(cpu, &sibling_leaf->shared_cpu_map);
 		}
-		cache_shared_cpu_map_setup(cpu, j);
-	}
 }
 
-static int detect_cache_attributes(unsigned int cpu)
+static void ci_leaf_init(struct cacheinfo *this_leaf,
+			 struct _cpuid4_info_regs *base)
 {
-	int			retval;
-
-	if (num_cache_leaves == 0)
-		return -ENOENT;
-
-	per_cpu(ici_cpuid4_info, cpu) = kzalloc(
-	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return -ENOMEM;
-
-	smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
-	if (retval) {
-		kfree(per_cpu(ici_cpuid4_info, cpu));
-		per_cpu(ici_cpuid4_info, cpu) = NULL;
-	}
-
-	return retval;
-}
-
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/cpu.h>
-
-/* pointer to kobject for cpuX/cache */
-static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
-
-struct _index_kobject {
-	struct kobject kobj;
-	unsigned int cpu;
-	unsigned short index;
-};
-
-/* pointer to array of kobjects for cpuX/cache/indexY */
-static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(ici_index_kobject, x))[y]))
-
-#define show_one_plus(file_name, object, val)				\
-static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \
-				unsigned int cpu)			\
-{									\
-	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
-}
-
-show_one_plus(level, base.eax.split.level, 0);
-show_one_plus(coherency_line_size, base.ebx.split.coherency_line_size, 1);
-show_one_plus(physical_line_partition, base.ebx.split.physical_line_partition, 1);
-show_one_plus(ways_of_associativity, base.ebx.split.ways_of_associativity, 1);
-show_one_plus(number_of_sets, base.ecx.split.number_of_sets, 1);
-
-static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	return sprintf(buf, "%luK\n", this_leaf->base.size / 1024);
-}
-
-static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
-					int type, char *buf)
-{
-	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
-	int n = 0;
-
-	if (len > 1) {
-		const struct cpumask *mask;
-
-		mask = to_cpumask(this_leaf->shared_cpu_map);
-		n = type ?
-			cpulist_scnprintf(buf, len-2, mask) :
-			cpumask_scnprintf(buf, len-2, mask);
-		buf[n++] = '\n';
-		buf[n] = '\0';
-	}
-	return n;
+	this_leaf->level = base->eax.split.level;
+	this_leaf->type = cache_type_map[base->eax.split.type];
+	this_leaf->coherency_line_size =
+				base->ebx.split.coherency_line_size + 1;
+	this_leaf->ways_of_associativity =
+				base->ebx.split.ways_of_associativity + 1;
+	this_leaf->size = base->size;
+	this_leaf->number_of_sets = base->ecx.split.number_of_sets + 1;
+	this_leaf->physical_line_partition =
+				base->ebx.split.physical_line_partition + 1;
+	this_leaf->priv = base->nb;
 }
 
-static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
-					  unsigned int cpu)
+static int __init_cache_level(unsigned int cpu)
 {
-	return show_shared_cpu_map_func(leaf, 0, buf);
-}
-
-static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,
-					   unsigned int cpu)
-{
-	return show_shared_cpu_map_func(leaf, 1, buf);
-}
-
-static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	switch (this_leaf->base.eax.split.type) {
-	case CACHE_TYPE_DATA:
-		return sprintf(buf, "Data\n");
-	case CACHE_TYPE_INST:
-		return sprintf(buf, "Instruction\n");
-	case CACHE_TYPE_UNIFIED:
-		return sprintf(buf, "Unified\n");
-	default:
-		return sprintf(buf, "Unknown\n");
-	}
-}
-
-#define to_object(k)	container_of(k, struct _index_kobject, kobj)
-#define to_attr(a)	container_of(a, struct _cache_attr, attr)
-
-#define define_one_ro(_name) \
-static struct _cache_attr _name = \
-	__ATTR(_name, 0444, show_##_name, NULL)
-
-define_one_ro(level);
-define_one_ro(type);
-define_one_ro(coherency_line_size);
-define_one_ro(physical_line_partition);
-define_one_ro(ways_of_associativity);
-define_one_ro(number_of_sets);
-define_one_ro(size);
-define_one_ro(shared_cpu_map);
-define_one_ro(shared_cpu_list);
-
-static struct attribute *default_attrs[] = {
-	&type.attr,
-	&level.attr,
-	&coherency_line_size.attr,
-	&physical_line_partition.attr,
-	&ways_of_associativity.attr,
-	&number_of_sets.attr,
-	&size.attr,
-	&shared_cpu_map.attr,
-	&shared_cpu_list.attr,
-	NULL
-};
-
-#ifdef CONFIG_AMD_NB
-static struct attribute **amd_l3_attrs(void)
-{
-	static struct attribute **attrs;
-	int n;
-
-	if (attrs)
-		return attrs;
-
-	n = ARRAY_SIZE(default_attrs);
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		n += 2;
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		n += 1;
-
-	attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);
-	if (attrs == NULL)
-		return attrs = default_attrs;
-
-	for (n = 0; default_attrs[n]; n++)
-		attrs[n] = default_attrs[n];
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
-		attrs[n++] = &cache_disable_0.attr;
-		attrs[n++] = &cache_disable_1.attr;
-	}
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		attrs[n++] = &subcaches.attr;
-
-	return attrs;
-}
-#endif
-
-static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->show ?
-		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, this_leaf->cpu) :
-		0;
-	return ret;
-}
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
-static ssize_t store(struct kobject *kobj, struct attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->store ?
-		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, count, this_leaf->cpu) :
-		0;
-	return ret;
-}
-
-static const struct sysfs_ops sysfs_ops = {
-	.show   = show,
-	.store  = store,
-};
-
-static struct kobj_type ktype_cache = {
-	.sysfs_ops	= &sysfs_ops,
-	.default_attrs	= default_attrs,
-};
-
-static struct kobj_type ktype_percpu_entry = {
-	.sysfs_ops	= &sysfs_ops,
-};
-
-static void cpuid4_cache_sysfs_exit(unsigned int cpu)
-{
-	kfree(per_cpu(ici_cache_kobject, cpu));
-	kfree(per_cpu(ici_index_kobject, cpu));
-	per_cpu(ici_cache_kobject, cpu) = NULL;
-	per_cpu(ici_index_kobject, cpu) = NULL;
-	free_cache_attributes(cpu);
-}
-
-static int cpuid4_cache_sysfs_init(unsigned int cpu)
-{
-	int err;
-
-	if (num_cache_leaves == 0)
+	if (!num_cache_leaves)
 		return -ENOENT;
-
-	err = detect_cache_attributes(cpu);
-	if (err)
-		return err;
-
-	/* Allocate all required memory */
-	per_cpu(ici_cache_kobject, cpu) =
-		kzalloc(sizeof(struct kobject), GFP_KERNEL);
-	if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
-		goto err_out;
-
-	per_cpu(ici_index_kobject, cpu) = kzalloc(
-	    sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
-	if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
-		goto err_out;
-
+	if (!this_cpu_ci)
+		return -EINVAL;
+	this_cpu_ci->num_levels = 3;
+	this_cpu_ci->num_leaves = num_cache_leaves;
 	return 0;
-
-err_out:
-	cpuid4_cache_sysfs_exit(cpu);
-	return -ENOMEM;
 }
 
-static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
-
-/* Add/Remove cache interface for CPU device */
-static int cache_add_dev(struct device *dev)
+static int __populate_cache_leaves(unsigned int cpu)
 {
-	unsigned int cpu = dev->id;
-	unsigned long i, j;
-	struct _index_kobject *this_object;
-	struct _cpuid4_info   *this_leaf;
-	int retval;
-
-	retval = cpuid4_cache_sysfs_init(cpu);
-	if (unlikely(retval < 0))
-		return retval;
-
-	retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
-				      &ktype_percpu_entry,
-				      &dev->kobj, "%s", "cache");
-	if (retval < 0) {
-		cpuid4_cache_sysfs_exit(cpu);
-		return retval;
-	}
-
-	for (i = 0; i < num_cache_leaves; i++) {
-		this_object = INDEX_KOBJECT_PTR(cpu, i);
-		this_object->cpu = cpu;
-		this_object->index = i;
+	unsigned int idx, ret;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+	struct _cpuid4_info_regs id4_regs = {};
 
-		this_leaf = CPUID4_INFO_IDX(cpu, i);
-
-		ktype_cache.default_attrs = default_attrs;
-#ifdef CONFIG_AMD_NB
-		if (this_leaf->base.nb)
-			ktype_cache.default_attrs = amd_l3_attrs();
-#endif
-		retval = kobject_init_and_add(&(this_object->kobj),
-					      &ktype_cache,
-					      per_cpu(ici_cache_kobject, cpu),
-					      "index%1lu", i);
-		if (unlikely(retval)) {
-			for (j = 0; j < i; j++)
-				kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
-			kobject_put(per_cpu(ici_cache_kobject, cpu));
-			cpuid4_cache_sysfs_exit(cpu);
-			return retval;
-		}
-		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+		ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
+		if (ret)
+			return ret;
+		ci_leaf_init(this_leaf++, &id4_regs);
+		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
-	cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
-
-	kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
 	return 0;
 }
 
-static void cache_remove_dev(struct device *dev)
-{
-	unsigned int cpu = dev->id;
-	unsigned long i;
-
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return;
-	if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
-		return;
-	cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
-
-	for (i = 0; i < num_cache_leaves; i++)
-		kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
-	kobject_put(per_cpu(ici_cache_kobject, cpu));
-	cpuid4_cache_sysfs_exit(cpu);
-}
-
-static int cacheinfo_cpu_callback(struct notifier_block *nfb,
-				  unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct device *dev;
-
-	dev = get_cpu_device(cpu);
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		cache_add_dev(dev);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		cache_remove_dev(dev);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cacheinfo_cpu_notifier = {
-	.notifier_call = cacheinfo_cpu_callback,
-};
-
-static int __init cache_sysfs_init(void)
-{
-	int i, err = 0;
-
-	if (num_cache_leaves == 0)
-		return 0;
-
-	cpu_notifier_register_begin();
-	for_each_online_cpu(i) {
-		struct device *dev = get_cpu_device(i);
-
-		err = cache_add_dev(dev);
-		if (err)
-			goto out;
-	}
-	__register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-
-out:
-	cpu_notifier_register_done();
-	return err;
-}
-
-device_initcall(cache_sysfs_init);
-
-#endif
+DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
+DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-01-08  7:50 [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure Sudeep Holla
@ 2015-01-23 13:55 ` Thomas Gleixner
  2015-01-23 18:15   ` Borislav Petkov
  2015-02-23 18:14 ` [PATCH RFT v2] " Sudeep Holla
  1 sibling, 1 reply; 32+ messages in thread
From: Thomas Gleixner @ 2015-01-23 13:55 UTC (permalink / raw)
  To: Sudeep Holla; +Cc: LKML, x86, H. Peter Anvin, Ingo Molnar, Borislav Petkov

Cc: Boris

On Thu, 8 Jan 2015, Sudeep Holla wrote:

> This patch removes the redundant sysfs cacheinfo code by reusing
> the newly introduced generic cacheinfo infrastructure through the
> commit 246246cbde5e ("drivers: base: support cpu cache information
> interface to userspace via sysfs")
> 
> The private pointer provided by the cacheinfo is used to implement
> the AMD L3 cache specific attributes.
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: "H. Peter Anvin" <hpa@zytor.com> 
> Cc: x86@kernel.org
> ---
>  arch/x86/kernel/cpu/intel_cacheinfo.c | 709 +++++++++-------------------------
>  1 file changed, 189 insertions(+), 520 deletions(-)
> 
> Hi,
> 
> Since I don't have access to any AMD machines, I would appreciate
> any testing on it. I have tested this on system with ntel Core i7-2600
> CPUs.
> 
> Regards,
> Sudeep
> 
> diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
> index c7035073dfc1..5746aea7e9b8 100644
> --- a/arch/x86/kernel/cpu/intel_cacheinfo.c
> +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
> @@ -7,16 +7,14 @@
>   *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
>   */
>  
> -#include <linux/init.h>
>  #include <linux/slab.h>
> -#include <linux/device.h>
> -#include <linux/compiler.h>
> +#include <linux/cacheinfo.h>
>  #include <linux/cpu.h>
>  #include <linux/sched.h>
> +#include <linux/sysfs.h>
>  #include <linux/pci.h>
>  
>  #include <asm/processor.h>
> -#include <linux/smp.h>
>  #include <asm/amd_nb.h>
>  #include <asm/smp.h>
>  
> @@ -116,10 +114,10 @@ static const struct _cache_table cache_table[] =
>  
>  
>  enum _cache_type {
> -	CACHE_TYPE_NULL	= 0,
> -	CACHE_TYPE_DATA = 1,
> -	CACHE_TYPE_INST = 2,
> -	CACHE_TYPE_UNIFIED = 3
> +	CTYPE_NULL = 0,
> +	CTYPE_DATA = 1,
> +	CTYPE_INST = 2,
> +	CTYPE_UNIFIED = 3
>  };
>  
>  union _cpuid4_leaf_eax {
> @@ -159,11 +157,6 @@ struct _cpuid4_info_regs {
>  	struct amd_northbridge *nb;
>  };
>  
> -struct _cpuid4_info {
> -	struct _cpuid4_info_regs base;
> -	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
> -};
> -
>  unsigned short			num_cache_leaves;
>  
>  /* AMD doesn't have CPUID4. Emulate it here to report the same
> @@ -220,6 +213,13 @@ static const unsigned short assocs[] = {
>  static const unsigned char levels[] = { 1, 1, 2, 3 };
>  static const unsigned char types[] = { 1, 2, 3, 3 };
>  
> +static const enum cache_type cache_type_map[] = {
> +	[CTYPE_NULL] = CACHE_TYPE_NOCACHE,
> +	[CTYPE_DATA] = CACHE_TYPE_DATA,
> +	[CTYPE_INST] = CACHE_TYPE_INST,
> +	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
> +};
> +
>  static void
>  amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
>  		     union _cpuid4_leaf_ebx *ebx,
> @@ -291,14 +291,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
>  		(ebx->split.ways_of_associativity + 1) - 1;
>  }
>  
> -struct _cache_attr {
> -	struct attribute attr;
> -	ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);
> -	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,
> -			 unsigned int);
> -};
> -
>  #if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
> +
>  /*
>   * L3 cache descriptors
>   */
> @@ -325,20 +319,6 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb)
>  	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
>  }
>  
> -static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
> -{
> -	int node;
> -
> -	/* only for L3, and not in virtualized environments */
> -	if (index < 3)
> -		return;
> -
> -	node = amd_get_nb_id(smp_processor_id());
> -	this_leaf->nb = node_to_amd_nb(node);
> -	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
> -		amd_calc_l3_indices(this_leaf->nb);
> -}
> -
>  /*
>   * check whether a slot used for disabling an L3 index is occupied.
>   * @l3: L3 cache descriptor
> @@ -359,15 +339,13 @@ int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot)
>  	return -1;
>  }
>  
> -static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
> +static ssize_t show_cache_disable(struct cacheinfo *this_leaf, char *buf,
>  				  unsigned int slot)
>  {
>  	int index;
> +	struct amd_northbridge *nb = this_leaf->priv;
>  
> -	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
> -		return -EINVAL;
> -
> -	index = amd_get_l3_disable_slot(this_leaf->base.nb, slot);
> +	index = amd_get_l3_disable_slot(nb, slot);
>  	if (index >= 0)
>  		return sprintf(buf, "%d\n", index);
>  
> @@ -376,9 +354,10 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
>  
>  #define SHOW_CACHE_DISABLE(slot)					\
>  static ssize_t								\
> -show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf,	\
> -			  unsigned int cpu)				\
> +cache_disable_##slot##_show(struct device *dev,				\
> +			    struct device_attribute *attr, char *buf)	\
>  {									\
> +	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
>  	return show_cache_disable(this_leaf, buf, slot);		\
>  }
>  SHOW_CACHE_DISABLE(0)
> @@ -446,25 +425,23 @@ int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot,
>  	return 0;
>  }
>  
> -static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
> -				  const char *buf, size_t count,
> -				  unsigned int slot)
> +static ssize_t store_cache_disable(struct cacheinfo *this_leaf,
> +				   const char *buf, size_t count,
> +				   unsigned int slot)
>  {
>  	unsigned long val = 0;
>  	int cpu, err = 0;
> +	struct amd_northbridge *nb = this_leaf->priv;
>  
>  	if (!capable(CAP_SYS_ADMIN))
>  		return -EPERM;
>  
> -	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
> -		return -EINVAL;
> -
> -	cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
> +	cpu = cpumask_first(&this_leaf->shared_cpu_map);
>  
>  	if (kstrtoul(buf, 10, &val) < 0)
>  		return -EINVAL;
>  
> -	err = amd_set_l3_disable_slot(this_leaf->base.nb, cpu, slot, val);
> +	err = amd_set_l3_disable_slot(nb, cpu, slot, val);
>  	if (err) {
>  		if (err == -EEXIST)
>  			pr_warning("L3 slot %d in use/index already disabled!\n",
> @@ -476,41 +453,36 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
>  
>  #define STORE_CACHE_DISABLE(slot)					\
>  static ssize_t								\
> -store_cache_disable_##slot(struct _cpuid4_info *this_leaf,		\
> -			   const char *buf, size_t count,		\
> -			   unsigned int cpu)				\
> +cache_disable_##slot##_store(struct device *dev,			\
> +			     struct device_attribute *attr,		\
> +			     const char *buf, size_t count)		\
>  {									\
> +	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
>  	return store_cache_disable(this_leaf, buf, count, slot);	\
>  }
>  STORE_CACHE_DISABLE(0)
>  STORE_CACHE_DISABLE(1)
>  
> -static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
> -		show_cache_disable_0, store_cache_disable_0);
> -static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
> -		show_cache_disable_1, store_cache_disable_1);
> -
> -static ssize_t
> -show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)
> +static ssize_t subcaches_show(struct device *dev,
> +			      struct device_attribute *attr, char *buf)
>  {
> -	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> -		return -EINVAL;
> +	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
> +	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
>  
>  	return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
>  }
>  
> -static ssize_t
> -store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
> -		unsigned int cpu)
> +static ssize_t subcaches_store(struct device *dev,
> +			       struct device_attribute *attr,
> +			       const char *buf, size_t count)
>  {
> +	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
> +	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
>  	unsigned long val;
>  
>  	if (!capable(CAP_SYS_ADMIN))
>  		return -EPERM;
>  
> -	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> -		return -EINVAL;
> -
>  	if (kstrtoul(buf, 16, &val) < 0)
>  		return -EINVAL;
>  
> @@ -520,9 +492,88 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
>  	return count;
>  }
>  
> -static struct _cache_attr subcaches =
> -	__ATTR(subcaches, 0644, show_subcaches, store_subcaches);
> +static DEVICE_ATTR_RW(cache_disable_0);
> +static DEVICE_ATTR_RW(cache_disable_1);
> +static DEVICE_ATTR_RW(subcaches);
> +
> +static umode_t
> +cache_private_attrs_is_visible(struct kobject *kobj,
> +			       struct attribute *attr, int unused)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
> +	umode_t mode = attr->mode;
> +
> +	if (!this_leaf->priv)
> +		return 0;
> +
> +	if ((attr == &dev_attr_subcaches.attr) &&
> +	    amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> +		return mode;
> +
> +	if ((attr == &dev_attr_cache_disable_0.attr ||
> +	     attr == &dev_attr_cache_disable_1.attr) &&
> +	    amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
> +		return mode;
> +
> +	return 0;
> +}
> +
> +static struct attribute_group cache_private_group = {
> +	.is_visible = cache_private_attrs_is_visible,
> +};
> +
> +static void init_amd_l3_attrs(void)
> +{
> +	int n = 1;
> +	static struct attribute **amd_l3_attrs;
> +
> +	if (amd_l3_attrs) /* already initialized */
> +		return;
> +
> +	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
> +		n += 2;
> +	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> +		n += 1;
> +
> +	amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
> +	if (!amd_l3_attrs)
> +		return;
> +
> +	n = 0;
> +	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
> +		amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
> +		amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
> +	}
> +	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> +		amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
> +
> +	cache_private_group.attrs = amd_l3_attrs;
> +}
> +
> +const struct attribute_group *
> +cache_get_priv_group(struct cacheinfo *this_leaf)
> +{
> +	if (!this_leaf->priv || !cache_private_group.attrs)
> +		return NULL;
> +	return &cache_private_group;
> +}
> +
> +static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
> +{
> +	int node;
> +
> +	/* only for L3, and not in virtualized environments */
> +	if (index < 3)
> +		return;
>  
> +	node = amd_get_nb_id(smp_processor_id());
> +	this_leaf->nb = node_to_amd_nb(node);
> +	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices) {
> +		amd_calc_l3_indices(this_leaf->nb);
> +		init_amd_l3_attrs();
> +	}
> +}
>  #else
>  #define amd_init_l3_cache(x, y)
>  #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
> @@ -546,7 +597,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
>  		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
>  	}
>  
> -	if (eax.split.type == CACHE_TYPE_NULL)
> +	if (eax.split.type == CTYPE_NULL)
>  		return -EIO; /* better error ? */
>  
>  	this_leaf->eax = eax;
> @@ -575,7 +626,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
>  		/* Do cpuid(op) loop to find out num_cache_leaves */
>  		cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
>  		cache_eax.full = eax;
> -	} while (cache_eax.split.type != CACHE_TYPE_NULL);
> +	} while (cache_eax.split.type != CTYPE_NULL);
>  	return i;
>  }
>  
> @@ -626,9 +677,9 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
>  
>  			switch (this_leaf.eax.split.level) {
>  			case 1:
> -				if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
> +				if (this_leaf.eax.split.type == CTYPE_DATA)
>  					new_l1d = this_leaf.size/1024;
> -				else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
> +				else if (this_leaf.eax.split.type == CTYPE_INST)
>  					new_l1i = this_leaf.size/1024;
>  				break;
>  			case 2:
> @@ -747,55 +798,46 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
>  	return l2;
>  }
>  
> -#ifdef CONFIG_SYSFS
> -
> -/* pointer to _cpuid4_info array (for each cache leaf) */
> -static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
> -#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(ici_cpuid4_info, x))[y]))
> -
> -#ifdef CONFIG_SMP
> -
> -static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
> +static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
> +				    struct _cpuid4_info_regs *base)
>  {
> -	struct _cpuid4_info *this_leaf;
> +	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
> +	struct cacheinfo *this_leaf;
>  	int i, sibling;
>  
>  	if (cpu_has_topoext) {
>  		unsigned int apicid, nshared, first, last;
>  
> -		if (!per_cpu(ici_cpuid4_info, cpu))
> -			return 0;
> -
> -		this_leaf = CPUID4_INFO_IDX(cpu, index);
> -		nshared = this_leaf->base.eax.split.num_threads_sharing + 1;
> +		this_leaf = this_cpu_ci->info_list + index;
> +		nshared = base->eax.split.num_threads_sharing + 1;
>  		apicid = cpu_data(cpu).apicid;
>  		first = apicid - (apicid % nshared);
>  		last = first + nshared - 1;
>  
>  		for_each_online_cpu(i) {
> +			this_cpu_ci = get_cpu_cacheinfo(i);
>  			apicid = cpu_data(i).apicid;
>  			if ((apicid < first) || (apicid > last))
>  				continue;
> -			if (!per_cpu(ici_cpuid4_info, i))
> -				continue;
> -			this_leaf = CPUID4_INFO_IDX(i, index);
> +			this_leaf = this_cpu_ci->info_list + index;
>  
>  			for_each_online_cpu(sibling) {
>  				apicid = cpu_data(sibling).apicid;
>  				if ((apicid < first) || (apicid > last))
>  					continue;
> -				set_bit(sibling, this_leaf->shared_cpu_map);
> +				cpumask_set_cpu(sibling,
> +						&this_leaf->shared_cpu_map);
>  			}
>  		}
>  	} else if (index == 3) {
>  		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
> -			if (!per_cpu(ici_cpuid4_info, i))
> -				continue;
> -			this_leaf = CPUID4_INFO_IDX(i, index);
> +			this_cpu_ci = get_cpu_cacheinfo(i);
> +			this_leaf = this_cpu_ci->info_list + index;
>  			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
>  				if (!cpu_online(sibling))
>  					continue;
> -				set_bit(sibling, this_leaf->shared_cpu_map);
> +				cpumask_set_cpu(sibling,
> +						&this_leaf->shared_cpu_map);
>  			}
>  		}
>  	} else
> @@ -804,459 +846,86 @@ static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
>  	return 1;
>  }
>  
> -static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
> +static void __cache_cpumap_setup(unsigned int cpu, int index,
> +				 struct _cpuid4_info_regs *base)
>  {
> -	struct _cpuid4_info *this_leaf, *sibling_leaf;
> +	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
> +	struct cacheinfo *this_leaf, *sibling_leaf;
>  	unsigned long num_threads_sharing;
>  	int index_msb, i;
>  	struct cpuinfo_x86 *c = &cpu_data(cpu);
>  
>  	if (c->x86_vendor == X86_VENDOR_AMD) {
> -		if (cache_shared_amd_cpu_map_setup(cpu, index))
> +		if (__cache_amd_cpumap_setup(cpu, index, base))
>  			return;
>  	}
>  
> -	this_leaf = CPUID4_INFO_IDX(cpu, index);
> -	num_threads_sharing = 1 + this_leaf->base.eax.split.num_threads_sharing;
> +	this_leaf = this_cpu_ci->info_list + index;
> +	num_threads_sharing = 1 + base->eax.split.num_threads_sharing;
>  
> +	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
>  	if (num_threads_sharing == 1)
> -		cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
> -	else {
> -		index_msb = get_count_order(num_threads_sharing);
> -
> -		for_each_online_cpu(i) {
> -			if (cpu_data(i).apicid >> index_msb ==
> -			    c->apicid >> index_msb) {
> -				cpumask_set_cpu(i,
> -					to_cpumask(this_leaf->shared_cpu_map));
> -				if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
> -					sibling_leaf =
> -						CPUID4_INFO_IDX(i, index);
> -					cpumask_set_cpu(cpu, to_cpumask(
> -						sibling_leaf->shared_cpu_map));
> -				}
> -			}
> -		}
> -	}
> -}
> -static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
> -{
> -	struct _cpuid4_info	*this_leaf, *sibling_leaf;
> -	int sibling;
> -
> -	this_leaf = CPUID4_INFO_IDX(cpu, index);
> -	for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
> -		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
> -		cpumask_clear_cpu(cpu,
> -				  to_cpumask(sibling_leaf->shared_cpu_map));
> -	}
> -}
> -#else
> -static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
> -{
> -}
> -
> -static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
> -{
> -}
> -#endif
> -
> -static void free_cache_attributes(unsigned int cpu)
> -{
> -	int i;
> -
> -	for (i = 0; i < num_cache_leaves; i++)
> -		cache_remove_shared_cpu_map(cpu, i);
> -
> -	kfree(per_cpu(ici_cpuid4_info, cpu));
> -	per_cpu(ici_cpuid4_info, cpu) = NULL;
> -}
> -
> -static void get_cpu_leaves(void *_retval)
> -{
> -	int j, *retval = _retval, cpu = smp_processor_id();
> +		return;
>  
> -	/* Do cpuid and store the results */
> -	for (j = 0; j < num_cache_leaves; j++) {
> -		struct _cpuid4_info *this_leaf = CPUID4_INFO_IDX(cpu, j);
> +	index_msb = get_count_order(num_threads_sharing);
>  
> -		*retval = cpuid4_cache_lookup_regs(j, &this_leaf->base);
> -		if (unlikely(*retval < 0)) {
> -			int i;
> +	for_each_online_cpu(i)
> +		if (cpu_data(i).apicid >> index_msb == c->apicid >> index_msb) {
> +			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
>  
> -			for (i = 0; i < j; i++)
> -				cache_remove_shared_cpu_map(cpu, i);
> -			break;
> +			if (i == cpu || !sib_cpu_ci->info_list)
> +				continue;/* skip if itself or no cacheinfo */
> +			sibling_leaf = sib_cpu_ci->info_list + index;
> +			cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
> +			cpumask_set_cpu(cpu, &sibling_leaf->shared_cpu_map);
>  		}
> -		cache_shared_cpu_map_setup(cpu, j);
> -	}
>  }
>  
> -static int detect_cache_attributes(unsigned int cpu)
> +static void ci_leaf_init(struct cacheinfo *this_leaf,
> +			 struct _cpuid4_info_regs *base)
>  {
> -	int			retval;
> -
> -	if (num_cache_leaves == 0)
> -		return -ENOENT;
> -
> -	per_cpu(ici_cpuid4_info, cpu) = kzalloc(
> -	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
> -	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
> -		return -ENOMEM;
> -
> -	smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
> -	if (retval) {
> -		kfree(per_cpu(ici_cpuid4_info, cpu));
> -		per_cpu(ici_cpuid4_info, cpu) = NULL;
> -	}
> -
> -	return retval;
> -}
> -
> -#include <linux/kobject.h>
> -#include <linux/sysfs.h>
> -#include <linux/cpu.h>
> -
> -/* pointer to kobject for cpuX/cache */
> -static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
> -
> -struct _index_kobject {
> -	struct kobject kobj;
> -	unsigned int cpu;
> -	unsigned short index;
> -};
> -
> -/* pointer to array of kobjects for cpuX/cache/indexY */
> -static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
> -#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(ici_index_kobject, x))[y]))
> -
> -#define show_one_plus(file_name, object, val)				\
> -static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \
> -				unsigned int cpu)			\
> -{									\
> -	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
> -}
> -
> -show_one_plus(level, base.eax.split.level, 0);
> -show_one_plus(coherency_line_size, base.ebx.split.coherency_line_size, 1);
> -show_one_plus(physical_line_partition, base.ebx.split.physical_line_partition, 1);
> -show_one_plus(ways_of_associativity, base.ebx.split.ways_of_associativity, 1);
> -show_one_plus(number_of_sets, base.ecx.split.number_of_sets, 1);
> -
> -static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,
> -			 unsigned int cpu)
> -{
> -	return sprintf(buf, "%luK\n", this_leaf->base.size / 1024);
> -}
> -
> -static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
> -					int type, char *buf)
> -{
> -	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
> -	int n = 0;
> -
> -	if (len > 1) {
> -		const struct cpumask *mask;
> -
> -		mask = to_cpumask(this_leaf->shared_cpu_map);
> -		n = type ?
> -			cpulist_scnprintf(buf, len-2, mask) :
> -			cpumask_scnprintf(buf, len-2, mask);
> -		buf[n++] = '\n';
> -		buf[n] = '\0';
> -	}
> -	return n;
> +	this_leaf->level = base->eax.split.level;
> +	this_leaf->type = cache_type_map[base->eax.split.type];
> +	this_leaf->coherency_line_size =
> +				base->ebx.split.coherency_line_size + 1;
> +	this_leaf->ways_of_associativity =
> +				base->ebx.split.ways_of_associativity + 1;
> +	this_leaf->size = base->size;
> +	this_leaf->number_of_sets = base->ecx.split.number_of_sets + 1;
> +	this_leaf->physical_line_partition =
> +				base->ebx.split.physical_line_partition + 1;
> +	this_leaf->priv = base->nb;
>  }
>  
> -static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
> -					  unsigned int cpu)
> +static int __init_cache_level(unsigned int cpu)
>  {
> -	return show_shared_cpu_map_func(leaf, 0, buf);
> -}
> -
> -static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,
> -					   unsigned int cpu)
> -{
> -	return show_shared_cpu_map_func(leaf, 1, buf);
> -}
> -
> -static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,
> -			 unsigned int cpu)
> -{
> -	switch (this_leaf->base.eax.split.type) {
> -	case CACHE_TYPE_DATA:
> -		return sprintf(buf, "Data\n");
> -	case CACHE_TYPE_INST:
> -		return sprintf(buf, "Instruction\n");
> -	case CACHE_TYPE_UNIFIED:
> -		return sprintf(buf, "Unified\n");
> -	default:
> -		return sprintf(buf, "Unknown\n");
> -	}
> -}
> -
> -#define to_object(k)	container_of(k, struct _index_kobject, kobj)
> -#define to_attr(a)	container_of(a, struct _cache_attr, attr)
> -
> -#define define_one_ro(_name) \
> -static struct _cache_attr _name = \
> -	__ATTR(_name, 0444, show_##_name, NULL)
> -
> -define_one_ro(level);
> -define_one_ro(type);
> -define_one_ro(coherency_line_size);
> -define_one_ro(physical_line_partition);
> -define_one_ro(ways_of_associativity);
> -define_one_ro(number_of_sets);
> -define_one_ro(size);
> -define_one_ro(shared_cpu_map);
> -define_one_ro(shared_cpu_list);
> -
> -static struct attribute *default_attrs[] = {
> -	&type.attr,
> -	&level.attr,
> -	&coherency_line_size.attr,
> -	&physical_line_partition.attr,
> -	&ways_of_associativity.attr,
> -	&number_of_sets.attr,
> -	&size.attr,
> -	&shared_cpu_map.attr,
> -	&shared_cpu_list.attr,
> -	NULL
> -};
> -
> -#ifdef CONFIG_AMD_NB
> -static struct attribute **amd_l3_attrs(void)
> -{
> -	static struct attribute **attrs;
> -	int n;
> -
> -	if (attrs)
> -		return attrs;
> -
> -	n = ARRAY_SIZE(default_attrs);
> -
> -	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
> -		n += 2;
> -
> -	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> -		n += 1;
> -
> -	attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);
> -	if (attrs == NULL)
> -		return attrs = default_attrs;
> -
> -	for (n = 0; default_attrs[n]; n++)
> -		attrs[n] = default_attrs[n];
> -
> -	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
> -		attrs[n++] = &cache_disable_0.attr;
> -		attrs[n++] = &cache_disable_1.attr;
> -	}
> -
> -	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
> -		attrs[n++] = &subcaches.attr;
> -
> -	return attrs;
> -}
> -#endif
> -
> -static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
> -{
> -	struct _cache_attr *fattr = to_attr(attr);
> -	struct _index_kobject *this_leaf = to_object(kobj);
> -	ssize_t ret;
> -
> -	ret = fattr->show ?
> -		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
> -			buf, this_leaf->cpu) :
> -		0;
> -	return ret;
> -}
> +	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
>  
> -static ssize_t store(struct kobject *kobj, struct attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct _cache_attr *fattr = to_attr(attr);
> -	struct _index_kobject *this_leaf = to_object(kobj);
> -	ssize_t ret;
> -
> -	ret = fattr->store ?
> -		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
> -			buf, count, this_leaf->cpu) :
> -		0;
> -	return ret;
> -}
> -
> -static const struct sysfs_ops sysfs_ops = {
> -	.show   = show,
> -	.store  = store,
> -};
> -
> -static struct kobj_type ktype_cache = {
> -	.sysfs_ops	= &sysfs_ops,
> -	.default_attrs	= default_attrs,
> -};
> -
> -static struct kobj_type ktype_percpu_entry = {
> -	.sysfs_ops	= &sysfs_ops,
> -};
> -
> -static void cpuid4_cache_sysfs_exit(unsigned int cpu)
> -{
> -	kfree(per_cpu(ici_cache_kobject, cpu));
> -	kfree(per_cpu(ici_index_kobject, cpu));
> -	per_cpu(ici_cache_kobject, cpu) = NULL;
> -	per_cpu(ici_index_kobject, cpu) = NULL;
> -	free_cache_attributes(cpu);
> -}
> -
> -static int cpuid4_cache_sysfs_init(unsigned int cpu)
> -{
> -	int err;
> -
> -	if (num_cache_leaves == 0)
> +	if (!num_cache_leaves)
>  		return -ENOENT;
> -
> -	err = detect_cache_attributes(cpu);
> -	if (err)
> -		return err;
> -
> -	/* Allocate all required memory */
> -	per_cpu(ici_cache_kobject, cpu) =
> -		kzalloc(sizeof(struct kobject), GFP_KERNEL);
> -	if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
> -		goto err_out;
> -
> -	per_cpu(ici_index_kobject, cpu) = kzalloc(
> -	    sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
> -	if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
> -		goto err_out;
> -
> +	if (!this_cpu_ci)
> +		return -EINVAL;
> +	this_cpu_ci->num_levels = 3;
> +	this_cpu_ci->num_leaves = num_cache_leaves;
>  	return 0;
> -
> -err_out:
> -	cpuid4_cache_sysfs_exit(cpu);
> -	return -ENOMEM;
>  }
>  
> -static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
> -
> -/* Add/Remove cache interface for CPU device */
> -static int cache_add_dev(struct device *dev)
> +static int __populate_cache_leaves(unsigned int cpu)
>  {
> -	unsigned int cpu = dev->id;
> -	unsigned long i, j;
> -	struct _index_kobject *this_object;
> -	struct _cpuid4_info   *this_leaf;
> -	int retval;
> -
> -	retval = cpuid4_cache_sysfs_init(cpu);
> -	if (unlikely(retval < 0))
> -		return retval;
> -
> -	retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
> -				      &ktype_percpu_entry,
> -				      &dev->kobj, "%s", "cache");
> -	if (retval < 0) {
> -		cpuid4_cache_sysfs_exit(cpu);
> -		return retval;
> -	}
> -
> -	for (i = 0; i < num_cache_leaves; i++) {
> -		this_object = INDEX_KOBJECT_PTR(cpu, i);
> -		this_object->cpu = cpu;
> -		this_object->index = i;
> +	unsigned int idx, ret;
> +	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
> +	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
> +	struct _cpuid4_info_regs id4_regs = {};
>  
> -		this_leaf = CPUID4_INFO_IDX(cpu, i);
> -
> -		ktype_cache.default_attrs = default_attrs;
> -#ifdef CONFIG_AMD_NB
> -		if (this_leaf->base.nb)
> -			ktype_cache.default_attrs = amd_l3_attrs();
> -#endif
> -		retval = kobject_init_and_add(&(this_object->kobj),
> -					      &ktype_cache,
> -					      per_cpu(ici_cache_kobject, cpu),
> -					      "index%1lu", i);
> -		if (unlikely(retval)) {
> -			for (j = 0; j < i; j++)
> -				kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
> -			kobject_put(per_cpu(ici_cache_kobject, cpu));
> -			cpuid4_cache_sysfs_exit(cpu);
> -			return retval;
> -		}
> -		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
> +	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
> +		ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
> +		if (ret)
> +			return ret;
> +		ci_leaf_init(this_leaf++, &id4_regs);
> +		__cache_cpumap_setup(cpu, idx, &id4_regs);
>  	}
> -	cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
> -
> -	kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
>  	return 0;
>  }
>  
> -static void cache_remove_dev(struct device *dev)
> -{
> -	unsigned int cpu = dev->id;
> -	unsigned long i;
> -
> -	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
> -		return;
> -	if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
> -		return;
> -	cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
> -
> -	for (i = 0; i < num_cache_leaves; i++)
> -		kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
> -	kobject_put(per_cpu(ici_cache_kobject, cpu));
> -	cpuid4_cache_sysfs_exit(cpu);
> -}
> -
> -static int cacheinfo_cpu_callback(struct notifier_block *nfb,
> -				  unsigned long action, void *hcpu)
> -{
> -	unsigned int cpu = (unsigned long)hcpu;
> -	struct device *dev;
> -
> -	dev = get_cpu_device(cpu);
> -	switch (action) {
> -	case CPU_ONLINE:
> -	case CPU_ONLINE_FROZEN:
> -		cache_add_dev(dev);
> -		break;
> -	case CPU_DEAD:
> -	case CPU_DEAD_FROZEN:
> -		cache_remove_dev(dev);
> -		break;
> -	}
> -	return NOTIFY_OK;
> -}
> -
> -static struct notifier_block cacheinfo_cpu_notifier = {
> -	.notifier_call = cacheinfo_cpu_callback,
> -};
> -
> -static int __init cache_sysfs_init(void)
> -{
> -	int i, err = 0;
> -
> -	if (num_cache_leaves == 0)
> -		return 0;
> -
> -	cpu_notifier_register_begin();
> -	for_each_online_cpu(i) {
> -		struct device *dev = get_cpu_device(i);
> -
> -		err = cache_add_dev(dev);
> -		if (err)
> -			goto out;
> -	}
> -	__register_hotcpu_notifier(&cacheinfo_cpu_notifier);
> -
> -out:
> -	cpu_notifier_register_done();
> -	return err;
> -}
> -
> -device_initcall(cache_sysfs_init);
> -
> -#endif
> +DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
> +DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
> -- 
> 1.9.1
> 
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-01-23 13:55 ` Thomas Gleixner
@ 2015-01-23 18:15   ` Borislav Petkov
  2015-02-23 16:36     ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-01-23 18:15 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: Sudeep Holla, LKML, x86, H. Peter Anvin, Ingo Molnar

On Fri, Jan 23, 2015 at 02:55:03PM +0100, Thomas Gleixner wrote:
> Cc: Boris
> 
> On Thu, 8 Jan 2015, Sudeep Holla wrote:
> 
> > This patch removes the redundant sysfs cacheinfo code by reusing
> > the newly introduced generic cacheinfo infrastructure through the
> > commit 246246cbde5e ("drivers: base: support cpu cache information
> > interface to userspace via sysfs")
> > 
> > The private pointer provided by the cacheinfo is used to implement
> > the AMD L3 cache specific attributes.
> > 
> > Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Ingo Molnar <mingo@redhat.com>
> > Cc: "H. Peter Anvin" <hpa@zytor.com> 
> > Cc: x86@kernel.org

...
[    2.878173] ACPI: processor limited to max C-state 1
[    2.884048] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
[    2.911085] 00:01: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A
[    2.920699] Linux agpgart interface v0.103
[    2.924908] [drm] Initialized drm 1.1.0 20060810
[    2.929719] ------------[ cut here ]------------
[    2.934419] WARNING: CPU: 0 PID: 1 at kernel/locking/lockdep.c:2744 lockdep_trace_alloc+0xd4/0xe0()
[    2.943591] DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags))
[    2.949024] Modules linked in:
[    2.952486] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.19.0-rc5+ #1
[    2.958921] Hardware name: MICRO-STAR INTERNATIONAL CO.,LTD MS-7599/870-C45 (MS-7599), BIOS V1.15 03/04/2011
[    2.968878]  ffffffff817e9f1f ffff880132183b08 ffffffff81567210 0000000000000000
[    2.976603]  ffff880132183b58 ffff880132183b48 ffffffff8107bbe5 ffff880132183b98
[    2.984333]  0000000000000096 00000000000080d0 0000000000000018 ffff880132001cc0
[    2.992063] Call Trace:
[    2.994594]  [<ffffffff81567210>] dump_stack+0x4f/0x7b
[    2.999818]  [<ffffffff8107bbe5>] warn_slowpath_common+0x95/0xe0
[    3.005909]  [<ffffffff8107bc76>] warn_slowpath_fmt+0x46/0x50
[    3.011740]  [<ffffffff810c5834>] lockdep_trace_alloc+0xd4/0xe0
[    3.017745]  [<ffffffff811ac3b1>] __kmalloc+0x51/0x230
[    3.022969]  [<ffffffff8101389d>] ? cpuid4_cache_lookup_regs+0x21d/0x480
[    3.029753]  [<ffffffff8101389d>] cpuid4_cache_lookup_regs+0x21d/0x480
[    3.036365]  [<ffffffff81013b00>] ? cpuid4_cache_lookup_regs+0x480/0x480
[    3.043149]  [<ffffffff81013b94>] _populate_cache_leaves+0x94/0x460
[    3.049498]  [<ffffffff81013b00>] ? cpuid4_cache_lookup_regs+0x480/0x480
[    3.056282]  [<ffffffff810fcec6>] generic_exec_single+0x136/0x1a0
[    3.062456]  [<ffffffff81013b00>] ? cpuid4_cache_lookup_regs+0x480/0x480
[    3.069237]  [<ffffffff810fcf93>] smp_call_function_single+0x63/0xd0
[    3.075674]  [<ffffffff811ac4e8>] ? __kmalloc+0x188/0x230
[    3.081155]  [<ffffffff81014862>] populate_cache_leaves+0x22/0x30
[    3.087329]  [<ffffffff813c342b>] detect_cache_attributes+0x7b/0x1a0
[    3.093767]  [<ffffffff81b1ed9b>] ? container_dev_init+0x2f/0x2f
[    3.099855]  [<ffffffff81b1eddd>] cacheinfo_sysfs_init+0x42/0x93
[    3.105946]  [<ffffffff81b1ed9b>] ? container_dev_init+0x2f/0x2f
[    3.112038]  [<ffffffff810002f0>] do_one_initcall+0xa0/0x1f0
[    3.117777]  [<ffffffff8109b000>] ? parse_args+0x1b0/0x420
[    3.123345]  [<ffffffff81aee001>] kernel_init_freeable+0x115/0x19d
[    3.129605]  [<ffffffff8157047f>] ? ret_from_fork+0xf/0xb0
[    3.135172]  [<ffffffff815628b0>] ? rest_init+0xd0/0xd0
[    3.140478]  [<ffffffff815628be>] kernel_init+0xe/0xf0
[    3.145699]  [<ffffffff815704ec>] ret_from_fork+0x7c/0xb0
[    3.151177]  [<ffffffff815628b0>] ? rest_init+0xd0/0xd0
[    3.156489] ---[ end trace 5a99fef82328e919 ]---
[    3.161190] BUG: unable to handle kernel NULL pointer dereference at 00000000000000f8
[    3.169248] IP: [<ffffffff81013f40>] _populate_cache_leaves+0x440/0x460
[    3.175993] PGD 0 
[    3.178141] Oops: 0002 [#1] PREEMPT SMP 
[    3.182297] Modules linked in:
[    3.185486] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W      3.19.0-rc5+ #1
[    3.193099] Hardware name: MICRO-STAR INTERNATIONAL CO.,LTD MS-7599/870-C45 (MS-7599), BIOS V1.15 03/04/2011
[    3.203053] task: ffff880132138000 ti: ffff880132180000 task.ti: ffff880132180000
[    3.210667] RIP: 0010:[<ffffffff81013f40>]  [<ffffffff81013f40>] _populate_cache_leaves+0x440/0x460
[    3.219892] RSP: 0000:ffff880132183c88  EFLAGS: 00010086
[    3.225286] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000000ffffffff
[    3.232503] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000000
[    3.239719] RBP: ffff880132183d28 R08: ffff880136c0a0c0 R09: ffff88013196eb60
[    3.246936] R10: 0000000000000002 R11: 0000000000000212 R12: 0000000000000000
[    3.254152] R13: 000000000000a0c0 R14: ffffffff81acdad8 R15: 0000000000000001
[    3.261369] FS:  0000000000000000(0000) GS:ffff880136c00000(0000) knlGS:0000000000000000
[    3.269586] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[    3.275414] CR2: 00000000000000f8 CR3: 0000000001a11000 CR4: 00000000000007f0
[    3.282630] Stack:
[    3.284724]  ffff880132183de4 000000000000a000 000000000000a000 ffff880136c0fbc0
[    3.292451]  0000000000000090 ffff88013197f4b0 0000000000000006 ffff88013197f520
[    3.300175]  000000000000a0c0 0000000300000000 0bc0003f14000163 00000000000007ff
[    3.307901] Call Trace:
[    3.310433]  [<ffffffff81013b00>] ? cpuid4_cache_lookup_regs+0x480/0x480
[    3.317216]  [<ffffffff810fcec6>] generic_exec_single+0x136/0x1a0
[    3.323392]  [<ffffffff81013b00>] ? cpuid4_cache_lookup_regs+0x480/0x480
[    3.330176]  [<ffffffff810fcf93>] smp_call_function_single+0x63/0xd0
[    3.336612]  [<ffffffff811ac4e8>] ? __kmalloc+0x188/0x230
[    3.342093]  [<ffffffff81014862>] populate_cache_leaves+0x22/0x30
[    3.348269]  [<ffffffff813c342b>] detect_cache_attributes+0x7b/0x1a0
[    3.354706]  [<ffffffff81b1ed9b>] ? container_dev_init+0x2f/0x2f
[    3.360795]  [<ffffffff81b1eddd>] cacheinfo_sysfs_init+0x42/0x93
[    3.366886]  [<ffffffff81b1ed9b>] ? container_dev_init+0x2f/0x2f
[    3.372976]  [<ffffffff810002f0>] do_one_initcall+0xa0/0x1f0
[    3.378717]  [<ffffffff8109b000>] ? parse_args+0x1b0/0x420
[    3.384283]  [<ffffffff81aee001>] kernel_init_freeable+0x115/0x19d
[    3.390543]  [<ffffffff8157047f>] ? ret_from_fork+0xf/0xb0
[    3.396111]  [<ffffffff815628b0>] ? rest_init+0xd0/0xd0
[    3.401416]  [<ffffffff815628be>] kernel_init+0xe/0xf0
[    3.406638]  [<ffffffff815704ec>] ret_from_fork+0x7c/0xb0
[    3.412116]  [<ffffffff815628b0>] ? rest_init+0xd0/0xd0
[    3.417422] Code: 3c dd 80 d7 ac 81 ff c2 48 63 d2 be 06 00 00 00 e8 c6 87 2b 00 3b 05 e4 ac ab 00 89 c2 7d a4 89 c0 49 0f a3 06 19 c9 85 c9 74 d0 <f0> 49 0f ab 84 24 f8 00 00 00 eb c4 4c 8b 65 98 e9 eb fd ff ff 
[    3.439789] RIP  [<ffffffff81013f40>] _populate_cache_leaves+0x440/0x460
[    3.446622]  RSP <ffff880132183c88>
[    3.450191] CR2: 00000000000000f8
[    3.453592] ---[ end trace 5a99fef82328e91a ]---
[    3.458290] Kernel panic - not syncing: Fatal exception
[    3.463659] Kernel Offset: 0x0 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffff9fffffff)
[    3.473965] ---[ end Kernel panic - not syncing: Fatal exception

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-01-23 18:15   ` Borislav Petkov
@ 2015-02-23 16:36     ` Sudeep Holla
  0 siblings, 0 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-02-23 16:36 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Thomas Gleixner, Sudeep Holla, LKML, x86, H. Peter Anvin, Ingo Molnar

Hi Boris,

On 23/01/15 18:15, Borislav Petkov wrote:
> On Fri, Jan 23, 2015 at 02:55:03PM +0100, Thomas Gleixner wrote:
>> Cc: Boris
>>
>> On Thu, 8 Jan 2015, Sudeep Holla wrote:
>>
>>> This patch removes the redundant sysfs cacheinfo code by reusing
>>> the newly introduced generic cacheinfo infrastructure through the
>>> commit 246246cbde5e ("drivers: base: support cpu cache information
>>> interface to userspace via sysfs")
>>>
>>> The private pointer provided by the cacheinfo is used to implement
>>> the AMD L3 cache specific attributes.
>>>
>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>> Cc: Thomas Gleixner <tglx@linutronix.de>
>>> Cc: Ingo Molnar <mingo@redhat.com>
>>> Cc: "H. Peter Anvin" <hpa@zytor.com>
>>> Cc: x86@kernel.org
>
> ...
> [    2.878173] ACPI: processor limited to max C-state 1
> [    2.884048] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
> [    2.911085] 00:01: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A
> [    2.920699] Linux agpgart interface v0.103
> [    2.924908] [drm] Initialized drm 1.1.0 20060810
> [    2.929719] ------------[ cut here ]------------
> [    2.934419] WARNING: CPU: 0 PID: 1 at kernel/locking/lockdep.c:2744 lockdep_trace_alloc+0xd4/0xe0()
> [    2.943591] DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags))

Sorry for late response, was on vacation.
I have fixed this issue now and will post the new version soon.
Thanks a lot for trying it out.

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-01-08  7:50 [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure Sudeep Holla
  2015-01-23 13:55 ` Thomas Gleixner
@ 2015-02-23 18:14 ` Sudeep Holla
  2015-02-24  7:58   ` Ingo Molnar
                     ` (2 more replies)
  1 sibling, 3 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-02-23 18:14 UTC (permalink / raw)
  To: linux-kernel, Borislav Petkov
  Cc: Sudeep Holla, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86

This patch removes the redundant sysfs cacheinfo code by reusing
the newly introduced generic cacheinfo infrastructure through the
commit 246246cbde5e ("drivers: base: support cpu cache information
interface to userspace via sysfs")

The private pointer provided by the cacheinfo is used to implement
the AMD L3 cache specific attributes.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: x86@kernel.org
---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 711 +++++++++-------------------------
 1 file changed, 193 insertions(+), 518 deletions(-)

v1->v2:
 - Rebased on v4.0-rc1
 - Fixed lockdep warning reported by Borislav

Hi,

Since I don't have access to any AMD machines, I would appreciate
any testing on it. I have tested this on system with Intel Core i7-2600
CPUs.

Regards,
Sudeep

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 659643376dbf..5f3059cd5ab1 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -7,16 +7,14 @@
  *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/compiler.h>
+#include <linux/cacheinfo.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/sysfs.h>
 #include <linux/pci.h>
 
 #include <asm/processor.h>
-#include <linux/smp.h>
 #include <asm/amd_nb.h>
 #include <asm/smp.h>
 
@@ -116,10 +114,10 @@ static const struct _cache_table cache_table[] =
 
 
 enum _cache_type {
-	CACHE_TYPE_NULL	= 0,
-	CACHE_TYPE_DATA = 1,
-	CACHE_TYPE_INST = 2,
-	CACHE_TYPE_UNIFIED = 3
+	CTYPE_NULL = 0,
+	CTYPE_DATA = 1,
+	CTYPE_INST = 2,
+	CTYPE_UNIFIED = 3
 };
 
 union _cpuid4_leaf_eax {
@@ -159,11 +157,6 @@ struct _cpuid4_info_regs {
 	struct amd_northbridge *nb;
 };
 
-struct _cpuid4_info {
-	struct _cpuid4_info_regs base;
-	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
-};
-
 unsigned short			num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -220,6 +213,13 @@ static const unsigned short assocs[] = {
 static const unsigned char levels[] = { 1, 1, 2, 3 };
 static const unsigned char types[] = { 1, 2, 3, 3 };
 
+static const enum cache_type cache_type_map[] = {
+	[CTYPE_NULL] = CACHE_TYPE_NOCACHE,
+	[CTYPE_DATA] = CACHE_TYPE_DATA,
+	[CTYPE_INST] = CACHE_TYPE_INST,
+	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
+};
+
 static void
 amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		     union _cpuid4_leaf_ebx *ebx,
@@ -291,14 +291,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
-struct _cache_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);
-	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,
-			 unsigned int);
-};
-
 #if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
+
 /*
  * L3 cache descriptors
  */
@@ -325,20 +319,6 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb)
 	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
-static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
-{
-	int node;
-
-	/* only for L3, and not in virtualized environments */
-	if (index < 3)
-		return;
-
-	node = amd_get_nb_id(smp_processor_id());
-	this_leaf->nb = node_to_amd_nb(node);
-	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
-		amd_calc_l3_indices(this_leaf->nb);
-}
-
 /*
  * check whether a slot used for disabling an L3 index is occupied.
  * @l3: L3 cache descriptor
@@ -359,15 +339,13 @@ int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot)
 	return -1;
 }
 
-static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
+static ssize_t show_cache_disable(struct cacheinfo *this_leaf, char *buf,
 				  unsigned int slot)
 {
 	int index;
+	struct amd_northbridge *nb = this_leaf->priv;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	index = amd_get_l3_disable_slot(this_leaf->base.nb, slot);
+	index = amd_get_l3_disable_slot(nb, slot);
 	if (index >= 0)
 		return sprintf(buf, "%d\n", index);
 
@@ -376,9 +354,10 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 
 #define SHOW_CACHE_DISABLE(slot)					\
 static ssize_t								\
-show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf,	\
-			  unsigned int cpu)				\
+cache_disable_##slot##_show(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return show_cache_disable(this_leaf, buf, slot);		\
 }
 SHOW_CACHE_DISABLE(0)
@@ -446,25 +425,23 @@ int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot,
 	return 0;
 }
 
-static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
-				  const char *buf, size_t count,
-				  unsigned int slot)
+static ssize_t store_cache_disable(struct cacheinfo *this_leaf,
+				   const char *buf, size_t count,
+				   unsigned int slot)
 {
 	unsigned long val = 0;
 	int cpu, err = 0;
+	struct amd_northbridge *nb = this_leaf->priv;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
+	cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	if (kstrtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	err = amd_set_l3_disable_slot(this_leaf->base.nb, cpu, slot, val);
+	err = amd_set_l3_disable_slot(nb, cpu, slot, val);
 	if (err) {
 		if (err == -EEXIST)
 			pr_warning("L3 slot %d in use/index already disabled!\n",
@@ -476,41 +453,36 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 
 #define STORE_CACHE_DISABLE(slot)					\
 static ssize_t								\
-store_cache_disable_##slot(struct _cpuid4_info *this_leaf,		\
-			   const char *buf, size_t count,		\
-			   unsigned int cpu)				\
+cache_disable_##slot##_store(struct device *dev,			\
+			     struct device_attribute *attr,		\
+			     const char *buf, size_t count)		\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return store_cache_disable(this_leaf, buf, count, slot);	\
 }
 STORE_CACHE_DISABLE(0)
 STORE_CACHE_DISABLE(1)
 
-static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
-		show_cache_disable_0, store_cache_disable_0);
-static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
-		show_cache_disable_1, store_cache_disable_1);
-
-static ssize_t
-show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)
+static ssize_t subcaches_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
 }
 
-static ssize_t
-store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
-		unsigned int cpu)
+static ssize_t subcaches_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
 {
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 	unsigned long val;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
-
 	if (kstrtoul(buf, 16, &val) < 0)
 		return -EINVAL;
 
@@ -520,9 +492,92 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
 	return count;
 }
 
-static struct _cache_attr subcaches =
-	__ATTR(subcaches, 0644, show_subcaches, store_subcaches);
+static DEVICE_ATTR_RW(cache_disable_0);
+static DEVICE_ATTR_RW(cache_disable_1);
+static DEVICE_ATTR_RW(subcaches);
+
+static umode_t
+cache_private_attrs_is_visible(struct kobject *kobj,
+			       struct attribute *attr, int unused)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	umode_t mode = attr->mode;
+
+	if (!this_leaf->priv)
+		return 0;
+
+	if ((attr == &dev_attr_subcaches.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		return mode;
+
+	if ((attr == &dev_attr_cache_disable_0.attr ||
+	     attr == &dev_attr_cache_disable_1.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		return mode;
+
+	return 0;
+}
+
+static struct attribute_group cache_private_group = {
+	.is_visible = cache_private_attrs_is_visible,
+};
+
+static void init_amd_l3_attrs(void)
+{
+	int n = 1;
+	static struct attribute **amd_l3_attrs;
+
+	if (amd_l3_attrs) /* already initialized */
+		return;
+
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		n += 2;
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		n += 1;
+
+	amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
+	if (!amd_l3_attrs)
+		return;
+
+	n = 0;
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
+	}
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
+
+	cache_private_group.attrs = amd_l3_attrs;
+}
+
+const struct attribute_group *
+cache_get_priv_group(struct cacheinfo *this_leaf)
+{
+	struct amd_northbridge *nb = this_leaf->priv;
+
+	if (this_leaf->level < 3)
+		return NULL;
+
+	if (nb && nb->l3_cache.indices)
+		init_amd_l3_attrs();
+
+	return &cache_private_group;
+}
+
+static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
+{
+	int node;
+
+	/* only for L3, and not in virtualized environments */
+	if (index < 3)
+		return;
 
+	node = amd_get_nb_id(smp_processor_id());
+	this_leaf->nb = node_to_amd_nb(node);
+	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
+		amd_calc_l3_indices(this_leaf->nb);
+}
 #else
 #define amd_init_l3_cache(x, y)
 #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
@@ -546,7 +601,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
 		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
 	}
 
-	if (eax.split.type == CACHE_TYPE_NULL)
+	if (eax.split.type == CTYPE_NULL)
 		return -EIO; /* better error ? */
 
 	this_leaf->eax = eax;
@@ -575,7 +630,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
 		/* Do cpuid(op) loop to find out num_cache_leaves */
 		cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
 		cache_eax.full = eax;
-	} while (cache_eax.split.type != CACHE_TYPE_NULL);
+	} while (cache_eax.split.type != CTYPE_NULL);
 	return i;
 }
 
@@ -626,9 +681,9 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
 			switch (this_leaf.eax.split.level) {
 			case 1:
-				if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
+				if (this_leaf.eax.split.type == CTYPE_DATA)
 					new_l1d = this_leaf.size/1024;
-				else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
+				else if (this_leaf.eax.split.type == CTYPE_INST)
 					new_l1i = this_leaf.size/1024;
 				break;
 			case 2:
@@ -747,55 +802,46 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 	return l2;
 }
 
-#ifdef CONFIG_SYSFS
-
-/* pointer to _cpuid4_info array (for each cache leaf) */
-static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(ici_cpuid4_info, x))[y]))
-
-#ifdef CONFIG_SMP
-
-static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
+static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
+				    struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf;
 	int i, sibling;
 
 	if (cpu_has_topoext) {
 		unsigned int apicid, nshared, first, last;
 
-		if (!per_cpu(ici_cpuid4_info, cpu))
-			return 0;
-
-		this_leaf = CPUID4_INFO_IDX(cpu, index);
-		nshared = this_leaf->base.eax.split.num_threads_sharing + 1;
+		this_leaf = this_cpu_ci->info_list + index;
+		nshared = base->eax.split.num_threads_sharing + 1;
 		apicid = cpu_data(cpu).apicid;
 		first = apicid - (apicid % nshared);
 		last = first + nshared - 1;
 
 		for_each_online_cpu(i) {
+			this_cpu_ci = get_cpu_cacheinfo(i);
 			apicid = cpu_data(i).apicid;
 			if ((apicid < first) || (apicid > last))
 				continue;
-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_leaf = this_cpu_ci->info_list + index;
 
 			for_each_online_cpu(sibling) {
 				apicid = cpu_data(sibling).apicid;
 				if ((apicid < first) || (apicid > last))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else if (index == 3) {
 		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_cpu_ci = get_cpu_cacheinfo(i);
+			this_leaf = this_cpu_ci->info_list + index;
 			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
 				if (!cpu_online(sibling))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else
@@ -804,457 +850,86 @@ static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
 	return 1;
 }
 
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
+static void __cache_cpumap_setup(unsigned int cpu, int index,
+				 struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf, *sibling_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf, *sibling_leaf;
 	unsigned long num_threads_sharing;
 	int index_msb, i;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 
 	if (c->x86_vendor == X86_VENDOR_AMD) {
-		if (cache_shared_amd_cpu_map_setup(cpu, index))
+		if (__cache_amd_cpumap_setup(cpu, index, base))
 			return;
 	}
 
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	num_threads_sharing = 1 + this_leaf->base.eax.split.num_threads_sharing;
+	this_leaf = this_cpu_ci->info_list + index;
+	num_threads_sharing = 1 + base->eax.split.num_threads_sharing;
 
+	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
 	if (num_threads_sharing == 1)
-		cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
-	else {
-		index_msb = get_count_order(num_threads_sharing);
-
-		for_each_online_cpu(i) {
-			if (cpu_data(i).apicid >> index_msb ==
-			    c->apicid >> index_msb) {
-				cpumask_set_cpu(i,
-					to_cpumask(this_leaf->shared_cpu_map));
-				if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
-					sibling_leaf =
-						CPUID4_INFO_IDX(i, index);
-					cpumask_set_cpu(cpu, to_cpumask(
-						sibling_leaf->shared_cpu_map));
-				}
-			}
-		}
-	}
-}
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-	struct _cpuid4_info	*this_leaf, *sibling_leaf;
-	int sibling;
-
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
-		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
-		cpumask_clear_cpu(cpu,
-				  to_cpumask(sibling_leaf->shared_cpu_map));
-	}
-}
-#else
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
-{
-}
-
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-}
-#endif
-
-static void free_cache_attributes(unsigned int cpu)
-{
-	int i;
-
-	for (i = 0; i < num_cache_leaves; i++)
-		cache_remove_shared_cpu_map(cpu, i);
-
-	kfree(per_cpu(ici_cpuid4_info, cpu));
-	per_cpu(ici_cpuid4_info, cpu) = NULL;
-}
-
-static void get_cpu_leaves(void *_retval)
-{
-	int j, *retval = _retval, cpu = smp_processor_id();
+		return;
 
-	/* Do cpuid and store the results */
-	for (j = 0; j < num_cache_leaves; j++) {
-		struct _cpuid4_info *this_leaf = CPUID4_INFO_IDX(cpu, j);
+	index_msb = get_count_order(num_threads_sharing);
 
-		*retval = cpuid4_cache_lookup_regs(j, &this_leaf->base);
-		if (unlikely(*retval < 0)) {
-			int i;
+	for_each_online_cpu(i)
+		if (cpu_data(i).apicid >> index_msb == c->apicid >> index_msb) {
+			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
 
-			for (i = 0; i < j; i++)
-				cache_remove_shared_cpu_map(cpu, i);
-			break;
+			if (i == cpu || !sib_cpu_ci->info_list)
+				continue;/* skip if itself or no cacheinfo */
+			sibling_leaf = sib_cpu_ci->info_list + index;
+			cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+			cpumask_set_cpu(cpu, &sibling_leaf->shared_cpu_map);
 		}
-		cache_shared_cpu_map_setup(cpu, j);
-	}
-}
-
-static int detect_cache_attributes(unsigned int cpu)
-{
-	int			retval;
-
-	if (num_cache_leaves == 0)
-		return -ENOENT;
-
-	per_cpu(ici_cpuid4_info, cpu) = kzalloc(
-	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return -ENOMEM;
-
-	smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
-	if (retval) {
-		kfree(per_cpu(ici_cpuid4_info, cpu));
-		per_cpu(ici_cpuid4_info, cpu) = NULL;
-	}
-
-	return retval;
-}
-
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/cpu.h>
-
-/* pointer to kobject for cpuX/cache */
-static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
-
-struct _index_kobject {
-	struct kobject kobj;
-	unsigned int cpu;
-	unsigned short index;
-};
-
-/* pointer to array of kobjects for cpuX/cache/indexY */
-static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(ici_index_kobject, x))[y]))
-
-#define show_one_plus(file_name, object, val)				\
-static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \
-				unsigned int cpu)			\
-{									\
-	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
-}
-
-show_one_plus(level, base.eax.split.level, 0);
-show_one_plus(coherency_line_size, base.ebx.split.coherency_line_size, 1);
-show_one_plus(physical_line_partition, base.ebx.split.physical_line_partition, 1);
-show_one_plus(ways_of_associativity, base.ebx.split.ways_of_associativity, 1);
-show_one_plus(number_of_sets, base.ecx.split.number_of_sets, 1);
-
-static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	return sprintf(buf, "%luK\n", this_leaf->base.size / 1024);
-}
-
-static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
-					int type, char *buf)
-{
-	const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map);
-	int ret;
-
-	if (type)
-		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
-				cpumask_pr_args(mask));
-	else
-		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pb",
-				cpumask_pr_args(mask));
-	buf[ret++] = '\n';
-	buf[ret] = '\0';
-	return ret;
-}
-
-static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
-					  unsigned int cpu)
-{
-	return show_shared_cpu_map_func(leaf, 0, buf);
-}
-
-static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,
-					   unsigned int cpu)
-{
-	return show_shared_cpu_map_func(leaf, 1, buf);
-}
-
-static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	switch (this_leaf->base.eax.split.type) {
-	case CACHE_TYPE_DATA:
-		return sprintf(buf, "Data\n");
-	case CACHE_TYPE_INST:
-		return sprintf(buf, "Instruction\n");
-	case CACHE_TYPE_UNIFIED:
-		return sprintf(buf, "Unified\n");
-	default:
-		return sprintf(buf, "Unknown\n");
-	}
-}
-
-#define to_object(k)	container_of(k, struct _index_kobject, kobj)
-#define to_attr(a)	container_of(a, struct _cache_attr, attr)
-
-#define define_one_ro(_name) \
-static struct _cache_attr _name = \
-	__ATTR(_name, 0444, show_##_name, NULL)
-
-define_one_ro(level);
-define_one_ro(type);
-define_one_ro(coherency_line_size);
-define_one_ro(physical_line_partition);
-define_one_ro(ways_of_associativity);
-define_one_ro(number_of_sets);
-define_one_ro(size);
-define_one_ro(shared_cpu_map);
-define_one_ro(shared_cpu_list);
-
-static struct attribute *default_attrs[] = {
-	&type.attr,
-	&level.attr,
-	&coherency_line_size.attr,
-	&physical_line_partition.attr,
-	&ways_of_associativity.attr,
-	&number_of_sets.attr,
-	&size.attr,
-	&shared_cpu_map.attr,
-	&shared_cpu_list.attr,
-	NULL
-};
-
-#ifdef CONFIG_AMD_NB
-static struct attribute **amd_l3_attrs(void)
-{
-	static struct attribute **attrs;
-	int n;
-
-	if (attrs)
-		return attrs;
-
-	n = ARRAY_SIZE(default_attrs);
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		n += 2;
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		n += 1;
-
-	attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);
-	if (attrs == NULL)
-		return attrs = default_attrs;
-
-	for (n = 0; default_attrs[n]; n++)
-		attrs[n] = default_attrs[n];
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
-		attrs[n++] = &cache_disable_0.attr;
-		attrs[n++] = &cache_disable_1.attr;
-	}
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		attrs[n++] = &subcaches.attr;
-
-	return attrs;
-}
-#endif
-
-static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->show ?
-		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, this_leaf->cpu) :
-		0;
-	return ret;
 }
 
-static ssize_t store(struct kobject *kobj, struct attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->store ?
-		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, count, this_leaf->cpu) :
-		0;
-	return ret;
-}
-
-static const struct sysfs_ops sysfs_ops = {
-	.show   = show,
-	.store  = store,
-};
-
-static struct kobj_type ktype_cache = {
-	.sysfs_ops	= &sysfs_ops,
-	.default_attrs	= default_attrs,
-};
-
-static struct kobj_type ktype_percpu_entry = {
-	.sysfs_ops	= &sysfs_ops,
-};
-
-static void cpuid4_cache_sysfs_exit(unsigned int cpu)
+static void ci_leaf_init(struct cacheinfo *this_leaf,
+			 struct _cpuid4_info_regs *base)
 {
-	kfree(per_cpu(ici_cache_kobject, cpu));
-	kfree(per_cpu(ici_index_kobject, cpu));
-	per_cpu(ici_cache_kobject, cpu) = NULL;
-	per_cpu(ici_index_kobject, cpu) = NULL;
-	free_cache_attributes(cpu);
+	this_leaf->level = base->eax.split.level;
+	this_leaf->type = cache_type_map[base->eax.split.type];
+	this_leaf->coherency_line_size =
+				base->ebx.split.coherency_line_size + 1;
+	this_leaf->ways_of_associativity =
+				base->ebx.split.ways_of_associativity + 1;
+	this_leaf->size = base->size;
+	this_leaf->number_of_sets = base->ecx.split.number_of_sets + 1;
+	this_leaf->physical_line_partition =
+				base->ebx.split.physical_line_partition + 1;
+	this_leaf->priv = base->nb;
 }
 
-static int cpuid4_cache_sysfs_init(unsigned int cpu)
+static int __init_cache_level(unsigned int cpu)
 {
-	int err;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
-	if (num_cache_leaves == 0)
+	if (!num_cache_leaves)
 		return -ENOENT;
-
-	err = detect_cache_attributes(cpu);
-	if (err)
-		return err;
-
-	/* Allocate all required memory */
-	per_cpu(ici_cache_kobject, cpu) =
-		kzalloc(sizeof(struct kobject), GFP_KERNEL);
-	if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
-		goto err_out;
-
-	per_cpu(ici_index_kobject, cpu) = kzalloc(
-	    sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
-	if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
-		goto err_out;
-
+	if (!this_cpu_ci)
+		return -EINVAL;
+	this_cpu_ci->num_levels = 3;
+	this_cpu_ci->num_leaves = num_cache_leaves;
 	return 0;
-
-err_out:
-	cpuid4_cache_sysfs_exit(cpu);
-	return -ENOMEM;
 }
 
-static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
-
-/* Add/Remove cache interface for CPU device */
-static int cache_add_dev(struct device *dev)
+static int __populate_cache_leaves(unsigned int cpu)
 {
-	unsigned int cpu = dev->id;
-	unsigned long i, j;
-	struct _index_kobject *this_object;
-	struct _cpuid4_info   *this_leaf;
-	int retval;
-
-	retval = cpuid4_cache_sysfs_init(cpu);
-	if (unlikely(retval < 0))
-		return retval;
-
-	retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
-				      &ktype_percpu_entry,
-				      &dev->kobj, "%s", "cache");
-	if (retval < 0) {
-		cpuid4_cache_sysfs_exit(cpu);
-		return retval;
-	}
+	unsigned int idx, ret;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+	struct _cpuid4_info_regs id4_regs = {};
 
-	for (i = 0; i < num_cache_leaves; i++) {
-		this_object = INDEX_KOBJECT_PTR(cpu, i);
-		this_object->cpu = cpu;
-		this_object->index = i;
-
-		this_leaf = CPUID4_INFO_IDX(cpu, i);
-
-		ktype_cache.default_attrs = default_attrs;
-#ifdef CONFIG_AMD_NB
-		if (this_leaf->base.nb)
-			ktype_cache.default_attrs = amd_l3_attrs();
-#endif
-		retval = kobject_init_and_add(&(this_object->kobj),
-					      &ktype_cache,
-					      per_cpu(ici_cache_kobject, cpu),
-					      "index%1lu", i);
-		if (unlikely(retval)) {
-			for (j = 0; j < i; j++)
-				kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
-			kobject_put(per_cpu(ici_cache_kobject, cpu));
-			cpuid4_cache_sysfs_exit(cpu);
-			return retval;
-		}
-		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+		ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
+		if (ret)
+			return ret;
+		ci_leaf_init(this_leaf++, &id4_regs);
+		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
-	cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
-
-	kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
 	return 0;
 }
 
-static void cache_remove_dev(struct device *dev)
-{
-	unsigned int cpu = dev->id;
-	unsigned long i;
-
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return;
-	if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
-		return;
-	cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
-
-	for (i = 0; i < num_cache_leaves; i++)
-		kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
-	kobject_put(per_cpu(ici_cache_kobject, cpu));
-	cpuid4_cache_sysfs_exit(cpu);
-}
-
-static int cacheinfo_cpu_callback(struct notifier_block *nfb,
-				  unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct device *dev;
-
-	dev = get_cpu_device(cpu);
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		cache_add_dev(dev);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		cache_remove_dev(dev);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cacheinfo_cpu_notifier = {
-	.notifier_call = cacheinfo_cpu_callback,
-};
-
-static int __init cache_sysfs_init(void)
-{
-	int i, err = 0;
-
-	if (num_cache_leaves == 0)
-		return 0;
-
-	cpu_notifier_register_begin();
-	for_each_online_cpu(i) {
-		struct device *dev = get_cpu_device(i);
-
-		err = cache_add_dev(dev);
-		if (err)
-			goto out;
-	}
-	__register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-
-out:
-	cpu_notifier_register_done();
-	return err;
-}
-
-device_initcall(cache_sysfs_init);
-
-#endif
+DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
+DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-23 18:14 ` [PATCH RFT v2] " Sudeep Holla
@ 2015-02-24  7:58   ` Ingo Molnar
  2015-02-24  9:30     ` Sudeep Holla
  2015-02-24 17:57   ` Borislav Petkov
  2015-03-04 12:00   ` [PATCH v3] " Sudeep Holla
  2 siblings, 1 reply; 32+ messages in thread
From: Ingo Molnar @ 2015-02-24  7:58 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86


* Sudeep Holla <sudeep.holla@arm.com> wrote:

> This patch removes the redundant sysfs cacheinfo code by 
> reusing the newly introduced generic cacheinfo 
> infrastructure through the commit 246246cbde5e ("drivers: 
> base: support cpu cache information interface to 
> userspace via sysfs")
> 
> The private pointer provided by the cacheinfo is used to 
> implement the AMD L3 cache specific attributes.

Is there any change expected to the functionality/output of 
the code?

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-24  7:58   ` Ingo Molnar
@ 2015-02-24  9:30     ` Sudeep Holla
  0 siblings, 0 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-02-24  9:30 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Sudeep Holla, linux-kernel, Borislav Petkov, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin, x86



On 24/02/15 07:58, Ingo Molnar wrote:
>
> * Sudeep Holla <sudeep.holla@arm.com> wrote:
>
>> This patch removes the redundant sysfs cacheinfo code by
>> reusing the newly introduced generic cacheinfo
>> infrastructure through the commit 246246cbde5e ("drivers:
>> base: support cpu cache information interface to
>> userspace via sysfs")
>>
>> The private pointer provided by the cacheinfo is used to
>> implement the AMD L3 cache specific attributes.
>
> Is there any change expected to the functionality/output of
> the code?
>

No, in-fact the generic code is almost based on the x86 implementation.

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-23 18:14 ` [PATCH RFT v2] " Sudeep Holla
  2015-02-24  7:58   ` Ingo Molnar
@ 2015-02-24 17:57   ` Borislav Petkov
  2015-02-24 18:09     ` Sudeep Holla
  2015-03-01 22:39     ` Andre Przywara
  2015-03-04 12:00   ` [PATCH v3] " Sudeep Holla
  2 siblings, 2 replies; 32+ messages in thread
From: Borislav Petkov @ 2015-02-24 17:57 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86

On Mon, Feb 23, 2015 at 06:14:25PM +0000, Sudeep Holla wrote:
>  - Rebased on v4.0-rc1
>  - Fixed lockdep warning reported by Borislav

You probably have fixed the lockdep splat but not the NULL pointer
dereference which was there in the first mail I sent you. I'd suggest
you find an AMD box with an L3 and do some testing yourself before
sending out another version.

Also, when testing, do a snapshot of the sysfs cache hierarchy by doing:

grep . -EriIn /sys/devices/system/cpu/cpu?/cache/*

before your changes and after and check for differences.

We can't allow ourselves any differences because this is an API.

HTH.

[    2.981740] BUG: unable to handle kernel NULL pointer dereference at 00000000000000f8
[    2.989918] IP: [<ffffffff810141c0>] _populate_cache_leaves+0x440/0x460
[    2.996724] PGD 0 
[    2.998928] Oops: 0002 [#1] PREEMPT SMP 
[    3.003147] Modules linked in:
[    3.006395] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.0.0-rc1+ #1
[    3.012801] Hardware name: MICRO-STAR INTERNATIONAL CO.,LTD MS-7599/870-C45 (MS-7599), BIOS V1.15 03/04/2011
[    3.022871] task: ffff880132138000 ti: ffff880132180000 task.ti: ffff880132180000
[    3.030598] RIP: 0010:[<ffffffff810141c0>]  [<ffffffff810141c0>] _populate_cache_leaves+0x440/0x460
[    3.039942] RSP: 0000:ffff880132183c88  EFLAGS: 00010086
[    3.045395] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000000ffffffff
[    3.052671] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000000
[    3.059945] RBP: ffff880132183d28 R08: ffff880136c0a0c0 R09: 0000000000000001
[    3.067221] R10: 0000000000000000 R11: 000000000000001c R12: 0000000000000000
[    3.074495] R13: 000000000000a0c0 R14: ffffffff81ac4f98 R15: 0000000000000001
[    3.081770] FS:  0000000000000000(0000) GS:ffff880136c00000(0000) knlGS:0000000000000000
[    3.090108] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[    3.095996] CR2: 00000000000000f8 CR3: 0000000001a0b000 CR4: 00000000000006f0
[    3.103270] Stack:
[    3.105426]  ffff880132183de4 000000000000a000 000000000000a000 ffff880136c0fbc0
[    3.113272]  0000000000000090 ffff8801322c16b0 0000000000000006 ffff8801322c1720
[    3.121120]  000000000000a0c0 0000000300000000 0bc0003f14000163 00000000000007ff
[    3.128959] Call Trace:
[    3.131548]  [<ffffffff81013d80>] ? cpuid4_cache_lookup_regs+0x3e0/0x3e0
[    3.138390]  [<ffffffff810fd666>] generic_exec_single+0x136/0x1a0
[    3.144625]  [<ffffffff81013d80>] ? cpuid4_cache_lookup_regs+0x3e0/0x3e0
[    3.151466]  [<ffffffff810fd733>] smp_call_function_single+0x63/0xd0
[    3.157960]  [<ffffffff811ab560>] ? __kmalloc+0x160/0x200
[    3.163500]  [<ffffffff81014b72>] populate_cache_leaves+0x22/0x30
[    3.169734]  [<ffffffff813c8feb>] detect_cache_attributes+0x7b/0x1a0
[    3.176230]  [<ffffffff810002e0>] ? do_one_initcall+0x90/0x1f0
[    3.182204]  [<ffffffff81b17076>] ? container_dev_init+0x2f/0x2f
[    3.188352]  [<ffffffff81b170b8>] cacheinfo_sysfs_init+0x42/0x93
[    3.194498]  [<ffffffff81b17076>] ? container_dev_init+0x2f/0x2f
[    3.200649]  [<ffffffff810002f0>] do_one_initcall+0xa0/0x1f0
[    3.206448]  [<ffffffff8109ab00>] ? parse_args+0x150/0x420
[    3.212076]  [<ffffffff81ae5fae>] kernel_init_freeable+0x115/0x19d
[    3.218397]  [<ffffffff8157683f>] ? ret_from_fork+0xf/0xb0
[    3.224025]  [<ffffffff81568b40>] ? rest_init+0xd0/0xd0
[    3.229393]  [<ffffffff81568b4e>] kernel_init+0xe/0xf0
[    3.234674]  [<ffffffff815768ac>] ret_from_fork+0x7c/0xb0
[    3.240214]  [<ffffffff81568b40>] ? rest_init+0xd0/0xd0
[    3.245579] Code: 3c dd 40 4c ac 81 ff c2 48 63 d2 be 06 00 00 00 e8 a6 7c 2b 00 3b 05 24 1f ab 00 89 c2 7d a4 89 c0 
[    3.268135] RIP  [<ffffffff810141c0>] _populate_cache_leaves+0x440/0x460
[    3.275024]  RSP <ffff880132183c88>
[    3.278652] CR2: 00000000000000f8
[    3.282112] ---[ end trace 17992ce30d6a630e ]---
[    3.286872] Kernel panic - not syncing: Fatal exception
[    3.292302] Kernel Offset: disabled
[    3.295934] ---[ end Kernel panic - not syncing: Fatal exception

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-24 17:57   ` Borislav Petkov
@ 2015-02-24 18:09     ` Sudeep Holla
  2015-02-24 18:58       ` Borislav Petkov
  2015-03-01 22:39     ` Andre Przywara
  1 sibling, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-02-24 18:09 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86

Hi Boris,

On 24/02/15 17:57, Borislav Petkov wrote:
> On Mon, Feb 23, 2015 at 06:14:25PM +0000, Sudeep Holla wrote:
>>   - Rebased on v4.0-rc1
>>   - Fixed lockdep warning reported by Borislav
>
> You probably have fixed the lockdep splat but not the NULL pointer
> dereference which was there in the first mail I sent you. I'd suggest
> you find an AMD box with an L3 and do some testing yourself before
> sending out another version.
>

Sorry for the trouble and thanks for giving it a try. OK I will try to
find one, but it may be difficult to grab one.

> Also, when testing, do a snapshot of the sysfs cache hierarchy by doing:
>
> grep . -EriIn /sys/devices/system/cpu/cpu?/cache/*
>

Yes I have checked it on x86.

> before your changes and after and check for differences.
>

And they are exactly same.

> We can't allow ourselves any differences because this is an API.
>

As I mentioned to Ingo in the other email, that shouldn't happen as
generic code is almost based on existing x86 implementation. It was
moved to avoid further duplication while adding support to arm/arm64
and also to consolidate multiple existing duplicate implementations
(x86, ia64, s390 and ppc)

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-24 18:09     ` Sudeep Holla
@ 2015-02-24 18:58       ` Borislav Petkov
  0 siblings, 0 replies; 32+ messages in thread
From: Borislav Petkov @ 2015-02-24 18:58 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86

On Tue, Feb 24, 2015 at 06:09:17PM +0000, Sudeep Holla wrote:
> Sorry for the trouble and thanks for giving it a try. OK I will try to
> find one, but it may be difficult to grab one.

Well, either that or I can take a look as I have the box here but it
won't happen immediately as I'm swamped.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-24 17:57   ` Borislav Petkov
  2015-02-24 18:09     ` Sudeep Holla
@ 2015-03-01 22:39     ` Andre Przywara
  2015-03-02 10:17       ` Sudeep Holla
  2015-03-03 18:45       ` Borislav Petkov
  1 sibling, 2 replies; 32+ messages in thread
From: Andre Przywara @ 2015-03-01 22:39 UTC (permalink / raw)
  To: Borislav Petkov, Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86

On Tue, 24 Feb 2015 18:57:49 +0100, Borislav Petkov wrote:
> On Mon, Feb 23, 2015 at 06:14:25PM +0000, Sudeep Holla wrote:
>>  - Rebased on v4.0-rc1
>>  - Fixed lockdep warning reported by Borislav
> You probably have fixed the lockdep splat but not the NULL pointer
> dereference which was there in the first mail I sent you. I'd suggest
> you find an AMD box with an L3 and do some testing yourself before
> sending out another version.

So I gave that a spin on my old PhenomII X6 box, and indeed there is a
NULL pointer dereference. I tracked it down to
__cache_amd_cpumap_setup(), where the sibling map for the L3 is
populated. When the function is called for the first CPU, subsequent
CPU's cacheinfo structures obviously haven't been initialized yet, so
the struct cpu_cacheinfo we obtain for the other CPUs is empty
(num_levels and num_leaves are 0). Dereferencing info_list + index is
then a bad idea.
I fixed it by simply skipping the sibling map setup in this case (see
the patch below). Later we revisit this code path because the most
outer loop iterates over all CPUs anyway, so the fields are valid then
and the sibling map is build up properly. Not sure if that is a proper
fix (should we check for info_list being NULL?, is num_levels the
right value?), but I don't feel like looking into this code deeper
than I already did (Sudeep should be decorated for doing that!).

Boris, can you try this on a Bulldozer class machine?

Sudeep, if Boris acknowledges this, can you merge those two lines (or
something similar) in your patch and repost it? I can give it a try
then again.

>
> Also, when testing, do a snapshot of the sysfs cache hierarchy by
> doing:
>
> grep . -EriIn /sys/devices/system/cpu/cpu?/cache/*
> before your changes and after and check for differences.
>
> We can't allow ourselves any differences because this is an API.

But as Sudeep mentioned, this is an orthogonal issue not directly
related to this patch.
Indeed I see a regression between 3.19.0 and a clean 4.0.0-rc1 in this
respect, the diff is like:
-cpu5/cache/index3/shared_cpu_map:00000000,0000003f
+cpu5/cache/index3/shared_cpu_map:3f
(for each cpu and index)

Can someone confirm (and investigate) this?

Cheers,
Andre.

---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 5f3059c..1f69ce7 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -836,6 +836,8 @@ static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
 	} else if (index == 3) {
 		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
 			this_cpu_ci = get_cpu_cacheinfo(i);
+			if (index >= this_cpu_ci->num_levels)
+				continue;
 			this_leaf = this_cpu_ci->info_list + index;
 			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
 				if (!cpu_online(sibling))
-- 
1.8.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-01 22:39     ` Andre Przywara
@ 2015-03-02 10:17       ` Sudeep Holla
  2015-03-03 18:45       ` Borislav Petkov
  1 sibling, 0 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-03-02 10:17 UTC (permalink / raw)
  To: Andre Przywara, Borislav Petkov
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86

Hi Andre,

On 01/03/15 22:39, Andre Przywara wrote:
> On Tue, 24 Feb 2015 18:57:49 +0100, Borislav Petkov wrote:
>> On Mon, Feb 23, 2015 at 06:14:25PM +0000, Sudeep Holla wrote:
>>>   - Rebased on v4.0-rc1
>>>   - Fixed lockdep warning reported by Borislav
>> You probably have fixed the lockdep splat but not the NULL pointer
>> dereference which was there in the first mail I sent you. I'd suggest
>> you find an AMD box with an L3 and do some testing yourself before
>> sending out another version.
>
> So I gave that a spin on my old PhenomII X6 box, and indeed there is a
> NULL pointer dereference. I tracked it down to
> __cache_amd_cpumap_setup(), where the sibling map for the L3 is
> populated. When the function is called for the first CPU, subsequent
> CPU's cacheinfo structures obviously haven't been initialized yet, so
> the struct cpu_cacheinfo we obtain for the other CPUs is empty
> (num_levels and num_leaves are 0). Dereferencing info_list + index is
> then a bad idea.

Thanks a lot for spending time on debugging this and providing the fix.

> I fixed it by simply skipping the sibling map setup in this case (see
> the patch below). Later we revisit this code path because the most
> outer loop iterates over all CPUs anyway, so the fields are valid then
> and the sibling map is build up properly. Not sure if that is a proper
> fix (should we check for info_list being NULL?, is num_levels the
> right value?), but I don't feel like looking into this code deeper
> than I already did (Sudeep should be decorated for doing that!).
>
> Boris, can you try this on a Bulldozer class machine?
>
> Sudeep, if Boris acknowledges this, can you merge those two lines (or
> something similar) in your patch and repost it? I can give it a try
> then again.
>

I am fine squashing this change into the patch if Boris is fine with
the change.

>>
>> Also, when testing, do a snapshot of the sysfs cache hierarchy by
>> doing:
>>
>> grep . -EriIn /sys/devices/system/cpu/cpu?/cache/*
>> before your changes and after and check for differences.
>>
>> We can't allow ourselves any differences because this is an API.
>
> But as Sudeep mentioned, this is an orthogonal issue not directly
> related to this patch.
> Indeed I see a regression between 3.19.0 and a clean 4.0.0-rc1 in this
> respect, the diff is like:
> -cpu5/cache/index3/shared_cpu_map:00000000,0000003f
> +cpu5/cache/index3/shared_cpu_map:3f
> (for each cpu and index)
>
> Can someone confirm (and investigate) this?
>

I saw this even on ARM64 platforms with 4.0-rc1 and did narrow down to
series of formatting functions changes introduced by Tejun Heo, mainly
commit 4a0792b0e7a6("bitmap: use %*pb[l] to print bitmaps including
cpumasks and nodemasks")

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-01 22:39     ` Andre Przywara
  2015-03-02 10:17       ` Sudeep Holla
@ 2015-03-03 18:45       ` Borislav Petkov
  2015-03-03 18:53         ` Tejun Heo
  2015-03-04  9:52         ` Sudeep Holla
  1 sibling, 2 replies; 32+ messages in thread
From: Borislav Petkov @ 2015-03-03 18:45 UTC (permalink / raw)
  To: Andre Przywara, Sudeep Holla, Tejun Heo
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86

@Tejun: scroll to the end :)

On Sun, Mar 01, 2015 at 10:39:24PM +0000, Andre Przywara wrote:
> So I gave that a spin on my old PhenomII X6 box, and indeed there is a
> NULL pointer dereference. I tracked it down to
> __cache_amd_cpumap_setup(), where the sibling map for the L3 is
> populated. When the function is called for the first CPU, subsequent
> CPU's cacheinfo structures obviously haven't been initialized yet, so

Right, let me try to understand the splat:

[    3.030598] RIP: 0010:[<ffffffff810141c0>]  [<ffffffff810141c0>] _populate_cache_leaves+0x440/0x460

This is:

     9d6:       49 0f a3 06             bt     %rax,(%r14)
     9da:       19 c9                   sbb    %ecx,%ecx
     9dc:       85 c9                   test   %ecx,%ecx
     9de:       74 d0                   je     9b0 <_populate_cache_leaves+0x410>
     9e0:       f0 49 0f ab 84 24 f8    lock bts %rax,0xf8(%r12)			<----
     9e7:       00 00 00 
     9ea:       eb c4                   jmp    9b0 <_populate_cache_leaves+0x410>
     9ec:       4c 8b 65 98             mov    -0x68(%rbp),%r12
     9f0:       e9 eb fd ff ff          jmpq   7e0 <_populate_cache_leaves+0x240>
     9f5:       66 66 2e 0f 1f 84 00    data16 nopw %cs:0x0(%rax,%rax,1)

%r12 is 0 and that is this hunk in __cache_amd_cpumap_setup():

        } else if (index == 3) {
                for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
                        this_cpu_ci = get_cpu_cacheinfo(i);
                        this_leaf = this_cpu_ci->info_list + index;
                        for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
                                if (!cpu_online(sibling))
                                        continue;
                                cpumask_set_cpu(sibling,			<--- set_bit() does LOCK
                                                &this_leaf->shared_cpu_map);
                        }
                }

so this_leaf is NULL.

We get it by doing

	this_leaf = this_cpu_ci->info_list + index;

and this_cpu_ci is a per-CPU variable.

Now, previously the code did

-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;


and __cache_cpumap_setup() already does:

                        if (i == cpu || !sib_cpu_ci->info_list)
                                continue;/* skip if itself or no cacheinfo */

so maybe we should do that too in __cache_amd_cpumap_setup():

                        if (!this_cpu_ci->info_list)
                                continue;

for the index == 3 case?

It boots fine here with that change and it is consistent with the
previous code.

And yes, the x86 cacheinfo code could use a serious rubbing and cleanup.

Btw, this patch introduces a bunch of new sysfs nodes in the caches
hierarchy:

--- caches-guest-before.txt     2015-03-03 15:11:09.168276423 +0100
+++ caches-guest-after.txt      2015-03-03 18:19:04.084426130 +0100
@@ -1,6 +1,22 @@
+/sys/devices/system/cpu/cpu0/cache/power/control:1:auto
+/sys/devices/system/cpu/cpu0/cache/power/async:1:disabled
+/sys/devices/system/cpu/cpu0/cache/power/runtime_enabled:1:disabled
+/sys/devices/system/cpu/cpu0/cache/power/runtime_active_kids:1:0
+/sys/devices/system/cpu/cpu0/cache/power/runtime_active_time:1:0
+/sys/devices/system/cpu/cpu0/cache/power/runtime_status:1:unsupported
+/sys/devices/system/cpu/cpu0/cache/power/runtime_usage:1:0
+/sys/devices/system/cpu/cpu0/cache/power/runtime_suspended_time:1:0
 /sys/devices/system/cpu/cpu0/cache/index0/size:1:64K
 /sys/devices/system/cpu/cpu0/cache/index0/type:1:Data
 /sys/devices/system/cpu/cpu0/cache/index0/level:1:1
+/sys/devices/system/cpu/cpu0/cache/index0/power/control:1:auto
+/sys/devices/system/cpu/cpu0/cache/index0/power/async:1:disabled
+/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_enabled:1:disabled
+/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_active_kids:1:0
+/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_active_time:1:0
+/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_status:1:unsupported
+/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_usage:1:0
+/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_suspended_time:1:0
 /sys/devices/system/cpu/cpu0/cache/index0/number_of_sets:1:512
 /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map:1:1
 /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list:1:0
 ...

What do those things mean? runtime_active_kids ?? Kids are active during
runtime?! Well, that's a given, no need for a sysfs node for that :-)

> > Indeed I see a regression between 3.19.0 and a clean 4.0.0-rc1 in this
> > respect, the diff is like:
> > -cpu5/cache/index3/shared_cpu_map:00000000,0000003f
> > +cpu5/cache/index3/shared_cpu_map:3f
> > (for each cpu and index)
> >
> > Can someone confirm (and investigate) this?
>
> I saw this even on ARM64 platforms with 4.0-rc1 and did narrow down to
> series of formatting functions changes introduced by Tejun Heo, mainly
> commit 4a0792b0e7a6("bitmap: use %*pb[l] to print bitmaps including
> cpumasks and nodemasks")

Strictly speaking, this is a regression if userspace is parsing those
masks. I hardly doubt anything is doing that but if we had to be
completely strict we should add back the zeroes.

Tejun, we have this change in user-visible masks formatting in sysfs
after your bitmaps printing changes:

-cpu5/cache/index3/shared_cpu_map:00000000,0000003f
+cpu5/cache/index3/shared_cpu_map:3f

What's the rationale on userspace parsing bitmaps in sysfs, we don't
care?

Thanks.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-03 18:45       ` Borislav Petkov
@ 2015-03-03 18:53         ` Tejun Heo
  2015-03-03 18:57           ` Borislav Petkov
  2015-03-04  9:52         ` Sudeep Holla
  1 sibling, 1 reply; 32+ messages in thread
From: Tejun Heo @ 2015-03-03 18:53 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Andre Przywara, Sudeep Holla, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin, x86

Hello, Borislav.

On Tue, Mar 03, 2015 at 07:45:27PM +0100, Borislav Petkov wrote:
> Tejun, we have this change in user-visible masks formatting in sysfs
> after your bitmaps printing changes:
> 
> -cpu5/cache/index3/shared_cpu_map:00000000,0000003f
> +cpu5/cache/index3/shared_cpu_map:3f
> 
> What's the rationale on userspace parsing bitmaps in sysfs, we don't
> care?

We were alternating between the two forms depending on
CONFIG_CPUMASK_OFFSTACK before.  Now we're always sticking to the
shorter format.  Please see 513e3d2d11c9 ("cpumask: always use
nr_cpu_ids in formatting and parsing functions").

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-03 18:53         ` Tejun Heo
@ 2015-03-03 18:57           ` Borislav Petkov
  2015-03-04 11:15             ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-03 18:57 UTC (permalink / raw)
  To: Tejun Heo, Sudeep Holla
  Cc: Andre Przywara, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86

On Tue, Mar 03, 2015 at 01:53:02PM -0500, Tejun Heo wrote:
> We were alternating between the two forms depending on
> CONFIG_CPUMASK_OFFSTACK before.  Now we're always sticking to the
> shorter format.  Please see 513e3d2d11c9 ("cpumask: always use
> nr_cpu_ids in formatting and parsing functions").

Got it, thanks.

Sudeep, please add Tejun's note to your commit message when resending.

Thanks.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-03 18:45       ` Borislav Petkov
  2015-03-03 18:53         ` Tejun Heo
@ 2015-03-04  9:52         ` Sudeep Holla
  1 sibling, 0 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-03-04  9:52 UTC (permalink / raw)
  To: Borislav Petkov, Andre Przywara, Tejun Heo
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86



On 03/03/15 18:45, Borislav Petkov wrote:
[...]

> Now, previously the code did
>
> -			if (!per_cpu(ici_cpuid4_info, i))
> -				continue;
>
>
> and __cache_cpumap_setup() already does:
>
>                          if (i == cpu || !sib_cpu_ci->info_list)
>                                  continue;/* skip if itself or no cacheinfo */
>
> so maybe we should do that too in __cache_amd_cpumap_setup():
>
>                          if (!this_cpu_ci->info_list)
>                                  continue;
>
> for the index == 3 case?
>
> It boots fine here with that change and it is consistent with the
> previous code.
>

Ok, I will add the above check. Sorry for missing that.

> And yes, the x86 cacheinfo code could use a serious rubbing and cleanup.
>
> Btw, this patch introduces a bunch of new sysfs nodes in the caches
> hierarchy:
>
> --- caches-guest-before.txt     2015-03-03 15:11:09.168276423 +0100
> +++ caches-guest-after.txt      2015-03-03 18:19:04.084426130 +0100
> @@ -1,6 +1,22 @@
> +/sys/devices/system/cpu/cpu0/cache/power/control:1:auto
> +/sys/devices/system/cpu/cpu0/cache/power/async:1:disabled
> +/sys/devices/system/cpu/cpu0/cache/power/runtime_enabled:1:disabled
> +/sys/devices/system/cpu/cpu0/cache/power/runtime_active_kids:1:0
> +/sys/devices/system/cpu/cpu0/cache/power/runtime_active_time:1:0
> +/sys/devices/system/cpu/cpu0/cache/power/runtime_status:1:unsupported
> +/sys/devices/system/cpu/cpu0/cache/power/runtime_usage:1:0
> +/sys/devices/system/cpu/cpu0/cache/power/runtime_suspended_time:1:0
>   /sys/devices/system/cpu/cpu0/cache/index0/size:1:64K
>   /sys/devices/system/cpu/cpu0/cache/index0/type:1:Data
>   /sys/devices/system/cpu/cpu0/cache/index0/level:1:1
> +/sys/devices/system/cpu/cpu0/cache/index0/power/control:1:auto
> +/sys/devices/system/cpu/cpu0/cache/index0/power/async:1:disabled
> +/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_enabled:1:disabled
> +/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_active_kids:1:0
> +/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_active_time:1:0
> +/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_status:1:unsupported
> +/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_usage:1:0
> +/sys/devices/system/cpu/cpu0/cache/index0/power/runtime_suspended_time:1:0
>   /sys/devices/system/cpu/cpu0/cache/index0/number_of_sets:1:512
>   /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map:1:1
>   /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list:1:0
>   ...
>
> What do those things mean? runtime_active_kids ?? Kids are active during
> runtime?! Well, that's a given, no need for a sysfs node for that :-)
>

Those extra sysfs are due to that fact that generic cacheinfo sysfs
is not using raw kobjects directly anymore (which was the case with most
of the old cacheinfo sysfs implementation), but uses device/device
attributes as Greg suggested to simply the code and reuse device model
code.

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-03 18:57           ` Borislav Petkov
@ 2015-03-04 11:15             ` Sudeep Holla
  2015-03-04 11:27               ` Borislav Petkov
  0 siblings, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-03-04 11:15 UTC (permalink / raw)
  To: Borislav Petkov, Tejun Heo
  Cc: Sudeep Holla, Andre Przywara, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin, x86

Hi Boris,

On 03/03/15 18:57, Borislav Petkov wrote:
> On Tue, Mar 03, 2015 at 01:53:02PM -0500, Tejun Heo wrote:
>> We were alternating between the two forms depending on
>> CONFIG_CPUMASK_OFFSTACK before.  Now we're always sticking to the
>> shorter format.  Please see 513e3d2d11c9 ("cpumask: always use
>> nr_cpu_ids in formatting and parsing functions").
>
> Got it, thanks.
>
> Sudeep, please add Tejun's note to your commit message when resending.
>

I can do that, but wouldn't that add confusion as this commit is not
changing that behaviour. It's already changed in v4.0-rc1

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-04 11:15             ` Sudeep Holla
@ 2015-03-04 11:27               ` Borislav Petkov
  2015-03-04 11:35                 ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-04 11:27 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Tejun Heo, Andre Przywara, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin, x86

On Wed, Mar 04, 2015 at 11:15:49AM +0000, Sudeep Holla wrote:
> I can do that, but wouldn't that add confusion as this commit is not
> changing that behaviour. It's already changed in v4.0-rc1

Nah, this would add a reference to the fact that the cpumask format is
not really a stable thing and thus cannot be considered a userpsace
regression. And having this info is important IMO in case someone is
wondering in the future.

In general, having more and even redundant info in the commit messages
is much better than having less info. I can't count the times I've been
staring at a one-liner commit message and trying to rhyme up what was
the purpose of doing it this way.

So more is more, in this case. :-)

Thanks.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH RFT v2] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-04 11:27               ` Borislav Petkov
@ 2015-03-04 11:35                 ` Sudeep Holla
  0 siblings, 0 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-03-04 11:35 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Sudeep Holla, Tejun Heo, Andre Przywara, linux-kernel,
	Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86



On 04/03/15 11:27, Borislav Petkov wrote:
> On Wed, Mar 04, 2015 at 11:15:49AM +0000, Sudeep Holla wrote:
>> I can do that, but wouldn't that add confusion as this commit is not
>> changing that behaviour. It's already changed in v4.0-rc1
>
> Nah, this would add a reference to the fact that the cpumask format is
> not really a stable thing and thus cannot be considered a userpsace
> regression. And having this info is important IMO in case someone is
> wondering in the future.
>

Thanks for clarifying, will add that info. Now I think it completely
makes sense especially since this commit will be the first target when
user-space first notice this cpumask format change.

> In general, having more and even redundant info in the commit messages
> is much better than having less info. I can't count the times I've been
> staring at a one-liner commit message and trying to rhyme up what was
> the purpose of doing it this way.
>
> So more is more, in this case. :-)
>

Agreed :)

--
Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-02-23 18:14 ` [PATCH RFT v2] " Sudeep Holla
  2015-02-24  7:58   ` Ingo Molnar
  2015-02-24 17:57   ` Borislav Petkov
@ 2015-03-04 12:00   ` Sudeep Holla
  2015-03-04 12:27     ` Borislav Petkov
  2015-03-09 14:46     ` [tip:x86/cpu] x86/cacheinfo: Move cacheinfo sysfs code to generic infrastructure tip-bot for Sudeep Holla
  2 siblings, 2 replies; 32+ messages in thread
From: Sudeep Holla @ 2015-03-04 12:00 UTC (permalink / raw)
  To: linux-kernel, Borislav Petkov
  Cc: Sudeep Holla, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

This patch removes the redundant sysfs cacheinfo code by reusing
the newly introduced generic cacheinfo infrastructure through the
commit 246246cbde5e ("drivers: base: support cpu cache information
interface to userspace via sysfs")

The private pointer provided by the cacheinfo is used to implement
the AMD L3 cache specific attributes.

Note that with v4.0-rc1, commit 513e3d2d11c9 ("cpumask: always use
nr_cpu_ids in formatting and parsing functions") in particular changes
from long format to shorter one for all cpumasks sysfs entries. As the
consequence of the same, even the shared_cpu_map in the cacheinfo sysfs
was also changed.

This patch neither alters any existing sysfs entries nor their formating,
however since the generic cacheinfo has switched to use the device
attributes instead of the traditional raw kobjects, a directory named
"power" along with its standard attributes are added similar to any
other device.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Andre Przywara <andre.przywara@arm.com>
Cc: x86@kernel.org
---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 711 ++++++++++------------------------
 1 file changed, 194 insertions(+), 517 deletions(-)

v2->v3:
 - Fixed the NULL pointer deference that occured as a check was missed
   when migrating to generic cacheinfo. Thanks to Andre Przywara for
   debugging the same and Borislav Petkov for suggesting the fix.
 - Added a note in the commit log regarding the recent change in
   cpumask sysfs formating.

v1->v2:
 - Rebased on v4.0-rc1
 - Fixed lockdep warning reported by Borislav

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 659643376dbf..54e43d58e714 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -7,16 +7,14 @@
  *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/compiler.h>
+#include <linux/cacheinfo.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/sysfs.h>
 #include <linux/pci.h>
 
 #include <asm/processor.h>
-#include <linux/smp.h>
 #include <asm/amd_nb.h>
 #include <asm/smp.h>
 
@@ -116,10 +114,10 @@ static const struct _cache_table cache_table[] =
 
 
 enum _cache_type {
-	CACHE_TYPE_NULL	= 0,
-	CACHE_TYPE_DATA = 1,
-	CACHE_TYPE_INST = 2,
-	CACHE_TYPE_UNIFIED = 3
+	CTYPE_NULL = 0,
+	CTYPE_DATA = 1,
+	CTYPE_INST = 2,
+	CTYPE_UNIFIED = 3
 };
 
 union _cpuid4_leaf_eax {
@@ -159,11 +157,6 @@ struct _cpuid4_info_regs {
 	struct amd_northbridge *nb;
 };
 
-struct _cpuid4_info {
-	struct _cpuid4_info_regs base;
-	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
-};
-
 unsigned short			num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -220,6 +213,13 @@ static const unsigned short assocs[] = {
 static const unsigned char levels[] = { 1, 1, 2, 3 };
 static const unsigned char types[] = { 1, 2, 3, 3 };
 
+static const enum cache_type cache_type_map[] = {
+	[CTYPE_NULL] = CACHE_TYPE_NOCACHE,
+	[CTYPE_DATA] = CACHE_TYPE_DATA,
+	[CTYPE_INST] = CACHE_TYPE_INST,
+	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
+};
+
 static void
 amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		     union _cpuid4_leaf_ebx *ebx,
@@ -291,14 +291,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
-struct _cache_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);
-	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,
-			 unsigned int);
-};
-
 #if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
+
 /*
  * L3 cache descriptors
  */
@@ -325,20 +319,6 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb)
 	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
-static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
-{
-	int node;
-
-	/* only for L3, and not in virtualized environments */
-	if (index < 3)
-		return;
-
-	node = amd_get_nb_id(smp_processor_id());
-	this_leaf->nb = node_to_amd_nb(node);
-	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
-		amd_calc_l3_indices(this_leaf->nb);
-}
-
 /*
  * check whether a slot used for disabling an L3 index is occupied.
  * @l3: L3 cache descriptor
@@ -359,15 +339,13 @@ int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot)
 	return -1;
 }
 
-static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
+static ssize_t show_cache_disable(struct cacheinfo *this_leaf, char *buf,
 				  unsigned int slot)
 {
 	int index;
+	struct amd_northbridge *nb = this_leaf->priv;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	index = amd_get_l3_disable_slot(this_leaf->base.nb, slot);
+	index = amd_get_l3_disable_slot(nb, slot);
 	if (index >= 0)
 		return sprintf(buf, "%d\n", index);
 
@@ -376,9 +354,10 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 
 #define SHOW_CACHE_DISABLE(slot)					\
 static ssize_t								\
-show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf,	\
-			  unsigned int cpu)				\
+cache_disable_##slot##_show(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return show_cache_disable(this_leaf, buf, slot);		\
 }
 SHOW_CACHE_DISABLE(0)
@@ -446,25 +425,23 @@ int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot,
 	return 0;
 }
 
-static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
-				  const char *buf, size_t count,
-				  unsigned int slot)
+static ssize_t store_cache_disable(struct cacheinfo *this_leaf,
+				   const char *buf, size_t count,
+				   unsigned int slot)
 {
 	unsigned long val = 0;
 	int cpu, err = 0;
+	struct amd_northbridge *nb = this_leaf->priv;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
+	cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	if (kstrtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	err = amd_set_l3_disable_slot(this_leaf->base.nb, cpu, slot, val);
+	err = amd_set_l3_disable_slot(nb, cpu, slot, val);
 	if (err) {
 		if (err == -EEXIST)
 			pr_warning("L3 slot %d in use/index already disabled!\n",
@@ -476,41 +453,36 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 
 #define STORE_CACHE_DISABLE(slot)					\
 static ssize_t								\
-store_cache_disable_##slot(struct _cpuid4_info *this_leaf,		\
-			   const char *buf, size_t count,		\
-			   unsigned int cpu)				\
+cache_disable_##slot##_store(struct device *dev,			\
+			     struct device_attribute *attr,		\
+			     const char *buf, size_t count)		\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return store_cache_disable(this_leaf, buf, count, slot);	\
 }
 STORE_CACHE_DISABLE(0)
 STORE_CACHE_DISABLE(1)
 
-static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
-		show_cache_disable_0, store_cache_disable_0);
-static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
-		show_cache_disable_1, store_cache_disable_1);
-
-static ssize_t
-show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)
+static ssize_t subcaches_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
 }
 
-static ssize_t
-store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
-		unsigned int cpu)
+static ssize_t subcaches_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
 {
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 	unsigned long val;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
-
 	if (kstrtoul(buf, 16, &val) < 0)
 		return -EINVAL;
 
@@ -520,9 +492,92 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
 	return count;
 }
 
-static struct _cache_attr subcaches =
-	__ATTR(subcaches, 0644, show_subcaches, store_subcaches);
+static DEVICE_ATTR_RW(cache_disable_0);
+static DEVICE_ATTR_RW(cache_disable_1);
+static DEVICE_ATTR_RW(subcaches);
+
+static umode_t
+cache_private_attrs_is_visible(struct kobject *kobj,
+			       struct attribute *attr, int unused)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	umode_t mode = attr->mode;
+
+	if (!this_leaf->priv)
+		return 0;
+
+	if ((attr == &dev_attr_subcaches.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		return mode;
+
+	if ((attr == &dev_attr_cache_disable_0.attr ||
+	     attr == &dev_attr_cache_disable_1.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		return mode;
+
+	return 0;
+}
+
+static struct attribute_group cache_private_group = {
+	.is_visible = cache_private_attrs_is_visible,
+};
+
+static void init_amd_l3_attrs(void)
+{
+	int n = 1;
+	static struct attribute **amd_l3_attrs;
+
+	if (amd_l3_attrs) /* already initialized */
+		return;
+
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		n += 2;
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		n += 1;
+
+	amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
+	if (!amd_l3_attrs)
+		return;
+
+	n = 0;
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
+	}
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
+
+	cache_private_group.attrs = amd_l3_attrs;
+}
+
+const struct attribute_group *
+cache_get_priv_group(struct cacheinfo *this_leaf)
+{
+	struct amd_northbridge *nb = this_leaf->priv;
+
+	if (this_leaf->level < 3)
+		return NULL;
+
+	if (nb && nb->l3_cache.indices)
+		init_amd_l3_attrs();
+
+	return &cache_private_group;
+}
+
+static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
+{
+	int node;
+
+	/* only for L3, and not in virtualized environments */
+	if (index < 3)
+		return;
 
+	node = amd_get_nb_id(smp_processor_id());
+	this_leaf->nb = node_to_amd_nb(node);
+	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
+		amd_calc_l3_indices(this_leaf->nb);
+}
 #else
 #define amd_init_l3_cache(x, y)
 #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
@@ -546,7 +601,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
 		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
 	}
 
-	if (eax.split.type == CACHE_TYPE_NULL)
+	if (eax.split.type == CTYPE_NULL)
 		return -EIO; /* better error ? */
 
 	this_leaf->eax = eax;
@@ -575,7 +630,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
 		/* Do cpuid(op) loop to find out num_cache_leaves */
 		cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
 		cache_eax.full = eax;
-	} while (cache_eax.split.type != CACHE_TYPE_NULL);
+	} while (cache_eax.split.type != CTYPE_NULL);
 	return i;
 }
 
@@ -626,9 +681,9 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
 			switch (this_leaf.eax.split.level) {
 			case 1:
-				if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
+				if (this_leaf.eax.split.type == CTYPE_DATA)
 					new_l1d = this_leaf.size/1024;
-				else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
+				else if (this_leaf.eax.split.type == CTYPE_INST)
 					new_l1i = this_leaf.size/1024;
 				break;
 			case 2:
@@ -747,55 +802,48 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 	return l2;
 }
 
-#ifdef CONFIG_SYSFS
-
-/* pointer to _cpuid4_info array (for each cache leaf) */
-static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(ici_cpuid4_info, x))[y]))
-
-#ifdef CONFIG_SMP
-
-static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
+static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
+				    struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf;
 	int i, sibling;
 
 	if (cpu_has_topoext) {
 		unsigned int apicid, nshared, first, last;
 
-		if (!per_cpu(ici_cpuid4_info, cpu))
-			return 0;
-
-		this_leaf = CPUID4_INFO_IDX(cpu, index);
-		nshared = this_leaf->base.eax.split.num_threads_sharing + 1;
+		this_leaf = this_cpu_ci->info_list + index;
+		nshared = base->eax.split.num_threads_sharing + 1;
 		apicid = cpu_data(cpu).apicid;
 		first = apicid - (apicid % nshared);
 		last = first + nshared - 1;
 
 		for_each_online_cpu(i) {
+			this_cpu_ci = get_cpu_cacheinfo(i);
 			apicid = cpu_data(i).apicid;
 			if ((apicid < first) || (apicid > last))
 				continue;
-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_leaf = this_cpu_ci->info_list + index;
 
 			for_each_online_cpu(sibling) {
 				apicid = cpu_data(sibling).apicid;
 				if ((apicid < first) || (apicid > last))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else if (index == 3) {
 		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
-			if (!per_cpu(ici_cpuid4_info, i))
+			this_cpu_ci = get_cpu_cacheinfo(i);
+			if (!this_cpu_ci->info_list)
 				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_leaf = this_cpu_ci->info_list + index;
 			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
 				if (!cpu_online(sibling))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else
@@ -804,457 +852,86 @@ static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
 	return 1;
 }
 
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
+static void __cache_cpumap_setup(unsigned int cpu, int index,
+				 struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf, *sibling_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf, *sibling_leaf;
 	unsigned long num_threads_sharing;
 	int index_msb, i;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 
 	if (c->x86_vendor == X86_VENDOR_AMD) {
-		if (cache_shared_amd_cpu_map_setup(cpu, index))
+		if (__cache_amd_cpumap_setup(cpu, index, base))
 			return;
 	}
 
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	num_threads_sharing = 1 + this_leaf->base.eax.split.num_threads_sharing;
+	this_leaf = this_cpu_ci->info_list + index;
+	num_threads_sharing = 1 + base->eax.split.num_threads_sharing;
 
+	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
 	if (num_threads_sharing == 1)
-		cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
-	else {
-		index_msb = get_count_order(num_threads_sharing);
-
-		for_each_online_cpu(i) {
-			if (cpu_data(i).apicid >> index_msb ==
-			    c->apicid >> index_msb) {
-				cpumask_set_cpu(i,
-					to_cpumask(this_leaf->shared_cpu_map));
-				if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
-					sibling_leaf =
-						CPUID4_INFO_IDX(i, index);
-					cpumask_set_cpu(cpu, to_cpumask(
-						sibling_leaf->shared_cpu_map));
-				}
-			}
-		}
-	}
-}
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-	struct _cpuid4_info	*this_leaf, *sibling_leaf;
-	int sibling;
-
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
-		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
-		cpumask_clear_cpu(cpu,
-				  to_cpumask(sibling_leaf->shared_cpu_map));
-	}
-}
-#else
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
-{
-}
-
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-}
-#endif
-
-static void free_cache_attributes(unsigned int cpu)
-{
-	int i;
-
-	for (i = 0; i < num_cache_leaves; i++)
-		cache_remove_shared_cpu_map(cpu, i);
-
-	kfree(per_cpu(ici_cpuid4_info, cpu));
-	per_cpu(ici_cpuid4_info, cpu) = NULL;
-}
-
-static void get_cpu_leaves(void *_retval)
-{
-	int j, *retval = _retval, cpu = smp_processor_id();
+		return;
 
-	/* Do cpuid and store the results */
-	for (j = 0; j < num_cache_leaves; j++) {
-		struct _cpuid4_info *this_leaf = CPUID4_INFO_IDX(cpu, j);
+	index_msb = get_count_order(num_threads_sharing);
 
-		*retval = cpuid4_cache_lookup_regs(j, &this_leaf->base);
-		if (unlikely(*retval < 0)) {
-			int i;
+	for_each_online_cpu(i)
+		if (cpu_data(i).apicid >> index_msb == c->apicid >> index_msb) {
+			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
 
-			for (i = 0; i < j; i++)
-				cache_remove_shared_cpu_map(cpu, i);
-			break;
+			if (i == cpu || !sib_cpu_ci->info_list)
+				continue;/* skip if itself or no cacheinfo */
+			sibling_leaf = sib_cpu_ci->info_list + index;
+			cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+			cpumask_set_cpu(cpu, &sibling_leaf->shared_cpu_map);
 		}
-		cache_shared_cpu_map_setup(cpu, j);
-	}
 }
 
-static int detect_cache_attributes(unsigned int cpu)
+static void ci_leaf_init(struct cacheinfo *this_leaf,
+			 struct _cpuid4_info_regs *base)
 {
-	int			retval;
-
-	if (num_cache_leaves == 0)
-		return -ENOENT;
-
-	per_cpu(ici_cpuid4_info, cpu) = kzalloc(
-	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return -ENOMEM;
-
-	smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
-	if (retval) {
-		kfree(per_cpu(ici_cpuid4_info, cpu));
-		per_cpu(ici_cpuid4_info, cpu) = NULL;
-	}
-
-	return retval;
-}
-
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/cpu.h>
-
-/* pointer to kobject for cpuX/cache */
-static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
-
-struct _index_kobject {
-	struct kobject kobj;
-	unsigned int cpu;
-	unsigned short index;
-};
-
-/* pointer to array of kobjects for cpuX/cache/indexY */
-static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(ici_index_kobject, x))[y]))
-
-#define show_one_plus(file_name, object, val)				\
-static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \
-				unsigned int cpu)			\
-{									\
-	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
-}
-
-show_one_plus(level, base.eax.split.level, 0);
-show_one_plus(coherency_line_size, base.ebx.split.coherency_line_size, 1);
-show_one_plus(physical_line_partition, base.ebx.split.physical_line_partition, 1);
-show_one_plus(ways_of_associativity, base.ebx.split.ways_of_associativity, 1);
-show_one_plus(number_of_sets, base.ecx.split.number_of_sets, 1);
-
-static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	return sprintf(buf, "%luK\n", this_leaf->base.size / 1024);
-}
-
-static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
-					int type, char *buf)
-{
-	const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map);
-	int ret;
-
-	if (type)
-		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
-				cpumask_pr_args(mask));
-	else
-		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pb",
-				cpumask_pr_args(mask));
-	buf[ret++] = '\n';
-	buf[ret] = '\0';
-	return ret;
-}
-
-static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
-					  unsigned int cpu)
-{
-	return show_shared_cpu_map_func(leaf, 0, buf);
-}
-
-static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,
-					   unsigned int cpu)
-{
-	return show_shared_cpu_map_func(leaf, 1, buf);
+	this_leaf->level = base->eax.split.level;
+	this_leaf->type = cache_type_map[base->eax.split.type];
+	this_leaf->coherency_line_size =
+				base->ebx.split.coherency_line_size + 1;
+	this_leaf->ways_of_associativity =
+				base->ebx.split.ways_of_associativity + 1;
+	this_leaf->size = base->size;
+	this_leaf->number_of_sets = base->ecx.split.number_of_sets + 1;
+	this_leaf->physical_line_partition =
+				base->ebx.split.physical_line_partition + 1;
+	this_leaf->priv = base->nb;
 }
 
-static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	switch (this_leaf->base.eax.split.type) {
-	case CACHE_TYPE_DATA:
-		return sprintf(buf, "Data\n");
-	case CACHE_TYPE_INST:
-		return sprintf(buf, "Instruction\n");
-	case CACHE_TYPE_UNIFIED:
-		return sprintf(buf, "Unified\n");
-	default:
-		return sprintf(buf, "Unknown\n");
-	}
-}
-
-#define to_object(k)	container_of(k, struct _index_kobject, kobj)
-#define to_attr(a)	container_of(a, struct _cache_attr, attr)
-
-#define define_one_ro(_name) \
-static struct _cache_attr _name = \
-	__ATTR(_name, 0444, show_##_name, NULL)
-
-define_one_ro(level);
-define_one_ro(type);
-define_one_ro(coherency_line_size);
-define_one_ro(physical_line_partition);
-define_one_ro(ways_of_associativity);
-define_one_ro(number_of_sets);
-define_one_ro(size);
-define_one_ro(shared_cpu_map);
-define_one_ro(shared_cpu_list);
-
-static struct attribute *default_attrs[] = {
-	&type.attr,
-	&level.attr,
-	&coherency_line_size.attr,
-	&physical_line_partition.attr,
-	&ways_of_associativity.attr,
-	&number_of_sets.attr,
-	&size.attr,
-	&shared_cpu_map.attr,
-	&shared_cpu_list.attr,
-	NULL
-};
-
-#ifdef CONFIG_AMD_NB
-static struct attribute **amd_l3_attrs(void)
+static int __init_cache_level(unsigned int cpu)
 {
-	static struct attribute **attrs;
-	int n;
-
-	if (attrs)
-		return attrs;
-
-	n = ARRAY_SIZE(default_attrs);
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		n += 2;
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		n += 1;
-
-	attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);
-	if (attrs == NULL)
-		return attrs = default_attrs;
-
-	for (n = 0; default_attrs[n]; n++)
-		attrs[n] = default_attrs[n];
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
-		attrs[n++] = &cache_disable_0.attr;
-		attrs[n++] = &cache_disable_1.attr;
-	}
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		attrs[n++] = &subcaches.attr;
-
-	return attrs;
-}
-#endif
-
-static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->show ?
-		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, this_leaf->cpu) :
-		0;
-	return ret;
-}
-
-static ssize_t store(struct kobject *kobj, struct attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->store ?
-		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, count, this_leaf->cpu) :
-		0;
-	return ret;
-}
-
-static const struct sysfs_ops sysfs_ops = {
-	.show   = show,
-	.store  = store,
-};
-
-static struct kobj_type ktype_cache = {
-	.sysfs_ops	= &sysfs_ops,
-	.default_attrs	= default_attrs,
-};
-
-static struct kobj_type ktype_percpu_entry = {
-	.sysfs_ops	= &sysfs_ops,
-};
-
-static void cpuid4_cache_sysfs_exit(unsigned int cpu)
-{
-	kfree(per_cpu(ici_cache_kobject, cpu));
-	kfree(per_cpu(ici_index_kobject, cpu));
-	per_cpu(ici_cache_kobject, cpu) = NULL;
-	per_cpu(ici_index_kobject, cpu) = NULL;
-	free_cache_attributes(cpu);
-}
-
-static int cpuid4_cache_sysfs_init(unsigned int cpu)
-{
-	int err;
-
-	if (num_cache_leaves == 0)
+	if (!num_cache_leaves)
 		return -ENOENT;
-
-	err = detect_cache_attributes(cpu);
-	if (err)
-		return err;
-
-	/* Allocate all required memory */
-	per_cpu(ici_cache_kobject, cpu) =
-		kzalloc(sizeof(struct kobject), GFP_KERNEL);
-	if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
-		goto err_out;
-
-	per_cpu(ici_index_kobject, cpu) = kzalloc(
-	    sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
-	if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
-		goto err_out;
-
+	if (!this_cpu_ci)
+		return -EINVAL;
+	this_cpu_ci->num_levels = 3;
+	this_cpu_ci->num_leaves = num_cache_leaves;
 	return 0;
-
-err_out:
-	cpuid4_cache_sysfs_exit(cpu);
-	return -ENOMEM;
 }
 
-static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
-
-/* Add/Remove cache interface for CPU device */
-static int cache_add_dev(struct device *dev)
+static int __populate_cache_leaves(unsigned int cpu)
 {
-	unsigned int cpu = dev->id;
-	unsigned long i, j;
-	struct _index_kobject *this_object;
-	struct _cpuid4_info   *this_leaf;
-	int retval;
-
-	retval = cpuid4_cache_sysfs_init(cpu);
-	if (unlikely(retval < 0))
-		return retval;
-
-	retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
-				      &ktype_percpu_entry,
-				      &dev->kobj, "%s", "cache");
-	if (retval < 0) {
-		cpuid4_cache_sysfs_exit(cpu);
-		return retval;
-	}
-
-	for (i = 0; i < num_cache_leaves; i++) {
-		this_object = INDEX_KOBJECT_PTR(cpu, i);
-		this_object->cpu = cpu;
-		this_object->index = i;
+	unsigned int idx, ret;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+	struct _cpuid4_info_regs id4_regs = {};
 
-		this_leaf = CPUID4_INFO_IDX(cpu, i);
-
-		ktype_cache.default_attrs = default_attrs;
-#ifdef CONFIG_AMD_NB
-		if (this_leaf->base.nb)
-			ktype_cache.default_attrs = amd_l3_attrs();
-#endif
-		retval = kobject_init_and_add(&(this_object->kobj),
-					      &ktype_cache,
-					      per_cpu(ici_cache_kobject, cpu),
-					      "index%1lu", i);
-		if (unlikely(retval)) {
-			for (j = 0; j < i; j++)
-				kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
-			kobject_put(per_cpu(ici_cache_kobject, cpu));
-			cpuid4_cache_sysfs_exit(cpu);
-			return retval;
-		}
-		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+		ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
+		if (ret)
+			return ret;
+		ci_leaf_init(this_leaf++, &id4_regs);
+		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
-	cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
-
-	kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
 	return 0;
 }
 
-static void cache_remove_dev(struct device *dev)
-{
-	unsigned int cpu = dev->id;
-	unsigned long i;
-
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return;
-	if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
-		return;
-	cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
-
-	for (i = 0; i < num_cache_leaves; i++)
-		kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
-	kobject_put(per_cpu(ici_cache_kobject, cpu));
-	cpuid4_cache_sysfs_exit(cpu);
-}
-
-static int cacheinfo_cpu_callback(struct notifier_block *nfb,
-				  unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct device *dev;
-
-	dev = get_cpu_device(cpu);
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		cache_add_dev(dev);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		cache_remove_dev(dev);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cacheinfo_cpu_notifier = {
-	.notifier_call = cacheinfo_cpu_callback,
-};
-
-static int __init cache_sysfs_init(void)
-{
-	int i, err = 0;
-
-	if (num_cache_leaves == 0)
-		return 0;
-
-	cpu_notifier_register_begin();
-	for_each_online_cpu(i) {
-		struct device *dev = get_cpu_device(i);
-
-		err = cache_add_dev(dev);
-		if (err)
-			goto out;
-	}
-	__register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-
-out:
-	cpu_notifier_register_done();
-	return err;
-}
-
-device_initcall(cache_sysfs_init);
-
-#endif
+DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
+DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-04 12:00   ` [PATCH v3] " Sudeep Holla
@ 2015-03-04 12:27     ` Borislav Petkov
  2015-03-05  8:16       ` Borislav Petkov
  2015-03-09 14:46     ` [tip:x86/cpu] x86/cacheinfo: Move cacheinfo sysfs code to generic infrastructure tip-bot for Sudeep Holla
  1 sibling, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-04 12:27 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

On Wed, Mar 04, 2015 at 12:00:16PM +0000, Sudeep Holla wrote:
> This patch removes the redundant sysfs cacheinfo code by reusing
> the newly introduced generic cacheinfo infrastructure through the
> commit 246246cbde5e ("drivers: base: support cpu cache information
> interface to userspace via sysfs")
> 
> The private pointer provided by the cacheinfo is used to implement
> the AMD L3 cache specific attributes.
> 
> Note that with v4.0-rc1, commit 513e3d2d11c9 ("cpumask: always use
> nr_cpu_ids in formatting and parsing functions") in particular changes
> from long format to shorter one for all cpumasks sysfs entries. As the
> consequence of the same, even the shared_cpu_map in the cacheinfo sysfs
> was also changed.
> 
> This patch neither alters any existing sysfs entries nor their formating,
> however since the generic cacheinfo has switched to use the device
> attributes instead of the traditional raw kobjects, a directory named
> "power" along with its standard attributes are added similar to any
> other device.
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Borislav Petkov <bp@suse.de>
> Cc: Andre Przywara <andre.przywara@arm.com>
> Cc: x86@kernel.org

Applied, thanks guys.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-04 12:27     ` Borislav Petkov
@ 2015-03-05  8:16       ` Borislav Petkov
  2015-03-05  9:28         ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-05  8:16 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

On Wed, Mar 04, 2015 at 01:27:20PM +0100, Borislav Petkov wrote:
> Applied, thanks guys.

Ok, we forgot to add the same check in the cpu_has_topoext case in
__cache_amd_cpumap_setup() and my F15h exploded this morning:

---
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 54e43d58e714..8008bc2dd2d0 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -820,9 +820,13 @@ static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
 
 		for_each_online_cpu(i) {
 			this_cpu_ci = get_cpu_cacheinfo(i);
+			if (!this_cpu_ci->info_list)
+				continue;
+
 			apicid = cpu_data(i).apicid;
 			if ((apicid < first) || (apicid > last))
 				continue;
+
 			this_leaf = this_cpu_ci->info_list + index;
 
 			for_each_online_cpu(sibling) {
---

I've folded the above into your patch.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-05  8:16       ` Borislav Petkov
@ 2015-03-05  9:28         ` Sudeep Holla
  2015-03-10 11:37           ` Borislav Petkov
  0 siblings, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-03-05  9:28 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andre Przywara, x86

Hi Boris,

On 05/03/15 08:16, Borislav Petkov wrote:
> On Wed, Mar 04, 2015 at 01:27:20PM +0100, Borislav Petkov wrote:
>> Applied, thanks guys.
>
> Ok, we forgot to add the same check in the cpu_has_topoext case in
> __cache_amd_cpumap_setup() and my F15h exploded this morning:
>
> ---
> diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
> index 54e43d58e714..8008bc2dd2d0 100644
> --- a/arch/x86/kernel/cpu/intel_cacheinfo.c
> +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
> @@ -820,9 +820,13 @@ static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
>
>   		for_each_online_cpu(i) {
>   			this_cpu_ci = get_cpu_cacheinfo(i);
> +			if (!this_cpu_ci->info_list)
> +				continue;
> +
>   			apicid = cpu_data(i).apicid;
>   			if ((apicid < first) || (apicid > last))
>   				continue;
> +
>   			this_leaf = this_cpu_ci->info_list + index;
>
>   			for_each_online_cpu(sibling) {
> ---
>
> I've folded the above into your patch.
>

Thanks a lot.

--
Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [tip:x86/cpu] x86/cacheinfo: Move cacheinfo sysfs code to generic infrastructure
  2015-03-04 12:00   ` [PATCH v3] " Sudeep Holla
  2015-03-04 12:27     ` Borislav Petkov
@ 2015-03-09 14:46     ` tip-bot for Sudeep Holla
  1 sibling, 0 replies; 32+ messages in thread
From: tip-bot for Sudeep Holla @ 2015-03-09 14:46 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: bp, tglx, hpa, mingo, mingo, sudeep.holla, andre.przywara, linux-kernel

Commit-ID:  0d55ba46bfbee64fd2b492b87bfe2ec172e7b056
Gitweb:     http://git.kernel.org/tip/0d55ba46bfbee64fd2b492b87bfe2ec172e7b056
Author:     Sudeep Holla <sudeep.holla@arm.com>
AuthorDate: Wed, 4 Mar 2015 12:00:16 +0000
Committer:  Borislav Petkov <bp@suse.de>
CommitDate: Mon, 9 Mar 2015 09:32:24 +0100

x86/cacheinfo: Move cacheinfo sysfs code to generic infrastructure

This patch removes the redundant sysfs cacheinfo code by reusing
the newly introduced generic cacheinfo infrastructure through the
commit

  246246cbde5e ("drivers: base: support cpu cache information
		 interface to userspace via sysfs")

The private pointer provided by the cacheinfo is used to implement
the AMD L3 cache-specific attributes.

Note that with v4.0-rc1, commit

  513e3d2d11c9 ("cpumask: always use nr_cpu_ids in formatting and parsing
		 functions")

in particular changes from long format to shorter one for all cpumasks
sysfs entries. As the consequence of the same, even the shared_cpu_map
in the cacheinfo sysfs was also changed.

This patch neither alters any existing sysfs entries nor their
formating, however since the generic cacheinfo has switched to use the
device attributes instead of the traditional raw kobjects, a directory
named "power" along with its standard attributes are added similar to
any other device.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Andre Przywara <andre.przywara@arm.com>
Link: http://lkml.kernel.org/r/1425470416-20691-1-git-send-email-sudeep.holla@arm.com
[ Add a check for uninitialized this_cpu_ci for the cpu_has_topoext case too
  in __cache_amd_cpumap_setup() ]
Signed-off-by: Borislav Petkov <bp@suse.de>
---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 715 ++++++++++------------------------
 1 file changed, 198 insertions(+), 517 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 6596433..8008bc2 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -7,16 +7,14 @@
  *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/compiler.h>
+#include <linux/cacheinfo.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/sysfs.h>
 #include <linux/pci.h>
 
 #include <asm/processor.h>
-#include <linux/smp.h>
 #include <asm/amd_nb.h>
 #include <asm/smp.h>
 
@@ -116,10 +114,10 @@ static const struct _cache_table cache_table[] =
 
 
 enum _cache_type {
-	CACHE_TYPE_NULL	= 0,
-	CACHE_TYPE_DATA = 1,
-	CACHE_TYPE_INST = 2,
-	CACHE_TYPE_UNIFIED = 3
+	CTYPE_NULL = 0,
+	CTYPE_DATA = 1,
+	CTYPE_INST = 2,
+	CTYPE_UNIFIED = 3
 };
 
 union _cpuid4_leaf_eax {
@@ -159,11 +157,6 @@ struct _cpuid4_info_regs {
 	struct amd_northbridge *nb;
 };
 
-struct _cpuid4_info {
-	struct _cpuid4_info_regs base;
-	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
-};
-
 unsigned short			num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -220,6 +213,13 @@ static const unsigned short assocs[] = {
 static const unsigned char levels[] = { 1, 1, 2, 3 };
 static const unsigned char types[] = { 1, 2, 3, 3 };
 
+static const enum cache_type cache_type_map[] = {
+	[CTYPE_NULL] = CACHE_TYPE_NOCACHE,
+	[CTYPE_DATA] = CACHE_TYPE_DATA,
+	[CTYPE_INST] = CACHE_TYPE_INST,
+	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
+};
+
 static void
 amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		     union _cpuid4_leaf_ebx *ebx,
@@ -291,14 +291,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
-struct _cache_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);
-	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,
-			 unsigned int);
-};
-
 #if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
+
 /*
  * L3 cache descriptors
  */
@@ -325,20 +319,6 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb)
 	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
-static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
-{
-	int node;
-
-	/* only for L3, and not in virtualized environments */
-	if (index < 3)
-		return;
-
-	node = amd_get_nb_id(smp_processor_id());
-	this_leaf->nb = node_to_amd_nb(node);
-	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
-		amd_calc_l3_indices(this_leaf->nb);
-}
-
 /*
  * check whether a slot used for disabling an L3 index is occupied.
  * @l3: L3 cache descriptor
@@ -359,15 +339,13 @@ int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot)
 	return -1;
 }
 
-static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
+static ssize_t show_cache_disable(struct cacheinfo *this_leaf, char *buf,
 				  unsigned int slot)
 {
 	int index;
+	struct amd_northbridge *nb = this_leaf->priv;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	index = amd_get_l3_disable_slot(this_leaf->base.nb, slot);
+	index = amd_get_l3_disable_slot(nb, slot);
 	if (index >= 0)
 		return sprintf(buf, "%d\n", index);
 
@@ -376,9 +354,10 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 
 #define SHOW_CACHE_DISABLE(slot)					\
 static ssize_t								\
-show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf,	\
-			  unsigned int cpu)				\
+cache_disable_##slot##_show(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return show_cache_disable(this_leaf, buf, slot);		\
 }
 SHOW_CACHE_DISABLE(0)
@@ -446,25 +425,23 @@ int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot,
 	return 0;
 }
 
-static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
-				  const char *buf, size_t count,
-				  unsigned int slot)
+static ssize_t store_cache_disable(struct cacheinfo *this_leaf,
+				   const char *buf, size_t count,
+				   unsigned int slot)
 {
 	unsigned long val = 0;
 	int cpu, err = 0;
+	struct amd_northbridge *nb = this_leaf->priv;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		return -EINVAL;
-
-	cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
+	cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	if (kstrtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	err = amd_set_l3_disable_slot(this_leaf->base.nb, cpu, slot, val);
+	err = amd_set_l3_disable_slot(nb, cpu, slot, val);
 	if (err) {
 		if (err == -EEXIST)
 			pr_warning("L3 slot %d in use/index already disabled!\n",
@@ -476,41 +453,36 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 
 #define STORE_CACHE_DISABLE(slot)					\
 static ssize_t								\
-store_cache_disable_##slot(struct _cpuid4_info *this_leaf,		\
-			   const char *buf, size_t count,		\
-			   unsigned int cpu)				\
+cache_disable_##slot##_store(struct device *dev,			\
+			     struct device_attribute *attr,		\
+			     const char *buf, size_t count)		\
 {									\
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
 	return store_cache_disable(this_leaf, buf, count, slot);	\
 }
 STORE_CACHE_DISABLE(0)
 STORE_CACHE_DISABLE(1)
 
-static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
-		show_cache_disable_0, store_cache_disable_0);
-static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
-		show_cache_disable_1, store_cache_disable_1);
-
-static ssize_t
-show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)
+static ssize_t subcaches_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 
 	return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
 }
 
-static ssize_t
-store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
-		unsigned int cpu)
+static ssize_t subcaches_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
 {
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
 	unsigned long val;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!this_leaf->base.nb || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		return -EINVAL;
-
 	if (kstrtoul(buf, 16, &val) < 0)
 		return -EINVAL;
 
@@ -520,9 +492,92 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
 	return count;
 }
 
-static struct _cache_attr subcaches =
-	__ATTR(subcaches, 0644, show_subcaches, store_subcaches);
+static DEVICE_ATTR_RW(cache_disable_0);
+static DEVICE_ATTR_RW(cache_disable_1);
+static DEVICE_ATTR_RW(subcaches);
+
+static umode_t
+cache_private_attrs_is_visible(struct kobject *kobj,
+			       struct attribute *attr, int unused)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
+	umode_t mode = attr->mode;
+
+	if (!this_leaf->priv)
+		return 0;
+
+	if ((attr == &dev_attr_subcaches.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		return mode;
+
+	if ((attr == &dev_attr_cache_disable_0.attr ||
+	     attr == &dev_attr_cache_disable_1.attr) &&
+	    amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		return mode;
+
+	return 0;
+}
+
+static struct attribute_group cache_private_group = {
+	.is_visible = cache_private_attrs_is_visible,
+};
+
+static void init_amd_l3_attrs(void)
+{
+	int n = 1;
+	static struct attribute **amd_l3_attrs;
+
+	if (amd_l3_attrs) /* already initialized */
+		return;
+
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
+		n += 2;
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		n += 1;
+
+	amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
+	if (!amd_l3_attrs)
+		return;
+
+	n = 0;
+	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
+		amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
+	}
+	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+		amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
 
+	cache_private_group.attrs = amd_l3_attrs;
+}
+
+const struct attribute_group *
+cache_get_priv_group(struct cacheinfo *this_leaf)
+{
+	struct amd_northbridge *nb = this_leaf->priv;
+
+	if (this_leaf->level < 3)
+		return NULL;
+
+	if (nb && nb->l3_cache.indices)
+		init_amd_l3_attrs();
+
+	return &cache_private_group;
+}
+
+static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
+{
+	int node;
+
+	/* only for L3, and not in virtualized environments */
+	if (index < 3)
+		return;
+
+	node = amd_get_nb_id(smp_processor_id());
+	this_leaf->nb = node_to_amd_nb(node);
+	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
+		amd_calc_l3_indices(this_leaf->nb);
+}
 #else
 #define amd_init_l3_cache(x, y)
 #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
@@ -546,7 +601,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
 		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
 	}
 
-	if (eax.split.type == CACHE_TYPE_NULL)
+	if (eax.split.type == CTYPE_NULL)
 		return -EIO; /* better error ? */
 
 	this_leaf->eax = eax;
@@ -575,7 +630,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
 		/* Do cpuid(op) loop to find out num_cache_leaves */
 		cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
 		cache_eax.full = eax;
-	} while (cache_eax.split.type != CACHE_TYPE_NULL);
+	} while (cache_eax.split.type != CTYPE_NULL);
 	return i;
 }
 
@@ -626,9 +681,9 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
 			switch (this_leaf.eax.split.level) {
 			case 1:
-				if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
+				if (this_leaf.eax.split.type == CTYPE_DATA)
 					new_l1d = this_leaf.size/1024;
-				else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
+				else if (this_leaf.eax.split.type == CTYPE_INST)
 					new_l1i = this_leaf.size/1024;
 				break;
 			case 2:
@@ -747,55 +802,52 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
 	return l2;
 }
 
-#ifdef CONFIG_SYSFS
-
-/* pointer to _cpuid4_info array (for each cache leaf) */
-static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(ici_cpuid4_info, x))[y]))
-
-#ifdef CONFIG_SMP
-
-static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
+static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
+				    struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf;
 	int i, sibling;
 
 	if (cpu_has_topoext) {
 		unsigned int apicid, nshared, first, last;
 
-		if (!per_cpu(ici_cpuid4_info, cpu))
-			return 0;
-
-		this_leaf = CPUID4_INFO_IDX(cpu, index);
-		nshared = this_leaf->base.eax.split.num_threads_sharing + 1;
+		this_leaf = this_cpu_ci->info_list + index;
+		nshared = base->eax.split.num_threads_sharing + 1;
 		apicid = cpu_data(cpu).apicid;
 		first = apicid - (apicid % nshared);
 		last = first + nshared - 1;
 
 		for_each_online_cpu(i) {
+			this_cpu_ci = get_cpu_cacheinfo(i);
+			if (!this_cpu_ci->info_list)
+				continue;
+
 			apicid = cpu_data(i).apicid;
 			if ((apicid < first) || (apicid > last))
 				continue;
-			if (!per_cpu(ici_cpuid4_info, i))
-				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+
+			this_leaf = this_cpu_ci->info_list + index;
 
 			for_each_online_cpu(sibling) {
 				apicid = cpu_data(sibling).apicid;
 				if ((apicid < first) || (apicid > last))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else if (index == 3) {
 		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
-			if (!per_cpu(ici_cpuid4_info, i))
+			this_cpu_ci = get_cpu_cacheinfo(i);
+			if (!this_cpu_ci->info_list)
 				continue;
-			this_leaf = CPUID4_INFO_IDX(i, index);
+			this_leaf = this_cpu_ci->info_list + index;
 			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
 				if (!cpu_online(sibling))
 					continue;
-				set_bit(sibling, this_leaf->shared_cpu_map);
+				cpumask_set_cpu(sibling,
+						&this_leaf->shared_cpu_map);
 			}
 		}
 	} else
@@ -804,457 +856,86 @@ static int cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
 	return 1;
 }
 
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
+static void __cache_cpumap_setup(unsigned int cpu, int index,
+				 struct _cpuid4_info_regs *base)
 {
-	struct _cpuid4_info *this_leaf, *sibling_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf, *sibling_leaf;
 	unsigned long num_threads_sharing;
 	int index_msb, i;
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 
 	if (c->x86_vendor == X86_VENDOR_AMD) {
-		if (cache_shared_amd_cpu_map_setup(cpu, index))
+		if (__cache_amd_cpumap_setup(cpu, index, base))
 			return;
 	}
 
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	num_threads_sharing = 1 + this_leaf->base.eax.split.num_threads_sharing;
+	this_leaf = this_cpu_ci->info_list + index;
+	num_threads_sharing = 1 + base->eax.split.num_threads_sharing;
 
+	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
 	if (num_threads_sharing == 1)
-		cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
-	else {
-		index_msb = get_count_order(num_threads_sharing);
-
-		for_each_online_cpu(i) {
-			if (cpu_data(i).apicid >> index_msb ==
-			    c->apicid >> index_msb) {
-				cpumask_set_cpu(i,
-					to_cpumask(this_leaf->shared_cpu_map));
-				if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
-					sibling_leaf =
-						CPUID4_INFO_IDX(i, index);
-					cpumask_set_cpu(cpu, to_cpumask(
-						sibling_leaf->shared_cpu_map));
-				}
-			}
-		}
-	}
-}
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-	struct _cpuid4_info	*this_leaf, *sibling_leaf;
-	int sibling;
-
-	this_leaf = CPUID4_INFO_IDX(cpu, index);
-	for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
-		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
-		cpumask_clear_cpu(cpu,
-				  to_cpumask(sibling_leaf->shared_cpu_map));
-	}
-}
-#else
-static void cache_shared_cpu_map_setup(unsigned int cpu, int index)
-{
-}
-
-static void cache_remove_shared_cpu_map(unsigned int cpu, int index)
-{
-}
-#endif
-
-static void free_cache_attributes(unsigned int cpu)
-{
-	int i;
-
-	for (i = 0; i < num_cache_leaves; i++)
-		cache_remove_shared_cpu_map(cpu, i);
-
-	kfree(per_cpu(ici_cpuid4_info, cpu));
-	per_cpu(ici_cpuid4_info, cpu) = NULL;
-}
-
-static void get_cpu_leaves(void *_retval)
-{
-	int j, *retval = _retval, cpu = smp_processor_id();
+		return;
 
-	/* Do cpuid and store the results */
-	for (j = 0; j < num_cache_leaves; j++) {
-		struct _cpuid4_info *this_leaf = CPUID4_INFO_IDX(cpu, j);
+	index_msb = get_count_order(num_threads_sharing);
 
-		*retval = cpuid4_cache_lookup_regs(j, &this_leaf->base);
-		if (unlikely(*retval < 0)) {
-			int i;
+	for_each_online_cpu(i)
+		if (cpu_data(i).apicid >> index_msb == c->apicid >> index_msb) {
+			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
 
-			for (i = 0; i < j; i++)
-				cache_remove_shared_cpu_map(cpu, i);
-			break;
+			if (i == cpu || !sib_cpu_ci->info_list)
+				continue;/* skip if itself or no cacheinfo */
+			sibling_leaf = sib_cpu_ci->info_list + index;
+			cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+			cpumask_set_cpu(cpu, &sibling_leaf->shared_cpu_map);
 		}
-		cache_shared_cpu_map_setup(cpu, j);
-	}
 }
 
-static int detect_cache_attributes(unsigned int cpu)
+static void ci_leaf_init(struct cacheinfo *this_leaf,
+			 struct _cpuid4_info_regs *base)
 {
-	int			retval;
-
-	if (num_cache_leaves == 0)
-		return -ENOENT;
-
-	per_cpu(ici_cpuid4_info, cpu) = kzalloc(
-	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return -ENOMEM;
-
-	smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
-	if (retval) {
-		kfree(per_cpu(ici_cpuid4_info, cpu));
-		per_cpu(ici_cpuid4_info, cpu) = NULL;
-	}
-
-	return retval;
+	this_leaf->level = base->eax.split.level;
+	this_leaf->type = cache_type_map[base->eax.split.type];
+	this_leaf->coherency_line_size =
+				base->ebx.split.coherency_line_size + 1;
+	this_leaf->ways_of_associativity =
+				base->ebx.split.ways_of_associativity + 1;
+	this_leaf->size = base->size;
+	this_leaf->number_of_sets = base->ecx.split.number_of_sets + 1;
+	this_leaf->physical_line_partition =
+				base->ebx.split.physical_line_partition + 1;
+	this_leaf->priv = base->nb;
 }
 
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/cpu.h>
-
-/* pointer to kobject for cpuX/cache */
-static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
-
-struct _index_kobject {
-	struct kobject kobj;
-	unsigned int cpu;
-	unsigned short index;
-};
-
-/* pointer to array of kobjects for cpuX/cache/indexY */
-static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(ici_index_kobject, x))[y]))
-
-#define show_one_plus(file_name, object, val)				\
-static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \
-				unsigned int cpu)			\
-{									\
-	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
-}
-
-show_one_plus(level, base.eax.split.level, 0);
-show_one_plus(coherency_line_size, base.ebx.split.coherency_line_size, 1);
-show_one_plus(physical_line_partition, base.ebx.split.physical_line_partition, 1);
-show_one_plus(ways_of_associativity, base.ebx.split.ways_of_associativity, 1);
-show_one_plus(number_of_sets, base.ecx.split.number_of_sets, 1);
-
-static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	return sprintf(buf, "%luK\n", this_leaf->base.size / 1024);
-}
-
-static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
-					int type, char *buf)
-{
-	const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map);
-	int ret;
-
-	if (type)
-		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
-				cpumask_pr_args(mask));
-	else
-		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pb",
-				cpumask_pr_args(mask));
-	buf[ret++] = '\n';
-	buf[ret] = '\0';
-	return ret;
-}
-
-static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
-					  unsigned int cpu)
+static int __init_cache_level(unsigned int cpu)
 {
-	return show_shared_cpu_map_func(leaf, 0, buf);
-}
-
-static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,
-					   unsigned int cpu)
-{
-	return show_shared_cpu_map_func(leaf, 1, buf);
-}
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
-static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,
-			 unsigned int cpu)
-{
-	switch (this_leaf->base.eax.split.type) {
-	case CACHE_TYPE_DATA:
-		return sprintf(buf, "Data\n");
-	case CACHE_TYPE_INST:
-		return sprintf(buf, "Instruction\n");
-	case CACHE_TYPE_UNIFIED:
-		return sprintf(buf, "Unified\n");
-	default:
-		return sprintf(buf, "Unknown\n");
-	}
-}
-
-#define to_object(k)	container_of(k, struct _index_kobject, kobj)
-#define to_attr(a)	container_of(a, struct _cache_attr, attr)
-
-#define define_one_ro(_name) \
-static struct _cache_attr _name = \
-	__ATTR(_name, 0444, show_##_name, NULL)
-
-define_one_ro(level);
-define_one_ro(type);
-define_one_ro(coherency_line_size);
-define_one_ro(physical_line_partition);
-define_one_ro(ways_of_associativity);
-define_one_ro(number_of_sets);
-define_one_ro(size);
-define_one_ro(shared_cpu_map);
-define_one_ro(shared_cpu_list);
-
-static struct attribute *default_attrs[] = {
-	&type.attr,
-	&level.attr,
-	&coherency_line_size.attr,
-	&physical_line_partition.attr,
-	&ways_of_associativity.attr,
-	&number_of_sets.attr,
-	&size.attr,
-	&shared_cpu_map.attr,
-	&shared_cpu_list.attr,
-	NULL
-};
-
-#ifdef CONFIG_AMD_NB
-static struct attribute **amd_l3_attrs(void)
-{
-	static struct attribute **attrs;
-	int n;
-
-	if (attrs)
-		return attrs;
-
-	n = ARRAY_SIZE(default_attrs);
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
-		n += 2;
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		n += 1;
-
-	attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);
-	if (attrs == NULL)
-		return attrs = default_attrs;
-
-	for (n = 0; default_attrs[n]; n++)
-		attrs[n] = default_attrs[n];
-
-	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
-		attrs[n++] = &cache_disable_0.attr;
-		attrs[n++] = &cache_disable_1.attr;
-	}
-
-	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
-		attrs[n++] = &subcaches.attr;
-
-	return attrs;
-}
-#endif
-
-static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->show ?
-		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, this_leaf->cpu) :
-		0;
-	return ret;
-}
-
-static ssize_t store(struct kobject *kobj, struct attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct _cache_attr *fattr = to_attr(attr);
-	struct _index_kobject *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->store ?
-		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-			buf, count, this_leaf->cpu) :
-		0;
-	return ret;
-}
-
-static const struct sysfs_ops sysfs_ops = {
-	.show   = show,
-	.store  = store,
-};
-
-static struct kobj_type ktype_cache = {
-	.sysfs_ops	= &sysfs_ops,
-	.default_attrs	= default_attrs,
-};
-
-static struct kobj_type ktype_percpu_entry = {
-	.sysfs_ops	= &sysfs_ops,
-};
-
-static void cpuid4_cache_sysfs_exit(unsigned int cpu)
-{
-	kfree(per_cpu(ici_cache_kobject, cpu));
-	kfree(per_cpu(ici_index_kobject, cpu));
-	per_cpu(ici_cache_kobject, cpu) = NULL;
-	per_cpu(ici_index_kobject, cpu) = NULL;
-	free_cache_attributes(cpu);
-}
-
-static int cpuid4_cache_sysfs_init(unsigned int cpu)
-{
-	int err;
-
-	if (num_cache_leaves == 0)
+	if (!num_cache_leaves)
 		return -ENOENT;
-
-	err = detect_cache_attributes(cpu);
-	if (err)
-		return err;
-
-	/* Allocate all required memory */
-	per_cpu(ici_cache_kobject, cpu) =
-		kzalloc(sizeof(struct kobject), GFP_KERNEL);
-	if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
-		goto err_out;
-
-	per_cpu(ici_index_kobject, cpu) = kzalloc(
-	    sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
-	if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
-		goto err_out;
-
+	if (!this_cpu_ci)
+		return -EINVAL;
+	this_cpu_ci->num_levels = 3;
+	this_cpu_ci->num_leaves = num_cache_leaves;
 	return 0;
-
-err_out:
-	cpuid4_cache_sysfs_exit(cpu);
-	return -ENOMEM;
 }
 
-static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
-
-/* Add/Remove cache interface for CPU device */
-static int cache_add_dev(struct device *dev)
+static int __populate_cache_leaves(unsigned int cpu)
 {
-	unsigned int cpu = dev->id;
-	unsigned long i, j;
-	struct _index_kobject *this_object;
-	struct _cpuid4_info   *this_leaf;
-	int retval;
-
-	retval = cpuid4_cache_sysfs_init(cpu);
-	if (unlikely(retval < 0))
-		return retval;
-
-	retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
-				      &ktype_percpu_entry,
-				      &dev->kobj, "%s", "cache");
-	if (retval < 0) {
-		cpuid4_cache_sysfs_exit(cpu);
-		return retval;
-	}
+	unsigned int idx, ret;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+	struct _cpuid4_info_regs id4_regs = {};
 
-	for (i = 0; i < num_cache_leaves; i++) {
-		this_object = INDEX_KOBJECT_PTR(cpu, i);
-		this_object->cpu = cpu;
-		this_object->index = i;
-
-		this_leaf = CPUID4_INFO_IDX(cpu, i);
-
-		ktype_cache.default_attrs = default_attrs;
-#ifdef CONFIG_AMD_NB
-		if (this_leaf->base.nb)
-			ktype_cache.default_attrs = amd_l3_attrs();
-#endif
-		retval = kobject_init_and_add(&(this_object->kobj),
-					      &ktype_cache,
-					      per_cpu(ici_cache_kobject, cpu),
-					      "index%1lu", i);
-		if (unlikely(retval)) {
-			for (j = 0; j < i; j++)
-				kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
-			kobject_put(per_cpu(ici_cache_kobject, cpu));
-			cpuid4_cache_sysfs_exit(cpu);
-			return retval;
-		}
-		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+		ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
+		if (ret)
+			return ret;
+		ci_leaf_init(this_leaf++, &id4_regs);
+		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
-	cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
-
-	kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
 	return 0;
 }
 
-static void cache_remove_dev(struct device *dev)
-{
-	unsigned int cpu = dev->id;
-	unsigned long i;
-
-	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
-		return;
-	if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
-		return;
-	cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
-
-	for (i = 0; i < num_cache_leaves; i++)
-		kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
-	kobject_put(per_cpu(ici_cache_kobject, cpu));
-	cpuid4_cache_sysfs_exit(cpu);
-}
-
-static int cacheinfo_cpu_callback(struct notifier_block *nfb,
-				  unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct device *dev;
-
-	dev = get_cpu_device(cpu);
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		cache_add_dev(dev);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		cache_remove_dev(dev);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cacheinfo_cpu_notifier = {
-	.notifier_call = cacheinfo_cpu_callback,
-};
-
-static int __init cache_sysfs_init(void)
-{
-	int i, err = 0;
-
-	if (num_cache_leaves == 0)
-		return 0;
-
-	cpu_notifier_register_begin();
-	for_each_online_cpu(i) {
-		struct device *dev = get_cpu_device(i);
-
-		err = cache_add_dev(dev);
-		if (err)
-			goto out;
-	}
-	__register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-
-out:
-	cpu_notifier_register_done();
-	return err;
-}
-
-device_initcall(cache_sysfs_init);
-
-#endif
+DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
+DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-05  9:28         ` Sudeep Holla
@ 2015-03-10 11:37           ` Borislav Petkov
  2015-03-10 11:53             ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-10 11:37 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

Hi,

I just triggered this is on rc3 + tip/master which has your patch. This
is an Intel SNB. Ideas, already fixed?

Thanks.

------------[ cut here ]------------
WARNING: CPU: 3 PID: 1 at fs/sysfs/group.c:102 internal_create_group+0x151/0x280()
sysfs: (bin_)attrs not set by subsystem for group: index3/
Modules linked in:
CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.0.0-rc3+ #1
Hardware name: Dell Inc. Precision T3600/0PTTT9, BIOS A13 05/11/2014
 ffffffff81cc6539 ffff88043be73bd8 ffffffff8184065b 0000000000000000
 ffff88043be73c28 ffff88043be73c18 ffffffff8107301a ffffffff81eff038
 0000000000000001 ffffffff81efef60 0000000000000000 ffffffff81e1c080
Call Trace:
 [<ffffffff8184065b>] dump_stack+0x4f/0x7b
 [<ffffffff8107301a>] warn_slowpath_common+0x8a/0xc0
 [<ffffffff81073096>] warn_slowpath_fmt+0x46/0x50
 [<ffffffff81277531>] internal_create_group+0x151/0x280
 [<ffffffff81277799>] sysfs_create_groups+0x49/0xa0
 [<ffffffff815d8823>] device_add+0x3e3/0x680
 [<ffffffff815de3d0>] cpu_device_create+0xc0/0xe0
 [<ffffffff811da78a>] ? __kmalloc+0x20a/0x220
 [<ffffffff815e15d6>] cache_add_dev+0x176/0x220
 [<ffffffff81fc3528>] cacheinfo_sysfs_init+0x51/0x93
 [<ffffffff81fc34d7>] ? container_dev_init+0x2f/0x2f
 [<ffffffff81002110>] do_one_initcall+0xa0/0x200
 [<ffffffff81f771e5>] kernel_init_freeable+0x1f5/0x27d
 [<ffffffff818345b0>] ? rest_init+0xd0/0xd0
 [<ffffffff818345be>] kernel_init+0xe/0xf0
 [<ffffffff8184ad93>] ret_from_fork+0x53/0x80
 [<ffffffff818345b0>] ? rest_init+0xd0/0xd0
---[ end trace 5505c77da0d6932a ]---
error populating cacheinfo..cpu0

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-10 11:37           ` Borislav Petkov
@ 2015-03-10 11:53             ` Sudeep Holla
  2015-03-10 14:22               ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-03-10 11:53 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andre Przywara, x86

Hi Boris,

On 10/03/15 11:37, Borislav Petkov wrote:
> Hi,
>
> I just triggered this is on rc3 + tip/master which has your patch. This
> is an Intel SNB. Ideas, already fixed?
>

No, not seen this before. I will test tip/master on my Intel i7 box
again and get back to you.

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-10 11:53             ` Sudeep Holla
@ 2015-03-10 14:22               ` Sudeep Holla
  2015-03-10 14:26                 ` Borislav Petkov
  0 siblings, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-03-10 14:22 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

On Tue, Mar 10, 2015 at 11:53:35AM +0000, Sudeep Holla wrote:
> Hi Boris,
>
> On 10/03/15 11:37, Borislav Petkov wrote:
> > Hi,
> >
> > I just triggered this is on rc3 + tip/master which has your patch. This
> > is an Intel SNB. Ideas, already fixed?
> >
>
> No, not seen this before. I will test tip/master on my Intel i7 box
> again and get back to you.

I was able to reproduce this and now I realise I had CONFIG_AMD_NB
disabled in my config earlier which hid this issue previously, sorry
for that.

The below patch fixed the issue on my Intel i7 box. I can post this
separately if required.

Regards,
Sudeep

 From b081cbf26071f4c8ce51f270931387415ab1a06c Mon Sep 17 00:00:00 2001
From: Sudeep Holla <sudeep.holla@arm.com>
Date: Tue, 10 Mar 2015 13:49:58 +0000
Subject: [PATCH] x86: cacheinfo: fix cache_get_priv_group for Intel 
processors

The private pointer provided by the cacheinfo is used to implement
the AMD L3 cache specific attributes using the northbridge pointer
obtained through cpuid4 registers. However, it's populated even on
Intel processors for Level 3 cache. This results in failure of
cacheinfo setup as shown below as cache_get_priv_group returns the
unintialised private attributes which are not valid for Intel
processors.

------------[ cut here ]------------
WARNING: CPU: 3 PID: 1 at fs/sysfs/group.c:102 
internal_create_group+0x151/0x280()
sysfs: (bin_)attrs not set by subsystem for group: index3/
Modules linked in:
CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.0.0-rc3+ #1
Hardware name: Dell Inc. Precision T3600/0PTTT9, BIOS A13 05/11/2014
  ffffffff81cc6539 ffff88043be73bd8 ffffffff8184065b 0000000000000000
  ffff88043be73c28 ffff88043be73c18 ffffffff8107301a ffffffff81eff038
  0000000000000001 ffffffff81efef60 0000000000000000 ffffffff81e1c080
Call Trace:
  [<ffffffff8184065b>] dump_stack+0x4f/0x7b
  [<ffffffff8107301a>] warn_slowpath_common+0x8a/0xc0
  [<ffffffff81073096>] warn_slowpath_fmt+0x46/0x50
  [<ffffffff81277531>] internal_create_group+0x151/0x280
  [<ffffffff81277799>] sysfs_create_groups+0x49/0xa0
  [<ffffffff815d8823>] device_add+0x3e3/0x680
  [<ffffffff815de3d0>] cpu_device_create+0xc0/0xe0
  [<ffffffff811da78a>] ? __kmalloc+0x20a/0x220
  [<ffffffff815e15d6>] cache_add_dev+0x176/0x220
  [<ffffffff81fc3528>] cacheinfo_sysfs_init+0x51/0x93
  [<ffffffff81fc34d7>] ? container_dev_init+0x2f/0x2f
  [<ffffffff81002110>] do_one_initcall+0xa0/0x200
  [<ffffffff81f771e5>] kernel_init_freeable+0x1f5/0x27d
  [<ffffffff818345b0>] ? rest_init+0xd0/0xd0
  [<ffffffff818345be>] kernel_init+0xe/0xf0
  [<ffffffff8184ad93>] ret_from_fork+0x53/0x80
  [<ffffffff818345b0>] ? rest_init+0xd0/0xd0
---[ end trace 5505c77da0d6932a ]---

This patch fixes the issue by checking if the l3 cache indicies are
populated correctly(happens only on AMD processors) before initializing
the private attributes.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: x86@kernel.org
---
  arch/x86/kernel/cpu/intel_cacheinfo.c | 5 ++---
  1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c 
b/arch/x86/kernel/cpu/intel_cacheinfo.c
index f98bdebcf047..63b7bb6e8492 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -556,11 +556,10 @@ cache_get_priv_group(struct cacheinfo *this_leaf)
  {
  	struct amd_northbridge *nb = this_leaf->priv;
  -	if (this_leaf->level < 3)
+	if (this_leaf->level < 3 || !(nb && nb->l3_cache.indices))
  		return NULL;
  -	if (nb && nb->l3_cache.indices)
-		init_amd_l3_attrs();
+	init_amd_l3_attrs();
   	return &cache_private_group;
  }
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-10 14:22               ` Sudeep Holla
@ 2015-03-10 14:26                 ` Borislav Petkov
  2015-03-10 14:35                   ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-10 14:26 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

On Tue, Mar 10, 2015 at 02:22:22PM +0000, Sudeep Holla wrote:
> I was able to reproduce this and now I realise I had CONFIG_AMD_NB
> disabled in my config earlier which hid this issue previously, sorry
> for that.
> 
> The below patch fixed the issue on my Intel i7 box. I can post this
> separately if required.
> 
> Regards,
> Sudeep
> 
> From b081cbf26071f4c8ce51f270931387415ab1a06c Mon Sep 17 00:00:00 2001
> From: Sudeep Holla <sudeep.holla@arm.com>
> Date: Tue, 10 Mar 2015 13:49:58 +0000
> Subject: [PATCH] x86: cacheinfo: fix cache_get_priv_group for Intel
> processors
> 
> The private pointer provided by the cacheinfo is used to implement
> the AMD L3 cache specific attributes using the northbridge pointer
> obtained through cpuid4 registers. However, it's populated even on
> Intel processors for Level 3 cache. This results in failure of

Do we need it populated on Intel?

Because if not, we can leave it NULL there and do only

	if (this_leaf->level < 3 || !nb)
		return NULL;

No?

Thanks.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-10 14:26                 ` Borislav Petkov
@ 2015-03-10 14:35                   ` Sudeep Holla
  2015-03-11 13:36                     ` Borislav Petkov
  0 siblings, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-03-10 14:35 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andre Przywara, x86



On 10/03/15 14:26, Borislav Petkov wrote:
> On Tue, Mar 10, 2015 at 02:22:22PM +0000, Sudeep Holla wrote:
>> I was able to reproduce this and now I realise I had CONFIG_AMD_NB
>> disabled in my config earlier which hid this issue previously, sorry
>> for that.
>>
>> The below patch fixed the issue on my Intel i7 box. I can post this
>> separately if required.
>>
>> Regards,
>> Sudeep
>>
>>  From b081cbf26071f4c8ce51f270931387415ab1a06c Mon Sep 17 00:00:00 2001
>> From: Sudeep Holla <sudeep.holla@arm.com>
>> Date: Tue, 10 Mar 2015 13:49:58 +0000
>> Subject: [PATCH] x86: cacheinfo: fix cache_get_priv_group for Intel
>> processors
>>
>> The private pointer provided by the cacheinfo is used to implement
>> the AMD L3 cache specific attributes using the northbridge pointer
>> obtained through cpuid4 registers. However, it's populated even on
>> Intel processors for Level 3 cache. This results in failure of
>
> Do we need it populated on Intel?
>
> Because if not, we can leave it NULL there and do only
>
> 	if (this_leaf->level < 3 || !nb)
> 		return NULL;
>

Yes we can do that. I leave that too you guys. I don't know the exact
reason why cpuid4_cache_lookup_regs is populating
	struct amd_northbridge *nb in struct _cpuid4_info_reg

My initial assumption was that it will be NULL for Intel processors and
hence I assigned cacheinfo->priv to nb pointer unconditionally.
So I don't have any strong opinion here.

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-10 14:35                   ` Sudeep Holla
@ 2015-03-11 13:36                     ` Borislav Petkov
  2015-03-11 15:44                       ` Sudeep Holla
  0 siblings, 1 reply; 32+ messages in thread
From: Borislav Petkov @ 2015-03-11 13:36 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

On Tue, Mar 10, 2015 at 02:35:12PM +0000, Sudeep Holla wrote:
> My initial assumption was that it will be NULL for Intel processors
> and hence I assigned cacheinfo->priv to nb pointer unconditionally. So
> I don't have any strong opinion here.

Right, we need the NB descriptor on AMD to do L3-specific operations,
see amd_l3_disable_index() for an example.

IOW, I ended up committing this:

---
From: Sudeep Holla <sudeep.holla@arm.com>
Date: Wed, 11 Mar 2015 11:54:29 +0100
Subject: [PATCH] x86/cacheinfo: Fix cache_get_priv_group() for Intel
 processors

The private pointer provided by the cacheinfo code is used to implement
the AMD L3 cache-specific attributes using a pointer to the northbridge
descriptor. It is needed for performing L3-specific operations and for
that we need a couple of PCI devices and other service information, all
contained in the northbridge descriptor.

However, it's populated even on Intel processors for an L3 cache.
This results in failure of cacheinfo setup as shown below as
cache_get_priv_group() returns the unintialised private attributes which
are not valid for Intel processors.

------------[ cut here ]------------
WARNING: CPU: 3 PID: 1 at fs/sysfs/group.c:102
internal_create_group+0x151/0x280()
sysfs: (bin_)attrs not set by subsystem for group: index3/
Modules linked in:
CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.0.0-rc3+ #1
Hardware name: Dell Inc. Precision T3600/0PTTT9, BIOS A13 05/11/2014
...
Call Trace:
  dump_stack
  warn_slowpath_common
  warn_slowpath_fmt
  internal_create_group
  sysfs_create_groups
  device_add
  cpu_device_create
  ? __kmalloc
  cache_add_dev
  cacheinfo_sysfs_init
  ? container_dev_init
  do_one_initcall
  kernel_init_freeable
  ? rest_init
  kernel_init
  ret_from_fork
  ? rest_init

This patch fixes the issue by checking if the l3 cache indices are
populated correctly (AMD-specific) before initializing the private
attributes.

Reported-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Signed-off-by: 
---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 8008bc2dd2d0..edcb0e28c336 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -556,7 +556,7 @@ cache_get_priv_group(struct cacheinfo *this_leaf)
 {
 	struct amd_northbridge *nb = this_leaf->priv;
 
-	if (this_leaf->level < 3)
+	if (this_leaf->level < 3 || !nb)
 		return NULL;
 
 	if (nb && nb->l3_cache.indices)
-- 
2.2.0.33.gc18b867

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-11 13:36                     ` Borislav Petkov
@ 2015-03-11 15:44                       ` Sudeep Holla
  2015-03-11 20:23                         ` Borislav Petkov
  0 siblings, 1 reply; 32+ messages in thread
From: Sudeep Holla @ 2015-03-11 15:44 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Sudeep Holla, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andre Przywara, x86

Hi Boris,

On 11/03/15 13:36, Borislav Petkov wrote:
> On Tue, Mar 10, 2015 at 02:35:12PM +0000, Sudeep Holla wrote:
>> My initial assumption was that it will be NULL for Intel processors
>> and hence I assigned cacheinfo->priv to nb pointer unconditionally. So
>> I don't have any strong opinion here.
>
> Right, we need the NB descriptor on AMD to do L3-specific operations,
> see amd_l3_disable_index() for an example.
>
> IOW, I ended up committing this:
>

It looks fine to me except one unwanted/incorrect line in the commit log 
as mentioned below. I gave it a spin on my i7 box and it works.
Thanks for the fix up.

> ---
> From: Sudeep Holla <sudeep.holla@arm.com>
> Date: Wed, 11 Mar 2015 11:54:29 +0100
> Subject: [PATCH] x86/cacheinfo: Fix cache_get_priv_group() for Intel
>   processors
>
> The private pointer provided by the cacheinfo code is used to implement
> the AMD L3 cache-specific attributes using a pointer to the northbridge
> descriptor. It is needed for performing L3-specific operations and for
> that we need a couple of PCI devices and other service information, all
> contained in the northbridge descriptor.
>
> However, it's populated even on Intel processors for an L3 cache.

After testing this patch, I think I had misunderstood before and it's
not populated on Intel processors, so you can drop the line above.

Regards,
Sudeep


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2015-03-11 15:44                       ` Sudeep Holla
@ 2015-03-11 20:23                         ` Borislav Petkov
  0 siblings, 0 replies; 32+ messages in thread
From: Borislav Petkov @ 2015-03-11 20:23 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Andre Przywara, x86

On Wed, Mar 11, 2015 at 03:44:39PM +0000, Sudeep Holla wrote:
> It looks fine to me except one unwanted/incorrect line in the commit log as
> mentioned below. I gave it a spin on my i7 box and it works.
> Thanks for the fix up.

Thanks for testing.

> After testing this patch, I think I had misunderstood before and it's
> not populated on Intel processors, so you can drop the line above.

Done. :)

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2015-03-11 20:25 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-08  7:50 [PATCH RFT] x86: move cacheinfo sysfs to generic cacheinfo infrastructure Sudeep Holla
2015-01-23 13:55 ` Thomas Gleixner
2015-01-23 18:15   ` Borislav Petkov
2015-02-23 16:36     ` Sudeep Holla
2015-02-23 18:14 ` [PATCH RFT v2] " Sudeep Holla
2015-02-24  7:58   ` Ingo Molnar
2015-02-24  9:30     ` Sudeep Holla
2015-02-24 17:57   ` Borislav Petkov
2015-02-24 18:09     ` Sudeep Holla
2015-02-24 18:58       ` Borislav Petkov
2015-03-01 22:39     ` Andre Przywara
2015-03-02 10:17       ` Sudeep Holla
2015-03-03 18:45       ` Borislav Petkov
2015-03-03 18:53         ` Tejun Heo
2015-03-03 18:57           ` Borislav Petkov
2015-03-04 11:15             ` Sudeep Holla
2015-03-04 11:27               ` Borislav Petkov
2015-03-04 11:35                 ` Sudeep Holla
2015-03-04  9:52         ` Sudeep Holla
2015-03-04 12:00   ` [PATCH v3] " Sudeep Holla
2015-03-04 12:27     ` Borislav Petkov
2015-03-05  8:16       ` Borislav Petkov
2015-03-05  9:28         ` Sudeep Holla
2015-03-10 11:37           ` Borislav Petkov
2015-03-10 11:53             ` Sudeep Holla
2015-03-10 14:22               ` Sudeep Holla
2015-03-10 14:26                 ` Borislav Petkov
2015-03-10 14:35                   ` Sudeep Holla
2015-03-11 13:36                     ` Borislav Petkov
2015-03-11 15:44                       ` Sudeep Holla
2015-03-11 20:23                         ` Borislav Petkov
2015-03-09 14:46     ` [tip:x86/cpu] x86/cacheinfo: Move cacheinfo sysfs code to generic infrastructure tip-bot for Sudeep Holla

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.