1 // SPDX-License-Identifier: GPL-2.0
3 * Intel Uncore Frequency Control: Common code implementation
4 * Copyright (c) 2022, Intel Corporation.
9 #include <linux/module.h>
10 #include "uncore-frequency-common.h"
12 /* Mutex to control all mutual exclusions */
13 static DEFINE_MUTEX(uncore_lock);
14 /* Root of the all uncore sysfs kobjs */
15 static struct kobject *uncore_root_kobj;
16 /* uncore instance count */
17 static int uncore_instance_count;
19 static DEFINE_IDA(intel_uncore_ida);
21 /* callbacks for actual HW read/write */
22 static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max);
23 static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
24 static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
26 static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
28 struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_kobj_attr);
30 return sprintf(buf, "%u\n", data->domain_id);
33 static ssize_t show_fabric_cluster_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
35 struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr);
37 return sprintf(buf, "%u\n", data->cluster_id);
40 static ssize_t show_package_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
42 struct uncore_data *data = container_of(attr, struct uncore_data, package_id_kobj_attr);
44 return sprintf(buf, "%u\n", data->package_id);
47 static ssize_t show_min_max_freq_khz(struct uncore_data *data,
48 char *buf, int min_max)
50 unsigned int min, max;
53 mutex_lock(&uncore_lock);
54 ret = uncore_read(data, &min, &max);
55 mutex_unlock(&uncore_lock);
60 return sprintf(buf, "%u\n", max);
62 return sprintf(buf, "%u\n", min);
65 static ssize_t store_min_max_freq_khz(struct uncore_data *data,
66 const char *buf, ssize_t count,
72 if (kstrtouint(buf, 10, &input))
75 mutex_lock(&uncore_lock);
76 ret = uncore_write(data, input, min_max);
77 mutex_unlock(&uncore_lock);
85 static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf)
90 mutex_lock(&uncore_lock);
91 ret = uncore_read_freq(data, &freq);
92 mutex_unlock(&uncore_lock);
96 return sprintf(buf, "%u\n", freq);
99 #define store_uncore_min_max(name, min_max) \
100 static ssize_t store_##name(struct kobject *kobj, \
101 struct kobj_attribute *attr, \
102 const char *buf, size_t count) \
104 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
106 return store_min_max_freq_khz(data, buf, count, \
110 #define show_uncore_min_max(name, min_max) \
111 static ssize_t show_##name(struct kobject *kobj, \
112 struct kobj_attribute *attr, char *buf)\
114 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
116 return show_min_max_freq_khz(data, buf, min_max); \
119 #define show_uncore_perf_status(name) \
120 static ssize_t show_##name(struct kobject *kobj, \
121 struct kobj_attribute *attr, char *buf)\
123 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
125 return show_perf_status_freq_khz(data, buf); \
128 store_uncore_min_max(min_freq_khz, 0);
129 store_uncore_min_max(max_freq_khz, 1);
131 show_uncore_min_max(min_freq_khz, 0);
132 show_uncore_min_max(max_freq_khz, 1);
134 show_uncore_perf_status(current_freq_khz);
136 #define show_uncore_data(member_name) \
137 static ssize_t show_##member_name(struct kobject *kobj, \
138 struct kobj_attribute *attr, char *buf)\
140 struct uncore_data *data = container_of(attr, struct uncore_data,\
141 member_name##_kobj_attr);\
143 return sysfs_emit(buf, "%u\n", \
144 data->member_name); \
147 show_uncore_data(initial_min_freq_khz);
148 show_uncore_data(initial_max_freq_khz);
150 #define init_attribute_rw(_name) \
152 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
153 data->_name##_kobj_attr.show = show_##_name; \
154 data->_name##_kobj_attr.store = store_##_name; \
155 data->_name##_kobj_attr.attr.name = #_name; \
156 data->_name##_kobj_attr.attr.mode = 0644; \
159 #define init_attribute_ro(_name) \
161 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
162 data->_name##_kobj_attr.show = show_##_name; \
163 data->_name##_kobj_attr.store = NULL; \
164 data->_name##_kobj_attr.attr.name = #_name; \
165 data->_name##_kobj_attr.attr.mode = 0444; \
168 #define init_attribute_root_ro(_name) \
170 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
171 data->_name##_kobj_attr.show = show_##_name; \
172 data->_name##_kobj_attr.store = NULL; \
173 data->_name##_kobj_attr.attr.name = #_name; \
174 data->_name##_kobj_attr.attr.mode = 0400; \
177 static int create_attr_group(struct uncore_data *data, char *name)
179 int ret, freq, index = 0;
181 init_attribute_rw(max_freq_khz);
182 init_attribute_rw(min_freq_khz);
183 init_attribute_ro(initial_min_freq_khz);
184 init_attribute_ro(initial_max_freq_khz);
185 init_attribute_root_ro(current_freq_khz);
187 if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
188 init_attribute_root_ro(domain_id);
189 data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;
190 init_attribute_root_ro(fabric_cluster_id);
191 data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;
192 init_attribute_root_ro(package_id);
193 data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr;
196 data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr;
197 data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr;
198 data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
199 data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;
201 ret = uncore_read_freq(data, &freq);
203 data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;
205 data->uncore_attrs[index] = NULL;
207 data->uncore_attr_group.name = name;
208 data->uncore_attr_group.attrs = data->uncore_attrs;
209 ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group);
214 static void delete_attr_group(struct uncore_data *data, char *name)
216 sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
219 int uncore_freq_add_entry(struct uncore_data *data, int cpu)
223 mutex_lock(&uncore_lock);
225 /* control cpu changed */
226 data->control_cpu = cpu;
230 if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
231 ret = ida_alloc(&intel_uncore_ida, GFP_KERNEL);
235 data->instance_id = ret;
236 sprintf(data->name, "uncore%02d", ret);
238 sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
241 uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz);
243 ret = create_attr_group(data, data->name);
245 if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
246 ida_free(&intel_uncore_ida, data->instance_id);
248 data->control_cpu = cpu;
253 mutex_unlock(&uncore_lock);
257 EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
259 void uncore_freq_remove_die_entry(struct uncore_data *data)
261 mutex_lock(&uncore_lock);
262 delete_attr_group(data, data->name);
263 data->control_cpu = -1;
265 if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
266 ida_free(&intel_uncore_ida, data->instance_id);
268 mutex_unlock(&uncore_lock);
270 EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
272 int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max),
273 int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max),
274 int (*read_freq)(struct uncore_data *data, unsigned int *freq))
276 mutex_lock(&uncore_lock);
278 uncore_read = read_control_freq;
279 uncore_write = write_control_freq;
280 uncore_read_freq = read_freq;
282 if (!uncore_root_kobj) {
283 struct device *dev_root = bus_get_dev_root(&cpu_subsys);
286 uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
288 put_device(dev_root);
291 if (uncore_root_kobj)
292 ++uncore_instance_count;
293 mutex_unlock(&uncore_lock);
295 return uncore_root_kobj ? 0 : -ENOMEM;
297 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
299 void uncore_freq_common_exit(void)
301 mutex_lock(&uncore_lock);
302 --uncore_instance_count;
303 if (!uncore_instance_count) {
304 kobject_put(uncore_root_kobj);
305 uncore_root_kobj = NULL;
307 mutex_unlock(&uncore_lock);
309 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
312 MODULE_LICENSE("GPL v2");
313 MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");