linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support
@ 2014-02-19 16:06 Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices Sudeep Holla
                   ` (8 more replies)
  0 siblings, 9 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: sudeep.holla, Greg Kroah-Hartman, linux-ia64, linux390,
	linux-s390, x86, linuxppc-dev, linux-arm-kernel

From: Sudeep Holla <sudeep.holla@arm.com>

Hi,

This series adds a generic cacheinfo support similar to topology. The
implementation is based on x86 cacheinfo support. Currently x86, powerpc,
ia64 and s390 have their own implementations. While adding similar support
to ARM and ARM64, here is the attempt to make it generic quite similar to
topology info support. It also adds the missing ABI documentation for
the cacheinfo sysfs which is already being used.

It moves all the existing different implementations on x86, ia64, powerpc
and s390 to use the generic cacheinfo infrastructure introduced here.
These changes on non-ARM platforms are only compile tested and hence
the request for testing too.

This series also adds support for ARM and ARM64 architectures based on
the generic support.

Changes v2[2]->v3:
	- Added new class "cpu" to group all cpu devices
	- Converted all "raw" kobjects used in cacheinfo to device_attr
	  by creating cache index devices
	- Added back s390 show_cacheinfo for /proc/cpuinfo
	- Added disable_sysfs to cache_info for preventing a cache node
	  to be exposed through sysfs if required(used on s390)

Changes v1[1]->v2[2]:
	- Extended the generic cacheinfo support to accomodate all
	  the existing implementations
	- Moved all the existing implementations to use this new
	  generic infrastructure
	- Added missing ABI documentation as suggested by Greg KH
	- Added support for unimplemented CTR on pre-ARMv6 implementations
	  as suggested by Russell. However the ctr_info_list is not yet
	  populated
	- not yet changed to device_attr as suggested by Greg KH,
	  registering cache as device won't eliminate the need of kobject
	  unless each index of cache is registered as a device which don't
	  seem to be good idea, but now it's unified it can be done easily
	  in one place if needed

[1] https://lkml.org/lkml/2014/1/8/523
[2] https://lkml.org/lkml/2014/2/7/654

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-ia64@vger.kernel.org
Cc: linux390@de.ibm.com
Cc: linux-s390@vger.kernel.org
Cc: x86@kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-arm-kernel@lists.infradead.org
---
Sudeep Holla (9):
  drivers: base: add new class "cpu" to group cpu devices
  drivers: base: support cpu cache information interface to userspace
    via sysfs
  ia64: move cacheinfo sysfs to generic cacheinfo infrastructure
  s390: move cacheinfo sysfs to generic cacheinfo infrastructure
  x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  ARM64: kernel: add support for cpu cache information
  ARM: kernel: add support for cpu cache information
  ARM: kernel: add outer cache support for cacheinfo implementation

 Documentation/ABI/testing/sysfs-devices-system-cpu |  40 +
 arch/arm/include/asm/outercache.h                  |  13 +
 arch/arm/kernel/Makefile                           |   1 +
 arch/arm/kernel/cacheinfo.c                        | 248 ++++++
 arch/arm/mm/Kconfig                                |  13 +
 arch/arm/mm/cache-l2x0.c                           |  14 +
 arch/arm/mm/cache-tauros2.c                        |  35 +
 arch/arm/mm/cache-xsc3l2.c                         |  15 +
 arch/arm64/kernel/Makefile                         |   2 +-
 arch/arm64/kernel/cacheinfo.c                      | 134 ++++
 arch/ia64/kernel/topology.c                        | 399 ++--------
 arch/powerpc/kernel/cacheinfo.c                    | 831 +++------------------
 arch/powerpc/kernel/cacheinfo.h                    |   8 -
 arch/powerpc/kernel/sysfs.c                        |   4 -
 arch/s390/kernel/cache.c                           | 388 +++-------
 arch/x86/kernel/cpu/intel_cacheinfo.c              | 647 ++++------------
 drivers/base/Makefile                              |   2 +-
 drivers/base/cacheinfo.c                           | 485 ++++++++++++
 drivers/base/core.c                                |  35 +-
 drivers/base/cpu.c                                 |   7 +
 include/linux/cacheinfo.h                          |  55 ++
 include/linux/cpu.h                                |   2 +
 22 files changed, 1523 insertions(+), 1855 deletions(-)
 create mode 100644 arch/arm/kernel/cacheinfo.c
 create mode 100644 arch/arm64/kernel/cacheinfo.c
 delete mode 100644 arch/powerpc/kernel/cacheinfo.h
 create mode 100644 drivers/base/cacheinfo.c
 create mode 100644 include/linux/cacheinfo.h

-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-03-01  0:42   ` Greg Kroah-Hartman
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs Sudeep Holla
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel; +Cc: sudeep.holla, Greg Kroah-Hartman

From: Sudeep Holla <sudeep.holla@arm.com>

This patch creates a new class called "cpu" and assigns it to all the
cpu devices. This helps in grouping all the cpu devices and associated
child devices under the same class.

This patch also:
1. modifies the get_parent_device to return the legacy path
   (/sys/devices/system/cpu/..) for the cpu class devices to support
   existing sysfs ABI
2. avoids creating link in the class directory pointing to the device as
   there would be per-cpu instance of these devices with the same name
3. makes sure subsystem symlink continues pointing to cpu bus instead of
   cpu class for cpu devices

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/base/core.c | 35 +++++++++++++++++++++++++++++++----
 drivers/base/cpu.c  |  7 +++++++
 include/linux/cpu.h |  2 ++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2b56717..80225ff 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -10,6 +10,7 @@
  *
  */
 
+#include <linux/cpu.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -759,6 +760,12 @@ static struct kobject *get_device_parent(struct device *dev,
 			return &block_class.p->subsys.kobj;
 		}
 #endif
+		/*
+		 * if the device is in cpu class, then use the default/legacy
+		 * /sys/devices/system/cpu/.. path
+		 */
+		if (dev->class == cpu_class)
+			return &parent->kobj;
 
 		/*
 		 * If we have no parent, we live in "virtual".
@@ -825,11 +832,17 @@ static int device_add_class_symlinks(struct device *dev)
 	if (!dev->class)
 		return 0;
 
-	error = sysfs_create_link(&dev->kobj,
+	/*
+	 * the subsystem symlink in each cpu device needs to continue
+	 * pointing to cpu bus
+	 */
+	if (dev->bus != &cpu_subsys) {
+		error = sysfs_create_link(&dev->kobj,
 				  &dev->class->p->subsys.kobj,
 				  "subsystem");
-	if (error)
-		goto out;
+		if (error)
+			goto out;
+	}
 
 	if (dev->parent && device_is_not_partition(dev)) {
 		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
@@ -843,6 +856,13 @@ static int device_add_class_symlinks(struct device *dev)
 	if (sysfs_deprecated && dev->class == &block_class)
 		return 0;
 #endif
+	/*
+	 * don't create a link in the cpu class directory pointing to the
+	 * device as there would be per-cpu instance of these devices with
+	 * the same name
+	 */
+	if (dev->class == cpu_class)
+		return 0;
 
 	/* link in the class directory pointing to the device */
 	error = sysfs_create_link(&dev->class->p->subsys.kobj,
@@ -868,11 +888,18 @@ static void device_remove_class_symlinks(struct device *dev)
 
 	if (dev->parent && device_is_not_partition(dev))
 		sysfs_remove_link(&dev->kobj, "device");
-	sysfs_remove_link(&dev->kobj, "subsystem");
+
+	/* if subsystem points to cpu bus, bus_remove_device will remove it */
+	if (dev->bus != &cpu_subsys)
+		sysfs_remove_link(&dev->kobj, "subsystem");
 #ifdef CONFIG_BLOCK
 	if (sysfs_deprecated && dev->class == &block_class)
 		return;
 #endif
+	/* symlinks are not created for cpu class devices, nothing to remove */
+	if (dev->class == cpu_class)
+		return;
+
 	sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev));
 }
 
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index f48370d..28386de 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -286,6 +286,7 @@ static void cpu_device_release(struct device *dev)
 	 */
 }
 
+struct class *cpu_class;
 /*
  * register_cpu - Setup a sysfs device for a CPU.
  * @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -302,6 +303,8 @@ int register_cpu(struct cpu *cpu, int num)
 	memset(&cpu->dev, 0x00, sizeof(struct device));
 	cpu->dev.id = num;
 	cpu->dev.bus = &cpu_subsys;
+	cpu->dev.parent = cpu_subsys.dev_root;
+	cpu->dev.class = cpu_class;
 	cpu->dev.release = cpu_device_release;
 	cpu->dev.offline_disabled = !cpu->hotpluggable;
 	cpu->dev.offline = !cpu_online(num);
@@ -387,5 +390,9 @@ void __init cpu_dev_init(void)
 	if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
 		panic("Failed to register CPU subsystem");
 
+	cpu_class = class_create(THIS_MODULE, "cpu");
+	if (IS_ERR(cpu_class))
+		panic("Failed to register CPU class");
+
 	cpu_dev_register_generic();
 }
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 03e235ad..d1279a5 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -39,6 +39,8 @@ extern void cpu_remove_dev_attr(struct device_attribute *attr);
 extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
 extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
 
+extern struct class *cpu_class;
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
 extern ssize_t arch_cpu_probe(const char *, size_t);
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-03-01  0:42   ` Greg Kroah-Hartman
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 3/9] ia64: move cacheinfo sysfs to generic cacheinfo infrastructure Sudeep Holla
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel; +Cc: sudeep.holla, Greg Kroah-Hartman, Rob Herring, linux-doc

From: Sudeep Holla <sudeep.holla@arm.com>

This patch adds initial support for providing processor cache information
to userspace through sysfs interface. This is based on already existing
implementations(x86, ia64, s390 and powerpc) and hence the interface is
intended to be fully compatible.

The main purpose of this generic support is to avoid further code
duplication to support new architectures and also to unify all the existing
different implementations.

This implementation maintains the hierarchy of cache objects which reflects
the system's cache topology. Cache devices are instantiated as needed as
CPUs come online. The cache information is replicated per-cpu even if they are
shared. A per-cpu array of cache information maintained is used mainly for
sysfs-related book keeping.

It also implements the shared_cpu_map attribute, which is essential for
enabling both kernel and user-space to discover the system's overall cache
topology.

This patch also add the missing ABI documentation for the cacheinfo sysfs
interface already, which is well defined and widely used.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Rob Herring <robh@kernel.org>
Cc: linux-doc@vger.kernel.org
---
 Documentation/ABI/testing/sysfs-devices-system-cpu |  40 ++
 drivers/base/Makefile                              |   2 +-
 drivers/base/cacheinfo.c                           | 484 +++++++++++++++++++++
 include/linux/cacheinfo.h                          |  55 +++
 4 files changed, 580 insertions(+), 1 deletion(-)
 create mode 100644 drivers/base/cacheinfo.c
 create mode 100644 include/linux/cacheinfo.h

diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index d5a0d33..dabe03e 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -224,3 +224,43 @@ Description:	Parameters for the Intel P-state driver
 		frequency range.
 
 		More details can be found in Documentation/cpu-freq/intel-pstate.txt
+
+What:		/sys/devices/system/cpu/cpu*/cache/index*/<set_of_attributes_mentioned_below>
+Date:		February 2014
+Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:	Parameters for the CPU cache attributes
+
+		attributes:
+			- writethrough: data is written to both the cache line
+					and to the block in the lower-level memory
+			- writeback: data is written only to the cache line and
+				     the modified cache line is written to main
+				     memory only when it is replaced
+			- writeallocate: allocate a memory location to a cache line
+					 on a cache miss because of a write
+			- readallocate: allocate a memory location to a cache line
+					on a cache miss because of a read
+
+		coherency_line_size: the minimum amount of data that gets transferred
+
+		level: the cache hierarcy in the multi-level cache configuration
+
+		number_of_sets: total number of sets in the cache, a set is a
+				collection of cache lines with the same cache index
+
+		physical_line_partition: number of physical cache line per cache tag
+
+		shared_cpu_list: the list of cpus sharing the cache
+
+		shared_cpu_map: logical cpu mask containing the list of cpus sharing
+				the cache
+
+		size: the total cache size in kB
+
+		type:
+			- instruction: cache that only holds instructions
+			- data: cache that only caches data
+			- unified: cache that holds both data and instructions
+
+		ways_of_associativity: degree of freedom in placing a particular block
+					of memory in the cache
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 04b314e..bad2ff8 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -4,7 +4,7 @@ obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o \
-			   topology.o container.o
+			   topology.o container.o cacheinfo.o
 obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o
 obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y			+= power/
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
new file mode 100644
index 0000000..146acc8
--- /dev/null
+++ b/drivers/base/cacheinfo.c
@@ -0,0 +1,484 @@
+/*
+ * cacheinfo support - processor cache information via sysfs
+ *
+ * Based on arch/x86/kernel/cpu/intel_cacheinfo.c
+ * Author: Sudeep Holla <sudeep.holla@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/bitops.h>
+#include <linux/cacheinfo.h>
+#include <linux/compiler.h>
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/sysfs.h>
+
+/* pointer to cpu_cacheinfo array (for each cache leaf) */
+static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cache_info);
+#define ci_cacheinfo(cpu)	(&per_cpu(ci_cpu_cache_info, cpu))
+#define cache_leaves(cpu)	(ci_cacheinfo(cpu)->num_leaves)
+#define per_cpu_cacheinfo(cpu)	(ci_cacheinfo(cpu)->info_list)
+
+struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu)
+{
+	return ci_cacheinfo(cpu);
+}
+
+#ifdef CONFIG_OF
+static int cache_setup_of_node(unsigned int cpu)
+{
+	struct device_node *np;
+	struct cache_info *this_leaf;
+	struct device *cpu_dev = get_cpu_device(cpu);
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	unsigned int index = 0;
+
+	/* skip if of_node is already populated */
+	if (this_cpu_ci->info_list->of_node)
+		return 0;
+
+	if (!cpu_dev) {
+		pr_err("No cpu device for CPU %d\n", cpu);
+		return -ENODEV;
+	}
+	np = cpu_dev->of_node;
+	if (!np) {
+		pr_err("Failed to find cpu%d device node\n", cpu);
+		return -ENOENT;
+	}
+
+	while (np && index < cache_leaves(cpu)) {
+		this_leaf = this_cpu_ci->info_list + index;
+		if (this_leaf->level != 1)
+			np = of_find_next_cache_node(np);
+		else
+			np = of_node_get(np);/* cpu node itself */
+		this_leaf->of_node = np;
+		index++;
+	}
+	return 0;
+}
+
+static inline bool cache_leaves_are_shared(struct cache_info *this_leaf,
+					   struct cache_info *sib_leaf)
+{
+	return sib_leaf->of_node == this_leaf->of_node;
+}
+
+static int of_cache_shared_cpu_map_setup(unsigned int cpu)
+{
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf, *sib_leaf;
+	unsigned int index;
+	int ret;
+
+	ret = cache_setup_of_node(cpu);
+	if (ret)
+		return ret;
+
+	for (index = 0; index < cache_leaves(cpu); index++) {
+		unsigned int i;
+		this_leaf = this_cpu_ci->info_list + index;
+		cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
+
+		for_each_online_cpu(i) {
+			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
+			if (i == cpu || !sib_cpu_ci->info_list)
+				continue;/* skip if itself or no cacheinfo */
+			sib_leaf = sib_cpu_ci->info_list + index;
+			if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
+				cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map);
+				cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+			}
+		}
+	}
+
+	return 0;
+}
+#else
+static inline int of_cache_shared_cpu_map_setup(unsigned int cpu)
+{
+	return 0;
+}
+#endif
+
+static void cache_shared_cpu_map_remove(unsigned int cpu)
+{
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf, *sib_leaf;
+	unsigned int sibling, index;
+
+	for (index = 0; index < cache_leaves(cpu); index++) {
+		this_leaf = this_cpu_ci->info_list + index;
+		for_each_cpu(sibling, &this_leaf->shared_cpu_map) {
+			struct cpu_cacheinfo *sib_cpu_ci;
+			if (sibling == cpu) /* skip itself */
+				continue;
+			sib_cpu_ci = get_cpu_cacheinfo(sibling);
+			sib_leaf = sib_cpu_ci->info_list + index;
+			cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map);
+			cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map);
+		}
+		of_node_put(this_leaf->of_node);
+	}
+}
+
+int __weak init_cache_level(unsigned int cpu)
+{
+	return -ENOENT;
+}
+
+int __weak populate_cache_leaves(unsigned int cpu)
+{
+	return -ENOENT;
+}
+
+static void free_cache_attributes(unsigned int cpu)
+{
+	cache_shared_cpu_map_remove(cpu);
+
+	kfree(per_cpu_cacheinfo(cpu));
+	per_cpu_cacheinfo(cpu) = NULL;
+}
+
+/* must be executed on the cpu whose cache attributes are being detected */
+static int detect_cache_attributes(unsigned int cpu)
+{
+	int ret;
+
+	if (init_cache_level(cpu))
+		return -ENOENT;
+
+	per_cpu_cacheinfo(cpu) = kzalloc(sizeof(struct cache_info) *
+					 cache_leaves(cpu), GFP_KERNEL);
+	if (per_cpu_cacheinfo(cpu) == NULL)
+		return -ENOMEM;
+
+	ret = populate_cache_leaves(cpu);
+	if (ret)
+		goto free_ci;
+	/*
+	 * For systems using DT for cache hierarcy, of_node and shared_cpu_map
+	 * will be set up here. Otherwise populate_cache_leaves needs to set
+	 * shared_cpu_map and next-level-cache should not be specified in DT
+	 */
+	ret = of_cache_shared_cpu_map_setup(cpu);
+	if (ret)
+		goto free_ci;
+	return 0;
+
+free_ci:
+	free_cache_attributes(cpu);
+	return ret;
+}
+
+#ifdef CONFIG_SYSFS
+
+/* pointer to cpuX/cache device */
+static DEFINE_PER_CPU(struct device *, ci_cache_dev);
+#define per_cpu_cache_dev(cpu)	(per_cpu(ci_cache_dev, cpu))
+
+static cpumask_t cache_dev_map;
+
+/* pointer to array of devices for cpuX/cache/indexY */
+static DEFINE_PER_CPU(struct device **, ci_index_dev);
+#define per_cpu_index_dev(cpu)	(per_cpu(ci_index_dev, cpu))
+#define per_cache_index_dev(cpu, idx)	((per_cpu_index_dev(cpu))[idx])
+
+#define show_one_plus(file_name, object)			\
+static ssize_t file_name##_show(struct device *dev,		\
+		struct device_attribute *attr, char *buf)	\
+{								\
+	struct cache_info *this_leaf = dev_get_drvdata(dev);	\
+	if (!this_leaf->object)					\
+		return sprintf(buf, "Unknown\n");		\
+	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object); \
+}
+
+show_one_plus(level, level);
+show_one_plus(coherency_line_size, coherency_line_size);
+show_one_plus(ways_of_associativity, ways_of_associativity);
+show_one_plus(number_of_sets, number_of_sets);
+show_one_plus(physical_line_partition, physical_line_partition);
+
+static ssize_t size_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct cache_info *this_leaf = dev_get_drvdata(dev);
+	return sprintf(buf, "%dK\n", this_leaf->size >> 10);
+}
+
+static ssize_t shared_cpumap_show_func(struct device *dev, int type, char *buf)
+{
+	struct cache_info *this_leaf = dev_get_drvdata(dev);
+	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
+	int n = 0;
+
+	if (len > 1) {
+		const struct cpumask *mask = &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;
+}
+
+static ssize_t shared_cpu_map_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return shared_cpumap_show_func(dev, 0, buf);
+}
+
+static ssize_t shared_cpu_list_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return shared_cpumap_show_func(dev, 1, buf);
+}
+
+static ssize_t type_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct cache_info *this_leaf = dev_get_drvdata(dev);
+	switch (this_leaf->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");
+	}
+}
+
+static ssize_t attributes_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct cache_info *this_leaf = dev_get_drvdata(dev);
+	unsigned int ci_attr = this_leaf->attributes;
+	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf - 2;
+	int n = 0;
+
+	if (!ci_attr)
+		return sprintf(buf, "Unknown\n");
+
+	if (ci_attr & CACHE_WRITE_THROUGH)
+		n += snprintf(buf + n, len - n, "WriteThrough\n");
+	if (ci_attr & CACHE_WRITE_BACK)
+		n += snprintf(buf + n, len - n, "WriteBack\n");
+	if (ci_attr & CACHE_READ_ALLOCATE)
+		n += snprintf(buf + n, len - n, "ReadAllocate\n");
+	if (ci_attr & CACHE_WRITE_ALLOCATE)
+		n += snprintf(buf + n, len - n, "WriteAllocate\n");
+	buf[n] = '\0';
+	return n;
+}
+
+#define define_one_ro(_name) \
+	static DEVICE_ATTR_RO(_name)
+
+define_one_ro(level);
+define_one_ro(type);
+define_one_ro(coherency_line_size);
+define_one_ro(ways_of_associativity);
+define_one_ro(number_of_sets);
+define_one_ro(size);
+define_one_ro(attributes);
+define_one_ro(shared_cpu_map);
+define_one_ro(shared_cpu_list);
+define_one_ro(physical_line_partition);
+
+static struct attribute *cache_default_attrs[] = {
+	&dev_attr_type.attr,
+	&dev_attr_level.attr,
+	&dev_attr_coherency_line_size.attr,
+	&dev_attr_ways_of_associativity.attr,
+	&dev_attr_number_of_sets.attr,
+	&dev_attr_size.attr,
+	&dev_attr_attributes.attr,
+	&dev_attr_physical_line_partition.attr,
+	&dev_attr_shared_cpu_map.attr,
+	&dev_attr_shared_cpu_list.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(cache_default);
+
+static void cpu_cache_sysfs_exit(unsigned int cpu)
+{
+	int i;
+	if (per_cpu_index_dev(cpu)) {
+		for (i = 0; i < cache_leaves(cpu); i++) {
+			struct device *tmp_dev = per_cache_index_dev(cpu, i);
+			if (!tmp_dev)
+				continue;
+			put_device(tmp_dev);
+			device_unregister(tmp_dev);
+		}
+		kfree(per_cpu_index_dev(cpu));
+		per_cpu_index_dev(cpu) = NULL;
+	}
+	put_device(per_cpu_cache_dev(cpu));
+	device_unregister(per_cpu_cache_dev(cpu));
+	per_cpu_cache_dev(cpu) = NULL;
+}
+
+static int cpu_cache_sysfs_init(unsigned int cpu)
+{
+	struct device *dev = get_cpu_device(cpu);
+
+	if (per_cpu_cacheinfo(cpu) == NULL)
+		return -ENOENT;
+
+	per_cpu_cache_dev(cpu) = device_create(dev->class, dev, cpu,
+					       NULL, "cache");
+	if (IS_ERR_OR_NULL(per_cpu_cache_dev(cpu)))
+		return PTR_ERR(per_cpu_cache_dev(cpu));
+
+	/* Allocate all required memory */
+	per_cpu_index_dev(cpu) = kzalloc(sizeof(struct device *) *
+					     cache_leaves(cpu), GFP_KERNEL);
+	if (unlikely(per_cpu_index_dev(cpu) == NULL))
+		goto err_out;
+
+	return 0;
+
+err_out:
+	cpu_cache_sysfs_exit(cpu);
+	return -ENOMEM;
+}
+
+int __weak cache_add_private_attributes(struct device *cache_idx_dev)
+{
+	return 0;
+}
+
+/* Add/Remove cache interface for CPU device */
+static int cache_add_dev(unsigned int cpu)
+{
+	struct device *tmp_dev, *parent;
+	struct cache_info *this_leaf;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	unsigned short i;
+	int rc;
+
+	rc = cpu_cache_sysfs_init(cpu);
+	if (unlikely(rc < 0))
+		return rc;
+
+	parent = per_cpu_cache_dev(cpu);
+	for (i = 0; i < cache_leaves(cpu); i++) {
+		this_leaf = this_cpu_ci->info_list + i;
+		if (this_leaf->disable_sysfs)
+			continue;
+		tmp_dev = device_create_with_groups(parent->class, parent, i,
+						    this_leaf,
+						    cache_default_groups,
+						    "index%1u", i);
+		if (IS_ERR_OR_NULL(tmp_dev)) {
+			rc = PTR_ERR(tmp_dev);
+			goto err;
+		}
+
+		rc = cache_add_private_attributes(tmp_dev);
+		if (unlikely(rc))
+			goto err;
+
+		per_cache_index_dev(cpu, i) = tmp_dev;
+	}
+	cpumask_set_cpu(cpu, &cache_dev_map);
+
+	return 0;
+err:
+	cpu_cache_sysfs_exit(cpu);
+	return rc;
+}
+
+static void cache_remove_dev(unsigned int cpu)
+{
+	if (!cpumask_test_cpu(cpu, &cache_dev_map))
+		return;
+	cpumask_clear_cpu(cpu, &cache_dev_map);
+
+	cpu_cache_sysfs_exit(cpu);
+}
+
+static int cacheinfo_cpu_callback(struct notifier_block *nfb,
+				  unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+	int rc = 0;
+
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		rc = detect_cache_attributes(cpu);
+		break;
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		rc = cache_add_dev(cpu);
+		break;
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		cache_remove_dev(cpu);
+	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
+		if (per_cpu_cacheinfo(cpu))
+			free_cache_attributes(cpu);
+		break;
+	}
+	return notifier_from_errno(rc);
+}
+
+/* Helpers to make sure detect_cache_attributes is called on right cpu */
+static void _detect_cache_attributes(void *retval)
+{
+	int cpu = smp_processor_id();
+	*(int *)retval = detect_cache_attributes(cpu);
+}
+
+static int __detect_cache_attributes(unsigned int cpu)
+{
+	int retval;
+	smp_call_function_single(cpu, _detect_cache_attributes, &retval, true);
+	return retval;
+}
+
+static int __init cacheinfo_sysfs_init(void)
+{
+	int cpu;
+	int rc;
+
+	for_each_online_cpu(cpu) {
+		rc = __detect_cache_attributes(cpu);
+		if (rc) {
+			pr_err("error detecting cacheinfo..cpu%d\n", cpu);
+			return rc;
+		}
+		rc = cache_add_dev(cpu);
+		if (rc) {
+			free_cache_attributes(cpu);
+			pr_err("error populating cacheinfo..cpu%d\n", cpu);
+			return rc;
+		}
+	}
+	hotcpu_notifier(cacheinfo_cpu_callback, 0);
+	return 0;
+}
+
+device_initcall(cacheinfo_sysfs_init);
+
+#endif	/* CONFIG_SYSFS */
diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h
new file mode 100644
index 0000000..fa61d83
--- /dev/null
+++ b/include/linux/cacheinfo.h
@@ -0,0 +1,55 @@
+#ifndef _LINUX_CACHEINFO_H
+#define _LINUX_CACHEINFO_H
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/sysfs.h>
+
+enum cache_type {
+	CACHE_TYPE_NOCACHE = 0,
+	CACHE_TYPE_INST = BIT(0),
+	CACHE_TYPE_DATA = BIT(1),
+	CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA,
+	CACHE_TYPE_UNIFIED = BIT(2),
+};
+
+struct cache_info {
+	/* core properties */
+	enum cache_type type; /* data, inst or unified */
+	unsigned int level;
+	unsigned int coherency_line_size; /* cache line size  */
+	unsigned int number_of_sets; /* no. of sets per way */
+	unsigned int ways_of_associativity; /* no. of ways */
+	unsigned int physical_line_partition; /* no. of lines per tag */
+	unsigned int size; /* total cache size */
+	cpumask_t shared_cpu_map;
+	unsigned int attributes;
+#define CACHE_WRITE_THROUGH	BIT(0)
+#define CACHE_WRITE_BACK	BIT(1)
+#define CACHE_READ_ALLOCATE	BIT(2)
+#define CACHE_WRITE_ALLOCATE	BIT(3)
+
+	/* book keeping */
+	struct device_node *of_node;	/* cpu if no explicit cache node */
+	bool disable_sysfs; /* don't expose this leaf through sysfs */
+	void *priv;
+};
+
+struct cpu_cacheinfo {
+	struct cache_info *info_list;
+	unsigned int num_levels;
+	unsigned int num_leaves;
+};
+
+struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu);
+int init_cache_level(unsigned int cpu);
+int populate_cache_leaves(unsigned int cpu);
+
+#ifdef CONFIG_SYSFS
+int cache_add_private_attributes(struct device *cache_idx_dev);
+#endif
+
+#endif /* _LINUX_CACHEINFO_H */
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 3/9] ia64: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 4/9] s390: " Sudeep Holla
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel; +Cc: sudeep.holla, Tony Luck, Fenghua Yu, linux-ia64

From: Sudeep Holla <sudeep.holla@arm.com>

This patch removes the redundant sysfs cacheinfo code by making use of
the newly introduced generic cacheinfo infrastructure.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: linux-ia64@vger.kernel.org
---
 arch/ia64/kernel/topology.c | 399 +++++++++-----------------------------------
 1 file changed, 79 insertions(+), 320 deletions(-)

diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index ca69a5a..78cdeda 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -13,6 +13,7 @@
  *	Populate cpu cache entries in sysfs for cpu cache info
  */
 
+#include <linux/cacheinfo.h>
 #include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -21,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/nodemask.h>
-#include <linux/notifier.h>
 #include <linux/export.h>
 #include <asm/mmzone.h>
 #include <asm/numa.h>
@@ -103,60 +103,25 @@ subsys_initcall(topology_init);
 /*
  * Export cpu cache information through sysfs
  */
-
-/*
- *  A bunch of string array to get pretty printing
- */
-static const char *cache_types[] = {
-	"",			/* not used */
-	"Instruction",
-	"Data",
-	"Unified"	/* unified */
-};
-
-static const char *cache_mattrib[]={
-	"WriteThrough",
-	"WriteBack",
-	"",		/* reserved */
-	""		/* reserved */
-};
-
-struct cache_info {
-	pal_cache_config_info_t	cci;
-	cpumask_t shared_cpu_map;
-	int level;
-	int type;
-	struct kobject kobj;
-};
-
-struct cpu_cache_info {
-	struct cache_info *cache_leaves;
-	int	num_cache_leaves;
-	struct kobject kobj;
-};
-
-static struct cpu_cache_info	all_cpu_cache_info[NR_CPUS];
-#define LEAF_KOBJECT_PTR(x,y)    (&all_cpu_cache_info[x].cache_leaves[y])
-
 #ifdef CONFIG_SMP
-static void cache_shared_cpu_map_setup(unsigned int cpu,
-		struct cache_info * this_leaf)
+static int __cache_cpumap_setup(unsigned int cpu, struct cache_info *this_leaf)
 {
 	pal_cache_shared_info_t	csi;
-	int num_shared, i = 0;
-	unsigned int j;
+	int num_shared, i = 0, j;
+	enum cache_type type = this_leaf->type;
 
 	if (cpu_data(cpu)->threads_per_core <= 1 &&
 		cpu_data(cpu)->cores_per_socket <= 1) {
 		cpu_set(cpu, this_leaf->shared_cpu_map);
-		return;
+		return 0;
 	}
 
-	if (ia64_pal_cache_shared_info(this_leaf->level,
-					this_leaf->type,
-					0,
-					&csi) != PAL_STATUS_SUCCESS)
-		return;
+	if (type == CACHE_TYPE_UNIFIED)
+		type = CACHE_TYPE_DATA;
+
+	if (ia64_pal_cache_shared_info(this_leaf->level, type, 0,
+				       &csi) != PAL_STATUS_SUCCESS)
+		return -EIO;
 
 	num_shared = (int) csi.num_shared;
 	do {
@@ -168,301 +133,95 @@ static void cache_shared_cpu_map_setup(unsigned int cpu,
 
 		i++;
 	} while (i < num_shared &&
-		ia64_pal_cache_shared_info(this_leaf->level,
-				this_leaf->type,
-				i,
-				&csi) == PAL_STATUS_SUCCESS);
-}
-#else
-static void cache_shared_cpu_map_setup(unsigned int cpu,
-		struct cache_info * this_leaf)
-{
-	cpu_set(cpu, this_leaf->shared_cpu_map);
-	return;
-}
-#endif
-
-static ssize_t show_coherency_line_size(struct cache_info *this_leaf,
-					char *buf)
-{
-	return sprintf(buf, "%u\n", 1 << this_leaf->cci.pcci_line_size);
-}
-
-static ssize_t show_ways_of_associativity(struct cache_info *this_leaf,
-					char *buf)
-{
-	return sprintf(buf, "%u\n", this_leaf->cci.pcci_assoc);
-}
-
-static ssize_t show_attributes(struct cache_info *this_leaf, char *buf)
-{
-	return sprintf(buf,
-			"%s\n",
-			cache_mattrib[this_leaf->cci.pcci_cache_attr]);
-}
-
-static ssize_t show_size(struct cache_info *this_leaf, char *buf)
-{
-	return sprintf(buf, "%uK\n", this_leaf->cci.pcci_cache_size / 1024);
-}
-
-static ssize_t show_number_of_sets(struct cache_info *this_leaf, char *buf)
-{
-	unsigned number_of_sets = this_leaf->cci.pcci_cache_size;
-	number_of_sets /= this_leaf->cci.pcci_assoc;
-	number_of_sets /= 1 << this_leaf->cci.pcci_line_size;
-
-	return sprintf(buf, "%u\n", number_of_sets);
-}
-
-static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf)
-{
-	ssize_t	len;
-	cpumask_t shared_cpu_map;
-
-	cpumask_and(&shared_cpu_map,
-				&this_leaf->shared_cpu_map, cpu_online_mask);
-	len = cpumask_scnprintf(buf, NR_CPUS+1, &shared_cpu_map);
-	len += sprintf(buf+len, "\n");
-	return len;
-}
-
-static ssize_t show_type(struct cache_info *this_leaf, char *buf)
-{
-	int type = this_leaf->type + this_leaf->cci.pcci_unified;
-	return sprintf(buf, "%s\n", cache_types[type]);
-}
-
-static ssize_t show_level(struct cache_info *this_leaf, char *buf)
-{
-	return sprintf(buf, "%u\n", this_leaf->level);
+		 ia64_pal_cache_shared_info(this_leaf->level, type, i,
+					    &csi) == PAL_STATUS_SUCCESS);
+	return 0;
 }
 
-struct cache_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct cache_info *, char *);
-	ssize_t (*store)(struct cache_info *, const char *, size_t count);
-};
-
-#ifdef define_one_ro
-	#undef define_one_ro
-#endif
-#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(ways_of_associativity);
-define_one_ro(size);
-define_one_ro(number_of_sets);
-define_one_ro(shared_cpu_map);
-define_one_ro(attributes);
-
-static struct attribute * cache_default_attrs[] = {
-	&type.attr,
-	&level.attr,
-	&coherency_line_size.attr,
-	&ways_of_associativity.attr,
-	&attributes.attr,
-	&size.attr,
-	&number_of_sets.attr,
-	&shared_cpu_map.attr,
-	NULL
-};
-
-#define to_object(k) container_of(k, struct cache_info, kobj)
-#define to_attr(a) container_of(a, struct cache_attr, attr)
-
-static ssize_t ia64_cache_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static int cache_shared_cpu_map_setup(unsigned int cpu)
 {
-	struct cache_attr *fattr = to_attr(attr);
-	struct cache_info *this_leaf = to_object(kobj);
-	ssize_t ret;
-
-	ret = fattr->show ? fattr->show(this_leaf, buf) : 0;
+	unsigned int idx;
+	int ret = 0;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++, this_leaf++) {
+		ret = __cache_cpumap_setup(cpu, this_leaf);
+		if (ret)
+			break;
+	}
 	return ret;
 }
-
-static const struct sysfs_ops cache_sysfs_ops = {
-	.show   = ia64_cache_show
-};
-
-static struct kobj_type cache_ktype = {
-	.sysfs_ops	= &cache_sysfs_ops,
-	.default_attrs	= cache_default_attrs,
-};
-
-static struct kobj_type cache_ktype_percpu_entry = {
-	.sysfs_ops	= &cache_sysfs_ops,
-};
-
-static void cpu_cache_sysfs_exit(unsigned int cpu)
-{
-	kfree(all_cpu_cache_info[cpu].cache_leaves);
-	all_cpu_cache_info[cpu].cache_leaves = NULL;
-	all_cpu_cache_info[cpu].num_cache_leaves = 0;
-	memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject));
-	return;
-}
-
-static int cpu_cache_sysfs_init(unsigned int cpu)
+#else
+static int cache_shared_cpu_map_setup(unsigned int cpu)
 {
-	unsigned long i, levels, unique_caches;
-	pal_cache_config_info_t cci;
-	int j;
-	long status;
-	struct cache_info *this_cache;
-	int num_cache_leaves = 0;
-
-	if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
-		printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status);
-		return -1;
-	}
-
-	this_cache=kzalloc(sizeof(struct cache_info)*unique_caches,
-			GFP_KERNEL);
-	if (this_cache == NULL)
-		return -ENOMEM;
-
-	for (i=0; i < levels; i++) {
-		for (j=2; j >0 ; j--) {
-			if ((status=ia64_pal_cache_config_info(i,j, &cci)) !=
-					PAL_STATUS_SUCCESS)
-				continue;
-
-			this_cache[num_cache_leaves].cci = cci;
-			this_cache[num_cache_leaves].level = i + 1;
-			this_cache[num_cache_leaves].type = j;
-
-			cache_shared_cpu_map_setup(cpu,
-					&this_cache[num_cache_leaves]);
-			num_cache_leaves ++;
-		}
-	}
-
-	all_cpu_cache_info[cpu].cache_leaves = this_cache;
-	all_cpu_cache_info[cpu].num_cache_leaves = num_cache_leaves;
-
-	memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject));
-
+	int idx;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++, this_leaf++)
+		cpu_set(cpu, this_leaf->shared_cpu_map);
 	return 0;
 }
+#endif
 
-/* Add cache interface for CPU device */
-static int cache_add_dev(struct device *sys_dev)
+static void ci_leaf_init(struct cache_info *this_leaf,
+			 pal_cache_config_info_t *cci,
+			 enum cache_type type, unsigned int level)
 {
-	unsigned int cpu = sys_dev->id;
-	unsigned long i, j;
-	struct cache_info *this_object;
-	int retval = 0;
-	cpumask_t oldmask;
-
-	if (all_cpu_cache_info[cpu].kobj.parent)
-		return 0;
-
-	oldmask = current->cpus_allowed;
-	retval = set_cpus_allowed_ptr(current, cpumask_of(cpu));
-	if (unlikely(retval))
-		return retval;
-
-	retval = cpu_cache_sysfs_init(cpu);
-	set_cpus_allowed_ptr(current, &oldmask);
-	if (unlikely(retval < 0))
-		return retval;
+	unsigned number_of_sets = cci->pcci_cache_size;
+	number_of_sets /= cci->pcci_assoc;
+	number_of_sets /= 1 << cci->pcci_line_size;
 
-	retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj,
-				      &cache_ktype_percpu_entry, &sys_dev->kobj,
-				      "%s", "cache");
-	if (unlikely(retval < 0)) {
-		cpu_cache_sysfs_exit(cpu);
-		return retval;
-	}
-
-	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) {
-		this_object = LEAF_KOBJECT_PTR(cpu,i);
-		retval = kobject_init_and_add(&(this_object->kobj),
-					      &cache_ktype,
-					      &all_cpu_cache_info[cpu].kobj,
-					      "index%1lu", i);
-		if (unlikely(retval)) {
-			for (j = 0; j < i; j++) {
-				kobject_put(&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
-			}
-			kobject_put(&all_cpu_cache_info[cpu].kobj);
-			cpu_cache_sysfs_exit(cpu);
-			return retval;
-		}
-		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
-	}
-	kobject_uevent(&all_cpu_cache_info[cpu].kobj, KOBJ_ADD);
-	return retval;
+	this_leaf->level = level;
+	this_leaf->type = cci->pcci_unified ? CACHE_TYPE_UNIFIED : type;
+	this_leaf->coherency_line_size = cci->pcci_line_size;
+	this_leaf->ways_of_associativity = cci->pcci_assoc;
+	this_leaf->size = cci->pcci_cache_size;
+	this_leaf->attributes = cci->pcci_cache_attr;
+	this_leaf->number_of_sets = number_of_sets;
 }
 
-/* Remove cache interface for CPU device */
-static int cache_remove_dev(struct device *sys_dev)
+int init_cache_level(unsigned int cpu)
 {
-	unsigned int cpu = sys_dev->id;
-	unsigned long i;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	unsigned long levels, unique_caches;
+	long status;
 
-	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++)
-		kobject_put(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
+	if (!this_cpu_ci)
+		return -EINVAL;
 
-	if (all_cpu_cache_info[cpu].kobj.parent) {
-		kobject_put(&all_cpu_cache_info[cpu].kobj);
-		memset(&all_cpu_cache_info[cpu].kobj,
-			0,
-			sizeof(struct kobject));
+	status = ia64_pal_cache_summary(&levels, &unique_caches);
+	if (status != PAL_STATUS_SUCCESS) {
+		pr_err("ia64_pal_cache_summary = %ld\n", status);
+		return -EIO;
 	}
-
-	cpu_cache_sysfs_exit(cpu);
+	this_cpu_ci->num_levels = levels;
+	this_cpu_ci->num_leaves = unique_caches;
 
 	return 0;
 }
 
-/*
- * When a cpu is hot-plugged, do a check and initiate
- * cache kobject if necessary
- */
-static int cache_cpu_callback(struct notifier_block *nfb,
-		unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct device *sys_dev;
-
-	sys_dev = get_cpu_device(cpu);
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		cache_add_dev(sys_dev);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		cache_remove_dev(sys_dev);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cache_cpu_notifier =
+int populate_cache_leaves(unsigned int cpu)
 {
-	.notifier_call = cache_cpu_callback
-};
-
-static int __init cache_sysfs_init(void)
-{
-	int i;
-
-	for_each_online_cpu(i) {
-		struct device *sys_dev = get_cpu_device((unsigned int)i);
-		cache_add_dev(sys_dev);
+	unsigned int level, idx;
+	s64 status;
+	pal_cache_config_info_t cci;
+	enum cache_type type;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
+
+	for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
+			idx < this_cpu_ci->num_leaves; idx++, level++) {
+		if (!this_leaf)
+			return -EINVAL;
+
+		type = CACHE_TYPE_INST;
+		status = ia64_pal_cache_config_info(level - 1, type, &cci);
+		if (status == PAL_STATUS_SUCCESS)
+			ci_leaf_init(this_leaf++, &cci, type, level);
+		type = CACHE_TYPE_DATA;
+		status = ia64_pal_cache_config_info(level - 1, type, &cci);
+		if (status == PAL_STATUS_SUCCESS)
+			ci_leaf_init(this_leaf++, &cci, type, level);
 	}
-
-	register_hotcpu_notifier(&cache_cpu_notifier);
-
-	return 0;
+	return cache_shared_cpu_map_setup(cpu);
 }
-
-device_initcall(cache_sysfs_init);
-
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 4/9] s390: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
                   ` (2 preceding siblings ...)
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 3/9] ia64: move cacheinfo sysfs to generic cacheinfo infrastructure Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-02-20  8:38   ` Heiko Carstens
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 5/9] x86: " Sudeep Holla
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: sudeep.holla, Martin Schwidefsky, Heiko Carstens, linux390, linux-s390

From: Sudeep Holla <sudeep.holla@arm.com>

This patch removes the redundant sysfs cacheinfo code by making use of
the newly introduced generic cacheinfo infrastructure.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux390@de.ibm.com
Cc: linux-s390@vger.kernel.org
---
 arch/s390/kernel/cache.c | 388 ++++++++++++-----------------------------------
 1 file changed, 93 insertions(+), 295 deletions(-)

diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c
index 3a414c0..e064f95 100644
--- a/arch/s390/kernel/cache.c
+++ b/arch/s390/kernel/cache.c
@@ -5,37 +5,11 @@
  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
-#include <linux/notifier.h>
 #include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/slab.h>
 #include <linux/cpu.h>
+#include <linux/cacheinfo.h>
 #include <asm/facility.h>
 
-struct cache {
-	unsigned long size;
-	unsigned int line_size;
-	unsigned int associativity;
-	unsigned int nr_sets;
-	unsigned int level   : 3;
-	unsigned int type    : 2;
-	unsigned int private : 1;
-	struct list_head list;
-};
-
-struct cache_dir {
-	struct kobject *kobj;
-	struct cache_index_dir *index;
-};
-
-struct cache_index_dir {
-	struct kobject kobj;
-	int cpu;
-	struct cache *cache;
-	struct cache_index_dir *next;
-};
-
 enum {
 	CACHE_SCOPE_NOTEXISTS,
 	CACHE_SCOPE_PRIVATE,
@@ -44,10 +18,10 @@ enum {
 };
 
 enum {
-	CACHE_TYPE_SEPARATE,
-	CACHE_TYPE_DATA,
-	CACHE_TYPE_INSTRUCTION,
-	CACHE_TYPE_UNIFIED,
+	CTYPE_SEPARATE,
+	CTYPE_DATA,
+	CTYPE_INSTRUCTION,
+	CTYPE_UNIFIED,
 };
 
 enum {
@@ -63,46 +37,65 @@ enum {
 	CACHE_TI_INSTRUCTION,
 };
 
-struct cache_info {
+struct _cacheinfo {
 	unsigned char	    : 4;
 	unsigned char scope : 2;
 	unsigned char type  : 2;
 };
 
 #define CACHE_MAX_LEVEL 8
-
 union cache_topology {
-	struct cache_info ci[CACHE_MAX_LEVEL];
+	struct _cacheinfo ci[CACHE_MAX_LEVEL];
 	unsigned long long raw;
 };
 
 static const char * const cache_type_string[] = {
-	"Data",
+	"",
 	"Instruction",
+	"Data",
+	"",
 	"Unified",
 };
 
-static struct cache_dir *cache_dir_cpu[NR_CPUS];
-static LIST_HEAD(cache_list);
+static const enum cache_type cache_type_map[] = {
+	[CTYPE_SEPARATE] = CACHE_TYPE_SEPARATE,
+	[CTYPE_DATA] = CACHE_TYPE_DATA,
+	[CTYPE_INSTRUCTION] = CACHE_TYPE_INST,
+	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
+};
 
 void show_cacheinfo(struct seq_file *m)
 {
-	struct cache *cache;
-	int index = 0;
+	int cpu = smp_processor_id(), idx;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *cache = this_cpu_ci->info_list;
 
-	list_for_each_entry(cache, &cache_list, list) {
-		seq_printf(m, "cache%-11d: ", index);
+	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+		seq_printf(m, "cache%-11d: ", idx);
 		seq_printf(m, "level=%d ", cache->level);
 		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
-		seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared");
-		seq_printf(m, "size=%luK ", cache->size >> 10);
-		seq_printf(m, "line_size=%u ", cache->line_size);
-		seq_printf(m, "associativity=%d", cache->associativity);
+		seq_printf(m, "scope=%s ",
+			   cache->disable_sysfs ? "Private" : "Shared");
+		seq_printf(m, "size=%dK ", cache->size >> 10);
+		seq_printf(m, "line_size=%u ", cache->coherency_line_size);
+		seq_printf(m, "associativity=%d", cache->ways_of_associativity);
 		seq_puts(m, "\n");
-		index++;
 	}
 }
 
+static inline enum cache_type get_cache_type(struct _cacheinfo *ci, int level)
+{
+	if (level >= CACHE_MAX_LEVEL)
+		return CACHE_TYPE_NOCACHE;
+
+	ci += level;
+
+	if (ci->scope != CACHE_SCOPE_SHARED && ci->scope != CACHE_SCOPE_PRIVATE)
+		return CACHE_TYPE_NOCACHE;
+
+	return cache_type_map[ci->type];
+}
+
 static inline unsigned long ecag(int ai, int li, int ti)
 {
 	unsigned long cmd, val;
@@ -113,274 +106,79 @@ static inline unsigned long ecag(int ai, int li, int ti)
 	return val;
 }
 
-static int __init cache_add(int level, int private, int type)
+static void ci_leaf_init(struct cache_info *this_leaf, int private,
+			 enum cache_type type, unsigned int level)
 {
-	struct cache *cache;
-	int ti;
+	int ti, num_sets;
+	int cpu = smp_processor_id();
 
-	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
-	if (!cache)
-		return -ENOMEM;
-	if (type == CACHE_TYPE_INSTRUCTION)
+	if (type == CACHE_TYPE_INST)
 		ti = CACHE_TI_INSTRUCTION;
 	else
 		ti = CACHE_TI_UNIFIED;
-	cache->size = ecag(EXTRACT_SIZE, level, ti);
-	cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
-	cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
-	cache->nr_sets = cache->size / cache->associativity;
-	cache->nr_sets /= cache->line_size;
-	cache->private = private;
-	cache->level = level + 1;
-	cache->type = type - 1;
-	list_add_tail(&cache->list, &cache_list);
-	return 0;
-}
 
-static void __init cache_build_info(void)
-{
-	struct cache *cache, *next;
-	union cache_topology ct;
-	int level, private, rc;
+	this_leaf->level = level + 1;
+	this_leaf->type = type;
+	this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
+	this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY,
+						level, ti);
+	this_leaf->size = ecag(EXTRACT_SIZE, level, ti);
 
-	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
-	for (level = 0; level < CACHE_MAX_LEVEL; level++) {
-		switch (ct.ci[level].scope) {
-		case CACHE_SCOPE_SHARED:
-			private = 0;
-			break;
-		case CACHE_SCOPE_PRIVATE:
-			private = 1;
-			break;
-		default:
-			return;
-		}
-		if (ct.ci[level].type == CACHE_TYPE_SEPARATE) {
-			rc  = cache_add(level, private, CACHE_TYPE_DATA);
-			rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION);
-		} else {
-			rc = cache_add(level, private, ct.ci[level].type);
-		}
-		if (rc)
-			goto error;
-	}
-	return;
-error:
-	list_for_each_entry_safe(cache, next, &cache_list, list) {
-		list_del(&cache->list);
-		kfree(cache);
-	}
-}
-
-static struct cache_dir *cache_create_cache_dir(int cpu)
-{
-	struct cache_dir *cache_dir;
-	struct kobject *kobj = NULL;
-	struct device *dev;
-
-	dev = get_cpu_device(cpu);
-	if (!dev)
-		goto out;
-	kobj = kobject_create_and_add("cache", &dev->kobj);
-	if (!kobj)
-		goto out;
-	cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL);
-	if (!cache_dir)
-		goto out;
-	cache_dir->kobj = kobj;
-	cache_dir_cpu[cpu] = cache_dir;
-	return cache_dir;
-out:
-	kobject_put(kobj);
-	return NULL;
-}
-
-static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj)
-{
-	return container_of(kobj, struct cache_index_dir, kobj);
-}
-
-static void cache_index_release(struct kobject *kobj)
-{
-	struct cache_index_dir *index;
-
-	index = kobj_to_cache_index_dir(kobj);
-	kfree(index);
+	num_sets = this_leaf->size / this_leaf->coherency_line_size;
+	num_sets /= this_leaf->ways_of_associativity;
+	this_leaf->number_of_sets = num_sets;
+	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
+	if (!private)
+		this_leaf->disable_sysfs = true;
 }
 
-static ssize_t cache_index_show(struct kobject *kobj,
-				struct attribute *attr, char *buf)
+int init_cache_level(unsigned int cpu)
 {
-	struct kobj_attribute *kobj_attr;
-
-	kobj_attr = container_of(attr, struct kobj_attribute, attr);
-	return kobj_attr->show(kobj, kobj_attr, buf);
-}
-
-#define DEFINE_CACHE_ATTR(_name, _format, _value)			\
-static ssize_t cache_##_name##_show(struct kobject *kobj,		\
-				    struct kobj_attribute *attr,	\
-				    char *buf)				\
-{									\
-	struct cache_index_dir *index;					\
-									\
-	index = kobj_to_cache_index_dir(kobj);				\
-	return sprintf(buf, _format, _value);				\
-}									\
-static struct kobj_attribute cache_##_name##_attr =			\
-	__ATTR(_name, 0444, cache_##_name##_show, NULL);
-
-DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10);
-DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size);
-DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets);
-DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity);
-DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]);
-DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level);
-
-static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf)
-{
-	struct cache_index_dir *index;
-	int len;
-
-	index = kobj_to_cache_index_dir(kobj);
-	len = type ?
-		cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) :
-		cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu));
-	len += sprintf(&buf[len], "\n");
-	return len;
-}
-
-static ssize_t shared_cpu_map_show(struct kobject *kobj,
-				   struct kobj_attribute *attr, char *buf)
-{
-	return shared_cpu_map_func(kobj, 0, buf);
-}
-static struct kobj_attribute cache_shared_cpu_map_attr =
-	__ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL);
-
-static ssize_t shared_cpu_list_show(struct kobject *kobj,
-				    struct kobj_attribute *attr, char *buf)
-{
-	return shared_cpu_map_func(kobj, 1, buf);
-}
-static struct kobj_attribute cache_shared_cpu_list_attr =
-	__ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL);
-
-static struct attribute *cache_index_default_attrs[] = {
-	&cache_type_attr.attr,
-	&cache_size_attr.attr,
-	&cache_number_of_sets_attr.attr,
-	&cache_ways_of_associativity_attr.attr,
-	&cache_level_attr.attr,
-	&cache_coherency_line_size_attr.attr,
-	&cache_shared_cpu_map_attr.attr,
-	&cache_shared_cpu_list_attr.attr,
-	NULL,
-};
-
-static const struct sysfs_ops cache_index_ops = {
-	.show = cache_index_show,
-};
-
-static struct kobj_type cache_index_type = {
-	.sysfs_ops = &cache_index_ops,
-	.release = cache_index_release,
-	.default_attrs = cache_index_default_attrs,
-};
-
-static int cache_create_index_dir(struct cache_dir *cache_dir,
-				  struct cache *cache, int index, int cpu)
-{
-	struct cache_index_dir *index_dir;
-	int rc;
-
-	index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL);
-	if (!index_dir)
-		return -ENOMEM;
-	index_dir->cache = cache;
-	index_dir->cpu = cpu;
-	rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type,
-				  cache_dir->kobj, "index%d", index);
-	if (rc)
-		goto out;
-	index_dir->next = cache_dir->index;
-	cache_dir->index = index_dir;
-	return 0;
-out:
-	kfree(index_dir);
-	return rc;
-}
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	unsigned int level = 0, leaves = 0;
+	union cache_topology ct;
+	enum cache_type ctype;
 
-static int cache_add_cpu(int cpu)
-{
-	struct cache_dir *cache_dir;
-	struct cache *cache;
-	int rc, index = 0;
+	if (!this_cpu_ci)
+		return -EINVAL;
 
-	if (list_empty(&cache_list))
-		return 0;
-	cache_dir = cache_create_cache_dir(cpu);
-	if (!cache_dir)
-		return -ENOMEM;
-	list_for_each_entry(cache, &cache_list, list) {
-		if (!cache->private)
+	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
+	do {
+		ctype = get_cache_type(&ct.ci[0], level);
+		if (ctype == CACHE_TYPE_NOCACHE)
 			break;
-		rc = cache_create_index_dir(cache_dir, cache, index, cpu);
-		if (rc)
-			return rc;
-		index++;
-	}
-	return 0;
-}
+		/* Separate instruction and data caches */
+		leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
+	} while (++level < CACHE_MAX_LEVEL);
 
-static void cache_remove_cpu(int cpu)
-{
-	struct cache_index_dir *index, *next;
-	struct cache_dir *cache_dir;
+	this_cpu_ci->num_levels = level;
+	this_cpu_ci->num_leaves = leaves;
 
-	cache_dir = cache_dir_cpu[cpu];
-	if (!cache_dir)
-		return;
-	index = cache_dir->index;
-	while (index) {
-		next = index->next;
-		kobject_put(&index->kobj);
-		index = next;
-	}
-	kobject_put(cache_dir->kobj);
-	kfree(cache_dir);
-	cache_dir_cpu[cpu] = NULL;
+	return 0;
 }
 
-static int cache_hotplug(struct notifier_block *nfb, unsigned long action,
-			 void *hcpu)
+int populate_cache_leaves(unsigned int cpu)
 {
-	int cpu = (long)hcpu;
-	int rc = 0;
+	unsigned int level, idx, pvt;
+	union cache_topology ct;
+	enum cache_type ctype;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
 
-	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_ONLINE:
-		rc = cache_add_cpu(cpu);
-		if (rc)
-			cache_remove_cpu(cpu);
-		break;
-	case CPU_DEAD:
-		cache_remove_cpu(cpu);
-		break;
+	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
+	for (idx = 0, level = 0; level < this_cpu_ci->num_levels &&
+			idx < this_cpu_ci->num_leaves; idx++, level++) {
+		if (!this_leaf)
+			return -EINVAL;
+
+		pvt = (ct.ci[level].scope == CACHE_SCOPE_PRIVATE) ? 1 : 0;
+		ctype = get_cache_type(&ct.ci[0], level);
+		if (ctype == CACHE_TYPE_SEPARATE) {
+			ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level);
+			ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level);
+		} else {
+			ci_leaf_init(this_leaf++, pvt, ctype, level);
+		}
 	}
-	return rc ? NOTIFY_BAD : NOTIFY_OK;
-}
-
-static int __init cache_init(void)
-{
-	int cpu;
-
-	if (!test_facility(34))
-		return 0;
-	cache_build_info();
-	for_each_online_cpu(cpu)
-		cache_add_cpu(cpu);
-	hotcpu_notifier(cache_hotplug, 0);
 	return 0;
 }
-device_initcall(cache_init);
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 5/9] x86: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
                   ` (3 preceding siblings ...)
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 4/9] s390: " Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 6/9] powerpc: " Sudeep Holla
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel; +Cc: sudeep.holla, Thomas Gleixner, Ingo Molnar, x86

From: Sudeep Holla <sudeep.holla@arm.com>

This patch removes the redundant sysfs cacheinfo code by making use of
the newly introduced generic cacheinfo infrastructure.

The private pointer provided by the cache_info 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: x86@kernel.org
---
 arch/x86/kernel/cpu/intel_cacheinfo.c | 647 ++++++++--------------------------
 1 file changed, 147 insertions(+), 500 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 0641113..03fc10d 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,12 +157,7 @@ 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;
+unsigned short                 num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
    information to the user.  This makes some assumptions about the machine:
@@ -291,14 +284,9 @@ 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)
+
+static struct attribute **amd_l3_attrs;
 /*
  * L3 cache descriptors
  */
@@ -325,6 +313,7 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb)
 	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
+static void init_amd_l3_attrs(void);
 static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
 {
 	int node;
@@ -335,8 +324,10 @@ static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
 
 	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)
+	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices) {
 		amd_calc_l3_indices(this_leaf->nb);
+		init_amd_l3_attrs();
+	}
 }
 
 /*
@@ -359,15 +350,16 @@ 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 cache_info *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))
+	if (!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 +368,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 cache_info *this_leaf = dev_get_drvdata(dev);		\
 	return show_cache_disable(this_leaf, buf, slot);		\
 }
 SHOW_CACHE_DISABLE(0)
@@ -446,25 +439,26 @@ 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 cache_info *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))
+	if (!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 (strict_strtoul(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,39 +470,39 @@ 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 cache_info *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))
+	struct cache_info *this_leaf = dev_get_drvdata(dev);
+	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
+	if (!this_leaf->priv || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
 		return -EINVAL;
 
 	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 cache_info *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))
+	if (!this_leaf->priv || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
 		return -EINVAL;
 
 	if (strict_strtoul(buf, 16, &val) < 0)
@@ -520,9 +514,46 @@ 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);
+#define define_one_rw(_name) \
+	static DEVICE_ATTR_RW(_name)
+
+define_one_rw(cache_disable_0);
+define_one_rw(cache_disable_1);
+define_one_rw(subcaches);
+
+static void init_amd_l3_attrs(void)
+{
+	int n = 0;
+
+	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 = kzalloc(n * sizeof(struct attribute *), 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;
+
+	return;
+}
+
+int cache_add_private_attributes(struct device *cache_idx_dev)
+{
+	struct cache_info *this_leaf = dev_get_drvdata(cache_idx_dev);
+	if (!this_leaf->priv || !amd_l3_attrs)
+		return 0;
 
+	return sysfs_create_files(&cache_idx_dev->kobj,
+				  (const struct attribute **)amd_l3_attrs);
+}
 #else
 #define amd_init_l3_cache(x, y)
 #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
@@ -546,7 +577,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 +606,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 +657,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:
@@ -735,55 +766,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 cache_info *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
@@ -792,456 +814,81 @@ 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 cache_info *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();
-
-	/* Do cpuid and store the results */
-	for (j = 0; j < num_cache_leaves; j++) {
-		struct _cpuid4_info *this_leaf = CPUID4_INFO_IDX(cpu, j);
+		return;
 
-		*retval = cpuid4_cache_lookup_regs(j, &this_leaf->base);
-		if (unlikely(*retval < 0)) {
-			int i;
+	index_msb = get_count_order(num_threads_sharing);
 
-			for (i = 0; i < j; i++)
-				cache_remove_shared_cpu_map(cpu, i);
-			break;
+	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);
+			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 cache_info *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 = base->eax.split.type;
+	this_leaf->coherency_line_size = base->ebx.split.coherency_line_size;
+	this_leaf->ways_of_associativity =
+				base->ebx.split.ways_of_associativity;
+	this_leaf->size = base->size;
+	this_leaf->number_of_sets = base->ecx.split.number_of_sets;
+	this_leaf->physical_line_partition =
+				base->ebx.split.physical_line_partition;
+	this_leaf->priv = base->nb;
 }
 
-static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
-					  unsigned int cpu)
+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;
-}
-
-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)
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	if (!num_cache_leaves)
 		return -ENOENT;
+	if (!this_cpu_ci)
+		return -EINVAL;
 
-	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;
-
+	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)
+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 cache_info *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;
-
-	if (num_cache_leaves == 0)
-		return 0;
-
-	for_each_online_cpu(i) {
-		int err;
-		struct device *dev = get_cpu_device(i);
-
-		err = cache_add_dev(dev);
-		if (err)
-			return err;
-	}
-	register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-	return 0;
-}
-
-device_initcall(cache_sysfs_init);
-
-#endif
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
                   ` (4 preceding siblings ...)
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 5/9] x86: " Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-03-07  4:06   ` Anshuman Khandual
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 7/9] ARM64: kernel: add support for cpu cache information Sudeep Holla
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: sudeep.holla, Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev

From: Sudeep Holla <sudeep.holla@arm.com>

This patch removes the redundant sysfs cacheinfo code by making use of
the newly introduced generic cacheinfo infrastructure.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org
---
 arch/powerpc/kernel/cacheinfo.c | 831 ++++++----------------------------------
 arch/powerpc/kernel/cacheinfo.h |   8 -
 arch/powerpc/kernel/sysfs.c     |   4 -
 3 files changed, 109 insertions(+), 734 deletions(-)
 delete mode 100644 arch/powerpc/kernel/cacheinfo.h

diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
index 2912b87..05b7580 100644
--- a/arch/powerpc/kernel/cacheinfo.c
+++ b/arch/powerpc/kernel/cacheinfo.c
@@ -10,38 +10,10 @@
  * 2 as published by the Free Software Foundation.
  */
 
+#include <linux/cacheinfo.h>
 #include <linux/cpu.h>
-#include <linux/cpumask.h>
 #include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/list.h>
-#include <linux/notifier.h>
 #include <linux/of.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-#include <asm/prom.h>
-
-#include "cacheinfo.h"
-
-/* per-cpu object for tracking:
- * - a "cache" kobject for the top-level directory
- * - a list of "index" objects representing the cpu's local cache hierarchy
- */
-struct cache_dir {
-	struct kobject *kobj; /* bare (not embedded) kobject for cache
-			       * directory */
-	struct cache_index_dir *index; /* list of index objects */
-};
-
-/* "index" object: each cpu's cache directory has an index
- * subdirectory corresponding to a cache object associated with the
- * cpu.  This object's lifetime is managed via the embedded kobject.
- */
-struct cache_index_dir {
-	struct kobject kobj;
-	struct cache_index_dir *next; /* next index in parent directory */
-	struct cache *cache;
-};
 
 /* Template for determining which OF properties to query for a given
  * cache type */
@@ -60,11 +32,6 @@ struct cache_type_info {
 	const char *nr_sets_prop;
 };
 
-/* These are used to index the cache_type_info array. */
-#define CACHE_TYPE_UNIFIED     0
-#define CACHE_TYPE_INSTRUCTION 1
-#define CACHE_TYPE_DATA        2
-
 static const struct cache_type_info cache_type_info[] = {
 	{
 		/* PowerPC Processor binding says the [di]-cache-*
@@ -77,246 +44,115 @@ static const struct cache_type_info cache_type_info[] = {
 		.nr_sets_prop    = "d-cache-sets",
 	},
 	{
-		.name            = "Instruction",
-		.size_prop       = "i-cache-size",
-		.line_size_props = { "i-cache-line-size",
-				     "i-cache-block-size", },
-		.nr_sets_prop    = "i-cache-sets",
-	},
-	{
 		.name            = "Data",
 		.size_prop       = "d-cache-size",
 		.line_size_props = { "d-cache-line-size",
 				     "d-cache-block-size", },
 		.nr_sets_prop    = "d-cache-sets",
 	},
+	{
+		.name            = "Instruction",
+		.size_prop       = "i-cache-size",
+		.line_size_props = { "i-cache-line-size",
+				     "i-cache-block-size", },
+		.nr_sets_prop    = "i-cache-sets",
+	},
 };
 
-/* Cache object: each instance of this corresponds to a distinct cache
- * in the system.  There are separate objects for Harvard caches: one
- * each for instruction and data, and each refers to the same OF node.
- * The refcount of the OF node is elevated for the lifetime of the
- * cache object.  A cache object is released when its shared_cpu_map
- * is cleared (see cache_cpu_clear).
- *
- * A cache object is on two lists: an unsorted global list
- * (cache_list) of cache objects; and a singly-linked list
- * representing the local cache hierarchy, which is ordered by level
- * (e.g. L1d -> L1i -> L2 -> L3).
- */
-struct cache {
-	struct device_node *ofnode;    /* OF node for this cache, may be cpu */
-	struct cpumask shared_cpu_map; /* online CPUs using this cache */
-	int type;                      /* split cache disambiguation */
-	int level;                     /* level not explicit in device tree */
-	struct list_head list;         /* global list of cache objects */
-	struct cache *next_local;      /* next cache of >= level */
-};
-
-static DEFINE_PER_CPU(struct cache_dir *, cache_dir_pcpu);
-
-/* traversal/modification of this list occurs only at cpu hotplug time;
- * access is serialized by cpu hotplug locking
- */
-static LIST_HEAD(cache_list);
-
-static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *k)
-{
-	return container_of(k, struct cache_index_dir, kobj);
-}
-
-static const char *cache_type_string(const struct cache *cache)
+static inline int get_cacheinfo_idx(enum cache_type type)
 {
-	return cache_type_info[cache->type].name;
-}
-
-static void cache_init(struct cache *cache, int type, int level,
-		       struct device_node *ofnode)
-{
-	cache->type = type;
-	cache->level = level;
-	cache->ofnode = of_node_get(ofnode);
-	INIT_LIST_HEAD(&cache->list);
-	list_add(&cache->list, &cache_list);
-}
-
-static struct cache *new_cache(int type, int level, struct device_node *ofnode)
-{
-	struct cache *cache;
-
-	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
-	if (cache)
-		cache_init(cache, type, level, ofnode);
-
-	return cache;
-}
-
-static void release_cache_debugcheck(struct cache *cache)
-{
-	struct cache *iter;
-
-	list_for_each_entry(iter, &cache_list, list)
-		WARN_ONCE(iter->next_local == cache,
-			  "cache for %s(%s) refers to cache for %s(%s)\n",
-			  iter->ofnode->full_name,
-			  cache_type_string(iter),
-			  cache->ofnode->full_name,
-			  cache_type_string(cache));
-}
-
-static void release_cache(struct cache *cache)
-{
-	if (!cache)
-		return;
-
-	pr_debug("freeing L%d %s cache for %s\n", cache->level,
-		 cache_type_string(cache), cache->ofnode->full_name);
-
-	release_cache_debugcheck(cache);
-	list_del(&cache->list);
-	of_node_put(cache->ofnode);
-	kfree(cache);
-}
-
-static void cache_cpu_set(struct cache *cache, int cpu)
-{
-	struct cache *next = cache;
-
-	while (next) {
-		WARN_ONCE(cpumask_test_cpu(cpu, &next->shared_cpu_map),
-			  "CPU %i already accounted in %s(%s)\n",
-			  cpu, next->ofnode->full_name,
-			  cache_type_string(next));
-		cpumask_set_cpu(cpu, &next->shared_cpu_map);
-		next = next->next_local;
-	}
+	if (type == CACHE_TYPE_UNIFIED)
+		return 0;
+	else
+		return type;
 }
 
-static int cache_size(const struct cache *cache, unsigned int *ret)
+static int cache_size(struct cache_info *this_leaf)
 {
 	const char *propname;
 	const __be32 *cache_size;
+	int ct_idx;
 
-	propname = cache_type_info[cache->type].size_prop;
-
-	cache_size = of_get_property(cache->ofnode, propname, NULL);
-	if (!cache_size)
-		return -ENODEV;
-
-	*ret = of_read_number(cache_size, 1);
-	return 0;
-}
-
-static int cache_size_kb(const struct cache *cache, unsigned int *ret)
-{
-	unsigned int size;
+	ct_idx = get_cacheinfo_idx(this_leaf->type);
+	propname = cache_type_info[ct_idx].size_prop;
 
-	if (cache_size(cache, &size))
+	cache_size = of_get_property(this_leaf->of_node, propname, NULL);
+	if (!cache_size) {
+		this_leaf->size = 0;
 		return -ENODEV;
-
-	*ret = size / 1024;
-	return 0;
+	} else {
+		this_leaf->size = of_read_number(cache_size, 1);
+		return 0;
+	}
 }
 
 /* not cache_line_size() because that's a macro in include/linux/cache.h */
-static int cache_get_line_size(const struct cache *cache, unsigned int *ret)
+static int cache_get_line_size(struct cache_info *this_leaf)
 {
 	const __be32 *line_size;
-	int i, lim;
+	int i, lim, ct_idx;
 
-	lim = ARRAY_SIZE(cache_type_info[cache->type].line_size_props);
+	ct_idx = get_cacheinfo_idx(this_leaf->type);
+	lim = ARRAY_SIZE(cache_type_info[ct_idx].line_size_props);
 
 	for (i = 0; i < lim; i++) {
 		const char *propname;
 
-		propname = cache_type_info[cache->type].line_size_props[i];
-		line_size = of_get_property(cache->ofnode, propname, NULL);
+		propname = cache_type_info[ct_idx].line_size_props[i];
+		line_size = of_get_property(this_leaf->of_node, propname, NULL);
 		if (line_size)
 			break;
 	}
 
-	if (!line_size)
+	if (!line_size) {
+		this_leaf->coherency_line_size = 0;
 		return -ENODEV;
-
-	*ret = of_read_number(line_size, 1);
-	return 0;
+	} else {
+		this_leaf->coherency_line_size = of_read_number(line_size, 1);
+		return 0;
+	}
 }
 
-static int cache_nr_sets(const struct cache *cache, unsigned int *ret)
+static int cache_nr_sets(struct cache_info *this_leaf)
 {
 	const char *propname;
 	const __be32 *nr_sets;
+	int ct_idx;
 
-	propname = cache_type_info[cache->type].nr_sets_prop;
+	ct_idx = get_cacheinfo_idx(this_leaf->type);
+	propname = cache_type_info[ct_idx].nr_sets_prop;
 
-	nr_sets = of_get_property(cache->ofnode, propname, NULL);
-	if (!nr_sets)
+	nr_sets = of_get_property(this_leaf->of_node, propname, NULL);
+	if (!nr_sets) {
+		this_leaf->number_of_sets = 0;
 		return -ENODEV;
-
-	*ret = of_read_number(nr_sets, 1);
-	return 0;
+	} else {
+		this_leaf->number_of_sets = of_read_number(nr_sets, 1);
+		return 0;
+	}
 }
 
-static int cache_associativity(const struct cache *cache, unsigned int *ret)
+static int cache_associativity(struct cache_info *this_leaf)
 {
-	unsigned int line_size;
-	unsigned int nr_sets;
-	unsigned int size;
-
-	if (cache_nr_sets(cache, &nr_sets))
-		goto err;
+	unsigned int line_size = this_leaf->coherency_line_size;
+	unsigned int nr_sets = this_leaf->number_of_sets;
+	unsigned int size = this_leaf->size;
 
 	/* If the cache is fully associative, there is no need to
 	 * check the other properties.
 	 */
 	if (nr_sets == 1) {
-		*ret = 0;
+		this_leaf->ways_of_associativity = 0;
 		return 0;
 	}
 
-	if (cache_get_line_size(cache, &line_size))
-		goto err;
-	if (cache_size(cache, &size))
-		goto err;
-
-	if (!(nr_sets > 0 && size > 0 && line_size > 0))
-		goto err;
-
-	*ret = (size / nr_sets) / line_size;
-	return 0;
-err:
-	return -ENODEV;
-}
-
-/* helper for dealing with split caches */
-static struct cache *cache_find_first_sibling(struct cache *cache)
-{
-	struct cache *iter;
-
-	if (cache->type == CACHE_TYPE_UNIFIED)
-		return cache;
-
-	list_for_each_entry(iter, &cache_list, list)
-		if (iter->ofnode == cache->ofnode && iter->next_local == cache)
-			return iter;
-
-	return cache;
-}
-
-/* return the first cache on a local list matching node */
-static struct cache *cache_lookup_by_node(const struct device_node *node)
-{
-	struct cache *cache = NULL;
-	struct cache *iter;
-
-	list_for_each_entry(iter, &cache_list, list) {
-		if (iter->ofnode != node)
-			continue;
-		cache = cache_find_first_sibling(iter);
-		break;
+	if (!(nr_sets > 0 && size > 0 && line_size > 0)) {
+		this_leaf->ways_of_associativity = 0;
+		return -ENODEV;
+	} else {
+		this_leaf->ways_of_associativity = (size / nr_sets) / line_size;
+		return 0;
 	}
-
-	return cache;
 }
 
 static bool cache_node_is_unified(const struct device_node *np)
@@ -324,523 +160,74 @@ static bool cache_node_is_unified(const struct device_node *np)
 	return of_get_property(np, "cache-unified", NULL);
 }
 
-static struct cache *cache_do_one_devnode_unified(struct device_node *node,
-						  int level)
-{
-	struct cache *cache;
-
-	pr_debug("creating L%d ucache for %s\n", level, node->full_name);
-
-	cache = new_cache(CACHE_TYPE_UNIFIED, level, node);
-
-	return cache;
-}
-
-static struct cache *cache_do_one_devnode_split(struct device_node *node,
-						int level)
-{
-	struct cache *dcache, *icache;
-
-	pr_debug("creating L%d dcache and icache for %s\n", level,
-		 node->full_name);
-
-	dcache = new_cache(CACHE_TYPE_DATA, level, node);
-	icache = new_cache(CACHE_TYPE_INSTRUCTION, level, node);
-
-	if (!dcache || !icache)
-		goto err;
-
-	dcache->next_local = icache;
-
-	return dcache;
-err:
-	release_cache(dcache);
-	release_cache(icache);
-	return NULL;
-}
-
-static struct cache *cache_do_one_devnode(struct device_node *node, int level)
-{
-	struct cache *cache;
-
-	if (cache_node_is_unified(node))
-		cache = cache_do_one_devnode_unified(node, level);
-	else
-		cache = cache_do_one_devnode_split(node, level);
-
-	return cache;
-}
-
-static struct cache *cache_lookup_or_instantiate(struct device_node *node,
-						 int level)
-{
-	struct cache *cache;
-
-	cache = cache_lookup_by_node(node);
-
-	WARN_ONCE(cache && cache->level != level,
-		  "cache level mismatch on lookup (got %d, expected %d)\n",
-		  cache->level, level);
-
-	if (!cache)
-		cache = cache_do_one_devnode(node, level);
-
-	return cache;
-}
-
-static void link_cache_lists(struct cache *smaller, struct cache *bigger)
-{
-	while (smaller->next_local) {
-		if (smaller->next_local == bigger)
-			return; /* already linked */
-		smaller = smaller->next_local;
-	}
-
-	smaller->next_local = bigger;
-}
-
-static void do_subsidiary_caches_debugcheck(struct cache *cache)
-{
-	WARN_ON_ONCE(cache->level != 1);
-	WARN_ON_ONCE(strcmp(cache->ofnode->type, "cpu"));
-}
-
-static void do_subsidiary_caches(struct cache *cache)
-{
-	struct device_node *subcache_node;
-	int level = cache->level;
-
-	do_subsidiary_caches_debugcheck(cache);
-
-	while ((subcache_node = of_find_next_cache_node(cache->ofnode))) {
-		struct cache *subcache;
-
-		level++;
-		subcache = cache_lookup_or_instantiate(subcache_node, level);
-		of_node_put(subcache_node);
-		if (!subcache)
-			break;
-
-		link_cache_lists(cache, subcache);
-		cache = subcache;
-	}
-}
-
-static struct cache *cache_chain_instantiate(unsigned int cpu_id)
-{
-	struct device_node *cpu_node;
-	struct cache *cpu_cache = NULL;
-
-	pr_debug("creating cache object(s) for CPU %i\n", cpu_id);
-
-	cpu_node = of_get_cpu_node(cpu_id, NULL);
-	WARN_ONCE(!cpu_node, "no OF node found for CPU %i\n", cpu_id);
-	if (!cpu_node)
-		goto out;
-
-	cpu_cache = cache_lookup_or_instantiate(cpu_node, 1);
-	if (!cpu_cache)
-		goto out;
-
-	do_subsidiary_caches(cpu_cache);
-
-	cache_cpu_set(cpu_cache, cpu_id);
-out:
-	of_node_put(cpu_node);
-
-	return cpu_cache;
-}
-
-static struct cache_dir *cacheinfo_create_cache_dir(unsigned int cpu_id)
-{
-	struct cache_dir *cache_dir;
-	struct device *dev;
-	struct kobject *kobj = NULL;
-
-	dev = get_cpu_device(cpu_id);
-	WARN_ONCE(!dev, "no dev for CPU %i\n", cpu_id);
-	if (!dev)
-		goto err;
-
-	kobj = kobject_create_and_add("cache", &dev->kobj);
-	if (!kobj)
-		goto err;
-
-	cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL);
-	if (!cache_dir)
-		goto err;
-
-	cache_dir->kobj = kobj;
-
-	WARN_ON_ONCE(per_cpu(cache_dir_pcpu, cpu_id) != NULL);
-
-	per_cpu(cache_dir_pcpu, cpu_id) = cache_dir;
-
-	return cache_dir;
-err:
-	kobject_put(kobj);
-	return NULL;
-}
-
-static void cache_index_release(struct kobject *kobj)
-{
-	struct cache_index_dir *index;
-
-	index = kobj_to_cache_index_dir(kobj);
-
-	pr_debug("freeing index directory for L%d %s cache\n",
-		 index->cache->level, cache_type_string(index->cache));
-
-	kfree(index);
-}
-
-static ssize_t cache_index_show(struct kobject *k, struct attribute *attr, char *buf)
+static void ci_leaf_init(struct cache_info *this_leaf,
+				enum cache_type type, unsigned int level)
 {
-	struct kobj_attribute *kobj_attr;
-
-	kobj_attr = container_of(attr, struct kobj_attribute, attr);
-
-	return kobj_attr->show(k, kobj_attr, buf);
-}
-
-static struct cache *index_kobj_to_cache(struct kobject *k)
-{
-	struct cache_index_dir *index;
-
-	index = kobj_to_cache_index_dir(k);
-
-	return index->cache;
+	this_leaf->level = level;
+	this_leaf->type = type;
+	cache_size(this_leaf);
+	cache_get_line_size(this_leaf);
+	cache_nr_sets(this_leaf);
+	cache_associativity(this_leaf);
 }
 
-static ssize_t size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+int init_cache_level(unsigned int cpu)
 {
-	unsigned int size_kb;
-	struct cache *cache;
+	struct device_node *np;
+	struct device *cpu_dev = get_cpu_device(cpu);
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	unsigned int level = 0, leaves = 0;
 
-	cache = index_kobj_to_cache(k);
-
-	if (cache_size_kb(cache, &size_kb))
+	if (!cpu_dev) {
+		pr_err("No cpu device for CPU %d\n", cpu);
 		return -ENODEV;
-
-	return sprintf(buf, "%uK\n", size_kb);
-}
-
-static struct kobj_attribute cache_size_attr =
-	__ATTR(size, 0444, size_show, NULL);
-
-
-static ssize_t line_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
-{
-	unsigned int line_size;
-	struct cache *cache;
-
-	cache = index_kobj_to_cache(k);
-
-	if (cache_get_line_size(cache, &line_size))
-		return -ENODEV;
-
-	return sprintf(buf, "%u\n", line_size);
-}
-
-static struct kobj_attribute cache_line_size_attr =
-	__ATTR(coherency_line_size, 0444, line_size_show, NULL);
-
-static ssize_t nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
-{
-	unsigned int nr_sets;
-	struct cache *cache;
-
-	cache = index_kobj_to_cache(k);
-
-	if (cache_nr_sets(cache, &nr_sets))
-		return -ENODEV;
-
-	return sprintf(buf, "%u\n", nr_sets);
-}
-
-static struct kobj_attribute cache_nr_sets_attr =
-	__ATTR(number_of_sets, 0444, nr_sets_show, NULL);
-
-static ssize_t associativity_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
-{
-	unsigned int associativity;
-	struct cache *cache;
-
-	cache = index_kobj_to_cache(k);
-
-	if (cache_associativity(cache, &associativity))
-		return -ENODEV;
-
-	return sprintf(buf, "%u\n", associativity);
-}
-
-static struct kobj_attribute cache_assoc_attr =
-	__ATTR(ways_of_associativity, 0444, associativity_show, NULL);
-
-static ssize_t type_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
-{
-	struct cache *cache;
-
-	cache = index_kobj_to_cache(k);
-
-	return sprintf(buf, "%s\n", cache_type_string(cache));
-}
-
-static struct kobj_attribute cache_type_attr =
-	__ATTR(type, 0444, type_show, NULL);
-
-static ssize_t level_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
-{
-	struct cache_index_dir *index;
-	struct cache *cache;
-
-	index = kobj_to_cache_index_dir(k);
-	cache = index->cache;
-
-	return sprintf(buf, "%d\n", cache->level);
-}
-
-static struct kobj_attribute cache_level_attr =
-	__ATTR(level, 0444, level_show, NULL);
-
-static ssize_t shared_cpu_map_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
-{
-	struct cache_index_dir *index;
-	struct cache *cache;
-	int len;
-	int n = 0;
-
-	index = kobj_to_cache_index_dir(k);
-	cache = index->cache;
-	len = PAGE_SIZE - 2;
-
-	if (len > 1) {
-		n = cpumask_scnprintf(buf, len, &cache->shared_cpu_map);
-		buf[n++] = '\n';
-		buf[n] = '\0';
 	}
-	return n;
-}
-
-static struct kobj_attribute cache_shared_cpu_map_attr =
-	__ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL);
-
-/* Attributes which should always be created -- the kobject/sysfs core
- * does this automatically via kobj_type->default_attrs.  This is the
- * minimum data required to uniquely identify a cache.
- */
-static struct attribute *cache_index_default_attrs[] = {
-	&cache_type_attr.attr,
-	&cache_level_attr.attr,
-	&cache_shared_cpu_map_attr.attr,
-	NULL,
-};
-
-/* Attributes which should be created if the cache device node has the
- * right properties -- see cacheinfo_create_index_opt_attrs
- */
-static struct kobj_attribute *cache_index_opt_attrs[] = {
-	&cache_size_attr,
-	&cache_line_size_attr,
-	&cache_nr_sets_attr,
-	&cache_assoc_attr,
-};
-
-static const struct sysfs_ops cache_index_ops = {
-	.show = cache_index_show,
-};
-
-static struct kobj_type cache_index_type = {
-	.release = cache_index_release,
-	.sysfs_ops = &cache_index_ops,
-	.default_attrs = cache_index_default_attrs,
-};
-
-static void cacheinfo_create_index_opt_attrs(struct cache_index_dir *dir)
-{
-	const char *cache_name;
-	const char *cache_type;
-	struct cache *cache;
-	char *buf;
-	int i;
-
-	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!buf)
-		return;
-
-	cache = dir->cache;
-	cache_name = cache->ofnode->full_name;
-	cache_type = cache_type_string(cache);
-
-	/* We don't want to create an attribute that can't provide a
-	 * meaningful value.  Check the return value of each optional
-	 * attribute's ->show method before registering the
-	 * attribute.
-	 */
-	for (i = 0; i < ARRAY_SIZE(cache_index_opt_attrs); i++) {
-		struct kobj_attribute *attr;
-		ssize_t rc;
-
-		attr = cache_index_opt_attrs[i];
-
-		rc = attr->show(&dir->kobj, attr, buf);
-		if (rc <= 0) {
-			pr_debug("not creating %s attribute for "
-				 "%s(%s) (rc = %zd)\n",
-				 attr->attr.name, cache_name,
-				 cache_type, rc);
-			continue;
-		}
-		if (sysfs_create_file(&dir->kobj, &attr->attr))
-			pr_debug("could not create %s attribute for %s(%s)\n",
-				 attr->attr.name, cache_name, cache_type);
+	np = cpu_dev->of_node;
+	if (!np) {
+		pr_err("Failed to find cpu%d device node\n", cpu);
+		return -ENOENT;
 	}
 
-	kfree(buf);
-}
-
-static void cacheinfo_create_index_dir(struct cache *cache, int index,
-				       struct cache_dir *cache_dir)
-{
-	struct cache_index_dir *index_dir;
-	int rc;
-
-	index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL);
-	if (!index_dir)
-		goto err;
-
-	index_dir->cache = cache;
-
-	rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type,
-				  cache_dir->kobj, "index%d", index);
-	if (rc)
-		goto err;
-
-	index_dir->next = cache_dir->index;
-	cache_dir->index = index_dir;
-
-	cacheinfo_create_index_opt_attrs(index_dir);
-
-	return;
-err:
-	kfree(index_dir);
-}
-
-static void cacheinfo_sysfs_populate(unsigned int cpu_id,
-				     struct cache *cache_list)
-{
-	struct cache_dir *cache_dir;
-	struct cache *cache;
-	int index = 0;
-
-	cache_dir = cacheinfo_create_cache_dir(cpu_id);
-	if (!cache_dir)
-		return;
-
-	cache = cache_list;
-	while (cache) {
-		cacheinfo_create_index_dir(cache, index, cache_dir);
-		index++;
-		cache = cache->next_local;
+	while (np) {
+		leaves += cache_node_is_unified(np) ? 1 : 2;
+		level++;
+		of_node_put(np);
+		np = of_find_next_cache_node(np);
 	}
-}
-
-void cacheinfo_cpu_online(unsigned int cpu_id)
-{
-	struct cache *cache;
-
-	cache = cache_chain_instantiate(cpu_id);
-	if (!cache)
-		return;
-
-	cacheinfo_sysfs_populate(cpu_id, cache);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU /* functions needed for cpu offline */
-
-static struct cache *cache_lookup_by_cpu(unsigned int cpu_id)
-{
-	struct device_node *cpu_node;
-	struct cache *cache;
-
-	cpu_node = of_get_cpu_node(cpu_id, NULL);
-	WARN_ONCE(!cpu_node, "no OF node found for CPU %i\n", cpu_id);
-	if (!cpu_node)
-		return NULL;
-
-	cache = cache_lookup_by_node(cpu_node);
-	of_node_put(cpu_node);
+	this_cpu_ci->num_levels = level;
+	this_cpu_ci->num_leaves = leaves;
 
-	return cache;
+	return 0;
 }
 
-static void remove_index_dirs(struct cache_dir *cache_dir)
+int populate_cache_leaves(unsigned int cpu)
 {
-	struct cache_index_dir *index;
-
-	index = cache_dir->index;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
+	struct device *cpu_dev = get_cpu_device(cpu);
+	struct device_node *np;
+	unsigned int level, idx;
 
-	while (index) {
-		struct cache_index_dir *next;
-
-		next = index->next;
-		kobject_put(&index->kobj);
-		index = next;
+	np = of_node_get(cpu_dev->of_node);
+	if (!np) {
+		pr_err("Failed to find cpu%d device node\n", cpu);
+		return -ENOENT;
 	}
-}
-
-static void remove_cache_dir(struct cache_dir *cache_dir)
-{
-	remove_index_dirs(cache_dir);
 
-	/* Remove cache dir from sysfs */
-	kobject_del(cache_dir->kobj);
-
-	kobject_put(cache_dir->kobj);
-
-	kfree(cache_dir);
-}
-
-static void cache_cpu_clear(struct cache *cache, int cpu)
-{
-	while (cache) {
-		struct cache *next = cache->next_local;
-
-		WARN_ONCE(!cpumask_test_cpu(cpu, &cache->shared_cpu_map),
-			  "CPU %i not accounted in %s(%s)\n",
-			  cpu, cache->ofnode->full_name,
-			  cache_type_string(cache));
-
-		cpumask_clear_cpu(cpu, &cache->shared_cpu_map);
-
-		/* Release the cache object if all the cpus using it
-		 * are offline */
-		if (cpumask_empty(&cache->shared_cpu_map))
-			release_cache(cache);
-
-		cache = next;
+	for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
+			idx < this_cpu_ci->num_leaves; idx++, level++) {
+		if (!this_leaf)
+			return -EINVAL;
+
+		this_leaf->of_node = np;
+		if (cache_node_is_unified(np)) {
+			ci_leaf_init(this_leaf++, CACHE_TYPE_UNIFIED, level);
+		} else {
+			ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
+			ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
+		}
+		np = of_find_next_cache_node(np);
 	}
+	return 0;
 }
 
-void cacheinfo_cpu_offline(unsigned int cpu_id)
-{
-	struct cache_dir *cache_dir;
-	struct cache *cache;
-
-	/* Prevent userspace from seeing inconsistent state - remove
-	 * the sysfs hierarchy first */
-	cache_dir = per_cpu(cache_dir_pcpu, cpu_id);
-
-	/* careful, sysfs population may have failed */
-	if (cache_dir)
-		remove_cache_dir(cache_dir);
-
-	per_cpu(cache_dir_pcpu, cpu_id) = NULL;
-
-	/* clear the CPU's bit in its cache chain, possibly freeing
-	 * cache objects */
-	cache = cache_lookup_by_cpu(cpu_id);
-	if (cache)
-		cache_cpu_clear(cache, cpu_id);
-}
-#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/powerpc/kernel/cacheinfo.h b/arch/powerpc/kernel/cacheinfo.h
deleted file mode 100644
index a7b74d3..0000000
--- a/arch/powerpc/kernel/cacheinfo.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _PPC_CACHEINFO_H
-#define _PPC_CACHEINFO_H
-
-/* These are just hooks for sysfs.c to use. */
-extern void cacheinfo_cpu_online(unsigned int cpu_id);
-extern void cacheinfo_cpu_offline(unsigned int cpu_id);
-
-#endif /* _PPC_CACHEINFO_H */
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 97e1dc9..2bc61d3 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -19,8 +19,6 @@
 #include <asm/pmc.h>
 #include <asm/firmware.h>
 
-#include "cacheinfo.h"
-
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #include <asm/lppaca.h>
@@ -730,7 +728,6 @@ static void register_cpu_online(unsigned int cpu)
 		device_create_file(s, &dev_attr_altivec_idle_wait_time);
 	}
 #endif
-	cacheinfo_cpu_online(cpu);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -811,7 +808,6 @@ static void unregister_cpu_online(unsigned int cpu)
 		device_remove_file(s, &dev_attr_altivec_idle_wait_time);
 	}
 #endif
-	cacheinfo_cpu_offline(cpu);
 }
 
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 7/9] ARM64: kernel: add support for cpu cache information
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
                   ` (5 preceding siblings ...)
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 6/9] powerpc: " Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 8/9] ARM: " Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 9/9] ARM: kernel: add outer cache support for cacheinfo implementation Sudeep Holla
  8 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: sudeep.holla, Catalin Marinas, Will Deacon, Lorenzo Pieralisi,
	linux-arm-kernel

From: Sudeep Holla <sudeep.holla@arm.com>

This patch adds support for cacheinfo on ARM64.

On ARMv8, the cache hierarchy can be identified through Cache Level ID
(CLIDR) register while the cache geometry is provided by Cache Size ID
(CCSIDR) register.

Since the architecture doesn't provide any way of detecting the cpus
sharing particular cache, device tree is used for the same purpose.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
---
 arch/arm64/kernel/Makefile    |   2 +-
 arch/arm64/kernel/cacheinfo.c | 134 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/kernel/cacheinfo.c

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2d4554b..7d94a51 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -9,7 +9,7 @@ AFLAGS_head.o		:= -DTEXT_OFFSET=$(TEXT_OFFSET)
 arm64-obj-y		:= cputable.o debug-monitors.o entry.o irq.o fpsimd.o	\
 			   entry-fpsimd.o process.o ptrace.o setup.o signal.o	\
 			   sys.o stacktrace.o time.o traps.o io.o vdso.o	\
-			   hyp-stub.o psci.o cpu_ops.o insn.o
+			   hyp-stub.o psci.o cpu_ops.o insn.o cacheinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
 					   sys_compat.o
diff --git a/arch/arm64/kernel/cacheinfo.c b/arch/arm64/kernel/cacheinfo.c
new file mode 100644
index 0000000..5d8b840
--- /dev/null
+++ b/arch/arm64/kernel/cacheinfo.c
@@ -0,0 +1,134 @@
+/*
+ *  ARM64 cacheinfo support
+ *
+ *  Copyright (C) 2014 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpu.h>
+#include <linux/compiler.h>
+#include <linux/of.h>
+
+#include <asm/processor.h>
+
+#define MAX_CACHE_LEVEL			7	/* Max 7 level supported */
+/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
+#define CLIDR_CTYPE_SHIFT(level)	(3 * (level - 1))
+#define CLIDR_CTYPE_MASK(level)		(7 << CLIDR_CTYPE_SHIFT(level))
+#define CLIDR_CTYPE(clidr, level)	\
+	(((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
+
+static inline enum cache_type get_cache_type(int level)
+{
+	unsigned int clidr;
+	if (level > MAX_CACHE_LEVEL)
+		return CACHE_TYPE_NOCACHE;
+	asm volatile ("mrs     %0, clidr_el1" : "=r" (clidr));
+	return CLIDR_CTYPE(clidr, level);
+}
+
+/*
+ * NumSets, bits[27:13] - (Number of sets in cache) - 1
+ * Associativity, bits[12:3] - (Associativity of cache) - 1
+ * LineSize, bits[2:0] - (Log2(Number of words in cache line)) - 2
+ */
+#define CCSIDR_WRITE_THROUGH	BIT(31)
+#define CCSIDR_WRITE_BACK	BIT(30)
+#define CCSIDR_READ_ALLOCATE	BIT(29)
+#define CCSIDR_WRITE_ALLOCATE	BIT(28)
+#define CCSIDR_LINESIZE_MASK	0x7
+#define CCSIDR_ASSOCIAT_SHIFT	3
+#define CCSIDR_ASSOCIAT_MASK	0x3FF
+#define CCSIDR_NUMSETS_SHIFT	13
+#define CCSIDR_NUMSETS_MASK	0x7FF
+
+/*
+ * Which cache CCSIDR represents depends on CSSELR value
+ * Make sure no one else changes CSSELR during this
+ * smp_call_function_single prevents preemption for us
+ */
+static inline u32 get_ccsidr(u32 csselr)
+{
+	u32 ccsidr;
+
+	/* Put value into CSSELR */
+	asm volatile("msr csselr_el1, %x0" : : "r" (csselr));
+	isb();
+	/* Read result out of CCSIDR */
+	asm volatile("mrs %0, ccsidr_el1" : "=r" (ccsidr));
+
+	return ccsidr;
+}
+
+static void ci_leaf_init(struct cache_info *this_leaf,
+			 enum cache_type type, unsigned int level)
+{
+	bool is_instr_cache = type & CACHE_TYPE_INST;
+	u32 tmp = get_ccsidr((level - 1) << 1 | is_instr_cache);
+
+	this_leaf->level = level;
+	this_leaf->type = type;
+	this_leaf->coherency_line_size =
+	    (1 << ((tmp & CCSIDR_LINESIZE_MASK) + 2)) * 4;
+	this_leaf->number_of_sets =
+	    ((tmp >> CCSIDR_NUMSETS_SHIFT) & CCSIDR_NUMSETS_MASK) + 1;
+	this_leaf->ways_of_associativity =
+	    ((tmp >> CCSIDR_ASSOCIAT_SHIFT) & CCSIDR_ASSOCIAT_MASK) + 1;
+	this_leaf->size = this_leaf->number_of_sets *
+	    this_leaf->coherency_line_size * this_leaf->ways_of_associativity;
+	this_leaf->attributes =
+		((tmp & CCSIDR_WRITE_THROUGH) ? CACHE_WRITE_THROUGH : 0) |
+		((tmp & CCSIDR_WRITE_BACK) ? CACHE_WRITE_BACK : 0) |
+		((tmp & CCSIDR_READ_ALLOCATE) ? CACHE_READ_ALLOCATE : 0) |
+		((tmp & CCSIDR_WRITE_ALLOCATE) ? CACHE_WRITE_ALLOCATE : 0);
+}
+
+int init_cache_level(unsigned int cpu)
+{
+	unsigned int ctype, level = 1, leaves = 0;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+
+	if (!this_cpu_ci)
+		return -EINVAL;
+
+	do {
+		ctype = get_cache_type(level);
+		if (ctype == CACHE_TYPE_NOCACHE)
+			break;
+		/* Separate instruction and data caches */
+		leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
+	} while (++level <= MAX_CACHE_LEVEL);
+
+	this_cpu_ci->num_levels = level - 1;
+	this_cpu_ci->num_leaves = leaves;
+	return 0;
+}
+
+int populate_cache_leaves(unsigned int cpu)
+{
+	unsigned int level, idx;
+	enum cache_type type;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
+
+	for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
+			idx < this_cpu_ci->num_leaves; idx++, level++) {
+		if (!this_leaf)
+			return -EINVAL;
+
+		type = get_cache_type(level);
+		if (type == CACHE_TYPE_SEPARATE) {
+			ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
+			ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
+		} else {
+			ci_leaf_init(this_leaf++, type, level);
+		}
+	}
+	return 0;
+}
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 8/9] ARM: kernel: add support for cpu cache information
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
                   ` (6 preceding siblings ...)
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 7/9] ARM64: kernel: add support for cpu cache information Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 9/9] ARM: kernel: add outer cache support for cacheinfo implementation Sudeep Holla
  8 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: sudeep.holla, Russell King, Will Deacon, Nicolas Pitre,
	Lorenzo Pieralisi, linux-arm-kernel

From: Sudeep Holla <sudeep.holla@arm.com>

This patch adds support for cacheinfo on ARM platforms.

On ARMv7, the cache hierarchy can be identified through Cache Level ID
register(CLIDR) while the cache geometry is provided by Cache Size ID
register(CCSIDR).

On architecture versions before ARMv7, CLIDR and CCSIDR is not
implemented. The cache type register(CTR) provides both cache hierarchy
and geometry if implemented. For implementations that doesn't support
CTR, we need to list the probable value of CTR if it was implemented
along with the cpuid for the sake of simplicity to handle them.

Since the architecture doesn't provide any way of detecting the cpus
sharing particular cache, device tree is used fo the same purpose.
On non-DT platforms, first level caches are per-cpu while higher level
caches are assumed system-wide.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
---
 arch/arm/kernel/Makefile    |   1 +
 arch/arm/kernel/cacheinfo.c | 228 ++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/Kconfig         |  13 +++
 3 files changed, 242 insertions(+)
 create mode 100644 arch/arm/kernel/cacheinfo.c

diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a30fc9b..f86a4ff 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -29,6 +29,7 @@ obj-y		+= entry-v7m.o v7m.o
 else
 obj-y		+= entry-armv.o
 endif
+obj-$(CONFIG_CPU_HAS_CACHE) += cacheinfo.o
 
 obj-$(CONFIG_OC_ETM)		+= etm.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
new file mode 100644
index 0000000..10045b7
--- /dev/null
+++ b/arch/arm/kernel/cacheinfo.c
@@ -0,0 +1,228 @@
+/*
+ *  ARM cacheinfo support
+ *
+ *  Copyright (C) 2014 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpu.h>
+#include <linux/compiler.h>
+#include <linux/of.h>
+
+#include <asm/cputype.h>
+#include <asm/processor.h>
+
+#if __LINUX_ARM_ARCH__ < 7 /* pre ARMv7 */
+
+#define MAX_CACHE_LEVEL		1	/* Only 1 level supported */
+#define CTR_CTYPE_SHIFT		24
+#define CTR_CTYPE_MASK		(1 << CTR_CTYPE_SHIFT)
+
+struct ctr_info {
+	unsigned int cpuid_id;
+	unsigned int ctr;
+};
+
+static struct ctr_info cache_ctr_list[] = {
+};
+
+static int get_unimplemented_ctr(unsigned int *ctr)
+{
+	int i, cpuid_id = read_cpuid_id();
+	for (i = 0; i < ARRAY_SIZE(cache_ctr_list); i++)
+		if (cache_ctr_list[i].cpuid_id == cpuid_id) {
+			*ctr = cache_ctr_list[i].ctr;
+			return 0;
+		}
+	return -ENOENT;
+}
+
+static unsigned int get_ctr(void)
+{
+	unsigned int ctr;
+	if (get_unimplemented_ctr(&ctr))
+		asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
+	return ctr;
+}
+
+static enum cache_type get_cache_type(int level)
+{
+	if (level > MAX_CACHE_LEVEL)
+		return CACHE_TYPE_NOCACHE;
+	return get_ctr() & CTR_CTYPE_MASK ?
+		CACHE_TYPE_SEPARATE : CACHE_TYPE_UNIFIED;
+}
+
+/*
+ *  +---------------------------------+
+ *  | 9  8  7  6 | 5  4  3 | 2 | 1  0 |
+ *  +---------------------------------+
+ *  |    size    |  assoc  | m |  len |
+ *  +---------------------------------+
+ * linelen        = 1 << (len + 3)
+ * multiplier     = 2 + m
+ * nsets          = 1 << (size + 6 - assoc - len)
+ * associativity  = multiplier << (assoc - 1)
+ * cache_size     = multiplier << (size + 8)
+ */
+#define CTR_LINESIZE_MASK	0x3
+#define CTR_MULTIPLIER_SHIFT	2
+#define CTR_MULTIPLIER_MASK	0x1
+#define CTR_ASSOCIAT_SHIFT	3
+#define CTR_ASSOCIAT_MASK	0x7
+#define CTR_SIZE_SHIFT		6
+#define CTR_SIZE_MASK		0xF
+#define CTR_DCACHE_SHIFT	12
+
+static void __ci_leaf_init(enum cache_type type,
+				  struct cache_info *this_leaf)
+{
+	unsigned int size, multiplier, assoc, len, tmp = get_ctr();
+
+	if (type == CACHE_TYPE_DATA)
+		tmp >>= CTR_DCACHE_SHIFT;
+
+	len = tmp & CTR_LINESIZE_MASK;
+	size = (tmp >> CTR_SIZE_SHIFT) & CTR_SIZE_MASK;
+	assoc = (tmp >> CTR_ASSOCIAT_SHIFT) & CTR_ASSOCIAT_MASK;
+	multiplier = ((tmp >> CTR_MULTIPLIER_SHIFT) & CTR_MULTIPLIER_MASK) + 2;
+
+	this_leaf->type = type;
+	this_leaf->coherency_line_size = 1 << (len + 3);
+	this_leaf->number_of_sets = 1 << (size + 6 - assoc - len);
+	this_leaf->ways_of_associativity = multiplier << (assoc - 1);
+	this_leaf->size = multiplier << (size + 8);
+}
+
+#else /* ARMv7 */
+
+#define MAX_CACHE_LEVEL			7	/* Max 7 level supported */
+/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
+#define CLIDR_CTYPE_SHIFT(level)	(3 * (level - 1))
+#define CLIDR_CTYPE_MASK(level)		(7 << CLIDR_CTYPE_SHIFT(level))
+#define CLIDR_CTYPE(clidr, level)	\
+	(((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
+
+static inline enum cache_type get_cache_type(int level)
+{
+	unsigned int clidr;
+	if (level > MAX_CACHE_LEVEL)
+		return CACHE_TYPE_NOCACHE;
+	asm volatile ("mrc p15, 1, %0, c0, c0, 1" : "=r" (clidr));
+	return CLIDR_CTYPE(clidr, level);
+}
+
+/*
+ * NumSets, bits[27:13] - (Number of sets in cache) - 1
+ * Associativity, bits[12:3] - (Associativity of cache) - 1
+ * LineSize, bits[2:0] - (Log2(Number of words in cache line)) - 2
+ */
+#define CCSIDR_WRITE_THROUGH	BIT(31)
+#define CCSIDR_WRITE_BACK	BIT(30)
+#define CCSIDR_READ_ALLOCATE	BIT(29)
+#define CCSIDR_WRITE_ALLOCATE	BIT(28)
+#define CCSIDR_LINESIZE_MASK	0x7
+#define CCSIDR_ASSOCIAT_SHIFT	3
+#define CCSIDR_ASSOCIAT_MASK	0x3FF
+#define CCSIDR_NUMSETS_SHIFT	13
+#define CCSIDR_NUMSETS_MASK	0x7FF
+
+/*
+ * Which cache CCSIDR represents depends on CSSELR value
+ * Make sure no one else changes CSSELR during this
+ * smp_call_function_single prevents preemption for us
+ */
+static inline u32 get_ccsidr(u32 csselr)
+{
+	u32 ccsidr;
+
+	/* Put value into CSSELR */
+	asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr));
+	isb();
+	/* Read result out of CCSIDR */
+	asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
+
+	return ccsidr;
+}
+
+static void __ci_leaf_init(enum cache_type type,
+				  struct cache_info *this_leaf)
+{
+	bool is_instr_cache = type & CACHE_TYPE_INST;
+	u32 tmp = get_ccsidr((this_leaf->level - 1) << 1 | is_instr_cache);
+
+	this_leaf->type = type;
+	this_leaf->coherency_line_size =
+	    (1 << ((tmp & CCSIDR_LINESIZE_MASK) + 2)) * 4;
+	this_leaf->number_of_sets =
+	    ((tmp >> CCSIDR_NUMSETS_SHIFT) & CCSIDR_NUMSETS_MASK) + 1;
+	this_leaf->ways_of_associativity =
+	    ((tmp >> CCSIDR_ASSOCIAT_SHIFT) & CCSIDR_ASSOCIAT_MASK) + 1;
+	this_leaf->size = this_leaf->number_of_sets *
+	    this_leaf->coherency_line_size * this_leaf->ways_of_associativity;
+	this_leaf->attributes =
+		((tmp & CCSIDR_WRITE_THROUGH) ? CACHE_WRITE_THROUGH : 0) |
+		((tmp & CCSIDR_WRITE_BACK) ? CACHE_WRITE_BACK : 0) |
+		((tmp & CCSIDR_READ_ALLOCATE) ? CACHE_READ_ALLOCATE : 0) |
+		((tmp & CCSIDR_WRITE_ALLOCATE) ? CACHE_WRITE_ALLOCATE : 0);
+}
+
+#endif
+
+static void ci_leaf_init(struct cache_info *this_leaf,
+			 enum cache_type type, unsigned int level)
+{
+	this_leaf->level = level;
+	__ci_leaf_init(type, this_leaf);
+}
+
+int init_cache_level(unsigned int cpu)
+{
+	unsigned int ctype, level = 1, leaves = 0;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+
+	if (!this_cpu_ci)
+		return -EINVAL;
+
+	do {
+		ctype = get_cache_type(level);
+		if (ctype == CACHE_TYPE_NOCACHE)
+			break;
+		/* Separate instruction and data caches */
+		leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
+	} while (++level <= MAX_CACHE_LEVEL);
+
+	this_cpu_ci->num_levels = level - 1;
+	this_cpu_ci->num_leaves = leaves;
+
+	return 0;
+}
+
+int populate_cache_leaves(unsigned int cpu)
+{
+	unsigned int level, idx;
+	enum cache_type type;
+	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+	struct cache_info *this_leaf = this_cpu_ci->info_list;
+
+	for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
+			idx < this_cpu_ci->num_leaves; idx++, level++) {
+		if (!this_leaf)
+			return -EINVAL;
+
+		type = get_cache_type(level);
+		if (type == CACHE_TYPE_SEPARATE) {
+			ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
+			ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
+		} else {
+			ci_leaf_init(this_leaf++, type, level);
+		}
+	}
+	return 0;
+}
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 1f8fed9..c4abb89 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -495,30 +495,42 @@ config CPU_PABRT_V7
 # The cache model
 config CPU_CACHE_V4
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_V4WT
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_V4WB
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_V6
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_V7
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_NOP
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_VIVT
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_VIPT
 	bool
+	select CPU_HAS_CACHE
 
 config CPU_CACHE_FA
 	bool
+	select CPU_HAS_CACHE
+
+config CPU_HAS_CACHE
+	bool
 
 if MMU
 # The copy-page model
@@ -846,6 +858,7 @@ config DMA_CACHE_RWFO
 
 config OUTER_CACHE
 	bool
+	select CPU_HAS_CACHE
 
 config OUTER_CACHE_SYNC
 	bool
-- 
1.8.3.2


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

* [PATCH RFC/RFT v3 9/9] ARM: kernel: add outer cache support for cacheinfo implementation
  2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
                   ` (7 preceding siblings ...)
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 8/9] ARM: " Sudeep Holla
@ 2014-02-19 16:06 ` Sudeep Holla
  8 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-19 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: sudeep.holla, Russell King, Will Deacon, Lorenzo Pieralisi,
	linux-arm-kernel

From: Sudeep Holla <sudeep.holla@arm.com>

In order to support outer cache in the cacheinfo infrastructure, a new
function 'get_info' is added to outer_cache_fns. This function is used
to get the outer cache information namely: line size, number of ways of
associativity and number of sets.

This patch adds 'get_info' supports to all L2 cache implementations on
ARM except Marvell's Feroceon L2 cache.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
---
 arch/arm/include/asm/outercache.h | 13 +++++++++++++
 arch/arm/kernel/cacheinfo.c       | 22 +++++++++++++++++++++-
 arch/arm/mm/cache-l2x0.c          | 14 ++++++++++++++
 arch/arm/mm/cache-tauros2.c       | 35 +++++++++++++++++++++++++++++++++++
 arch/arm/mm/cache-xsc3l2.c        | 15 +++++++++++++++
 5 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index f94784f..1471ff2 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -23,7 +23,14 @@
 
 #include <linux/types.h>
 
+struct outer_cache_info {
+	unsigned int num_ways;
+	unsigned int num_sets;
+	unsigned int line_size;
+};
+
 struct outer_cache_fns {
+	void (*get_info)(struct outer_cache_info *info);
 	void (*inv_range)(unsigned long, unsigned long);
 	void (*clean_range)(unsigned long, unsigned long);
 	void (*flush_range)(unsigned long, unsigned long);
@@ -41,6 +48,11 @@ extern struct outer_cache_fns outer_cache;
 
 #ifdef CONFIG_OUTER_CACHE
 
+static inline void outer_get_info(struct outer_cache_info *info)
+{
+	if (outer_cache.get_info)
+		outer_cache.get_info(info);
+}
 static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
 {
 	if (outer_cache.inv_range)
@@ -83,6 +95,7 @@ static inline void outer_resume(void)
 
 #else
 
+static inline void outer_get_info(struct outer_cache_info *info) { }
 static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
 { }
 static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
index 10045b7..4463833 100644
--- a/arch/arm/kernel/cacheinfo.c
+++ b/arch/arm/kernel/cacheinfo.c
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 
 #include <asm/cputype.h>
+#include <asm/outercache.h>
 #include <asm/processor.h>
 
 #if __LINUX_ARM_ARCH__ < 7 /* pre ARMv7 */
@@ -175,11 +176,27 @@ static void __ci_leaf_init(enum cache_type type,
 
 #endif
 
+static void __outer_ci_leaf_init(struct cache_info *this_leaf)
+{
+	struct outer_cache_info info;
+
+	outer_get_info(&info);
+
+	this_leaf->type = CACHE_TYPE_UNIFIED;/* record it as Unified */
+	this_leaf->ways_of_associativity = info.num_ways;
+	this_leaf->number_of_sets = info.num_sets;
+	this_leaf->coherency_line_size = info.line_size;
+	this_leaf->size = info.num_ways * info.num_sets * info.line_size;
+}
+
 static void ci_leaf_init(struct cache_info *this_leaf,
 			 enum cache_type type, unsigned int level)
 {
 	this_leaf->level = level;
-	__ci_leaf_init(type, this_leaf);
+	if (type == CACHE_TYPE_NOCACHE)	/* must be outer cache */
+		__outer_ci_leaf_init(this_leaf);
+	else
+		__ci_leaf_init(type, this_leaf);
 }
 
 int init_cache_level(unsigned int cpu)
@@ -201,6 +218,9 @@ int init_cache_level(unsigned int cpu)
 	this_cpu_ci->num_levels = level - 1;
 	this_cpu_ci->num_leaves = leaves;
 
+	if (IS_ENABLED(CONFIG_OUTER_CACHE) && outer_cache.get_info)
+		this_cpu_ci->num_leaves++, this_cpu_ci->num_levels++;
+
 	return 0;
 }
 
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 7abde2ce..b850771 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -183,6 +183,15 @@ static void l2x0_inv_all(void)
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
+static void l2x0_getinfo(struct outer_cache_info *info)
+{
+	if (!info)
+		return;
+	info->num_ways = get_count_order(l2x0_way_mask);
+	info->line_size = CACHE_LINE_SIZE;
+	info->num_sets = l2x0_size / (info->num_ways * CACHE_LINE_SIZE);
+}
+
 static void l2x0_inv_range(unsigned long start, unsigned long end)
 {
 	void __iomem *base = l2x0_base;
@@ -416,6 +425,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		outer_cache.flush_all = l2x0_flush_all;
 		outer_cache.inv_all = l2x0_inv_all;
 		outer_cache.disable = l2x0_disable;
+		outer_cache.get_info = l2x0_getinfo;
 	}
 
 	pr_info("%s cache controller enabled\n", type);
@@ -886,6 +896,7 @@ static const struct l2x0_of_data pl310_data = {
 		.flush_all   = l2x0_flush_all,
 		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
+		.get_info    = l2x0_getinfo,
 	},
 };
 
@@ -901,6 +912,7 @@ static const struct l2x0_of_data l2x0_data = {
 		.flush_all   = l2x0_flush_all,
 		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
+		.get_info    = l2x0_getinfo,
 	},
 };
 
@@ -916,6 +928,7 @@ static const struct l2x0_of_data aurora_with_outer_data = {
 		.flush_all   = l2x0_flush_all,
 		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
+		.get_info    = l2x0_getinfo,
 	},
 };
 
@@ -948,6 +961,7 @@ static const struct l2x0_of_data bcm_l2x0_data = {
 		.flush_all   = l2x0_flush_all,
 		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
+		.get_info    = l2x0_getinfo,
 	},
 };
 
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
index 1be0f4e..3a43401 100644
--- a/arch/arm/mm/cache-tauros2.c
+++ b/arch/arm/mm/cache-tauros2.c
@@ -60,6 +60,7 @@ static inline void tauros2_inv_pa(unsigned long addr)
  * noninclusive.
  */
 #define CACHE_LINE_SIZE		32
+#define CACHE_LINE_SHIFT	5
 
 static void tauros2_inv_range(unsigned long start, unsigned long end)
 {
@@ -131,6 +132,38 @@ static void tauros2_resume(void)
 	"mcr	p15, 0, %0, c1, c0, 0 @Enable L2 Cache\n\t"
 	: : "r" (0x0));
 }
+
+/*
+ *  +----------------------------------------+
+ *  | 11 10 9  8 | 7  6  5  4  3 | 2 |  1  0 |
+ *  +----------------------------------------+
+ *  |  way size  | associativity | - |line_sz|
+ *  +----------------------------------------+
+ */
+#define L2CTR_ASSOCIAT_SHIFT	3
+#define L2CTR_ASSOCIAT_MASK	0x1F
+#define L2CTR_WAYSIZE_SHIFT	8
+#define L2CTR_WAYSIZE_MASK	0xF
+#define CACHE_WAY_PER_SET(l2ctr)	\
+	(((l2_ctr) >> L2CTR_ASSOCIAT_SHIFT) & L2CTR_ASSOCIAT_MASK)
+#define CACHE_WAY_SIZE(l2ctr)		\
+	(8192 << (((l2ctr) >> L2CTR_WAYSIZE_SHIFT) & L2CTR_WAYSIZE_MASK))
+#define CACHE_SET_SIZE(l2ctr)	(CACHE_WAY_SIZE(l2ctr) >> CACHE_LINE_SHIFT)
+
+static void tauros2_getinfo(struct outer_cache_info *info)
+{
+	unsigned int l2_ctr;
+
+	if (!info)
+		return;
+
+	__asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2_ctr));
+
+	info->line_size = CACHE_LINE_SIZE;
+	info->num_ways = CACHE_WAY_PER_SET(l2_ctr);
+	info->num_sets = CACHE_SET_SIZE(l2_ctr);
+}
+
 #endif
 
 static inline u32 __init read_extra_features(void)
@@ -226,6 +259,7 @@ static void __init tauros2_internal_init(unsigned int features)
 		outer_cache.flush_range = tauros2_flush_range;
 		outer_cache.disable = tauros2_disable;
 		outer_cache.resume = tauros2_resume;
+		outer_cache.get_info = tauros2_getinfo;
 	}
 #endif
 
@@ -253,6 +287,7 @@ static void __init tauros2_internal_init(unsigned int features)
 		outer_cache.flush_range = tauros2_flush_range;
 		outer_cache.disable = tauros2_disable;
 		outer_cache.resume = tauros2_resume;
+		outer_cache.get_info = tauros2_getinfo;
 	}
 #endif
 
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 6c3edeb..353c642 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -201,6 +201,20 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
 	dsb();
 }
 
+static void xsc3_l2_getinfo(struct outer_cache_info *info)
+{
+	unsigned long l2ctype;
+
+	if (!info)
+		return;
+
+	__asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
+
+	info->num_ways = CACHE_WAY_PER_SET;
+	info->line_size = CACHE_LINE_SIZE;
+	info->num_sets = CACHE_SET_SIZE(l2ctype);
+}
+
 static int __init xsc3_l2_init(void)
 {
 	if (!cpu_is_xsc3() || !xsc3_l2_present())
@@ -213,6 +227,7 @@ static int __init xsc3_l2_init(void)
 		outer_cache.inv_range = xsc3_l2_inv_range;
 		outer_cache.clean_range = xsc3_l2_clean_range;
 		outer_cache.flush_range = xsc3_l2_flush_range;
+		outer_cache.get_info    = xsc3_l2_getinfo;
 	}
 
 	return 0;
-- 
1.8.3.2


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

* Re: [PATCH RFC/RFT v3 4/9] s390: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 4/9] s390: " Sudeep Holla
@ 2014-02-20  8:38   ` Heiko Carstens
  2014-02-20 13:33     ` Sudeep Holla
  0 siblings, 1 reply; 23+ messages in thread
From: Heiko Carstens @ 2014-02-20  8:38 UTC (permalink / raw)
  To: Sudeep Holla; +Cc: linux-kernel, Martin Schwidefsky, linux390, linux-s390

On Wed, Feb 19, 2014 at 04:06:11PM +0000, Sudeep Holla wrote:
> From: Sudeep Holla <sudeep.holla@arm.com>
> 
> This patch removes the redundant sysfs cacheinfo code by making use of
> the newly introduced generic cacheinfo infrastructure.
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
> Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
> Cc: linux390@de.ibm.com
> Cc: linux-s390@vger.kernel.org
> ---
>  arch/s390/kernel/cache.c | 388 ++++++++++++-----------------------------------
>  1 file changed, 93 insertions(+), 295 deletions(-)

(FWIW, if you send an update of your series, please cc me on all patches, so I
 don't have to search LKML for the rest of the patch set)

I gave your patches series a test and I get this nice message on boot:

io scheduler cfq registered
DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags))
------------[ cut here ]------------
WARNING: at kernel/locking/lockdep.c:2742
Modules linked in:
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.14.0-rc3-00177-g468cee08c2ea #7
task: 0000000000adcc60 ti: 0000000000ac4000 task.ti: 0000000000ac4000
Krnl PSW : 0404c00180000000 000000000019af3e (lockdep_trace_alloc+0x116/0x120)
           R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 EA:3
Krnl GPRS: 0000000000000020 0000000000adcc60 000000000000002f 0000000000000000
           000000000019af3a 0000000000000000 0000000000000001 0000000000000000
           000000003ff26140 000000000055fb92 00000000000001b0 00000000000080d0
           0400000000000000 00000000000080d0 000000000019af3a 000000000001bc30
Krnl Code: 000000000019af2e: c020003b1e34       larl    %r2,8feb96
           000000000019af34: c0e5002e0304       brasl   %r14,75b53c
          #000000000019af3a: a7f40001           brc     15,19af3c
          >000000000019af3e: e32003100004       lg      %r2,784
           000000000019af44: a7f4ff9f           brc     15,19ae82
           000000000019af48: e31003100004       lg      %r1,784
           000000000019af4e: e32013f00150       sty     %r2,5104(%r1)
           000000000019af54: 07fe               bcr     15,%r14
Call Trace:
([<000000000019af3a>] lockdep_trace_alloc+0x112/0x120)
 [<000000000027a7d2>] __kmalloc+0x5a/0x204
 [<000000000055fb92>] detect_cache_attributes+0x66/0xd4
 [<000000000055fc2e>] _detect_cache_attributes+0x2e/0x3c
 [<00000000001ce7a2>] generic_smp_call_function_single_interrupt+0x9a/0xe8
 [<000000000010b462>] do_ext_interrupt+0x12a/0x24c
 [<00000000001afab0>] handle_irq_event_percpu+0x70/0x240
 [<00000000001b3218>] handle_percpu_irq+0x6c/0x98
 [<00000000001af16e>] generic_handle_irq+0x46/0x68
 [<000000000010b6c2>] do_IRQ+0x5e/0x84
 [<0000000000768b06>] ext_skip+0x44/0x4a
 [<000000000076827c>] vtime_stop_cpu+0x50/0xa4
([<0000000000768262>] vtime_stop_cpu+0x36/0xa4)
 [<0000000000103848>] arch_cpu_idle+0x6c/0xbc
 [<00000000001af032>] cpu_startup_entry+0x146/0x218
 [<0000000000b64932>] start_kernel+0x3fa/0x408
 [<0000000000100020>] _stext+0x20/0x80
INFO: lockdep is turned off.
Last Breaking-Event-Address:
 [<000000000019af3a>] lockdep_trace_alloc+0x112/0x120
---[ end trace 9c0011ccc7b324d6 ]---
brd: module loaded

In addition /proc/cpuinfo is now incorrect.
With your patches it looks like this:

[root@p2345007 ~]# cat /proc/cpuinfo 
vendor_id       : IBM/S390
# processors    : 4
bogomips per cpu: 18115.00
features        : esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs 
cache0          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
cache1          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
cache2          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
cache3          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
cache4          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
cache5          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
processor 0: version = FF,  identification = 2F6D15,  machine = 2827
processor 1: version = FF,  identification = 2F6D15,  machine = 2827
processor 2: version = FF,  identification = 2F6D15,  machine = 2827
processor 3: version = FF,  identification = 2F6D15,  machine = 2827

However it is supposed to look like this:

[root@p2345007 ~]# cat /proc/cpuinfo 
vendor_id       : IBM/S390
# processors    : 4
bogomips per cpu: 18115.00
features        : esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs 
cache0          : level=1 type=Data scope=Private size=96K line_size=256 associativity=6
cache1          : level=1 type=Instruction scope=Private size=64K line_size=256 associativity=4
cache2          : level=2 type=Data scope=Private size=1024K line_size=256 associativity=8
cache3          : level=2 type=Instruction scope=Private size=1024K line_size=256 associativity=8
cache4          : level=3 type=Unified scope=Shared size=49152K line_size=256 associativity=12
cache5          : level=4 type=Unified scope=Shared size=393216K line_size=256 associativity=24
processor 0: version = FF,  identification = 2F6D15,  machine = 2827
processor 1: version = FF,  identification = 2F6D15,  machine = 2827
processor 2: version = FF,  identification = 2F6D15,  machine = 2827
processor 3: version = FF,  identification = 2F6D15,  machine = 2827

The sysfs files and it contents seem to be ok.


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

* Re: [PATCH RFC/RFT v3 4/9] s390: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-20  8:38   ` Heiko Carstens
@ 2014-02-20 13:33     ` Sudeep Holla
  2014-02-20 14:07       ` Heiko Carstens
  0 siblings, 1 reply; 23+ messages in thread
From: Sudeep Holla @ 2014-02-20 13:33 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: Sudeep.Holla, linux-kernel, Martin Schwidefsky, linux390, linux-s390

Hi Heiko,

Thanks for testing this series, much appreciated.

On 20/02/14 08:38, Heiko Carstens wrote:
> On Wed, Feb 19, 2014 at 04:06:11PM +0000, Sudeep Holla wrote:
>> From: Sudeep Holla <sudeep.holla@arm.com>
>>
>> This patch removes the redundant sysfs cacheinfo code by making use of
>> the newly introduced generic cacheinfo infrastructure.
>>
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
>> Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
>> Cc: linux390@de.ibm.com
>> Cc: linux-s390@vger.kernel.org
>> ---
>>  arch/s390/kernel/cache.c | 388 ++++++++++++-----------------------------------
>>  1 file changed, 93 insertions(+), 295 deletions(-)
> 
> (FWIW, if you send an update of your series, please cc me on all patches, so I
>  don't have to search LKML for the rest of the patch set)
> 
Sorry, will make sure you will be cc-ed in the future updates.

> I gave your patches series a test and I get this nice message on boot:
> 
> io scheduler cfq registered
> DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags))
> ------------[ cut here ]------------
> WARNING: at kernel/locking/lockdep.c:2742
> Modules linked in:
> CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.14.0-rc3-00177-g468cee08c2ea #7
> task: 0000000000adcc60 ti: 0000000000ac4000 task.ti: 0000000000ac4000
> Krnl PSW : 0404c00180000000 000000000019af3e (lockdep_trace_alloc+0x116/0x120)
>            R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 EA:3
> Krnl GPRS: 0000000000000020 0000000000adcc60 000000000000002f 0000000000000000
>            000000000019af3a 0000000000000000 0000000000000001 0000000000000000
>            000000003ff26140 000000000055fb92 00000000000001b0 00000000000080d0
>            0400000000000000 00000000000080d0 000000000019af3a 000000000001bc30
> Krnl Code: 000000000019af2e: c020003b1e34       larl    %r2,8feb96
>            000000000019af34: c0e5002e0304       brasl   %r14,75b53c
>           #000000000019af3a: a7f40001           brc     15,19af3c
>           >000000000019af3e: e32003100004       lg      %r2,784
>            000000000019af44: a7f4ff9f           brc     15,19ae82
>            000000000019af48: e31003100004       lg      %r1,784
>            000000000019af4e: e32013f00150       sty     %r2,5104(%r1)
>            000000000019af54: 07fe               bcr     15,%r14
> Call Trace:
> ([<000000000019af3a>] lockdep_trace_alloc+0x112/0x120)
>  [<000000000027a7d2>] __kmalloc+0x5a/0x204
>  [<000000000055fb92>] detect_cache_attributes+0x66/0xd4
>  [<000000000055fc2e>] _detect_cache_attributes+0x2e/0x3c
>  [<00000000001ce7a2>] generic_smp_call_function_single_interrupt+0x9a/0xe8
>  [<000000000010b462>] do_ext_interrupt+0x12a/0x24c
>  [<00000000001afab0>] handle_irq_event_percpu+0x70/0x240
>  [<00000000001b3218>] handle_percpu_irq+0x6c/0x98
>  [<00000000001af16e>] generic_handle_irq+0x46/0x68
>  [<000000000010b6c2>] do_IRQ+0x5e/0x84
>  [<0000000000768b06>] ext_skip+0x44/0x4a
>  [<000000000076827c>] vtime_stop_cpu+0x50/0xa4
> ([<0000000000768262>] vtime_stop_cpu+0x36/0xa4)
>  [<0000000000103848>] arch_cpu_idle+0x6c/0xbc
>  [<00000000001af032>] cpu_startup_entry+0x146/0x218
>  [<0000000000b64932>] start_kernel+0x3fa/0x408
>  [<0000000000100020>] _stext+0x20/0x80
> INFO: lockdep is turned off.
> Last Breaking-Event-Address:
>  [<000000000019af3a>] lockdep_trace_alloc+0x112/0x120
> ---[ end trace 9c0011ccc7b324d6 ]---
> brd: module loaded
> 

Ah, my bad, I had this fixed initially when I implemented only on ARM and
introduced back while reorganising it to support multiple architectures, it's
now fixed.

> In addition /proc/cpuinfo is now incorrect.
> With your patches it looks like this:
> 
> [root@p2345007 ~]# cat /proc/cpuinfo 
> vendor_id       : IBM/S390
> # processors    : 4
> bogomips per cpu: 18115.00
> features        : esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs 
> cache0          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
> cache1          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
> cache2          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
> cache3          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
> cache4          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
> cache5          : level=1 type=Data scope=Shared size=96K line_size=256 associativity=6
> processor 0: version = FF,  identification = 2F6D15,  machine = 2827
> processor 1: version = FF,  identification = 2F6D15,  machine = 2827
> processor 2: version = FF,  identification = 2F6D15,  machine = 2827
> processor 3: version = FF,  identification = 2F6D15,  machine = 2827
> 
> However it is supposed to look like this:
> 
> [root@p2345007 ~]# cat /proc/cpuinfo 
> vendor_id       : IBM/S390
> # processors    : 4
> bogomips per cpu: 18115.00
> features        : esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs 
> cache0          : level=1 type=Data scope=Private size=96K line_size=256 associativity=6
> cache1          : level=1 type=Instruction scope=Private size=64K line_size=256 associativity=4
> cache2          : level=2 type=Data scope=Private size=1024K line_size=256 associativity=8
> cache3          : level=2 type=Instruction scope=Private size=1024K line_size=256 associativity=8
> cache4          : level=3 type=Unified scope=Shared size=49152K line_size=256 associativity=12
> cache5          : level=4 type=Unified scope=Shared size=393216K line_size=256 associativity=24
> processor 0: version = FF,  identification = 2F6D15,  machine = 2827
> processor 1: version = FF,  identification = 2F6D15,  machine = 2827
> processor 2: version = FF,  identification = 2F6D15,  machine = 2827
> processor 3: version = FF,  identification = 2F6D15,  machine = 2827
> 
> The sysfs files and it contents seem to be ok.
> 

Thanks, this info was helpful and looks like it's stupid mistake I did. I
deleted a line unknowingly while trying to minimise the diff for show_cacheinfo.
The below fix-up must work IIUC the issue. I will squash this in my next update
if it works.

Regards,
Sudeep

--->8

>From 77690bc34b2b4b492377998019371f6e2f8f90b7 Mon Sep 17 00:00:00 2001
From: Sudeep Holla <sudeep.holla@arm.com>
Date: Thu, 20 Feb 2014 13:14:09 +0000
Subject: [PATCH] fixup! s390: move cacheinfo sysfs to generic cacheinfo
 infrastructure

---
 arch/s390/kernel/cache.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c
index e064f95..aeedb7f 100644
--- a/arch/s390/kernel/cache.c
+++ b/arch/s390/kernel/cache.c
@@ -68,14 +68,15 @@ void show_cacheinfo(struct seq_file *m)
 {
 	int cpu = smp_processor_id(), idx;
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
-	struct cache_info *cache = this_cpu_ci->info_list;
+	struct cache_info *cache;

 	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+		cache = this_cpu_ci->info_list + idx;
 		seq_printf(m, "cache%-11d: ", idx);
 		seq_printf(m, "level=%d ", cache->level);
 		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
 		seq_printf(m, "scope=%s ",
-			   cache->disable_sysfs ? "Private" : "Shared");
+			   cache->disable_sysfs ? "Shared" : "Private");
 		seq_printf(m, "size=%dK ", cache->size >> 10);
 		seq_printf(m, "line_size=%u ", cache->coherency_line_size);
 		seq_printf(m, "associativity=%d", cache->ways_of_associativity);




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

* Re: [PATCH RFC/RFT v3 4/9] s390: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-20 13:33     ` Sudeep Holla
@ 2014-02-20 14:07       ` Heiko Carstens
  2014-02-20 14:37         ` Sudeep Holla
  0 siblings, 1 reply; 23+ messages in thread
From: Heiko Carstens @ 2014-02-20 14:07 UTC (permalink / raw)
  To: Sudeep Holla; +Cc: linux-kernel, Martin Schwidefsky, linux390, linux-s390

On Thu, Feb 20, 2014 at 01:33:56PM +0000, Sudeep Holla wrote:
> Thanks, this info was helpful and looks like it's stupid mistake I did. I
> deleted a line unknowingly while trying to minimise the diff for show_cacheinfo.
> The below fix-up must work IIUC the issue. I will squash this in my next update
> if it works.
> 
> Regards,
> Sudeep
> 
> --->8
> 
> From 77690bc34b2b4b492377998019371f6e2f8f90b7 Mon Sep 17 00:00:00 2001
> From: Sudeep Holla <sudeep.holla@arm.com>
> Date: Thu, 20 Feb 2014 13:14:09 +0000
> Subject: [PATCH] fixup! s390: move cacheinfo sysfs to generic cacheinfo
>  infrastructure
> 
> ---
>  arch/s390/kernel/cache.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c
> index e064f95..aeedb7f 100644
> --- a/arch/s390/kernel/cache.c
> +++ b/arch/s390/kernel/cache.c
> @@ -68,14 +68,15 @@ void show_cacheinfo(struct seq_file *m)
>  {
>  	int cpu = smp_processor_id(), idx;
>  	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
> -	struct cache_info *cache = this_cpu_ci->info_list;
> +	struct cache_info *cache;
> 
>  	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
> +		cache = this_cpu_ci->info_list + idx;
>  		seq_printf(m, "cache%-11d: ", idx);
>  		seq_printf(m, "level=%d ", cache->level);
>  		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
>  		seq_printf(m, "scope=%s ",
> -			   cache->disable_sysfs ? "Private" : "Shared");
> +			   cache->disable_sysfs ? "Shared" : "Private");
>  		seq_printf(m, "size=%dK ", cache->size >> 10);
>  		seq_printf(m, "line_size=%u ", cache->coherency_line_size);
>  		seq_printf(m, "associativity=%d", cache->ways_of_associativity);

With this patch applied the output looks ok again.

Thanks,
Heiko


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

* Re: [PATCH RFC/RFT v3 4/9] s390: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-20 14:07       ` Heiko Carstens
@ 2014-02-20 14:37         ` Sudeep Holla
  0 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-02-20 14:37 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: Sudeep.Holla, linux-kernel, Martin Schwidefsky, linux390, linux-s390

On 20/02/14 14:07, Heiko Carstens wrote:
> On Thu, Feb 20, 2014 at 01:33:56PM +0000, Sudeep Holla wrote:
>> Thanks, this info was helpful and looks like it's stupid mistake I did. I
>> deleted a line unknowingly while trying to minimise the diff for show_cacheinfo.
>> The below fix-up must work IIUC the issue. I will squash this in my next update
>> if it works.
>>
>> Regards,
>> Sudeep
>>
>> --->8
>>
>> From 77690bc34b2b4b492377998019371f6e2f8f90b7 Mon Sep 17 00:00:00 2001
>> From: Sudeep Holla <sudeep.holla@arm.com>
>> Date: Thu, 20 Feb 2014 13:14:09 +0000
>> Subject: [PATCH] fixup! s390: move cacheinfo sysfs to generic cacheinfo
>>  infrastructure
>>
>> ---
>>  arch/s390/kernel/cache.c | 5 +++--
>>  1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c
>> index e064f95..aeedb7f 100644
>> --- a/arch/s390/kernel/cache.c
>> +++ b/arch/s390/kernel/cache.c
>> @@ -68,14 +68,15 @@ void show_cacheinfo(struct seq_file *m)
>>  {
>>  	int cpu = smp_processor_id(), idx;
>>  	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
>> -	struct cache_info *cache = this_cpu_ci->info_list;
>> +	struct cache_info *cache;
>>
>>  	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
>> +		cache = this_cpu_ci->info_list + idx;
>>  		seq_printf(m, "cache%-11d: ", idx);
>>  		seq_printf(m, "level=%d ", cache->level);
>>  		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
>>  		seq_printf(m, "scope=%s ",
>> -			   cache->disable_sysfs ? "Private" : "Shared");
>> +			   cache->disable_sysfs ? "Shared" : "Private");
>>  		seq_printf(m, "size=%dK ", cache->size >> 10);
>>  		seq_printf(m, "line_size=%u ", cache->coherency_line_size);
>>  		seq_printf(m, "associativity=%d", cache->ways_of_associativity);
> 
> With this patch applied the output looks ok again.
> 

Thanks a lot for retesting and confirming results with this fix-up, will squash
it in my next update.

Regards,
Sudeep


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

* Re: [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs Sudeep Holla
@ 2014-03-01  0:42   ` Greg Kroah-Hartman
  2014-03-03  7:39     ` Sudeep Holla
  0 siblings, 1 reply; 23+ messages in thread
From: Greg Kroah-Hartman @ 2014-03-01  0:42 UTC (permalink / raw)
  To: Sudeep Holla; +Cc: linux-kernel, Rob Herring, linux-doc

On Wed, Feb 19, 2014 at 04:06:09PM +0000, Sudeep Holla wrote:
> From: Sudeep Holla <sudeep.holla@arm.com>
> 
> This patch adds initial support for providing processor cache information
> to userspace through sysfs interface. This is based on already existing
> implementations(x86, ia64, s390 and powerpc) and hence the interface is
> intended to be fully compatible.
> 
> The main purpose of this generic support is to avoid further code
> duplication to support new architectures and also to unify all the existing
> different implementations.
> 
> This implementation maintains the hierarchy of cache objects which reflects
> the system's cache topology. Cache devices are instantiated as needed as
> CPUs come online. The cache information is replicated per-cpu even if they are
> shared. A per-cpu array of cache information maintained is used mainly for
> sysfs-related book keeping.
> 
> It also implements the shared_cpu_map attribute, which is essential for
> enabling both kernel and user-space to discover the system's overall cache
> topology.
> 
> This patch also add the missing ABI documentation for the cacheinfo sysfs
> interface already, which is well defined and widely used.
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Rob Herring <robh@kernel.org>
> Cc: linux-doc@vger.kernel.org
> ---
>  Documentation/ABI/testing/sysfs-devices-system-cpu |  40 ++
>  drivers/base/Makefile                              |   2 +-
>  drivers/base/cacheinfo.c                           | 484 +++++++++++++++++++++
>  include/linux/cacheinfo.h                          |  55 +++
>  4 files changed, 580 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/base/cacheinfo.c
>  create mode 100644 include/linux/cacheinfo.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
> index d5a0d33..dabe03e 100644
> --- a/Documentation/ABI/testing/sysfs-devices-system-cpu
> +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
> @@ -224,3 +224,43 @@ Description:	Parameters for the Intel P-state driver
>  		frequency range.
>  
>  		More details can be found in Documentation/cpu-freq/intel-pstate.txt
> +
> +What:		/sys/devices/system/cpu/cpu*/cache/index*/<set_of_attributes_mentioned_below>
> +Date:		February 2014
> +Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>

No, your name goes here, you don't get to run away from this new code :)

> +Description:	Parameters for the CPU cache attributes
> +
> +		attributes:
> +			- writethrough: data is written to both the cache line
> +					and to the block in the lower-level memory
> +			- writeback: data is written only to the cache line and
> +				     the modified cache line is written to main
> +				     memory only when it is replaced
> +			- writeallocate: allocate a memory location to a cache line
> +					 on a cache miss because of a write
> +			- readallocate: allocate a memory location to a cache line
> +					on a cache miss because of a read
> +
> +		coherency_line_size: the minimum amount of data that gets transferred
> +
> +		level: the cache hierarcy in the multi-level cache configuration
> +
> +		number_of_sets: total number of sets in the cache, a set is a
> +				collection of cache lines with the same cache index
> +
> +		physical_line_partition: number of physical cache line per cache tag
> +
> +		shared_cpu_list: the list of cpus sharing the cache
> +
> +		shared_cpu_map: logical cpu mask containing the list of cpus sharing
> +				the cache
> +
> +		size: the total cache size in kB
> +
> +		type:
> +			- instruction: cache that only holds instructions
> +			- data: cache that only caches data
> +			- unified: cache that holds both data and instructions
> +
> +		ways_of_associativity: degree of freedom in placing a particular block
> +					of memory in the cache

With this patch, does this all work for x86, or does it need more glue
logic?

thanks,

greg k-h

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

* Re: [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices Sudeep Holla
@ 2014-03-01  0:42   ` Greg Kroah-Hartman
  2014-03-03  7:28     ` Sudeep Holla
  0 siblings, 1 reply; 23+ messages in thread
From: Greg Kroah-Hartman @ 2014-03-01  0:42 UTC (permalink / raw)
  To: Sudeep Holla; +Cc: linux-kernel

On Wed, Feb 19, 2014 at 04:06:08PM +0000, Sudeep Holla wrote:
> From: Sudeep Holla <sudeep.holla@arm.com>
> 
> This patch creates a new class called "cpu" and assigns it to all the
> cpu devices. This helps in grouping all the cpu devices and associated
> child devices under the same class.
> 
> This patch also:
> 1. modifies the get_parent_device to return the legacy path
>    (/sys/devices/system/cpu/..) for the cpu class devices to support
>    existing sysfs ABI
> 2. avoids creating link in the class directory pointing to the device as
>    there would be per-cpu instance of these devices with the same name
> 3. makes sure subsystem symlink continues pointing to cpu bus instead of
>    cpu class for cpu devices
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Does the sysfs layout change at all with this patch applied?

thanks,

greg k-h

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

* Re: [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices
  2014-03-01  0:42   ` Greg Kroah-Hartman
@ 2014-03-03  7:28     ` Sudeep Holla
  0 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-03-03  7:28 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

Hi Greg,

On Sat, Mar 1, 2014 at 12:42 AM, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Wed, Feb 19, 2014 at 04:06:08PM +0000, Sudeep Holla wrote:
>> From: Sudeep Holla <sudeep.holla@arm.com>
>>
>> This patch creates a new class called "cpu" and assigns it to all the
>> cpu devices. This helps in grouping all the cpu devices and associated
>> child devices under the same class.
>>
>> This patch also:
>> 1. modifies the get_parent_device to return the legacy path
>>    (/sys/devices/system/cpu/..) for the cpu class devices to support
>>    existing sysfs ABI
>> 2. avoids creating link in the class directory pointing to the device as
>>    there would be per-cpu instance of these devices with the same name
>> 3. makes sure subsystem symlink continues pointing to cpu bus instead of
>>    cpu class for cpu devices
>>
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> Does the sysfs layout change at all with this patch applied?
>

No change to the existing layout, it just adds new entries, e.g. device symlink.

Before this patch:
/ # ls /sys/devices/system/cpu/cpu0/ -l
total 0
drwxr-xr-x    5 root     0                0 Jan  1 00:02 cpuidle
-rw-r--r--    1 root     0             4096 Jan  1 00:02 online
drwxr-xr-x    2 root     0                0 Jan  1 00:02 power
lrwxrwxrwx    1 root     0                0 Jan  1 00:02 subsystem ->
../../../../bus/cpu
drwxr-xr-x    2 root     0                0 Jan  1 00:02 topology
-rw-r--r--    1 root     0             4096 Jan  1 00:02 uevent

After this patch:
/sys/class/cpu # ls /sys/devices/system/cpu/cpu0 -l
total 0
drwxr-xr-x    6 root     0                0 Jan  1 00:00 cache
drwxr-xr-x    5 root     0                0 Jan  1 00:00 cpuidle
lrwxrwxrwx    1 root     0                0 Jan  1 00:00 device -> ../../cpu
-rw-r--r--    1 root     0             4096 Jan  1 00:00 online
drwxr-xr-x    2 root     0                0 Jan  1 00:00 power
lrwxrwxrwx    1 root     0                0 Jan  1 00:00 subsystem ->
../../../../bus/cpu
drwxr-xr-x    2 root     0                0 Jan  1 00:00 topology
-rw-r--r--    1 root     0             4096 Jan  1 00:00 uevent

Regards,
Sudeep

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

* Re: [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs
  2014-03-01  0:42   ` Greg Kroah-Hartman
@ 2014-03-03  7:39     ` Sudeep Holla
  0 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-03-03  7:39 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel, Rob Herring, linux-doc

Hi Greg,

On Sat, Mar 1, 2014 at 12:42 AM, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Wed, Feb 19, 2014 at 04:06:09PM +0000, Sudeep Holla wrote:
>> From: Sudeep Holla <sudeep.holla@arm.com>
>>
>> This patch adds initial support for providing processor cache information
>> to userspace through sysfs interface. This is based on already existing
>> implementations(x86, ia64, s390 and powerpc) and hence the interface is
>> intended to be fully compatible.
>>
>> The main purpose of this generic support is to avoid further code
>> duplication to support new architectures and also to unify all the existing
>> different implementations.
>>
>> This implementation maintains the hierarchy of cache objects which reflects
>> the system's cache topology. Cache devices are instantiated as needed as
>> CPUs come online. The cache information is replicated per-cpu even if they are
>> shared. A per-cpu array of cache information maintained is used mainly for
>> sysfs-related book keeping.
>>
>> It also implements the shared_cpu_map attribute, which is essential for
>> enabling both kernel and user-space to discover the system's overall cache
>> topology.
>>
>> This patch also add the missing ABI documentation for the cacheinfo sysfs
>> interface already, which is well defined and widely used.
>>
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Rob Herring <robh@kernel.org>
>> Cc: linux-doc@vger.kernel.org
>> ---
>>  Documentation/ABI/testing/sysfs-devices-system-cpu |  40 ++
>>  drivers/base/Makefile                              |   2 +-
>>  drivers/base/cacheinfo.c                           | 484 +++++++++++++++++++++
>>  include/linux/cacheinfo.h                          |  55 +++
>>  4 files changed, 580 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/base/cacheinfo.c
>>  create mode 100644 include/linux/cacheinfo.h
>>
>> diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
>> index d5a0d33..dabe03e 100644
>> --- a/Documentation/ABI/testing/sysfs-devices-system-cpu
>> +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
>> @@ -224,3 +224,43 @@ Description:     Parameters for the Intel P-state driver
>>               frequency range.
>>
>>               More details can be found in Documentation/cpu-freq/intel-pstate.txt
>> +
>> +What:                /sys/devices/system/cpu/cpu*/cache/index*/<set_of_attributes_mentioned_below>
>> +Date:                February 2014
>> +Contact:     Linux kernel mailing list <linux-kernel@vger.kernel.org>
>
> No, your name goes here, you don't get to run away from this new code :)
>

No problem, I can add my name and I am happy to do that. I am only adding
missing documentation to already existing interface as I have mentioned
in the patch description. I didn't want to take that credit :), but am
OK if that's
acceptable.

>> +Description: Parameters for the CPU cache attributes
>> +
>> +             attributes:
>> +                     - writethrough: data is written to both the cache line
>> +                                     and to the block in the lower-level memory
>> +                     - writeback: data is written only to the cache line and
>> +                                  the modified cache line is written to main
>> +                                  memory only when it is replaced
>> +                     - writeallocate: allocate a memory location to a cache line
>> +                                      on a cache miss because of a write
>> +                     - readallocate: allocate a memory location to a cache line
>> +                                     on a cache miss because of a read
>> +
>> +             coherency_line_size: the minimum amount of data that gets transferred
>> +
>> +             level: the cache hierarcy in the multi-level cache configuration
>> +
>> +             number_of_sets: total number of sets in the cache, a set is a
>> +                             collection of cache lines with the same cache index
>> +
>> +             physical_line_partition: number of physical cache line per cache tag
>> +
>> +             shared_cpu_list: the list of cpus sharing the cache
>> +
>> +             shared_cpu_map: logical cpu mask containing the list of cpus sharing
>> +                             the cache
>> +
>> +             size: the total cache size in kB
>> +
>> +             type:
>> +                     - instruction: cache that only holds instructions
>> +                     - data: cache that only caches data
>> +                     - unified: cache that holds both data and instructions
>> +
>> +             ways_of_associativity: degree of freedom in placing a particular block
>> +                                     of memory in the cache
>
> With this patch, does this all work for x86, or does it need more glue
> logic?

No, the core code is mainly based on existing x86 implementation. There
should be no extra glue logic required. I have not yet tested on x86,
but will do that before the first non-RFC post if the overall approach
is now acceptable. But I still need help in testing on AMD, ia64 and ppc.

Regards,
Sudeep

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

* Re: [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-02-19 16:06 ` [PATCH RFC/RFT v3 6/9] powerpc: " Sudeep Holla
@ 2014-03-07  4:06   ` Anshuman Khandual
  2014-03-07  6:14     ` Anshuman Khandual
  0 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2014-03-07  4:06 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev

On 02/19/2014 09:36 PM, Sudeep Holla wrote:
> From: Sudeep Holla <sudeep.holla@arm.com>
> 
> This patch removes the redundant sysfs cacheinfo code by making use of
> the newly introduced generic cacheinfo infrastructure.
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: linuxppc-dev@lists.ozlabs.org
> ---
>  arch/powerpc/kernel/cacheinfo.c | 831 ++++++----------------------------------
>  arch/powerpc/kernel/cacheinfo.h |   8 -
>  arch/powerpc/kernel/sysfs.c     |   4 -
>  3 files changed, 109 insertions(+), 734 deletions(-)
>  delete mode 100644 arch/powerpc/kernel/cacheinfo.h
> 
> diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
> index 2912b87..05b7580 100644
> --- a/arch/powerpc/kernel/cacheinfo.c
> +++ b/arch/powerpc/kernel/cacheinfo.c
> @@ -10,38 +10,10 @@
>   * 2 as published by the Free Software Foundation.
>   */
> 
> +#include <linux/cacheinfo.h>
>  #include <linux/cpu.h>
> -#include <linux/cpumask.h>
>  #include <linux/kernel.h>
> -#include <linux/kobject.h>
> -#include <linux/list.h>
> -#include <linux/notifier.h>
>  #include <linux/of.h>
> -#include <linux/percpu.h>
> -#include <linux/slab.h>
> -#include <asm/prom.h>
> -
> -#include "cacheinfo.h"
> -
> -/* per-cpu object for tracking:
> - * - a "cache" kobject for the top-level directory
> - * - a list of "index" objects representing the cpu's local cache hierarchy
> - */
> -struct cache_dir {
> -	struct kobject *kobj; /* bare (not embedded) kobject for cache
> -			       * directory */
> -	struct cache_index_dir *index; /* list of index objects */
> -};
> -
> -/* "index" object: each cpu's cache directory has an index
> - * subdirectory corresponding to a cache object associated with the
> - * cpu.  This object's lifetime is managed via the embedded kobject.
> - */
> -struct cache_index_dir {
> -	struct kobject kobj;
> -	struct cache_index_dir *next; /* next index in parent directory */
> -	struct cache *cache;
> -};
> 
>  /* Template for determining which OF properties to query for a given
>   * cache type */
> @@ -60,11 +32,6 @@ struct cache_type_info {
>  	const char *nr_sets_prop;
>  };
> 
> -/* These are used to index the cache_type_info array. */
> -#define CACHE_TYPE_UNIFIED     0
> -#define CACHE_TYPE_INSTRUCTION 1
> -#define CACHE_TYPE_DATA        2
> -
>  static const struct cache_type_info cache_type_info[] = {
>  	{
>  		/* PowerPC Processor binding says the [di]-cache-*
> @@ -77,246 +44,115 @@ static const struct cache_type_info cache_type_info[] = {
>  		.nr_sets_prop    = "d-cache-sets",
>  	},
>  	{
> -		.name            = "Instruction",
> -		.size_prop       = "i-cache-size",
> -		.line_size_props = { "i-cache-line-size",
> -				     "i-cache-block-size", },
> -		.nr_sets_prop    = "i-cache-sets",
> -	},
> -	{
>  		.name            = "Data",
>  		.size_prop       = "d-cache-size",
>  		.line_size_props = { "d-cache-line-size",
>  				     "d-cache-block-size", },
>  		.nr_sets_prop    = "d-cache-sets",
>  	},
> +	{
> +		.name            = "Instruction",
> +		.size_prop       = "i-cache-size",
> +		.line_size_props = { "i-cache-line-size",
> +				     "i-cache-block-size", },
> +		.nr_sets_prop    = "i-cache-sets",
> +	},
>  };


Hey Sudeep,

After applying this patch, the cache_type_info array looks like this.

static const struct cache_type_info cache_type_info[] = {
        {
                /* 
                 * PowerPC Processor binding says the [di]-cache-*
                 * must be equal on unified caches, so just use
                 * d-cache properties.
                 */
                .name            = "Unified",
                .size_prop       = "d-cache-size",
                .line_size_props = { "d-cache-line-size",
                                     "d-cache-block-size", },
                .nr_sets_prop    = "d-cache-sets",
        },
        {
                .name            = "Data",
                .size_prop       = "d-cache-size",
                .line_size_props = { "d-cache-line-size",
                                     "d-cache-block-size", },
                .nr_sets_prop    = "d-cache-sets",
        },
        {
                .name            = "Instruction",
                .size_prop       = "i-cache-size",
                .line_size_props = { "i-cache-line-size",
                                     "i-cache-block-size", },
                .nr_sets_prop    = "i-cache-sets",
        },
};

and this function computes the the array index for any given cache type
define for PowerPC.

static inline int get_cacheinfo_idx(enum cache_type type)
{
        if (type == CACHE_TYPE_UNIFIED)
                return 0;
        else
                return type;
}

These types are define in include/linux/cacheinfo.h as

enum cache_type {
        CACHE_TYPE_NOCACHE = 0,
        CACHE_TYPE_INST = BIT(0),		---> 1
        CACHE_TYPE_DATA = BIT(1),		---> 2
        CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA,
        CACHE_TYPE_UNIFIED = BIT(2),
};

When it is UNIFIED we return index 0, which is correct. But the index
for instruction and data cache seems to be swapped which wrong. This
will fetch invalid properties for any given cache type.

I have done some initial review and testing for this patch's impact on
PowerPC (ppc64 POWER specifically). I am trying to do some code clean-up
and re-arrangements. Will post out soon. Thanks !

Regards
Anshuman




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

* Re: [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-03-07  4:06   ` Anshuman Khandual
@ 2014-03-07  6:14     ` Anshuman Khandual
  2014-03-10 11:12       ` Sudeep Holla
  0 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2014-03-07  6:14 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev

On 03/07/2014 09:36 AM, Anshuman Khandual wrote:
> On 02/19/2014 09:36 PM, Sudeep Holla wrote:
>> From: Sudeep Holla <sudeep.holla@arm.com>
>>
>> This patch removes the redundant sysfs cacheinfo code by making use of
>> the newly introduced generic cacheinfo infrastructure.
>>
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> Cc: Paul Mackerras <paulus@samba.org>
>> Cc: linuxppc-dev@lists.ozlabs.org
>> ---
>>  arch/powerpc/kernel/cacheinfo.c | 831 ++++++----------------------------------
>>  arch/powerpc/kernel/cacheinfo.h |   8 -
>>  arch/powerpc/kernel/sysfs.c     |   4 -
>>  3 files changed, 109 insertions(+), 734 deletions(-)
>>  delete mode 100644 arch/powerpc/kernel/cacheinfo.h
>>
>> diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
>> index 2912b87..05b7580 100644
>> --- a/arch/powerpc/kernel/cacheinfo.c
>> +++ b/arch/powerpc/kernel/cacheinfo.c
>> @@ -10,38 +10,10 @@
>>   * 2 as published by the Free Software Foundation.
>>   */
>>
>> +#include <linux/cacheinfo.h>
>>  #include <linux/cpu.h>
>> -#include <linux/cpumask.h>
>>  #include <linux/kernel.h>
>> -#include <linux/kobject.h>
>> -#include <linux/list.h>
>> -#include <linux/notifier.h>
>>  #include <linux/of.h>
>> -#include <linux/percpu.h>
>> -#include <linux/slab.h>
>> -#include <asm/prom.h>
>> -
>> -#include "cacheinfo.h"
>> -
>> -/* per-cpu object for tracking:
>> - * - a "cache" kobject for the top-level directory
>> - * - a list of "index" objects representing the cpu's local cache hierarchy
>> - */
>> -struct cache_dir {
>> -	struct kobject *kobj; /* bare (not embedded) kobject for cache
>> -			       * directory */
>> -	struct cache_index_dir *index; /* list of index objects */
>> -};
>> -
>> -/* "index" object: each cpu's cache directory has an index
>> - * subdirectory corresponding to a cache object associated with the
>> - * cpu.  This object's lifetime is managed via the embedded kobject.
>> - */
>> -struct cache_index_dir {
>> -	struct kobject kobj;
>> -	struct cache_index_dir *next; /* next index in parent directory */
>> -	struct cache *cache;
>> -};
>>
>>  /* Template for determining which OF properties to query for a given
>>   * cache type */
>> @@ -60,11 +32,6 @@ struct cache_type_info {
>>  	const char *nr_sets_prop;
>>  };
>>
>> -/* These are used to index the cache_type_info array. */
>> -#define CACHE_TYPE_UNIFIED     0
>> -#define CACHE_TYPE_INSTRUCTION 1
>> -#define CACHE_TYPE_DATA        2
>> -
>>  static const struct cache_type_info cache_type_info[] = {
>>  	{
>>  		/* PowerPC Processor binding says the [di]-cache-*
>> @@ -77,246 +44,115 @@ static const struct cache_type_info cache_type_info[] = {
>>  		.nr_sets_prop    = "d-cache-sets",
>>  	},
>>  	{
>> -		.name            = "Instruction",
>> -		.size_prop       = "i-cache-size",
>> -		.line_size_props = { "i-cache-line-size",
>> -				     "i-cache-block-size", },
>> -		.nr_sets_prop    = "i-cache-sets",
>> -	},
>> -	{
>>  		.name            = "Data",
>>  		.size_prop       = "d-cache-size",
>>  		.line_size_props = { "d-cache-line-size",
>>  				     "d-cache-block-size", },
>>  		.nr_sets_prop    = "d-cache-sets",
>>  	},
>> +	{
>> +		.name            = "Instruction",
>> +		.size_prop       = "i-cache-size",
>> +		.line_size_props = { "i-cache-line-size",
>> +				     "i-cache-block-size", },
>> +		.nr_sets_prop    = "i-cache-sets",
>> +	},
>>  };
> 
> 
> Hey Sudeep,
> 
> After applying this patch, the cache_type_info array looks like this.
> 
> static const struct cache_type_info cache_type_info[] = {
>         {
>                 /* 
>                  * PowerPC Processor binding says the [di]-cache-*
>                  * must be equal on unified caches, so just use
>                  * d-cache properties.
>                  */
>                 .name            = "Unified",
>                 .size_prop       = "d-cache-size",
>                 .line_size_props = { "d-cache-line-size",
>                                      "d-cache-block-size", },
>                 .nr_sets_prop    = "d-cache-sets",
>         },
>         {
>                 .name            = "Data",
>                 .size_prop       = "d-cache-size",
>                 .line_size_props = { "d-cache-line-size",
>                                      "d-cache-block-size", },
>                 .nr_sets_prop    = "d-cache-sets",
>         },
>         {
>                 .name            = "Instruction",
>                 .size_prop       = "i-cache-size",
>                 .line_size_props = { "i-cache-line-size",
>                                      "i-cache-block-size", },
>                 .nr_sets_prop    = "i-cache-sets",
>         },
> };
> 
> and this function computes the the array index for any given cache type
> define for PowerPC.
> 
> static inline int get_cacheinfo_idx(enum cache_type type)
> {
>         if (type == CACHE_TYPE_UNIFIED)
>                 return 0;
>         else
>                 return type;
> }
> 
> These types are define in include/linux/cacheinfo.h as
> 
> enum cache_type {
>         CACHE_TYPE_NOCACHE = 0,
>         CACHE_TYPE_INST = BIT(0),		---> 1
>         CACHE_TYPE_DATA = BIT(1),		---> 2
>         CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA,
>         CACHE_TYPE_UNIFIED = BIT(2),
> };
> 
> When it is UNIFIED we return index 0, which is correct. But the index
> for instruction and data cache seems to be swapped which wrong. This
> will fetch invalid properties for any given cache type.
> 
> I have done some initial review and testing for this patch's impact on
> PowerPC (ppc64 POWER specifically). I am trying to do some code clean-up
> and re-arrangements. Will post out soon. Thanks !

It does not work correctly on POWER.

The new patchset adds some more attributes for every cache entry apart from
what we used to have on PowerPC before. From the ABI perspective, the old ones
should reflect the correct value in the same manner as before. Looks like
the generic code will make any attribute as "Unknown" if the arch code does
not populate them in the respective callback.

Here are some problems found on a POWER7 system

(1) L1 instruction cache (cpu<N>/cache/index1/)

	====== Before patch ======

	coherency_line_size: 	128
	level:			1
	shared_cpu_map:		00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
        			00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
				00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
				00000000,00000000,00000000,00000000,00000f00
	size:			32K
	type:			Instruction 

	===== After patch ========

	coherency_line_size:	Unknown						----> Wrong
	level:			1
	shared_cpu_map:		00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
        			00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
				00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
				00000000,00000000,00000000,00000000,00ffffff	----> Wrong
	size:			0K						----> Wrong
	type:			Instruction	

(2) L3 cache (cpu<N>/cache/index3/)

	====== Before patch ======

	number_of_sets:		1
	size:			4096K
	ways_of_associativity:	0

	===== After patch ========

	number_of_sets:		1
	size:			4096K
	ways_of_associativity:	Unknown		----> Wrong

Need to revisit this implementation on PowerPC and figure out the cause of these problems.


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

* Re: [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-03-07  6:14     ` Anshuman Khandual
@ 2014-03-10 11:12       ` Sudeep Holla
  2014-03-21  3:44         ` Anshuman Khandual
  0 siblings, 1 reply; 23+ messages in thread
From: Sudeep Holla @ 2014-03-10 11:12 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Sudeep Holla, linux-kernel, Benjamin Herrenschmidt,
	Paul Mackerras, linuxppc-dev

Hi Anshuman,

On 07/03/14 06:14, Anshuman Khandual wrote:
> On 03/07/2014 09:36 AM, Anshuman Khandual wrote:
>> On 02/19/2014 09:36 PM, Sudeep Holla wrote:
>>> From: Sudeep Holla <sudeep.holla@arm.com>
>>>
>>> This patch removes the redundant sysfs cacheinfo code by making use of
>>> the newly introduced generic cacheinfo infrastructure.
>>>
>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>> Cc: Paul Mackerras <paulus@samba.org>
>>> Cc: linuxppc-dev@lists.ozlabs.org
>>> ---
>>>   arch/powerpc/kernel/cacheinfo.c | 831 ++++++----------------------------------
>>>   arch/powerpc/kernel/cacheinfo.h |   8 -
>>>   arch/powerpc/kernel/sysfs.c     |   4 -
>>>   3 files changed, 109 insertions(+), 734 deletions(-)
>>>   delete mode 100644 arch/powerpc/kernel/cacheinfo.h
>>>
>>> diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
>>> index 2912b87..05b7580 100644
>>> --- a/arch/powerpc/kernel/cacheinfo.c
>>> +++ b/arch/powerpc/kernel/cacheinfo.c
>>> @@ -10,38 +10,10 @@
>>>    * 2 as published by the Free Software Foundation.
>>>    */
>>>
>>> +#include <linux/cacheinfo.h>
>>>   #include <linux/cpu.h>
>>> -#include <linux/cpumask.h>
>>>   #include <linux/kernel.h>
>>> -#include <linux/kobject.h>
>>> -#include <linux/list.h>
>>> -#include <linux/notifier.h>
>>>   #include <linux/of.h>
>>> -#include <linux/percpu.h>
>>> -#include <linux/slab.h>
>>> -#include <asm/prom.h>
>>> -
>>> -#include "cacheinfo.h"
>>> -
>>> -/* per-cpu object for tracking:
>>> - * - a "cache" kobject for the top-level directory
>>> - * - a list of "index" objects representing the cpu's local cache hierarchy
>>> - */
>>> -struct cache_dir {
>>> -	struct kobject *kobj; /* bare (not embedded) kobject for cache
>>> -			       * directory */
>>> -	struct cache_index_dir *index; /* list of index objects */
>>> -};
>>> -
>>> -/* "index" object: each cpu's cache directory has an index
>>> - * subdirectory corresponding to a cache object associated with the
>>> - * cpu.  This object's lifetime is managed via the embedded kobject.
>>> - */
>>> -struct cache_index_dir {
>>> -	struct kobject kobj;
>>> -	struct cache_index_dir *next; /* next index in parent directory */
>>> -	struct cache *cache;
>>> -};
>>>
>>>   /* Template for determining which OF properties to query for a given
>>>    * cache type */
>>> @@ -60,11 +32,6 @@ struct cache_type_info {
>>>   	const char *nr_sets_prop;
>>>   };
>>>
>>> -/* These are used to index the cache_type_info array. */
>>> -#define CACHE_TYPE_UNIFIED     0
>>> -#define CACHE_TYPE_INSTRUCTION 1
>>> -#define CACHE_TYPE_DATA        2
>>> -
>>>   static const struct cache_type_info cache_type_info[] = {
>>>   	{
>>>   		/* PowerPC Processor binding says the [di]-cache-*
>>> @@ -77,246 +44,115 @@ static const struct cache_type_info cache_type_info[] = {
>>>   		.nr_sets_prop    = "d-cache-sets",
>>>   	},
>>>   	{
>>> -		.name            = "Instruction",
>>> -		.size_prop       = "i-cache-size",
>>> -		.line_size_props = { "i-cache-line-size",
>>> -				     "i-cache-block-size", },
>>> -		.nr_sets_prop    = "i-cache-sets",
>>> -	},
>>> -	{
>>>   		.name            = "Data",
>>>   		.size_prop       = "d-cache-size",
>>>   		.line_size_props = { "d-cache-line-size",
>>>   				     "d-cache-block-size", },
>>>   		.nr_sets_prop    = "d-cache-sets",
>>>   	},
>>> +	{
>>> +		.name            = "Instruction",
>>> +		.size_prop       = "i-cache-size",
>>> +		.line_size_props = { "i-cache-line-size",
>>> +				     "i-cache-block-size", },
>>> +		.nr_sets_prop    = "i-cache-sets",
>>> +	},
>>>   };
>>
>>
>> Hey Sudeep,
>>
>> After applying this patch, the cache_type_info array looks like this.
>>
>> static const struct cache_type_info cache_type_info[] = {
>>          {
>>                  /*
>>                   * PowerPC Processor binding says the [di]-cache-*
>>                   * must be equal on unified caches, so just use
>>                   * d-cache properties.
>>                   */
>>                  .name            = "Unified",
>>                  .size_prop       = "d-cache-size",
>>                  .line_size_props = { "d-cache-line-size",
>>                                       "d-cache-block-size", },
>>                  .nr_sets_prop    = "d-cache-sets",
>>          },
>>          {
>>                  .name            = "Data",
>>                  .size_prop       = "d-cache-size",
>>                  .line_size_props = { "d-cache-line-size",
>>                                       "d-cache-block-size", },
>>                  .nr_sets_prop    = "d-cache-sets",
>>          },
>>          {
>>                  .name            = "Instruction",
>>                  .size_prop       = "i-cache-size",
>>                  .line_size_props = { "i-cache-line-size",
>>                                       "i-cache-block-size", },
>>                  .nr_sets_prop    = "i-cache-sets",
>>          },
>> };
>>
>> and this function computes the the array index for any given cache type
>> define for PowerPC.
>>
>> static inline int get_cacheinfo_idx(enum cache_type type)
>> {
>>          if (type == CACHE_TYPE_UNIFIED)
>>                  return 0;
>>          else
>>                  return type;
>> }
>>
>> These types are define in include/linux/cacheinfo.h as
>>
>> enum cache_type {
>>          CACHE_TYPE_NOCACHE = 0,
>>          CACHE_TYPE_INST = BIT(0),		---> 1
>>          CACHE_TYPE_DATA = BIT(1),		---> 2
>>          CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA,
>>          CACHE_TYPE_UNIFIED = BIT(2),
>> };
>>
>> When it is UNIFIED we return index 0, which is correct. But the index
>> for instruction and data cache seems to be swapped which wrong. This
>> will fetch invalid properties for any given cache type.
>>

Ah, that's silly mistake on my side, will fix it.

>> I have done some initial review and testing for this patch's impact on
>> PowerPC (ppc64 POWER specifically). I am trying to do some code clean-up
>> and re-arrangements. Will post out soon. Thanks !

Thanks for taking time for testing and reviewing these patches.

>
> It does not work correctly on POWER.
>
> The new patchset adds some more attributes for every cache entry apart from
> what we used to have on PowerPC before. From the ABI perspective, the old ones
> should reflect the correct value in the same manner as before. Looks like
> the generic code will make any attribute as "Unknown" if the arch code does
> not populate them in the respective callback.
>

Yes this is on my list, I need to avoid populating the sysfs files with 
"Unknown" as value, will do that in next version.

> Here are some problems found on a POWER7 system
>
> (1) L1 instruction cache (cpu<N>/cache/index1/)
>
> 	====== Before patch ======
>
> 	coherency_line_size: 	128
> 	level:			1
> 	shared_cpu_map:		00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
>          			00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
> 				00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
> 				00000000,00000000,00000000,00000000,00000f00
> 	size:			32K
> 	type:			Instruction
>
> 	===== After patch ========
>
> 	coherency_line_size:	Unknown						----> Wrong
> 	level:			1
> 	shared_cpu_map:		00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
>          			00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
> 				00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
> 				00000000,00000000,00000000,00000000,00ffffff	----> Wrong
> 	size:			0K						----> Wrong
> 	type:			Instruction	
>
> (2) L3 cache (cpu<N>/cache/index3/)
>
> 	====== Before patch ======
>
> 	number_of_sets:		1
> 	size:			4096K
> 	ways_of_associativity:	0
>
> 	===== After patch ========
>
> 	number_of_sets:		1
> 	size:			4096K
> 	ways_of_associativity:	Unknown		----> Wrong
>
> Need to revisit this implementation on PowerPC and figure out the cause of these problems.
>

Yes, based on the logs you have provided, I will check for the root 
cause of these issues. I will get back with questions if I need 
clarifications.

Regards,
Sudeep


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

* Re: [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-03-10 11:12       ` Sudeep Holla
@ 2014-03-21  3:44         ` Anshuman Khandual
  2014-03-21 12:04           ` Sudeep Holla
  0 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2014-03-21  3:44 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-kernel, Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev

On 03/10/2014 04:42 PM, Sudeep Holla wrote:
> Hi Anshuman,
> 
> On 07/03/14 06:14, Anshuman Khandual wrote:
>> On 03/07/2014 09:36 AM, Anshuman Khandual wrote:
>>> On 02/19/2014 09:36 PM, Sudeep Holla wrote:
>>>> From: Sudeep Holla <sudeep.holla@arm.com>
>>>>
>>>> This patch removes the redundant sysfs cacheinfo code by making use of
>>>> the newly introduced generic cacheinfo infrastructure.
>>>>
>>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>>> Cc: Paul Mackerras <paulus@samba.org>
>>>> Cc: linuxppc-dev@lists.ozlabs.org
>>>> ---
>>>>   arch/powerpc/kernel/cacheinfo.c | 831
>>>> ++++++----------------------------------
>>>>   arch/powerpc/kernel/cacheinfo.h |   8 -
>>>>   arch/powerpc/kernel/sysfs.c     |   4 -
>>>>   3 files changed, 109 insertions(+), 734 deletions(-)
>>>>   delete mode 100644 arch/powerpc/kernel/cacheinfo.h
>>>>
>>>> diff --git a/arch/powerpc/kernel/cacheinfo.c
>>>> b/arch/powerpc/kernel/cacheinfo.c
>>>> index 2912b87..05b7580 100644
>>>> --- a/arch/powerpc/kernel/cacheinfo.c
>>>> +++ b/arch/powerpc/kernel/cacheinfo.c
>>>> @@ -10,38 +10,10 @@
>>>>    * 2 as published by the Free Software Foundation.
>>>>    */
>>>>
>>>> +#include <linux/cacheinfo.h>
>>>>   #include <linux/cpu.h>
>>>> -#include <linux/cpumask.h>
>>>>   #include <linux/kernel.h>
>>>> -#include <linux/kobject.h>
>>>> -#include <linux/list.h>
>>>> -#include <linux/notifier.h>
>>>>   #include <linux/of.h>
>>>> -#include <linux/percpu.h>
>>>> -#include <linux/slab.h>
>>>> -#include <asm/prom.h>
>>>> -
>>>> -#include "cacheinfo.h"
>>>> -
>>>> -/* per-cpu object for tracking:
>>>> - * - a "cache" kobject for the top-level directory
>>>> - * - a list of "index" objects representing the cpu's local cache
>>>> hierarchy
>>>> - */
>>>> -struct cache_dir {
>>>> -    struct kobject *kobj; /* bare (not embedded) kobject for cache
>>>> -                   * directory */
>>>> -    struct cache_index_dir *index; /* list of index objects */
>>>> -};
>>>> -
>>>> -/* "index" object: each cpu's cache directory has an index
>>>> - * subdirectory corresponding to a cache object associated with the
>>>> - * cpu.  This object's lifetime is managed via the embedded kobject.
>>>> - */
>>>> -struct cache_index_dir {
>>>> -    struct kobject kobj;
>>>> -    struct cache_index_dir *next; /* next index in parent directory */
>>>> -    struct cache *cache;
>>>> -};
>>>>
>>>>   /* Template for determining which OF properties to query for a given
>>>>    * cache type */
>>>> @@ -60,11 +32,6 @@ struct cache_type_info {
>>>>       const char *nr_sets_prop;
>>>>   };
>>>>
>>>> -/* These are used to index the cache_type_info array. */
>>>> -#define CACHE_TYPE_UNIFIED     0
>>>> -#define CACHE_TYPE_INSTRUCTION 1
>>>> -#define CACHE_TYPE_DATA        2
>>>> -
>>>>   static const struct cache_type_info cache_type_info[] = {
>>>>       {
>>>>           /* PowerPC Processor binding says the [di]-cache-*
>>>> @@ -77,246 +44,115 @@ static const struct cache_type_info
>>>> cache_type_info[] = {
>>>>           .nr_sets_prop    = "d-cache-sets",
>>>>       },
>>>>       {
>>>> -        .name            = "Instruction",
>>>> -        .size_prop       = "i-cache-size",
>>>> -        .line_size_props = { "i-cache-line-size",
>>>> -                     "i-cache-block-size", },
>>>> -        .nr_sets_prop    = "i-cache-sets",
>>>> -    },
>>>> -    {
>>>>           .name            = "Data",
>>>>           .size_prop       = "d-cache-size",
>>>>           .line_size_props = { "d-cache-line-size",
>>>>                        "d-cache-block-size", },
>>>>           .nr_sets_prop    = "d-cache-sets",
>>>>       },
>>>> +    {
>>>> +        .name            = "Instruction",
>>>> +        .size_prop       = "i-cache-size",
>>>> +        .line_size_props = { "i-cache-line-size",
>>>> +                     "i-cache-block-size", },
>>>> +        .nr_sets_prop    = "i-cache-sets",
>>>> +    },
>>>>   };
>>>
>>>
>>> Hey Sudeep,
>>>
>>> After applying this patch, the cache_type_info array looks like this.
>>>
>>> static const struct cache_type_info cache_type_info[] = {
>>>          {
>>>                  /*
>>>                   * PowerPC Processor binding says the [di]-cache-*
>>>                   * must be equal on unified caches, so just use
>>>                   * d-cache properties.
>>>                   */
>>>                  .name            = "Unified",
>>>                  .size_prop       = "d-cache-size",
>>>                  .line_size_props = { "d-cache-line-size",
>>>                                       "d-cache-block-size", },
>>>                  .nr_sets_prop    = "d-cache-sets",
>>>          },
>>>          {
>>>                  .name            = "Data",
>>>                  .size_prop       = "d-cache-size",
>>>                  .line_size_props = { "d-cache-line-size",
>>>                                       "d-cache-block-size", },
>>>                  .nr_sets_prop    = "d-cache-sets",
>>>          },
>>>          {
>>>                  .name            = "Instruction",
>>>                  .size_prop       = "i-cache-size",
>>>                  .line_size_props = { "i-cache-line-size",
>>>                                       "i-cache-block-size", },
>>>                  .nr_sets_prop    = "i-cache-sets",
>>>          },
>>> };
>>>
>>> and this function computes the the array index for any given cache type
>>> define for PowerPC.
>>>
>>> static inline int get_cacheinfo_idx(enum cache_type type)
>>> {
>>>          if (type == CACHE_TYPE_UNIFIED)
>>>                  return 0;
>>>          else
>>>                  return type;
>>> }
>>>
>>> These types are define in include/linux/cacheinfo.h as
>>>
>>> enum cache_type {
>>>          CACHE_TYPE_NOCACHE = 0,
>>>          CACHE_TYPE_INST = BIT(0),        ---> 1
>>>          CACHE_TYPE_DATA = BIT(1),        ---> 2
>>>          CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA,
>>>          CACHE_TYPE_UNIFIED = BIT(2),
>>> };
>>>
>>> When it is UNIFIED we return index 0, which is correct. But the index
>>> for instruction and data cache seems to be swapped which wrong. This
>>> will fetch invalid properties for any given cache type.
>>>
> 
> Ah, that's silly mistake on my side, will fix it.
> 
>>> I have done some initial review and testing for this patch's impact on
>>> PowerPC (ppc64 POWER specifically). I am trying to do some code clean-up
>>> and re-arrangements. Will post out soon. Thanks !
> 
> Thanks for taking time for testing and reviewing these patches.

Now that you got some of the problems to work on and resend the patches, I will
hold on to the clean up patches I had.


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

* Re: [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
  2014-03-21  3:44         ` Anshuman Khandual
@ 2014-03-21 12:04           ` Sudeep Holla
  0 siblings, 0 replies; 23+ messages in thread
From: Sudeep Holla @ 2014-03-21 12:04 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Sudeep Holla, linux-kernel, Benjamin Herrenschmidt,
	Paul Mackerras, linuxppc-dev

Hi Anshuman,

On 21/03/14 03:44, Anshuman Khandual wrote:
> On 03/10/2014 04:42 PM, Sudeep Holla wrote:
>> Hi Anshuman,
>>
>> On 07/03/14 06:14, Anshuman Khandual wrote:
>>> On 03/07/2014 09:36 AM, Anshuman Khandual wrote:
>>>> On 02/19/2014 09:36 PM, Sudeep Holla wrote:
>>>>> From: Sudeep Holla <sudeep.holla@arm.com>
>>>>>
>>>>> This patch removes the redundant sysfs cacheinfo code by making use of
>>>>> the newly introduced generic cacheinfo infrastructure.

[...]

>>>> When it is UNIFIED we return index 0, which is correct. But the index
>>>> for instruction and data cache seems to be swapped which wrong. This
>>>> will fetch invalid properties for any given cache type.
>>>>
>>
>> Ah, that's silly mistake on my side, will fix it.
>>
>>>> I have done some initial review and testing for this patch's impact on
>>>> PowerPC (ppc64 POWER specifically). I am trying to do some code clean-up
>>>> and re-arrangements. Will post out soon. Thanks !
>>
>> Thanks for taking time for testing and reviewing these patches.
> 
> Now that you got some of the problems to work on and resend the patches, I will
> hold on to the clean up patches I had.
> 

I have done most of the changes but still unable to find why the shared_cpu_map
is getting incorrect on PPC. All the other wrong entries are fixed. Any clue on
shared_cpu_map ?

Regards,
Sudeep


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

end of thread, other threads:[~2014-03-21 12:03 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-19 16:06 [PATCH RFC/RFT v3 0/9] drivers: cacheinfo support Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 1/9] drivers: base: add new class "cpu" to group cpu devices Sudeep Holla
2014-03-01  0:42   ` Greg Kroah-Hartman
2014-03-03  7:28     ` Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 2/9] drivers: base: support cpu cache information interface to userspace via sysfs Sudeep Holla
2014-03-01  0:42   ` Greg Kroah-Hartman
2014-03-03  7:39     ` Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 3/9] ia64: move cacheinfo sysfs to generic cacheinfo infrastructure Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 4/9] s390: " Sudeep Holla
2014-02-20  8:38   ` Heiko Carstens
2014-02-20 13:33     ` Sudeep Holla
2014-02-20 14:07       ` Heiko Carstens
2014-02-20 14:37         ` Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 5/9] x86: " Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 6/9] powerpc: " Sudeep Holla
2014-03-07  4:06   ` Anshuman Khandual
2014-03-07  6:14     ` Anshuman Khandual
2014-03-10 11:12       ` Sudeep Holla
2014-03-21  3:44         ` Anshuman Khandual
2014-03-21 12:04           ` Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 7/9] ARM64: kernel: add support for cpu cache information Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 8/9] ARM: " Sudeep Holla
2014-02-19 16:06 ` [PATCH RFC/RFT v3 9/9] ARM: kernel: add outer cache support for cacheinfo implementation Sudeep Holla

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).