Messages in this thread Patch in this message | | | From | Kohei Tarumizu <> | Subject | [RFC PATCH v2 3/5] driver: hwpf: Add support for Intel to hardware prefetch driver | Date | Thu, 4 Nov 2021 14:21:20 +0900 |
| |
This adds module init/exit code, and creates sysfs attribute files for "enable". It works on only INTEL_FAM6_BROADWELL_X.
Signed-off-by: Kohei Tarumizu <tarumizu.kohei@fujitsu.com> --- drivers/hwpf/intel_hwpf.c | 219 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 drivers/hwpf/intel_hwpf.c
diff --git a/drivers/hwpf/intel_hwpf.c b/drivers/hwpf/intel_hwpf.c new file mode 100644 index 000000000..391a58200 --- /dev/null +++ b/drivers/hwpf/intel_hwpf.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0. +/* + * Copyright 2021 FUJITSU LIMITED + * + * Intel Hardware Prefetch support + */ + +#include <linux/bitfield.h> +#include <linux/hwpf.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <asm/intel-family.h> +#include <asm/msr.h> + +enum cache_level { + CACHE_LEVEL_L1 = 0, + CACHE_LEVEL_L2, + CACHE_LEVEL_NOCACHE, +}; + +/* + * Classify the register specification of MSR_MISC_FEATURE_CONTROL depending on + * the target model. + * + * Note: This enum type is added for future extension. Currently, this driver + * supports only one TYPE. However, the register has several different + * specifications. For example, XEON_PHI series (06_57H, 06_85H) has different + * specification for each bits as follow: + * [0] DCU Hardware Prefetcher Disable (R/W) + * [1] L2 Hardware Prefetcher Disable (R/W) + * [63:2] Reserved + */ +enum register_type { + /* + * The register specification for each bits of REGISTER_TYPE_BROADWELL + * is as follow: + * [0] L2 Hardware Prefetcher Disable (R/W) + * [1] L2 Adjacent Cache Line Prefetcher Disable (R/W) + * [2] DCU Hardware Prefetcher Disable (R/W) + * [3] DCU IP Prefetcher Disable (R/W) + * [63:4] Reserved + */ + REGISTER_TYPE_BROADWELL, + REGISTER_TYPE_NONE, /* Hardware prefetch is not supported */ +}; + +#define TYPE_BROADWELL_L1_FIELD GENMASK_ULL(3, 2) +#define TYPE_BROADWELL_L2_FIELD GENMASK_ULL(1, 0) + +static enum register_type hwpf_rtype; + +static unsigned int cache_leaves; + +static enum cache_level get_cache_level(unsigned int level) +{ + if (level >= cache_leaves) + return CACHE_LEVEL_NOCACHE; + + return level; +} + +/* + * Return: 0 if enabled, 1 if disabled, negative errno if an error occurs. + * If any bit in TYPE_XXX_FIELD is set to 1, it is considered disabled. + */ +static int get_enable(unsigned int cpu, unsigned int level) +{ + u64 reg; + int ret, val; + enum cache_level clevel; + + clevel = get_cache_level(level); + if (clevel == CACHE_LEVEL_NOCACHE) + return -EINVAL; + + ret = rdmsrl_on_cpu(cpu, MSR_MISC_FEATURE_CONTROL, ®); + if (ret) + return ret; + + switch (hwpf_rtype) { + case REGISTER_TYPE_BROADWELL: + switch (clevel) { + case CACHE_LEVEL_L1: + val = FIELD_GET(TYPE_BROADWELL_L1_FIELD, reg); + break; + case CACHE_LEVEL_L2: + val = FIELD_GET(TYPE_BROADWELL_L2_FIELD, reg); + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + if (val > 0) + return 1; + else if (val == 0) + return 0; + else + return -EINVAL; +} + +static int set_enable(unsigned int cpu, unsigned int level, int val) +{ + int ret; + u64 reg; + enum cache_level clevel; + + clevel = get_cache_level(level); + if (clevel == CACHE_LEVEL_NOCACHE) + return -EINVAL; + + ret = rdmsrl_on_cpu(cpu, MSR_MISC_FEATURE_CONTROL, ®); + if (ret) + return ret; + + switch (hwpf_rtype) { + case REGISTER_TYPE_BROADWELL: + if (val == 1) + val = 0x3; + else if (val == 0) + val = 0x0; + else + return -EINVAL; + + switch (clevel) { + case CACHE_LEVEL_L1: + reg &= ~TYPE_BROADWELL_L1_FIELD; + reg |= FIELD_PREP(TYPE_BROADWELL_L1_FIELD, val); + break; + case CACHE_LEVEL_L2: + reg &= ~TYPE_BROADWELL_L2_FIELD; + reg |= FIELD_PREP(TYPE_BROADWELL_L2_FIELD, val); + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + ret = wrmsrl_on_cpu(cpu, MSR_MISC_FEATURE_CONTROL, reg); + if (ret) + return ret; + + return 0; +} + + +struct hwpf_driver intel_hwpf_driver = { + .get_enable = get_enable, + .set_enable = set_enable, +}; + +enum register_type __init get_register_type(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return REGISTER_TYPE_NONE; + + switch (boot_cpu_data.x86_model) { + /* + * Note: In addition to BROADWELL, NEHALEM and others have same register + * specifications as REGISTER_TYPE_BROADWELL. If you want to add support + * for these processor, add the target model case here. + */ + case INTEL_FAM6_BROADWELL_X: + return REGISTER_TYPE_BROADWELL; + default: + return REGISTER_TYPE_NONE; + } +} + +static int __init setup_hwpf_driver_params(void) +{ + hwpf_rtype = get_register_type(); + + switch (hwpf_rtype) { + case REGISTER_TYPE_BROADWELL: + cache_leaves = 2; + break; + default: + return -ENODEV; + } + + intel_hwpf_driver.cache_leaves = cache_leaves; + + return 0; +} + +static int __init hwpf_init(void) +{ + int ret; + + ret = setup_hwpf_driver_params(); + if (ret < 0) + return ret; + + ret = hwpf_register_driver(&intel_hwpf_driver); + if (ret < 0) + return ret; + + return 0; +} + +static void __exit hwpf_exit(void) +{ + hwpf_unregister_driver(&intel_hwpf_driver); +} + +module_init(hwpf_init); +module_exit(hwpf_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("FUJITSU LIMITED"); +MODULE_DESCRIPTION("Intel Hardware Prefetch Driver"); -- 2.27.0
| |