Skip to content

Commit

Permalink
platform/x86/intel/uncore-freq: Use sysfs API to create attributes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Srinivas Pandruvada authored and Hans de Goede committed Feb 17, 2022
1 parent ce2645c commit ae7b2ce
Showing 1 changed file with 113 additions and 112 deletions.
225 changes: 113 additions & 112 deletions drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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 */
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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);
Expand All @@ -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;

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);

complete(&data->kobj_unregister);
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)
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit ae7b2ce

Please sign in to comment.