diff --git a/Makefile b/Makefile index 5c8014ae2613429194c8bbf6eed3e797dfba6594..4bac84cda0fae24db3d5572c526aab1a96a0e2d5 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,8 @@ BUILD ?= /lib/modules/`uname -r`/build obj-m := prefetch_tuning.o -EXTRA_CFLAGS += -Wall -Werror +prefetch_tuning-objs := prefetch_reg.o prefetch_mod.o +EXTRA_CFLAGS += -Wall -Werror -I./ .PHONY : all all: diff --git a/prefetch_mod.c b/prefetch_mod.c new file mode 100644 index 0000000000000000000000000000000000000000..d8dfe950ad365ea89ada345b45a40ac2d1db88e1 --- /dev/null +++ b/prefetch_mod.c @@ -0,0 +1,277 @@ + // SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2019 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "prefetch_mod.h" + +#ifndef is_affinity_mask_valid +#define is_affinity_mask_valid(val) 1 +#endif + +static cpumask_var_t prefetch_cpumask_value; +static cfg_t __percpu *cur_cfg; +static cfg_t __percpu *old_cfg; +static DEFINE_MUTEX(prefetch_mtx); + +static ssize_t read_unique_store(struct device* dev, + struct device_attribute* attr, const char* buf, size_t count); +static ssize_t read_unique_show(struct device* dev, + struct device_attribute* attr, char* buf); +static ssize_t prefetch_store(struct device* dev, + struct device_attribute* attr, const char* buf, size_t count); +static ssize_t prefetch_show(struct device* dev, + struct device_attribute* attr, char* buf); +static ssize_t prefetch_mask_store(struct device* dev, + struct device_attribute* attr, const char* buf, size_t count); +static ssize_t prefetch_mask_show(struct device* dev, + struct device_attribute* attr, char* buf); + +/* Device create */ +static DEVICE_ATTR(read_unique, S_IRUGO|S_IWUSR, + read_unique_show, read_unique_store); + +static DEVICE_ATTR(policy, S_IRUGO|S_IWUSR, + prefetch_show, prefetch_store); + +static DEVICE_ATTR(cpumask, S_IRUGO|S_IWUSR, + prefetch_mask_show, prefetch_mask_store); + + +static struct attribute *prefetch_attrs[] = { + &dev_attr_policy.attr, + &dev_attr_cpumask.attr, + &dev_attr_read_unique.attr, + NULL, +}; + +static const struct attribute_group prefetch_attr_group = { + .attrs = prefetch_attrs, +}; + +static const struct attribute_group *attr_groups[] = { + &prefetch_attr_group, + NULL, +}; + +static struct miscdevice misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "prefetch", + .groups = attr_groups, +}; + +/* 0--close, 1--open */ +static ssize_t read_unique_store(struct device* dev, + struct device_attribute* attr, const char* buf, size_t count) +{ + ssize_t ret = -1; + int value = -1; + + ret = kstrtouint(buf, 0, &value); + if (ret || (value != 0 && value != 1)) { + pr_err("invalid input(0-close,1-open,other-invalid)!\n"); + return count; + } + + mutex_lock(&prefetch_mtx); + on_each_cpu_mask(prefetch_cpumask_value, read_unique_set, &value, 1); + mutex_unlock(&prefetch_mtx); + + return count; +} + +static ssize_t read_unique_show(struct device* dev, + struct device_attribute* attr, char* buf) +{ + int cpu = -1; + int count = 0; + + int __percpu *cur = alloc_percpu(int); + if (!cur) { + pr_err("alloc_percpu fail\n"); + return -ENOMEM; + } + mutex_lock(&prefetch_mtx); + on_each_cpu_mask(prefetch_cpumask_value, read_unique_get, cur, 1); + + for_each_cpu(cpu, prefetch_cpumask_value) { + int *ptr = per_cpu_ptr(cur, cpu); + count += scnprintf(buf + count, PAGE_SIZE, "cpu(%d): %s.\n", + cpu, (ptr == NULL) ? "n/a" : ((*ptr == 0) ? "close" : "open")); + } + mutex_unlock(&prefetch_mtx); + free_percpu(cur); + return count; +} + + +static ssize_t prefetch_store(struct device* dev, + struct device_attribute* attr, const char* buf, size_t count) +{ + ssize_t ret = -1; + int policy = -1; + + ret = kstrtouint(buf, 0, &policy); + if (ret) { + pr_err("invalid input\n"); + return count; + } + + mutex_lock(&prefetch_mtx); + if (policy < prefetch_policy_num()) { + on_each_cpu_mask(prefetch_cpumask_value, set_prefetch, &policy, 1); + } else { + pr_err("policy %d is out of range\n", policy); + } + mutex_unlock(&prefetch_mtx); + + return count; +} + +static ssize_t prefetch_show(struct device* dev, + struct device_attribute* attr, char* buf) +{ + int cpu = -1; + int policy = -1; + int count = 0; + + mutex_lock(&prefetch_mtx); + on_each_cpu_mask(prefetch_cpumask_value, get_prefetch, cur_cfg, 1); + for_each_cpu(cpu, prefetch_cpumask_value) { + cfg_t *this_cfg = per_cpu_ptr(cur_cfg, cpu); + for (policy = prefetch_policy_num() - 1; policy >= 0; policy--) { + if (!memcmp(prefetch_policy(policy), this_cfg, sizeof(cfg_t))) + break; + } + count += scnprintf(buf + count, PAGE_SIZE, "cpu(%d): %d\n", + cpu, policy); + } + mutex_unlock(&prefetch_mtx); + + return count; +} + +static ssize_t prefetch_mask_store(struct device* dev, + struct device_attribute* attr, const char* buf, size_t count) +{ + int ret = -1; + + mutex_lock(&prefetch_mtx); + ret = cpulist_parse(buf, prefetch_cpumask_value); + if (ret) { + pr_err("cpulist_parse error: %d\n", ret); + goto prefetch_mask_end; + } + + if (!is_affinity_mask_valid(prefetch_cpumask_value)) { + pr_err("mask value error\n"); + goto prefetch_mask_end; + } + +prefetch_mask_end: + mutex_unlock(&prefetch_mtx); + return count; +} + +static ssize_t prefetch_mask_show(struct device* dev, + struct device_attribute* attr, char* buf) +{ + ssize_t ret = -1; + mutex_lock(&prefetch_mtx); + ret = cpumap_print_to_pagebuf(true, buf, prefetch_cpumask_value); + mutex_unlock(&prefetch_mtx); + return ret; +} + +/* + * prefetch policy, can be 0~15: + * 0: disable; 1~15: different thresholds for sms,amop algrithom; + */ + + +static int __init prefetch_init(void) +{ + int ret = -1; + int cpu = -1; + /* mask: initial a mask */ + if (!alloc_cpumask_var(&prefetch_cpumask_value, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_mask_alloc; + } + + cpumask_clear(prefetch_cpumask_value); + for_each_online_cpu(cpu) + cpumask_set_cpu(cpu, prefetch_cpumask_value); + + if (!is_affinity_mask_valid(prefetch_cpumask_value)) { + pr_err("incalid affinity_mask\n"); + ret = -EINVAL; + goto err_mask_init; + } + + cur_cfg = alloc_percpu(cfg_t); + if (!cur_cfg) { + pr_err("alloc_percpu fail\n"); + ret = -ENOMEM; + goto err_mask_init; + } + + old_cfg = alloc_percpu(cfg_t); + if (!old_cfg) { + pr_err("alloc_percpu fail\n"); + ret = -ENOMEM; + goto err_cfg_alloc; + } + + on_each_cpu(get_prefetch, old_cfg, 1); + + /* initial prefetch misc and initial prefetch_ops */ + ret = misc_register(&misc); + if (ret < 0) { + pr_err("misc register fail\n"); + goto err_misc_reg; + } + + return 0; + +err_misc_reg: + free_percpu(old_cfg); +err_cfg_alloc: + free_percpu(cur_cfg); +err_mask_init: + free_cpumask_var(prefetch_cpumask_value); +err_mask_alloc: + return ret; +} + +static void __exit prefetch_exit(void) +{ + misc_deregister(&misc); + on_each_cpu(reset_prefetch, old_cfg, 1); + free_percpu(old_cfg); + free_percpu(cur_cfg); + free_cpumask_var(prefetch_cpumask_value); +} + +module_init(prefetch_init); +module_exit(prefetch_exit); +MODULE_LICENSE("GPL"); diff --git a/prefetch_mod.h b/prefetch_mod.h new file mode 100644 index 0000000000000000000000000000000000000000..387323f9478fa5e4b1b53874fb73aa7b67ddb9a9 --- /dev/null +++ b/prefetch_mod.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2019 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * Create: 2020-07-02 + * Author: Liqiang (liqiang9102@gitee) + */ +#ifndef __PREFETCH_TUNING__ +#define __PREFETCH_TUNING__ + +enum { + DISABLE = 0, + ENABLE +}; + +#define CACHE_READUNIQ_CTRL (1L << 40) + +#ifdef CONFIG_ARCH_HISI +typedef struct { + long cpuprefctrl_el1; + long adps_lld_ddr_el1; + long adpp_l1v_mop_el1; + long adps_lld_l3_el1; +} cfg_t; +#else +typedef long cfg_t; +#endif + +extern void set_prefetch(void* dummy); +extern void get_prefetch(void* dummy); +extern void read_unique_set(void *dummy); +extern void read_unique_get(void *dummy); +extern void reset_prefetch(void* dummy); + +extern int prefetch_policy_num(void); +extern cfg_t *prefetch_policy(int policy); + +#endif diff --git a/prefetch_reg.c b/prefetch_reg.c new file mode 100644 index 0000000000000000000000000000000000000000..ab393f2bdf02fb1659eb5e646fd6a3aba99c5b94 --- /dev/null +++ b/prefetch_reg.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2019 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * Create: 2020-07-02 + * Author: Liqiang (liqiang9102@gitee) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "prefetch_mod.h" + +#ifdef CONFIG_ARCH_HISI +#define PREFETCH_POLICY_MAX 15 +static cfg_t prefetch_cfg[] = { + [0] = {.cpuprefctrl_el1 = 0x112f8127f, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [1] = {.cpuprefctrl_el1 = 0x112f81254, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [2] = {.cpuprefctrl_el1 = 0x112f81254, + .adps_lld_ddr_el1 = 0x4d34a200, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [3] = {.cpuprefctrl_el1 = 0xb52f81254, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [4] = {.cpuprefctrl_el1 = 0x112f81254, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29080082a880, + .adps_lld_l3_el1 = 0x65965700}, + [5] = {.cpuprefctrl_el1 = 0x3012f81254, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29080082a880, + .adps_lld_l3_el1 = 0x65965700}, + [6] = {.cpuprefctrl_el1 = 0x3012f81254, + .adps_lld_ddr_el1 = 0x4d142000, + .adpp_l1v_mop_el1 = 0x29080082a880, + .adps_lld_l3_el1 = 0x65965700}, + [7] = {.cpuprefctrl_el1 = 0x3012f81254, + .adps_lld_ddr_el1 = 0x4d142000, + .adpp_l1v_mop_el1 = 0x29080082a880, + .adps_lld_l3_el1 = 0x4d145100}, + [8] = {.cpuprefctrl_el1 = 0x4112f81254, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [9] = {.cpuprefctrl_el1 = 0x112f81260, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [10] = {.cpuprefctrl_el1 = 0x112f81260, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x658e5700}, + [11] = {.cpuprefctrl_el1 = 0x3412f81254, + .adps_lld_ddr_el1 = 0x4d142000, + .adpp_l1v_mop_el1 = 0x29080082a880, + .adps_lld_l3_el1 = 0x65965700}, + [12] = {.cpuprefctrl_el1 = 0x3412F81260, + .adps_lld_ddr_el1 = 0x4d12000, + .adpp_l1v_mop_el1 = 0x29080082a880, + .adps_lld_l3_el1 = 0x65965700}, + [13] = {.cpuprefctrl_el1 = 0x112f81240, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [14] = {.cpuprefctrl_el1 = 0x112f81240, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x69154332a840, + .adps_lld_l3_el1 = 0x65965700}, + [15] = {.cpuprefctrl_el1 = 0x80110f81380, + .adps_lld_ddr_el1 = 0x6554a000, + .adpp_l1v_mop_el1 = 0x29154332a840, + .adps_lld_l3_el1 = 0x65965700}, +}; + +void set_prefetch(void* dummy) +{ + cfg_t *cfg = NULL; + int policy = *(int *)dummy; + unsigned long read_uniq = read_sysreg(S3_1_c15_c6_4); + if (policy < 0 || policy > PREFETCH_POLICY_MAX) + return; + cfg = &prefetch_cfg[policy]; + read_uniq &= CACHE_READUNIQ_CTRL; + write_sysreg(cfg->cpuprefctrl_el1 | read_uniq, S3_1_c15_c6_4); + write_sysreg(cfg->adps_lld_ddr_el1, S3_1_c15_c7_1); + write_sysreg(cfg->adpp_l1v_mop_el1, S3_1_c15_c6_5); + write_sysreg(cfg->adps_lld_l3_el1, S3_1_c15_c7_0); + return; +} + +void get_prefetch(void* dummy) +{ + cfg_t *pcfg = this_cpu_ptr((cfg_t __percpu *)dummy); + pcfg->cpuprefctrl_el1 = read_sysreg(S3_1_c15_c6_4); + pcfg->adps_lld_ddr_el1 = read_sysreg(S3_1_c15_c7_1); + pcfg->adpp_l1v_mop_el1 = read_sysreg(S3_1_c15_c6_5); + pcfg->adps_lld_l3_el1 = read_sysreg(S3_1_c15_c7_0); + + /* Ignore READUNIQ bit */ + pcfg->cpuprefctrl_el1 &= ~(CACHE_READUNIQ_CTRL); + return; +} + +void read_unique_set(void *dummy) +{ + int *value = (int *)dummy; + if (*value == ENABLE) + sysreg_clear_set(S3_1_c15_c6_4, 0, CACHE_READUNIQ_CTRL); + else if (*value == DISABLE) + sysreg_clear_set(S3_1_c15_c6_4, CACHE_READUNIQ_CTRL, 0); + + return; +} + +static const u64 readUniqueOffset = 40; +void read_unique_get(void *dummy) +{ + int *value = this_cpu_ptr((int __percpu *)dummy); + u64 reg_value = read_sysreg(S3_1_c15_c6_4); + *value = (reg_value >> readUniqueOffset) & 0x1; + return; +} +#else +#define PREFETCH_POLICY_MAX 0 +static cfg_t prefetch_cfg[] = {}; + +void set_prefetch(void* dummy) +{ + return; +} + +void get_prefetch(void* dummy) +{ + return; +} + +void read_unique_set(void *dummy) +{ + return; +} + +void read_unique_get(void *dummy) +{ + return; +} +#endif + +int prefetch_policy_num(void) +{ + return ARRAY_SIZE(prefetch_cfg); +} + +cfg_t *prefetch_policy(int policy) +{ + if (policy < 0 || policy > PREFETCH_POLICY_MAX) + return NULL; + return &prefetch_cfg[policy]; +} + +void reset_prefetch(void* dummy) +{ + cfg_t *pcfg = this_cpu_ptr((cfg_t __percpu *)dummy); + set_prefetch(pcfg); +} + +MODULE_LICENSE("GPL"); diff --git a/prefetch_tuning.c b/prefetch_tuning.c deleted file mode 100644 index 96341ca1e78c8e45c6198e8c3a0715c8ac042b7d..0000000000000000000000000000000000000000 --- a/prefetch_tuning.c +++ /dev/null @@ -1,377 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2019 Huawei Technologies Co., Ltd - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef is_affinity_mask_valid -#define is_affinity_mask_valid(val) 1 -#endif - -#ifdef CONFIG_ARCH_HISI -typedef struct { - long cpuprefctrl_el1; - long adps_lld_ddr_el1; - long adpp_l1v_mop_el1; - long adps_lld_l3_el1; -} cfg_t; -#else -typedef long cfg_t; -#endif - -static cpumask_var_t mask_value; -cfg_t __percpu *cur_cfg; -cfg_t __percpu *old_cfg; -static DEFINE_MUTEX(prefetch_mtx); - -#ifdef CONFIG_ARCH_HISI -static cfg_t cfg[] = { - [0] = {.cpuprefctrl_el1 = 0x112f8127f, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [1] = {.cpuprefctrl_el1 = 0x112f81254, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [2] = {.cpuprefctrl_el1 = 0x112f81254, - .adps_lld_ddr_el1 = 0x4d34a200, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [3] = {.cpuprefctrl_el1 = 0xb52f81254, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [4] = {.cpuprefctrl_el1 = 0x112f81254, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29080082a880, - .adps_lld_l3_el1 = 0x65965700}, - [5] = {.cpuprefctrl_el1 = 0x3012f81254, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29080082a880, - .adps_lld_l3_el1 = 0x65965700}, - [6] = {.cpuprefctrl_el1 = 0x3012f81254, - .adps_lld_ddr_el1 = 0x4d142000, - .adpp_l1v_mop_el1 = 0x29080082a880, - .adps_lld_l3_el1 = 0x65965700}, - [7] = {.cpuprefctrl_el1 = 0x3012f81254, - .adps_lld_ddr_el1 = 0x4d142000, - .adpp_l1v_mop_el1 = 0x29080082a880, - .adps_lld_l3_el1 = 0x4d145100}, - [8] = {.cpuprefctrl_el1 = 0x4112f81254, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [9] = {.cpuprefctrl_el1 = 0x112f81260, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [10] = {.cpuprefctrl_el1 = 0x112f81260, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x658e5700}, - [11] = {.cpuprefctrl_el1 = 0x3412f81254, - .adps_lld_ddr_el1 = 0x4d142000, - .adpp_l1v_mop_el1 = 0x29080082a880, - .adps_lld_l3_el1 = 0x65965700}, - [12] = {.cpuprefctrl_el1 = 0x3412F81260, - .adps_lld_ddr_el1 = 0x4d12000, - .adpp_l1v_mop_el1 = 0x29080082a880, - .adps_lld_l3_el1 = 0x65965700}, - [13] = {.cpuprefctrl_el1 = 0x112f81240, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [14] = {.cpuprefctrl_el1 = 0x112f81240, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x69154332a840, - .adps_lld_l3_el1 = 0x65965700}, - [15] = {.cpuprefctrl_el1 = 0x80110f81380, - .adps_lld_ddr_el1 = 0x6554a000, - .adpp_l1v_mop_el1 = 0x29154332a840, - .adps_lld_l3_el1 = 0x65965700}, -}; - -static void set_prefetch(void* dummy) -{ - cfg_t cfg = *((cfg_t *)dummy); - - __asm__ __volatile__( - "msr S3_1_c15_c6_4, %0 \n" - : - : "r"(cfg.cpuprefctrl_el1) - : - ); - - __asm__ __volatile__( - "msr S3_1_c15_c7_1, %0 \n" - : - : "r"(cfg.adps_lld_ddr_el1) - : - ); - - __asm__ __volatile__( - "msr S3_1_c15_c6_5, %0 \n" - : - : "r"(cfg.adpp_l1v_mop_el1) - : - ); - - __asm__ __volatile__( - "msr S3_1_c15_c7_0, %0 \n" - : - : "r"(cfg.adps_lld_l3_el1) - : - ); -} - -static void get_prefetch(void* dummy) -{ - cfg_t *pcfg = this_cpu_ptr((cfg_t __percpu *)dummy); - cfg_t cfg; - - __asm__ __volatile__( - "mrs %0, S3_1_c15_c6_4 \n" - : "=r"(cfg.cpuprefctrl_el1) - : - : - ); - - __asm__ __volatile__( - "mrs %0, S3_1_c15_c7_1 \n" - : "=r"(cfg.adps_lld_ddr_el1) - : - : - ); - - __asm__ __volatile__( - "mrs %0, S3_1_c15_c6_5 \n" - : "=r"(cfg.adpp_l1v_mop_el1) - : - : - ); - - __asm__ __volatile__( - "mrs %0, S3_1_c15_c7_0 \n" - : "=r"(cfg.adps_lld_l3_el1) - : - : - ); - - *pcfg = cfg; -} -#else -static cfg_t cfg[] = {}; - -static void set_prefetch(void* dummy) -{ -} - -static void get_prefetch(void* dummy) -{ -} -#endif - -static void reset_prefetch(void* dummy) -{ - cfg_t *pcfg = this_cpu_ptr((cfg_t __percpu *)dummy); - set_prefetch(pcfg); -} - -static ssize_t prefetch_store(struct device* dev, - struct device_attribute* attr, const char* buf, size_t count) -{ - ssize_t ret; - int value; - - ret = kstrtouint(buf, 0, &value); - if (ret) { - pr_err("invalid input\n"); - return count; - } - - mutex_lock(&prefetch_mtx); - if (value < ARRAY_SIZE(cfg)) { - on_each_cpu_mask(mask_value, set_prefetch, &cfg[value], 1); - } else { - pr_err("value %d is out of range\n", value); - } - mutex_unlock(&prefetch_mtx); - - return count; -} - -static ssize_t prefetch_show(struct device* dev, - struct device_attribute* attr, char* buf) -{ - int cpu, policy; - int count = 0; - - mutex_lock(&prefetch_mtx); - on_each_cpu_mask(mask_value, get_prefetch, cur_cfg, 1); - - for_each_cpu(cpu, mask_value) { - for (policy = ARRAY_SIZE(cfg) - 1; policy >= 0; policy--) { - if (!memcmp(&cfg[policy], per_cpu_ptr(cur_cfg, cpu), - sizeof(cfg_t))) - break; - } - count += scnprintf(buf + count, PAGE_SIZE, "cpu(%d): %d\n", - cpu, policy); - } - mutex_unlock(&prefetch_mtx); - - return count; -} - -static ssize_t prefetch_mask_store(struct device* dev, - struct device_attribute* attr, const char* buf, size_t count) -{ - int ret; - - mutex_lock(&prefetch_mtx); - ret = cpulist_parse(buf, mask_value); - if (ret) { - pr_err("cpulist_parse error: %d\n", ret); - goto prefetch_mask_end; - } - - if (!is_affinity_mask_valid(mask_value)) { - pr_err("mask value error\n"); - goto prefetch_mask_end; - } - -prefetch_mask_end: - mutex_unlock(&prefetch_mtx); - return count; -} - -static ssize_t prefetch_mask_show(struct device* dev, - struct device_attribute* attr, char* buf) -{ - ssize_t ret; - mutex_lock(&prefetch_mtx); - ret = cpumap_print_to_pagebuf(true, buf, mask_value); - mutex_unlock(&prefetch_mtx); - return ret; -} - -/* - * prefetch policy, can be 0~15: - * 0: disable; 1~15: different thresholds for sms,amop algrithom; - */ -static DEVICE_ATTR(policy, S_IRUGO|S_IWUSR, - prefetch_show, prefetch_store); - -/* assign the effective cpu, can be a list */ -static DEVICE_ATTR(cpumask, S_IRUGO|S_IWUSR, - prefetch_mask_show, prefetch_mask_store); - -static struct attribute *prefetch_attrs[] = { - &dev_attr_policy.attr, - &dev_attr_cpumask.attr, - NULL, -}; - -static const struct attribute_group prefetch_attr_group = { - .attrs = prefetch_attrs, -}; - -static const struct attribute_group *prefetch_attr_groups[] = { - &prefetch_attr_group, - NULL, -}; - -static struct miscdevice misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "prefetch", - .groups = prefetch_attr_groups, -}; - -static int __init prefetch_init(void) -{ - int ret; - int cpu; - - /* mask: initial a mask */ - if (!alloc_cpumask_var(&mask_value, GFP_KERNEL)) { - ret = -ENOMEM; - goto err_mask_alloc; - } - - cpumask_clear(mask_value); - for_each_online_cpu(cpu) - cpumask_set_cpu(cpu, mask_value); - - if (!is_affinity_mask_valid(mask_value)) { - pr_err("incalid affinity_mask\n"); - ret = -EINVAL; - goto err_mask_init; - } - - cur_cfg = alloc_percpu(cfg_t); - if (!cur_cfg) { - pr_err("alloc_percpu fail\n"); - ret = -ENOMEM; - goto err_mask_init; - } - - old_cfg = alloc_percpu(cfg_t); - if (!old_cfg) { - pr_err("alloc_percpu fail\n"); - ret = -ENOMEM; - goto err_cfg_alloc; - } - - on_each_cpu(get_prefetch, old_cfg, 1); - - /* initial prefetch misc and initial prefetch_ops */ - ret = misc_register(&misc); - if (ret < 0) { - pr_err("misc register fail\n"); - goto err_misc_reg; - } - - return 0; - -err_misc_reg: - free_percpu(old_cfg); -err_cfg_alloc: - free_percpu(cur_cfg); -err_mask_init: - free_cpumask_var(mask_value); -err_mask_alloc: - return ret; -} - -static void __exit prefetch_exit(void) -{ - misc_deregister(&misc); - on_each_cpu(reset_prefetch, old_cfg, 1); - free_percpu(old_cfg); - free_percpu(cur_cfg); - free_cpumask_var(mask_value); -} - -module_init(prefetch_init); -module_exit(prefetch_exit); -MODULE_LICENSE("GPL"); diff --git a/tests/simple_test.sh b/tests/simple_test.sh new file mode 100644 index 0000000000000000000000000000000000000000..ded7d1994f40fa5930c50b34d1e78737b8942030 --- /dev/null +++ b/tests/simple_test.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# * Copyright(c) 2019 Huawei Technologies Co., Ltd +# * +# * This program is free software; you can redistribute it and/or modify it +# * under the terms and conditions of the GNU General Public License, +# * version 2, as published by the Free Software Foundation. +# * +# * This program is distributed in the hope it will be useful, but WITHOUT +# * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# * for more details. +# Create: 2020-07-02 +# Author: Liqiang (liqiang9102@gitee) + +GREP=cpu\(1\) + +echo "Policy set test, (exp:0~15):" +for i in {0..15} +do + echo $i > /sys/class/misc/prefetch/policy + cat /sys/class/misc/prefetch/policy | grep $GREP +done + +echo "Set read_unique to 0, (exp:close,15):" +echo 0 > /sys/class/misc/prefetch/read_unique +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP +echo "Set policy to 8, (exp:close,8):" +echo 8 > /sys/class/misc/prefetch/policy +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP + +echo "Set read_unique to 1, (exp:open,8):" +echo 1 > /sys/class/misc/prefetch/read_unique +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP + +echo "Set policy to 10, (exp:open,10):" +echo 10 > /sys/class/misc/prefetch/policy +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP + + +echo "Set policy to 5, (exp:open, 5):" +echo 5 > /sys/class/misc/prefetch/policy +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP + +echo "Set read_unique to 0, (close,5):" +echo 0 > /sys/class/misc/prefetch/read_unique +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP + +echo "Set read_unique to 1, (open,5):" +echo 1 > /sys/class/misc/prefetch/read_unique +cat /sys/class/misc/prefetch/read_unique | grep $GREP +cat /sys/class/misc/prefetch/policy | grep $GREP