未验证 提交 b6923261 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!840 intel: backport uncore-freq current frequency sysfs related patches

Merge Pull Request from: @jiayingbao 
 
there is new sysfs interface current_freq_khz added in upstream. Backport related patches for uncore-freq driver.

below 3 patches is backported: 
ae7b2ce5 platform/x86/intel/uncore-freq: Use sysfs API to create.
414eef27 platform/x86/intel/uncore-freq: Display uncore current frequency.
8d75f7b4 platform/x86: intel-uncore-freq: Prevent driver loading in guests.

test:
build pass
new sysfs current_freq_khz functional as expected 
 
Link:https://gitee.com/openeuler/kernel/pulls/840 

Reviewed-by: Jason Zeng <jason.zeng@intel.com> 
Reviewed-by: Aichun Shi <aichun.shi@intel.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
// 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,
......@@ -22,6 +22,7 @@
#include <asm/intel-family.h>
#define MSR_UNCORE_RATIO_LIMIT 0x620
#define MSR_UNCORE_PERF_STATUS 0x621
#define UNCORE_FREQ_KHZ_MULTIPLIER 100000
/**
......@@ -32,22 +33,39 @@
* @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
* @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
* 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 device_attribute current_freq_khz_dev_attr;
struct attribute *uncore_attrs[6];
};
#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 +79,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 +106,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 +127,60 @@ 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:
return 0;
}
static int uncore_read_freq(struct uncore_data *data, unsigned int *freq)
{
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_freq(data, &freq);
mutex_unlock(&uncore_lock);
if (ret)
return ret;
return ret;
return sprintf(buf, "%u\n", freq);
}
static ssize_t store_min_max_freq_khz(struct kobject *kobj,
struct attribute *attr,
static ssize_t store_min_max_freq_khz(struct uncore_data *data,
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;
mutex_lock(&uncore_lock);
uncore_write_ratio(data, input, min_max);
mutex_unlock(&uncore_lock);
return count;
}
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;
......@@ -192,21 +197,32 @@ static ssize_t show_min_max_freq_khz(struct kobject *kobj,
}
#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); \
}
#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);
......@@ -215,29 +231,76 @@ 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);
show_uncore_perf_status(current_freq_khz);
static struct attribute *uncore_attrs[] = {
&initial_min_freq_khz.attr,
&initial_max_freq_khz.attr,
&max_freq_khz.attr,
&min_freq_khz.attr,
NULL
};
#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 void uncore_sysfs_entry_release(struct kobject *kobj)
show_uncore_data(initial_min_freq_khz);
show_uncore_data(initial_max_freq_khz);
#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)
#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)
{
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);
init_attribute_root_ro(current_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++] = &data->current_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 +328,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 +354,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);
}
......@@ -387,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;
......@@ -433,16 +498,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);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册