From d49b72c0afd9113716515378e8c6d5987b41a5e6 Mon Sep 17 00:00:00 2001 From: chris hyser Date: Thu, 7 Apr 2016 12:32:48 -0700 Subject: [PATCH] sparc64: Add 3rd level cache info to /sys 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 --- arch/sparc/include/asm/cpudata_64.h | 10 +- arch/sparc/kernel/mdesc.c | 20 +-- arch/sparc/kernel/sysfs.c | 241 +++++++++++++++++++++++++++- 3 files changed, 257 insertions(+), 14 deletions(-) diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index a6cfdabb6054..ddc39405d17b 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -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; diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 33bdfcba694f..713c04d60f94 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -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); } } diff --git a/arch/sparc/kernel/sysfs.c b/arch/sparc/kernel/sysfs.c index 7f41d40b7e6e..3708a783d369 100644 --- a/arch/sparc/kernel/sysfs.c +++ b/arch/sparc/kernel/sysfs.c @@ -2,6 +2,7 @@ * * Copyright (C) 2007 David S. Miller */ +#include #include #include #include @@ -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 -- 2.50.1