[PATCH 09/10] soc: fujitsu: hwb: Add sysfs entry
From: Misono Tomohiro <hidden>
Date: 2021-01-08 10:26:59
Subsystem:
the rest · Maintainer:
Linus Torvalds
This adds sysfs entry per CMG to show running barrier driver status
for debugging user application. The following entries will be created:
/sys/class/misc/fujitsu_hwb
|- hwinfo ... number of CMG/BB/BW/pe_per_cmg on running system
|- CMG0
|- core_map ... cpuid belonging to this CMG
|- used_bb_bmap ... bitmap of currently allocated BB
|- used_bw_bmap ... bitmap of currently allocated BW
|- init_sync_bb0 ... current value of INIT_SYNC register 0
|- init_sync_bb1 ... current value of INIT_SYNC register 1
...
|- CMG1
...
Signed-off-by: Misono Tomohiro <redacted>
---
drivers/soc/fujitsu/fujitsu_hwb.c | 258 ++++++++++++++++++++++++++++++
1 file changed, 258 insertions(+)
diff --git a/drivers/soc/fujitsu/fujitsu_hwb.c b/drivers/soc/fujitsu/fujitsu_hwb.c
index 46f1f244f93a..a3a0e314f63a 100644
--- a/drivers/soc/fujitsu/fujitsu_hwb.c
+++ b/drivers/soc/fujitsu/fujitsu_hwb.c@@ -32,6 +32,7 @@ #include <linux/cpu.h> #include <linux/cpumask.h> #include <linux/kernel.h> +#include <linux/kobject.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/spinlock.h>
@@ -931,6 +932,254 @@ static int hwb_cpu_online(unsigned int cpu) return 0; } +static void read_init_sync_reg(void *args) +{ + struct init_sync_args *sync_args = (struct init_sync_args *)args; + u64 val = 0; + + switch (sync_args->bb) { + case 0: + val = read_sysreg_s(FHWB_INIT_SYNC_BB0_EL1); + break; + case 1: + val = read_sysreg_s(FHWB_INIT_SYNC_BB1_EL1); + break; + case 2: + val = read_sysreg_s(FHWB_INIT_SYNC_BB2_EL1); + break; + case 3: + val = read_sysreg_s(FHWB_INIT_SYNC_BB3_EL1); + break; + case 4: + val = read_sysreg_s(FHWB_INIT_SYNC_BB4_EL1); + break; + case 5: + val = read_sysreg_s(FHWB_INIT_SYNC_BB5_EL1); + break; + } + + sync_args->val = val; +} + +struct hwb_attr { + struct kobj_attribute attr; + u8 bb; +}; +static struct hwb_attr *battr; + +/* kobject for each CMG */ +static struct kobject **cmg_kobj; + +/* Get CMG number based on index value of cmg_kobj */ +static int get_cmg_from_kobj(struct kobject *kobj) +{ + int i; + + for (i = 0; i < _hwinfo.num_cmg; i++) { + if (cmg_kobj[i] == kobj) + return i; + } + /* should not happen */ + WARN_ON_ONCE("cmg_kobj not found\n"); + return 0; +} + +static ssize_t hwb_init_sync_bb_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct hwb_attr *battr = container_of(attr, struct hwb_attr, attr); + struct init_sync_args args = {0}; + ssize_t written = 0; + int cpu; + int cmg; + u64 mask; + u64 bst; + + /* Find online cpu in target cmg */ + cmg = get_cmg_from_kobj(kobj); + for_each_online_cpu(cpu) { + if (_hwinfo.core_map[cpu].cmg == cmg) + break; + } + if (cpu >= nr_cpu_ids) + return 0; + + /* Send IPI to read INIT_SYNC register */ + args.bb = battr->bb; + on_each_cpu_mask(cpumask_of(cpu), read_init_sync_reg, &args, 1); + + mask = FIELD_GET(FHWB_INIT_SYNC_BB_EL1_MASK_FIELD, args.val); + bst = FIELD_GET(FHWB_INIT_SYNC_BB_EL1_BST_FIELD, args.val); + + written += scnprintf(buf, PAGE_SIZE, "%04llx\n", mask); + written += scnprintf(buf + written, PAGE_SIZE - written, "%04llx\n", bst); + + return written; +} + +#define BARRIER_ATTR(name) \ +static struct kobj_attribute hwb_##name##_attribute = \ + __ATTR(name, 0444, hwb_##name##_show, NULL) + +static ssize_t hwb_hwinfo_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d %d %d %d\n", + _hwinfo.num_cmg, _hwinfo.num_bb, + _hwinfo.num_bw, _hwinfo.max_pe_per_cmg); +} +BARRIER_ATTR(hwinfo); + +static ssize_t hwb_used_bb_bmap_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int cmg; + + cmg = get_cmg_from_kobj(kobj); + + return scnprintf(buf, PAGE_SIZE, "%04lx\n", _hwinfo.used_bb_bmap[cmg]); +} +BARRIER_ATTR(used_bb_bmap); + +static ssize_t hwb_used_bw_bmap_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t written = 0; + int cmg; + int cpu; + + cmg = get_cmg_from_kobj(kobj); + for (cpu = 0; cpu < num_possible_cpus(); cpu++) { + if (_hwinfo.core_map[cpu].cmg == cmg) + written += scnprintf(buf + written, PAGE_SIZE - written, "%d %04lx\n", + cpu, _hwinfo.used_bw_bmap[cpu]); + } + + return written; +} +BARRIER_ATTR(used_bw_bmap); + +static ssize_t hwb_core_map_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t written = 0; + int cmg; + int cpu; + + cmg = get_cmg_from_kobj(kobj); + for (cpu = 0; cpu < num_possible_cpus(); cpu++) { + if (_hwinfo.core_map[cpu].cmg == cmg) + written += scnprintf(buf + written, PAGE_SIZE - written, "%d %d\n", + cpu, _hwinfo.core_map[cpu].ppe); + } + + return written; +} +BARRIER_ATTR(core_map); + +static struct attribute *hwb_attrs[] = { + &hwb_used_bb_bmap_attribute.attr, + &hwb_used_bw_bmap_attribute.attr, + &hwb_core_map_attribute.attr, + NULL, +}; + +static const struct attribute_group hwb_attribute = { + .attrs = hwb_attrs, +}; + +static void destroy_sysfs(void) +{ + int cmg; + int bb; + int i; + + sysfs_remove_file(&bar_miscdev.this_device->kobj, &hwb_hwinfo_attribute.attr); + + for (cmg = 0; cmg < _hwinfo.num_cmg; cmg++) { + for (bb = 0; bb < _hwinfo.num_bb; bb++) { + i = (cmg * _hwinfo.num_bb) + bb; + if (battr[i].attr.attr.name) + sysfs_remove_file(cmg_kobj[cmg], &battr[i].attr.attr); + } + } + kfree(battr); + + for (cmg = 0; cmg < _hwinfo.num_cmg; cmg++) { + if (cmg_kobj[cmg]) { + sysfs_remove_group(cmg_kobj[cmg], &hwb_attribute); + kobject_put(cmg_kobj[cmg]); + } + } + kfree(cmg_kobj); +} + +/* Create sysfs file under /sys/class/misc/fujitsu_hwb */ +#define NAME_LEN 16 +static int __init init_sysfs(void) +{ + char name[NAME_LEN]; + int ret; + int cmg; + int bb; + int i; + + /* Create file to show number of CMG/BB/BW/pe_per_cmg */ + ret = sysfs_create_file(&bar_miscdev.this_device->kobj, &hwb_hwinfo_attribute.attr); + if (ret) + return ret; + + cmg_kobj = kcalloc(_hwinfo.num_cmg, sizeof(struct kobject *), GFP_KERNEL); + battr = kcalloc(_hwinfo.num_cmg * _hwinfo.num_bb, sizeof(struct hwb_attr), GFP_KERNEL); + if (!cmg_kobj || !battr) { + kfree(cmg_kobj); + kfree(battr); + return -ENOMEM; + } + + /* Create folder for each CMG and create core_map/bitmap file */ + for (cmg = 0; cmg < _hwinfo.num_cmg; cmg++) { + scnprintf(name, NAME_LEN, "CMG%d", cmg); + cmg_kobj[cmg] = kobject_create_and_add(name, &bar_miscdev.this_device->kobj); + if (!cmg_kobj[cmg]) { + ret = -ENOMEM; + goto fail; + } + + ret = sysfs_create_group(cmg_kobj[cmg], &hwb_attribute); + if (ret) + goto fail; + } + + /* Create files for INIT_SYNC register */ + for (cmg = 0; cmg < _hwinfo.num_cmg; cmg++) { + for (bb = 0; bb < _hwinfo.num_bb; bb++) { + i = (cmg * _hwinfo.num_bb) + bb; + + scnprintf(name, NAME_LEN, "init_sync_bb%d", bb); + battr[i].bb = bb; + battr[i].attr.attr.name = kstrdup(name, GFP_KERNEL); + if (!battr[i].attr.attr.name) { + ret = -ENOMEM; + goto fail; + } + battr[i].attr.attr.mode = 0400; /* root only */ + battr[i].attr.show = hwb_init_sync_bb_show; + + sysfs_attr_init(&battr[i].attr.attr); + ret = sysfs_create_file(cmg_kobj[cmg], &battr[i].attr.attr); + if (ret < 0) + goto fail; + } + } + + return 0; + +fail: + destroy_sysfs(); + return ret; +} + static int __init hwb_init(void) { int ret;
@@ -967,8 +1216,16 @@ static int __init hwb_init(void) goto out3; } + ret = init_sysfs(); + if (ret < 0) { + pr_err("sysfs creation failed: %d\n", ret); + goto out4; + } + return 0; +out4: + misc_deregister(&bar_miscdev); out3: cpuhp_remove_state(_hp_state); out2:
@@ -981,6 +1238,7 @@ static int __init hwb_init(void) static void __exit hwb_exit(void) { + destroy_sysfs(); misc_deregister(&bar_miscdev); cpuhp_remove_state(_hp_state); destroy_bb_info_cachep();
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel