]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: Add 3rd level cache info to /sys
authorchris hyser <chris.hyser@oracle.com>
Thu, 7 Apr 2016 19:32:48 +0000 (12:32 -0700)
committerAllen Pais <allen.pais@oracle.com>
Wed, 20 Apr 2016 16:34:08 +0000 (22:04 +0530)
This patch pulls line size and cache size info from the machine description and
adds l3 caches files to /sys/bus/cpu/devices/cpu* directories. It also
structures the information in the same directory hierachy as x86 so that user
programs like irqbalance can find the needed information to work correctly.

> ls /sys/bus/cpu/devices/cpu*
clock_tick           l1_dcache_size       l2_cache_line_size  l3_cache_size
crash_notes          l1_icache_line_size  l2_cache_size       node0
l1_dcache_line_size  l1_icache_size       l3_cache_line_size  topology

Sample results on a T7-4:

> cat /sys/bus/cpu/devices/cpu*/l3*
64
8388608

/sys/bus/cpu/devices/cpu*/cache/index0/:
coherency_line_size  level  shared_cpu_list  shared_cpu_map  size  type

/sys/bus/cpu/devices/cpu*/cache/index1/:
coherency_line_size  level  shared_cpu_list  shared_cpu_map  size  type

/sys/bus/cpu/devices/cpu*/cache/index2/:
coherency_line_size  level  shared_cpu_list  shared_cpu_map  size  type

/sys/bus/cpu/devices/cpu*/cache/index3/:
coherency_line_size  level  shared_cpu_list  shared_cpu_map  size  type

cat /sys/bus/cpu/devices/cpu32/cache/index3/*
64
3
32-63,128-223
0,ffffffff,ffffffff,ffffffff,00000000,00000000,ffffffff,00000000
8388608
Unified

Orabug: 22748950

Signed-off-by: Chris Hyser <chris.hyser@oracle.com>
arch/sparc/include/asm/cpudata_64.h
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/sysfs.c

index a6cfdabb6054aef28846342f49fdb2718e1263a5..ddc39405d17bc01b8f293a29a68550fe2d9a9a10 100644 (file)
@@ -19,11 +19,15 @@ typedef struct {
 
        /* Dcache line 2, rarely used */
        unsigned int    dcache_size;
-       unsigned int    dcache_line_size;
        unsigned int    icache_size;
-       unsigned int    icache_line_size;
        unsigned int    ecache_size;
-       unsigned int    ecache_line_size;
+       unsigned int    l3_cache_size;
+
+       unsigned short  icache_line_size;
+       unsigned short  dcache_line_size;
+       unsigned short  ecache_line_size;
+       unsigned short  l3_cache_line_size;
+
        unsigned short  sock_id;
        unsigned short  core_id;
        int             proc_id;
index 33bdfcba694f47de99277bcd414609e6ddbfd4b8..713c04d60f94885fda9ffd6c8b9956529bafbdb6 100644 (file)
@@ -792,6 +792,7 @@ static void fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_handle *hp, u64 mp)
        const u64 *line_size = mdesc_get_property(hp, mp, "line-size", NULL);
        const char *type;
        int type_len;
+       u64 a;
 
        type = mdesc_get_property(hp, mp, "type", &type_len);
 
@@ -811,20 +812,21 @@ static void fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_handle *hp, u64 mp)
                c->ecache_line_size = *line_size;
                break;
 
+       case 3:
+               c->l3_cache_size = *size;
+               c->l3_cache_line_size = *line_size;
+               break;
+
        default:
                break;
        }
 
-       if (*level == 1) {
-               u64 a;
-
-               mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
-                       u64 target = mdesc_arc_target(hp, a);
-                       const char *name = mdesc_node_name(hp, target);
+       mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+               u64 target = mdesc_arc_target(hp, a);
+               const char *name = mdesc_node_name(hp, target);
 
-                       if (!strcmp(name, "cache"))
-                               fill_in_one_cache(c, hp, target);
-               }
+               if (!strcmp(name, "cache"))
+                       fill_in_one_cache(c, hp, target);
        }
 }
 
index 7f41d40b7e6e8ccf89b5ce12a9422bbf4e84ac2e..3708a783d36998cfe67c55036ae7bbdcaaf1a04e 100644 (file)
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
  */
+#include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/cpu.h>
@@ -208,6 +209,8 @@ SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size);
 SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size);
 SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size);
 SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size);
+SHOW_CPUDATA_UINT_NAME(l3_cache_size, l3_cache_size);
+SHOW_CPUDATA_UINT_NAME(l3_cache_line_size, l3_cache_line_size);
 
 static struct device_attribute cpu_core_attrs[] = {
        __ATTR(clock_tick,          0444, show_clock_tick, NULL),
@@ -217,20 +220,254 @@ static struct device_attribute cpu_core_attrs[] = {
        __ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL),
        __ATTR(l2_cache_size,       0444, show_l2_cache_size, NULL),
        __ATTR(l2_cache_line_size,  0444, show_l2_cache_line_size, NULL),
+       __ATTR(l3_cache_size,       0444, show_l3_cache_size, NULL),
+       __ATTR(l3_cache_line_size,  0444, show_l3_cache_line_size, NULL),
 };
 
+
+#define to_object(k)    container_of(k, struct _index_kobject, kobj)
+#define to_attr(a)      container_of(a, struct _cache_attr, attr)
+
+struct _index_kobject {
+        struct kobject kobj;
+        unsigned int cpu;
+        unsigned short index;
+};
+
+struct _cache_attr {
+        struct attribute attr;
+       ssize_t (*show)(struct _index_kobject *ca, char *buf);
+       ssize_t (*store)(struct _index_kobject *ca, const char *buf, size_t cnt);
+};
+
+
+static ssize_t show_level(struct _index_kobject *iko, char *buf)
+{
+       return sprintf(buf, "%d\n", iko->index);
+}
+
+static ssize_t show_size(struct _index_kobject *iko, char *buf)
+{
+       int size = 0;
+       cpuinfo_sparc *c = &cpu_data(iko->cpu);
+
+       switch (iko->index) {
+       case 0:
+               size = c->dcache_size;
+               break;
+       case 1:
+               size = c->icache_size;
+               break;
+       case 2:
+               size = c->ecache_size;
+               break;
+       case 3:
+               size = c->l3_cache_size;
+               break;
+       }
+
+       return sprintf(buf, "%d\n", size);
+}
+
+static ssize_t show_line_size(struct _index_kobject *iko, char *buf)
+{
+       int size = 0;
+       cpuinfo_sparc *c = &cpu_data(iko->cpu);
+
+       switch (iko->index) {
+       case 0:
+               size = c->dcache_line_size;
+               break;
+       case 1:
+               size = c->icache_line_size;
+               break;
+       case 2:
+               size = c->ecache_line_size;
+               break;
+       case 3:
+               size = c->l3_cache_line_size;
+               break;
+       }
+
+       return sprintf(buf, "%d\n", size);
+}
+
+static ssize_t show_shared_cpu_map_func(struct _index_kobject *iko, int type,
+                                       char *buf)
+{
+       const struct cpumask *mask;
+       cpumask_t cpu_map;
+
+
+        ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
+        int n = 0;
+
+       if (len < 2)
+               return 0;
+
+       switch (iko->index) {
+       case 2:
+               mask = &cpu_core_map[iko->cpu];
+               break;
+       case 3:
+               mask = &cpu_core_sib_map[iko->cpu];
+               break;
+       default:
+               cpumask_clear(&cpu_map);
+               cpumask_set_cpu(iko->cpu, &cpu_map);
+               mask = &cpu_map;
+               break;
+       }
+
+       n = type ?
+               scnprintf(buf, len-2, "%*pbl", NR_CPUS, mask) :
+               scnprintf(buf, len-2, "%*pb", NR_CPUS, mask);
+
+       buf[n++] = '\n';
+       buf[n] = '\0';
+        return n;
+}
+
+static ssize_t show_shared_cpu_map(struct _index_kobject *iko, char *buf)
+{
+       return show_shared_cpu_map_func(iko, 0, buf);
+}
+
+static ssize_t show_shared_cpu_list(struct _index_kobject *iko, char *buf)
+{
+       return show_shared_cpu_map_func(iko, 1, buf);
+}
+
+static ssize_t show_type(struct _index_kobject *iko, char *buf)
+{
+       switch (iko->index) {
+       case 0:
+               return sprintf(buf, "DATA\n");
+       case 1:
+               return sprintf(buf, "Instruction\n");
+       default:
+               return sprintf(buf, "Unified\n");
+       }
+}
+
+#define define_one_ro(_name) \
+static struct _cache_attr _name = \
+        __ATTR(_name, 0444, show_##_name, NULL)
+
+static struct _cache_attr level = __ATTR(level, 0444, show_level, NULL);
+static struct _cache_attr coherency_line_size = __ATTR(coherency_line_size, 0444, show_line_size, NULL);
+static struct _cache_attr size = __ATTR(size, 0444, show_size, NULL);
+static struct _cache_attr type = __ATTR(type, 0444, show_type, NULL);
+static struct _cache_attr shared_cpu_map = __ATTR(shared_cpu_map, 0444, show_shared_cpu_map, NULL);
+static struct _cache_attr shared_cpu_list = __ATTR(shared_cpu_list, 0444, show_shared_cpu_list, NULL);
+
+static struct attribute *default_attrs[] = {
+        &type.attr,
+        &level.attr,
+        &coherency_line_size.attr,
+        &size.attr,
+        &shared_cpu_map.attr,
+        &shared_cpu_list.attr,
+        NULL
+};
+
+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(this_leaf, buf) : 0;
+        return ret;
+}
+
+static ssize_t store(struct kobject *kobj, struct attribute *attr,
+                     const char *buf, size_t count)
+{
+        return 0;
+}
+
+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,
+};
+
+#define MAX_CACHE_LEVEL 4  /* max level plus one for both I and D */
+
+static struct kobject *cache_kobjs[4096];
+static struct _index_kobject *index_kobjs[4096];
+
+static int init_kobjs(unsigned int cpu)
+{
+        /* Allocate all required memory */
+        cache_kobjs[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+        if (unlikely(cache_kobjs[cpu] == NULL))
+                goto err_out;
+
+        index_kobjs[cpu] = kzalloc(sizeof(struct _index_kobject) * MAX_CACHE_LEVEL, GFP_KERNEL);
+        if (unlikely(index_kobjs[cpu] == NULL))
+                goto err_out;
+
+        return 0;
+
+err_out:
+        return -1;
+}
+
+#define INDEX_KOBJECT_PTR(x, y)         (&((index_kobjs[x])[y]))
+
+
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
-static void register_cpu_online(unsigned int cpu)
+static int register_cpu_online(unsigned int cpu)
 {
        struct cpu *c = &per_cpu(cpu_devices, cpu);
        struct device *s = &c->dev;
-       int i;
+       struct _index_kobject *this_object;
+       int i, j;
+       int retval;
 
        for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++)
                device_create_file(s, &cpu_core_attrs[i]);
 
        register_mmu_stats(s);
+
+       init_kobjs(cpu);
+
+        retval = kobject_init_and_add(cache_kobjs[cpu], &ktype_percpu_entry,
+                                      &s->kobj, "%s", "cache");
+
+        for (i = 0; i < MAX_CACHE_LEVEL; i++) {
+                this_object = INDEX_KOBJECT_PTR(cpu, i);
+                this_object->cpu = cpu;
+                this_object->index = i;
+
+                ktype_cache.default_attrs = default_attrs;
+
+                retval = kobject_init_and_add(&(this_object->kobj),
+                                              &ktype_cache,
+                                              cache_kobjs[cpu],
+                                              "index%1d", i);
+                if (unlikely(retval)) {
+                        for (j = 0; j < i; j++)
+                                kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
+                        kobject_put(cache_kobjs[cpu]);
+                        return retval;
+                }
+                kobject_uevent(&(this_object->kobj), KOBJ_ADD);
+        }
+
+        kobject_uevent(cache_kobjs[cpu], KOBJ_ADD);
+       return 0;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU