mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 23:51:39 +00:00
platform/x86/intel/uncore-freq: Use sysfs API to create attributes
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 <srinivas.pandruvada@intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Link: https://lore.kernel.org/r/20220204000306.2517447-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
ce2645c458
commit
ae7b2ce578
@ -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,21 +32,36 @@
|
||||
* @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];
|
||||
|
||||
#define to_uncore_data(a) container_of(a, struct uncore_data, kobj)
|
||||
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];
|
||||
};
|
||||
|
||||
/* Max instances for uncore data, one for each die */
|
||||
static int uncore_max_entries __read_mostly;
|
||||
@ -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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,30 +191,64 @@ 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
|
||||
};
|
||||
ATTRIBUTE_GROUPS(uncore);
|
||||
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);
|
||||
|
||||
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 struct kobj_type uncore_ktype = {
|
||||
.release = uncore_sysfs_entry_release,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.default_groups = uncore_groups,
|
||||
};
|
||||
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)
|
||||
@ -266,21 +276,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;
|
||||
@ -296,8 +302,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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user