From 6dbbc7834ad162401c86b992e06b9ed7a614c951 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 3 Feb 2022 16:03:04 -0800 Subject: [PATCH 1/3] platform/x86/intel/uncore-freq: Use sysfs API to create attributes mainline inclusion from mainline-v5.18-rc1 commit ae7b2ce578513adf0a77f0127e27ee4447d50443 category: feature bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I78KDD CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ae7b2ce578513adf0a77f0127e27ee4447d50443 Intel-SIG: commit ae7b2ce57851 platform/x86/intel/uncore-freq: Use sysfs API to create attributes. Backport for intel-uncore-freqe driver ------------------------------------------------- Use of sysfs API is always preferable over using kobject calls to create attributes. Remove usage of kobject_init_and_add() and use sysfs_create_group(). To create relationship between sysfs attribute and uncore instance use device_attribute*, which is defined per uncore instance. To create uniform locking for both read and write attributes take lock in the sysfs callbacks, not in the actual functions where the MSRs are read or updated. No functional changes are expected. Signed-off-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20220204000306.2517447-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Hans de Goede Signed-off-by: yingbao jia --- drivers/platform/x86/intel-uncore-frequency.c | 225 +++++++++--------- 1 file changed, 113 insertions(+), 112 deletions(-) diff --git a/drivers/platform/x86/intel-uncore-frequency.c b/drivers/platform/x86/intel-uncore-frequency.c index a72fbc7f1dfe..001bf7ff149c 100644 --- a/drivers/platform/x86/intel-uncore-frequency.c +++ b/drivers/platform/x86/intel-uncore-frequency.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Intel Uncore Frequency Setting - * Copyright (c) 2019, Intel Corporation. + * Copyright (c) 2022, Intel Corporation. * All rights reserved. * * Provide interface to set MSR 620 at a granularity of per die. On CPU online, @@ -32,22 +32,37 @@ * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init * @control_cpu: Designated CPU for a die to read/write * @valid: Mark the data valid/invalid + * @package_id: Package id for this instance + * @die_id: Die id for this instance + * @name: Sysfs entry name for this instance + * @uncore_attr_group: Attribute group storage + * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz + * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz + * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_max_freq_khz + * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_min_freq_khz + * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs * settings for a die/package. */ struct uncore_data { - struct kobject kobj; - struct completion kobj_unregister; u64 stored_uncore_data; u32 initial_min_freq_khz; u32 initial_max_freq_khz; int control_cpu; bool valid; + int package_id; + int die_id; + char name[32]; + + struct attribute_group uncore_attr_group; + struct device_attribute max_freq_khz_dev_attr; + struct device_attribute min_freq_khz_dev_attr; + struct device_attribute initial_max_freq_khz_dev_attr; + struct device_attribute initial_min_freq_khz_dev_attr; + struct attribute *uncore_attrs[5]; }; -#define to_uncore_data(a) container_of(a, struct uncore_data, kobj) - /* Max instances for uncore data, one for each die */ static int uncore_max_entries __read_mostly; /* Storage for uncore data for all instances */ @@ -61,36 +76,6 @@ static enum cpuhp_state uncore_hp_state __read_mostly; /* Mutex to control all mutual exclusions */ static DEFINE_MUTEX(uncore_lock); -struct uncore_attr { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, - struct attribute *attr, char *buf); - ssize_t (*store)(struct kobject *kobj, - struct attribute *attr, const char *c, ssize_t count); -}; - -#define define_one_uncore_ro(_name) \ -static struct uncore_attr _name = \ -__ATTR(_name, 0444, show_##_name, NULL) - -#define define_one_uncore_rw(_name) \ -static struct uncore_attr _name = \ -__ATTR(_name, 0644, show_##_name, store_##_name) - -#define show_uncore_data(member_name) \ - static ssize_t show_##member_name(struct kobject *kobj, \ - struct attribute *attr, \ - char *buf) \ - { \ - struct uncore_data *data = to_uncore_data(kobj); \ - return scnprintf(buf, PAGE_SIZE, "%u\n", \ - data->member_name); \ - } \ - define_one_uncore_ro(member_name) - -show_uncore_data(initial_min_freq_khz); -show_uncore_data(initial_max_freq_khz); - /* Common function to read MSR 0x620 and read min/max */ static int uncore_read_ratio(struct uncore_data *data, unsigned int *min, unsigned int *max) @@ -118,22 +103,16 @@ static int uncore_write_ratio(struct uncore_data *data, unsigned int input, int ret; u64 cap; - mutex_lock(&uncore_lock); - - if (data->control_cpu < 0) { - ret = -ENXIO; - goto finish_write; - } + if (data->control_cpu < 0) + return -ENXIO; input /= UNCORE_FREQ_KHZ_MULTIPLIER; - if (!input || input > 0x7F) { - ret = -EINVAL; - goto finish_write; - } + if (!input || input > 0x7F) + return -EINVAL; ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); if (ret) - goto finish_write; + return ret; if (set_max) { cap &= ~0x7F; @@ -145,37 +124,16 @@ static int uncore_write_ratio(struct uncore_data *data, unsigned int input, ret = wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap); if (ret) - goto finish_write; + return ret; data->stored_uncore_data = cap; -finish_write: - mutex_unlock(&uncore_lock); - - return ret; -} - -static ssize_t store_min_max_freq_khz(struct kobject *kobj, - struct attribute *attr, - const char *buf, ssize_t count, - int min_max) -{ - struct uncore_data *data = to_uncore_data(kobj); - unsigned int input; - - if (kstrtouint(buf, 10, &input)) - return -EINVAL; - - uncore_write_ratio(data, input, min_max); - - return count; + return 0; } -static ssize_t show_min_max_freq_khz(struct kobject *kobj, - struct attribute *attr, +static ssize_t show_min_max_freq_khz(struct uncore_data *data, char *buf, int min_max) { - struct uncore_data *data = to_uncore_data(kobj); unsigned int min, max; int ret; @@ -191,22 +149,40 @@ static ssize_t show_min_max_freq_khz(struct kobject *kobj, return sprintf(buf, "%u\n", min); } +static ssize_t store_min_max_freq_khz(struct uncore_data *data, + const char *buf, ssize_t count, + int min_max) +{ + unsigned int input; + + if (kstrtouint(buf, 10, &input)) + return -EINVAL; + + mutex_lock(&uncore_lock); + uncore_write_ratio(data, input, min_max); + mutex_unlock(&uncore_lock); + + return count; +} + #define store_uncore_min_max(name, min_max) \ - static ssize_t store_##name(struct kobject *kobj, \ - struct attribute *attr, \ - const char *buf, ssize_t count) \ - { \ + static ssize_t store_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ \ - return store_min_max_freq_khz(kobj, attr, buf, count, \ - min_max); \ + return store_min_max_freq_khz(data, buf, count, \ + min_max); \ } #define show_uncore_min_max(name, min_max) \ - static ssize_t show_##name(struct kobject *kobj, \ - struct attribute *attr, char *buf) \ + static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ { \ + struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ \ - return show_min_max_freq_khz(kobj, attr, buf, min_max); \ + return show_min_max_freq_khz(data, buf, min_max); \ } store_uncore_min_max(min_freq_khz, 0); @@ -215,29 +191,63 @@ store_uncore_min_max(max_freq_khz, 1); show_uncore_min_max(min_freq_khz, 0); show_uncore_min_max(max_freq_khz, 1); -define_one_uncore_rw(min_freq_khz); -define_one_uncore_rw(max_freq_khz); +#define show_uncore_data(member_name) \ + static ssize_t show_##member_name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data = container_of(attr, struct uncore_data,\ + member_name##_dev_attr);\ + \ + return scnprintf(buf, PAGE_SIZE, "%u\n", \ + data->member_name); \ + } \ -static struct attribute *uncore_attrs[] = { - &initial_min_freq_khz.attr, - &initial_max_freq_khz.attr, - &max_freq_khz.attr, - &min_freq_khz.attr, - NULL -}; +show_uncore_data(initial_min_freq_khz); +show_uncore_data(initial_max_freq_khz); -static void uncore_sysfs_entry_release(struct kobject *kobj) +#define init_attribute_rw(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show = show_##_name; \ + data->_name##_dev_attr.store = store_##_name; \ + data->_name##_dev_attr.attr.name = #_name; \ + data->_name##_dev_attr.attr.mode = 0644; \ + } while (0) + +#define init_attribute_ro(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show = show_##_name; \ + data->_name##_dev_attr.store = NULL; \ + data->_name##_dev_attr.attr.name = #_name; \ + data->_name##_dev_attr.attr.mode = 0444; \ + } while (0) + +static int create_attr_group(struct uncore_data *data, char *name) { - struct uncore_data *data = to_uncore_data(kobj); + int ret, index = 0; - complete(&data->kobj_unregister); -} + init_attribute_rw(max_freq_khz); + init_attribute_rw(min_freq_khz); + init_attribute_ro(initial_min_freq_khz); + init_attribute_ro(initial_max_freq_khz); -static struct kobj_type uncore_ktype = { - .release = uncore_sysfs_entry_release, - .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = uncore_attrs, -}; + data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr; + data->uncore_attrs[index] = NULL; + + data->uncore_attr_group.name = name; + data->uncore_attr_group.attrs = data->uncore_attrs; + ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group); + + return ret; +} +static void delete_attr_group(struct uncore_data *data, char *name) +{ + sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group); +} /* Caller provides protection */ static struct uncore_data *uncore_get_instance(unsigned int cpu) @@ -265,21 +275,17 @@ static void uncore_add_die_entry(int cpu) /* control cpu changed */ data->control_cpu = cpu; } else { - char str[64]; int ret; memset(data, 0, sizeof(*data)); - sprintf(str, "package_%02d_die_%02d", + sprintf(data->name, "package_%02d_die_%02d", topology_physical_package_id(cpu), topology_die_id(cpu)); uncore_read_ratio(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz); - init_completion(&data->kobj_unregister); - - ret = kobject_init_and_add(&data->kobj, &uncore_ktype, - uncore_root_kobj, str); + ret = create_attr_group(data, data->name); if (!ret) { data->control_cpu = cpu; data->valid = true; @@ -295,8 +301,11 @@ static void uncore_remove_die_entry(int cpu) mutex_lock(&uncore_lock); data = uncore_get_instance(cpu); - if (data) + if (data) { + delete_attr_group(data, data->name); data->control_cpu = -1; + data->valid = false; + } mutex_unlock(&uncore_lock); } @@ -433,16 +442,8 @@ module_init(intel_uncore_init) static void __exit intel_uncore_exit(void) { - int i; - unregister_pm_notifier(&uncore_pm_nb); cpuhp_remove_state(uncore_hp_state); - for (i = 0; i < uncore_max_entries; ++i) { - if (uncore_instances[i].valid) { - kobject_put(&uncore_instances[i].kobj); - wait_for_completion(&uncore_instances[i].kobj_unregister); - } - } kobject_put(uncore_root_kobj); kfree(uncore_instances); } -- Gitee From f235ce96ddb550cde0d35a825ffa1c911314ba5f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 3 Feb 2022 16:03:05 -0800 Subject: [PATCH 2/3] platform/x86/intel/uncore-freq: Display uncore current frequency mainline inclusion from mainline-v5.18-rc1 commit 414eef27283a2133a0998beb8e3e35f84eaac961 category: feature bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I78KDD CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=414eef27283a2133a0998beb8e3e35f84eaac961 Intel-SIG: commit 414eef27283a platform/x86/intel/uncore-freq: Display uncore current frequency. Backport for intel-uncore-freqe driver ------------------------------------------------- Add a new sysfs attribute "current_freq_khz" to display current uncore frequency. This value is read from MSR 0x621. Root user permission is required to read uncore current frequency. Signed-off-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20220204000306.2517447-4-srinivas.pandruvada@linux.intel.com Signed-off-by: Hans de Goede Signed-off-by: yingbao jia --- drivers/platform/x86/intel-uncore-frequency.c | 71 ++++++++++++++++--- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/intel-uncore-frequency.c b/drivers/platform/x86/intel-uncore-frequency.c index 001bf7ff149c..c22830c50032 100644 --- a/drivers/platform/x86/intel-uncore-frequency.c +++ b/drivers/platform/x86/intel-uncore-frequency.c @@ -22,6 +22,7 @@ #include #define MSR_UNCORE_RATIO_LIMIT 0x620 +#define MSR_UNCORE_PERF_STATUS 0x621 #define UNCORE_FREQ_KHZ_MULTIPLIER 100000 /** @@ -40,6 +41,7 @@ * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_max_freq_khz * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_min_freq_khz + * @current_freq_khz_dev_attr: Storage for device attribute current_freq_khz * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs @@ -60,7 +62,8 @@ struct uncore_data { struct device_attribute min_freq_khz_dev_attr; struct device_attribute initial_max_freq_khz_dev_attr; struct device_attribute initial_min_freq_khz_dev_attr; - struct attribute *uncore_attrs[5]; + struct device_attribute current_freq_khz_dev_attr; + struct attribute *uncore_attrs[6]; }; /* Max instances for uncore data, one for each die */ @@ -131,22 +134,32 @@ static int uncore_write_ratio(struct uncore_data *data, unsigned int input, return 0; } -static ssize_t show_min_max_freq_khz(struct uncore_data *data, - char *buf, int min_max) +static int uncore_read_freq(struct uncore_data *data, unsigned int *freq) { - unsigned int min, max; + u64 ratio; + int ret; + + ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_PERF_STATUS, &ratio); + if (ret) + return ret; + + *freq = (ratio & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; + + return 0; +} + +static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf) +{ + unsigned int freq; int ret; mutex_lock(&uncore_lock); - ret = uncore_read_ratio(data, &min, &max); + ret = uncore_read_freq(data, &freq); mutex_unlock(&uncore_lock); if (ret) return ret; - if (min_max) - return sprintf(buf, "%u\n", max); - - return sprintf(buf, "%u\n", min); + return sprintf(buf, "%u\n", freq); } static ssize_t store_min_max_freq_khz(struct uncore_data *data, @@ -165,6 +178,24 @@ static ssize_t store_min_max_freq_khz(struct uncore_data *data, return count; } +static ssize_t show_min_max_freq_khz(struct uncore_data *data, + char *buf, int min_max) +{ + unsigned int min, max; + int ret; + + mutex_lock(&uncore_lock); + ret = uncore_read_ratio(data, &min, &max); + mutex_unlock(&uncore_lock); + if (ret) + return ret; + + if (min_max) + return sprintf(buf, "%u\n", max); + + return sprintf(buf, "%u\n", min); +} + #define store_uncore_min_max(name, min_max) \ static ssize_t store_##name(struct device *dev, \ struct device_attribute *attr, \ @@ -185,12 +216,23 @@ static ssize_t store_min_max_freq_khz(struct uncore_data *data, return show_min_max_freq_khz(data, buf, min_max); \ } +#define show_uncore_perf_status(name) \ + static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ + \ + return show_perf_status_freq_khz(data, buf); \ + } + store_uncore_min_max(min_freq_khz, 0); store_uncore_min_max(max_freq_khz, 1); show_uncore_min_max(min_freq_khz, 0); show_uncore_min_max(max_freq_khz, 1); +show_uncore_perf_status(current_freq_khz); + #define show_uncore_data(member_name) \ static ssize_t show_##member_name(struct device *dev, \ struct device_attribute *attr, char *buf)\ @@ -223,6 +265,15 @@ show_uncore_data(initial_max_freq_khz); data->_name##_dev_attr.attr.mode = 0444; \ } while (0) +#define init_attribute_root_ro(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show = show_##_name; \ + data->_name##_dev_attr.store = NULL; \ + data->_name##_dev_attr.attr.name = #_name; \ + data->_name##_dev_attr.attr.mode = 0400; \ + } while (0) + static int create_attr_group(struct uncore_data *data, char *name) { int ret, index = 0; @@ -231,11 +282,13 @@ static int create_attr_group(struct uncore_data *data, char *name) init_attribute_rw(min_freq_khz); init_attribute_ro(initial_min_freq_khz); init_attribute_ro(initial_max_freq_khz); + init_attribute_root_ro(current_freq_khz); data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr; data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr; data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr; data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr; data->uncore_attrs[index] = NULL; data->uncore_attr_group.name = name; -- Gitee From a8486dc812ac1377302b09123fccc5f07913091d Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 27 Apr 2022 03:03:04 -0700 Subject: [PATCH 3/3] platform/x86: intel-uncore-freq: Prevent driver loading in guests mainline inclusion from mainline-v5.18-rc5 commit 8d75f7b4a3dfd5714a5dc87cfdaa27bd2d14aa48 category: feature bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I78KDD CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8d75f7b4a3dfd5714a5dc87cfdaa27bd2d14aa48 Intel-SIG: commit 8d75f7b4a3df platform/x86: intel-uncore-freq: Prevent driver loading in guests. Backport for intel-uncore-freqe driver ------------------------------------------------- Loading this driver in guests results in unchecked MSR access error for MSR 0x620. There is no use of reading and modifying package/die scope uncore MSRs in guests. So check for CPU feature X86_FEATURE_HYPERVISOR to prevent loading of this driver in guests. Fixes: dbce412a7733 ("platform/x86/intel-uncore-freq: Split common and enumeration part") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215870 Suggested-by: Borislav Petkov Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20220427100304.2562990-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Hans de Goede Signed-off-by: yingbao jia --- drivers/platform/x86/intel-uncore-frequency.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/intel-uncore-frequency.c b/drivers/platform/x86/intel-uncore-frequency.c index c22830c50032..bbffcaefe40b 100644 --- a/drivers/platform/x86/intel-uncore-frequency.c +++ b/drivers/platform/x86/intel-uncore-frequency.c @@ -449,6 +449,9 @@ static int __init intel_uncore_init(void) const struct x86_cpu_id *id; int ret; + if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) + return -ENODEV; + id = x86_match_cpu(intel_uncore_cpu_ids); if (!id) return -ENODEV; -- Gitee