aboutsummaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/Makefile2
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c252
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h62
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c332
4 files changed, 365 insertions, 283 deletions
diff --git a/drivers/platform/x86/intel/uncore-frequency/Makefile b/drivers/platform/x86/intel/uncore-frequency/Makefile
index e22186a480e2..e0f7968e8285 100644
--- a/drivers/platform/x86/intel/uncore-frequency/Makefile
+++ b/drivers/platform/x86/intel/uncore-frequency/Makefile
@@ -5,3 +5,5 @@
obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o
intel-uncore-frequency-y := uncore-frequency.o
+obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency-common.o
+intel-uncore-frequency-common-y := uncore-frequency-common.o
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
new file mode 100644
index 000000000000..e4d5a7960234
--- /dev/null
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Uncore Frequency Control: Common code implementation
+ * Copyright (c) 2022, Intel Corporation.
+ * All rights reserved.
+ *
+ */
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include "uncore-frequency-common.h"
+
+/* Mutex to control all mutual exclusions */
+static DEFINE_MUTEX(uncore_lock);
+/* Root of the all uncore sysfs kobjs */
+static struct kobject *uncore_root_kobj;
+/* uncore instance count */
+static int uncore_instance_count;
+
+/* callbacks for actual HW read/write */
+static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max);
+static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
+static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
+
+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(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);
+}
+
+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(data, input, min_max);
+ mutex_unlock(&uncore_lock);
+
+ return count;
+}
+
+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 sprintf(buf, "%u\n", freq);
+}
+
+#define store_uncore_min_max(name, min_max) \
+ 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(data, buf, count, \
+ min_max); \
+ }
+
+#define show_uncore_min_max(name, min_max) \
+ 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(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)\
+ { \
+ struct uncore_data *data = container_of(attr, struct uncore_data,\
+ member_name##_dev_attr);\
+ \
+ return scnprintf(buf, PAGE_SIZE, "%u\n", \
+ data->member_name); \
+ } \
+
+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)
+{
+ 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);
+ 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;
+ 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);
+}
+
+int uncore_freq_add_entry(struct uncore_data *data, int cpu)
+{
+ int ret = 0;
+
+ mutex_lock(&uncore_lock);
+ if (data->valid) {
+ /* control cpu changed */
+ data->control_cpu = cpu;
+ goto uncore_unlock;
+ }
+
+ sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
+
+ uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz);
+
+ ret = create_attr_group(data, data->name);
+ if (!ret) {
+ data->control_cpu = cpu;
+ data->valid = true;
+ }
+
+uncore_unlock:
+ mutex_unlock(&uncore_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
+
+void uncore_freq_remove_die_entry(struct uncore_data *data)
+{
+ mutex_lock(&uncore_lock);
+ delete_attr_group(data, data->name);
+ data->control_cpu = -1;
+ data->valid = false;
+ mutex_unlock(&uncore_lock);
+}
+EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
+
+int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max),
+ int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max),
+ int (*read_freq)(struct uncore_data *data, unsigned int *freq))
+{
+ mutex_lock(&uncore_lock);
+
+ uncore_read = read_control_freq;
+ uncore_write = write_control_freq;
+ uncore_read_freq = read_freq;
+
+ if (!uncore_root_kobj)
+ uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
+ &cpu_subsys.dev_root->kobj);
+ if (uncore_root_kobj)
+ ++uncore_instance_count;
+ mutex_unlock(&uncore_lock);
+
+ return (!!uncore_root_kobj);
+}
+EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
+
+void uncore_freq_common_exit(void)
+{
+ mutex_lock(&uncore_lock);
+ --uncore_instance_count;
+ if (!uncore_instance_count) {
+ kobject_put(uncore_root_kobj);
+ uncore_root_kobj = NULL;
+ }
+ mutex_unlock(&uncore_lock);
+}
+EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
+
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
new file mode 100644
index 000000000000..f5dcfa2fb285
--- /dev/null
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Intel Uncore Frequency Control: Common defines and prototypes
+ * Copyright (c) 2022, Intel Corporation.
+ * All rights reserved.
+ *
+ */
+
+#ifndef __INTEL_UNCORE_FREQ_COMMON_H
+#define __INTEL_UNCORE_FREQ_COMMON_H
+
+#include <linux/device.h>
+
+/**
+ * struct uncore_data - Encapsulate all uncore data
+ * @stored_uncore_data: Last user changed MSR 620 value, which will be restored
+ * on system resume.
+ * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init
+ * @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 {
+ 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];
+};
+
+int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max),
+ int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int min_max),
+ int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq));
+void uncore_freq_common_exit(void);
+int uncore_freq_add_entry(struct uncore_data *data, int cpu);
+void uncore_freq_remove_die_entry(struct uncore_data *data);
+
+#endif
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
index f5e980163911..791af0e287e4 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
@@ -21,67 +21,23 @@
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
-#define MSR_UNCORE_RATIO_LIMIT 0x620
-#define MSR_UNCORE_PERF_STATUS 0x621
-#define UNCORE_FREQ_KHZ_MULTIPLIER 100000
-
-/**
- * struct uncore_data - Encapsulate all uncore data
- * @stored_uncore_data: Last user changed MSR 620 value, which will be restored
- * on system resume.
- * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init
- * @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 {
- 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];
-};
+#include "uncore-frequency-common.h"
/* Max instances for uncore data, one for each die */
static int uncore_max_entries __read_mostly;
/* Storage for uncore data for all instances */
static struct uncore_data *uncore_instances;
-/* Root of the all uncore sysfs kobjs */
-static struct kobject *uncore_root_kobj;
/* Stores the CPU mask of the target CPUs to use during uncore read/write */
static cpumask_t uncore_cpu_mask;
/* CPU online callback register instance */
static enum cpuhp_state uncore_hp_state __read_mostly;
-/* Mutex to control all mutual exclusions */
-static DEFINE_MUTEX(uncore_lock);
-/* 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)
+#define MSR_UNCORE_RATIO_LIMIT 0x620
+#define MSR_UNCORE_PERF_STATUS 0x621
+#define UNCORE_FREQ_KHZ_MULTIPLIER 100000
+
+static int uncore_read_control_freq(struct uncore_data *data, unsigned int *min,
+ unsigned int *max)
{
u64 cap;
int ret;
@@ -99,25 +55,24 @@ static int uncore_read_ratio(struct uncore_data *data, unsigned int *min,
return 0;
}
-/* Common function to set min/max ratios to be used by sysfs callbacks */
-static int uncore_write_ratio(struct uncore_data *data, unsigned int input,
- int set_max)
+static int uncore_write_control_freq(struct uncore_data *data, unsigned int input,
+ unsigned int min_max)
{
int ret;
u64 cap;
- if (data->control_cpu < 0)
- return -ENXIO;
-
input /= UNCORE_FREQ_KHZ_MULTIPLIER;
if (!input || input > 0x7F)
return -EINVAL;
+ if (data->control_cpu < 0)
+ return -ENXIO;
+
ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap);
if (ret)
return ret;
- if (set_max) {
+ if (min_max) {
cap &= ~0x7F;
cap |= input;
} else {
@@ -139,6 +94,9 @@ static int uncore_read_freq(struct uncore_data *data, unsigned int *freq)
u64 ratio;
int ret;
+ if (data->control_cpu < 0)
+ return -ENXIO;
+
ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_PERF_STATUS, &ratio);
if (ret)
return ret;
@@ -148,161 +106,6 @@ static int uncore_read_freq(struct uncore_data *data, unsigned int *freq)
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 sprintf(buf, "%u\n", freq);
-}
-
-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;
-}
-
-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, \
- 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(data, buf, count, \
- min_max); \
- }
-
-#define show_uncore_min_max(name, min_max) \
- 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(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)\
- { \
- struct uncore_data *data = container_of(attr, struct uncore_data,\
- member_name##_dev_attr);\
- \
- return scnprintf(buf, PAGE_SIZE, "%u\n", \
- data->member_name); \
- } \
-
-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)
-{
- 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);
- 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;
- 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)
{
@@ -314,57 +117,9 @@ static struct uncore_data *uncore_get_instance(unsigned int cpu)
return NULL;
}
-static void uncore_add_die_entry(int cpu)
-{
- struct uncore_data *data;
-
- mutex_lock(&uncore_lock);
- data = uncore_get_instance(cpu);
- if (!data) {
- mutex_unlock(&uncore_lock);
- return;
- }
-
- if (data->valid) {
- /* control cpu changed */
- data->control_cpu = cpu;
- } else {
- int ret;
-
- memset(data, 0, sizeof(*data));
- 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);
-
- ret = create_attr_group(data, data->name);
- if (!ret) {
- data->control_cpu = cpu;
- data->valid = true;
- }
- }
- mutex_unlock(&uncore_lock);
-}
-
-/* Last CPU in this die is offline, make control cpu invalid */
-static void uncore_remove_die_entry(int cpu)
-{
- struct uncore_data *data;
-
- mutex_lock(&uncore_lock);
- data = uncore_get_instance(cpu);
- if (data) {
- delete_attr_group(data, data->name);
- data->control_cpu = -1;
- data->valid = false;
- }
- mutex_unlock(&uncore_lock);
-}
-
static int uncore_event_cpu_online(unsigned int cpu)
{
+ struct uncore_data *data;
int target;
/* Check if there is an online cpu in the package for uncore MSR */
@@ -374,15 +129,26 @@ static int uncore_event_cpu_online(unsigned int cpu)
/* Use this CPU on this die as a control CPU */
cpumask_set_cpu(cpu, &uncore_cpu_mask);
- uncore_add_die_entry(cpu);
- return 0;
+ data = uncore_get_instance(cpu);
+ if (!data)
+ return 0;
+
+ data->package_id = topology_physical_package_id(cpu);
+ data->die_id = topology_die_id(cpu);
+
+ return uncore_freq_add_entry(data, cpu);
}
static int uncore_event_cpu_offline(unsigned int cpu)
{
+ struct uncore_data *data;
int target;
+ data = uncore_get_instance(cpu);
+ if (!data)
+ return 0;
+
/* Check if existing cpu is used for uncore MSRs */
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
return 0;
@@ -392,9 +158,9 @@ static int uncore_event_cpu_offline(unsigned int cpu)
if (target < nr_cpu_ids) {
cpumask_set_cpu(target, &uncore_cpu_mask);
- uncore_add_die_entry(target);
+ uncore_freq_add_entry(data, target);
} else {
- uncore_remove_die_entry(cpu);
+ uncore_freq_remove_die_entry(data);
}
return 0;
@@ -403,24 +169,20 @@ static int uncore_event_cpu_offline(unsigned int cpu)
static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode,
void *_unused)
{
- int cpu;
+ int i;
switch (mode) {
case PM_POST_HIBERNATION:
case PM_POST_RESTORE:
case PM_POST_SUSPEND:
- for_each_cpu(cpu, &uncore_cpu_mask) {
- struct uncore_data *data;
- int ret;
+ for (i = 0; i < uncore_max_entries; ++i) {
+ struct uncore_data *data = &uncore_instances[i];
- data = uncore_get_instance(cpu);
if (!data || !data->valid || !data->stored_uncore_data)
- continue;
+ return 0;
- ret = wrmsrl_on_cpu(cpu, MSR_UNCORE_RATIO_LIMIT,
- data->stored_uncore_data);
- if (ret)
- return ret;
+ wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT,
+ data->stored_uncore_data);
}
break;
default:
@@ -443,6 +205,7 @@ static const struct x86_cpu_id intel_uncore_cpu_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL),
{}
};
+MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids);
static int __init intel_uncore_init(void)
{
@@ -460,12 +223,10 @@ static int __init intel_uncore_init(void)
if (!uncore_instances)
return -ENOMEM;
- uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
- &cpu_subsys.dev_root->kobj);
- if (!uncore_root_kobj) {
- ret = -ENOMEM;
+ ret = uncore_freq_common_init(uncore_read_control_freq, uncore_write_control_freq,
+ uncore_read_freq);
+ if (!ret)
goto err_free;
- }
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"platform/x86/uncore-freq:online",
@@ -485,7 +246,7 @@ static int __init intel_uncore_init(void)
err_rem_state:
cpuhp_remove_state(uncore_hp_state);
err_rem_kobj:
- kobject_put(uncore_root_kobj);
+ uncore_freq_common_exit();
err_free:
kfree(uncore_instances);
@@ -495,12 +256,17 @@ 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);
- kobject_put(uncore_root_kobj);
+ for (i = 0; i < uncore_max_entries; ++i)
+ uncore_freq_remove_die_entry(&uncore_instances[i]);
+ uncore_freq_common_exit();
kfree(uncore_instances);
}
module_exit(intel_uncore_exit)
+MODULE_IMPORT_NS(INTEL_UNCORE_FREQUENCY);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver");