]> Git Repo - linux.git/blob - drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / platform / x86 / intel / uncore-frequency / uncore-frequency-common.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel Uncore Frequency Control: Common code implementation
4  * Copyright (c) 2022, Intel Corporation.
5  * All rights reserved.
6  *
7  */
8 #include <linux/cpu.h>
9 #include <linux/module.h>
10 #include "uncore-frequency-common.h"
11
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;
18
19 static DEFINE_IDA(intel_uncore_ida);
20
21 /* callbacks for actual HW read/write */
22 static int (*uncore_read)(struct uncore_data *data, unsigned int *value, enum uncore_index index);
23 static int (*uncore_write)(struct uncore_data *data, unsigned int input, enum uncore_index index);
24
25 static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
26 {
27         struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_kobj_attr);
28
29         return sprintf(buf, "%u\n", data->domain_id);
30 }
31
32 static ssize_t show_fabric_cluster_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
33 {
34         struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr);
35
36         return sprintf(buf, "%u\n", data->cluster_id);
37 }
38
39 static ssize_t show_package_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
40 {
41         struct uncore_data *data = container_of(attr, struct uncore_data, package_id_kobj_attr);
42
43         return sprintf(buf, "%u\n", data->package_id);
44 }
45
46 static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index index)
47 {
48         unsigned int value;
49         int ret;
50
51         mutex_lock(&uncore_lock);
52         ret = uncore_read(data, &value, index);
53         mutex_unlock(&uncore_lock);
54         if (ret)
55                 return ret;
56
57         return sprintf(buf, "%u\n", value);
58 }
59
60 static ssize_t store_attr(struct uncore_data *data, const char *buf, ssize_t count,
61                           enum uncore_index index)
62 {
63         unsigned int input = 0;
64         int ret;
65
66         if (index == UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE) {
67                 if (kstrtobool(buf, (bool *)&input))
68                         return -EINVAL;
69         } else {
70                 if (kstrtouint(buf, 10, &input))
71                         return -EINVAL;
72         }
73
74         mutex_lock(&uncore_lock);
75         ret = uncore_write(data, input, index);
76         mutex_unlock(&uncore_lock);
77
78         if (ret)
79                 return ret;
80
81         return count;
82 }
83
84 #define store_uncore_attr(name, index)                                  \
85         static ssize_t store_##name(struct kobject *kobj,               \
86                                      struct kobj_attribute *attr,       \
87                                      const char *buf, size_t count)     \
88         {                                                               \
89                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
90                                                                         \
91                 return store_attr(data, buf, count, index);             \
92         }
93
94 #define show_uncore_attr(name, index)                                   \
95         static ssize_t show_##name(struct kobject *kobj,                \
96                                     struct kobj_attribute *attr, char *buf)\
97         {                                                               \
98                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
99                                                                         \
100                 return show_attr(data, buf, index);                     \
101         }
102
103 store_uncore_attr(min_freq_khz, UNCORE_INDEX_MIN_FREQ);
104 store_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);
105
106 show_uncore_attr(min_freq_khz, UNCORE_INDEX_MIN_FREQ);
107 show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);
108
109 show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ);
110
111 store_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
112 store_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
113 store_uncore_attr(elc_high_threshold_enable,
114                   UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
115 store_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);
116
117 show_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
118 show_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
119 show_uncore_attr(elc_high_threshold_enable,
120                  UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
121 show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);
122
123 #define show_uncore_data(member_name)                                   \
124         static ssize_t show_##member_name(struct kobject *kobj, \
125                                            struct kobj_attribute *attr, char *buf)\
126         {                                                               \
127                 struct uncore_data *data = container_of(attr, struct uncore_data,\
128                                                           member_name##_kobj_attr);\
129                                                                         \
130                 return sysfs_emit(buf, "%u\n",                          \
131                                  data->member_name);                    \
132         }                                                               \
133
134 show_uncore_data(initial_min_freq_khz);
135 show_uncore_data(initial_max_freq_khz);
136
137 #define init_attribute_rw(_name)                                        \
138         do {                                                            \
139                 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
140                 data->_name##_kobj_attr.show = show_##_name;            \
141                 data->_name##_kobj_attr.store = store_##_name;          \
142                 data->_name##_kobj_attr.attr.name = #_name;             \
143                 data->_name##_kobj_attr.attr.mode = 0644;               \
144         } while (0)
145
146 #define init_attribute_ro(_name)                                        \
147         do {                                                            \
148                 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
149                 data->_name##_kobj_attr.show = show_##_name;            \
150                 data->_name##_kobj_attr.store = NULL;                   \
151                 data->_name##_kobj_attr.attr.name = #_name;             \
152                 data->_name##_kobj_attr.attr.mode = 0444;               \
153         } while (0)
154
155 #define init_attribute_root_ro(_name)                                   \
156         do {                                                            \
157                 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
158                 data->_name##_kobj_attr.show = show_##_name;            \
159                 data->_name##_kobj_attr.store = NULL;                   \
160                 data->_name##_kobj_attr.attr.name = #_name;             \
161                 data->_name##_kobj_attr.attr.mode = 0400;               \
162         } while (0)
163
164 static int create_attr_group(struct uncore_data *data, char *name)
165 {
166         int ret, index = 0;
167         unsigned int val;
168
169         init_attribute_rw(max_freq_khz);
170         init_attribute_rw(min_freq_khz);
171         init_attribute_ro(initial_min_freq_khz);
172         init_attribute_ro(initial_max_freq_khz);
173         init_attribute_root_ro(current_freq_khz);
174
175         if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
176                 init_attribute_root_ro(domain_id);
177                 data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;
178                 init_attribute_root_ro(fabric_cluster_id);
179                 data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;
180                 init_attribute_root_ro(package_id);
181                 data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr;
182         }
183
184         data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr;
185         data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr;
186         data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
187         data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;
188
189         ret = uncore_read(data, &val, UNCORE_INDEX_CURRENT_FREQ);
190         if (!ret)
191                 data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;
192
193         ret = uncore_read(data, &val, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
194         if (!ret) {
195                 init_attribute_rw(elc_low_threshold_percent);
196                 init_attribute_rw(elc_high_threshold_percent);
197                 init_attribute_rw(elc_high_threshold_enable);
198                 init_attribute_rw(elc_floor_freq_khz);
199
200                 data->uncore_attrs[index++] = &data->elc_low_threshold_percent_kobj_attr.attr;
201                 data->uncore_attrs[index++] = &data->elc_high_threshold_percent_kobj_attr.attr;
202                 data->uncore_attrs[index++] =
203                         &data->elc_high_threshold_enable_kobj_attr.attr;
204                 data->uncore_attrs[index++] = &data->elc_floor_freq_khz_kobj_attr.attr;
205         }
206
207         data->uncore_attrs[index] = NULL;
208
209         data->uncore_attr_group.name = name;
210         data->uncore_attr_group.attrs = data->uncore_attrs;
211         ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group);
212
213         return ret;
214 }
215
216 static void delete_attr_group(struct uncore_data *data, char *name)
217 {
218         sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
219 }
220
221 int uncore_freq_add_entry(struct uncore_data *data, int cpu)
222 {
223         int ret = 0;
224
225         mutex_lock(&uncore_lock);
226         if (data->valid) {
227                 /* control cpu changed */
228                 data->control_cpu = cpu;
229                 goto uncore_unlock;
230         }
231
232         if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
233                 ret = ida_alloc(&intel_uncore_ida, GFP_KERNEL);
234                 if (ret < 0)
235                         goto uncore_unlock;
236
237                 data->instance_id = ret;
238                 sprintf(data->name, "uncore%02d", ret);
239         } else {
240                 sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
241         }
242
243         uncore_read(data, &data->initial_min_freq_khz, UNCORE_INDEX_MIN_FREQ);
244         uncore_read(data, &data->initial_max_freq_khz, UNCORE_INDEX_MAX_FREQ);
245
246         ret = create_attr_group(data, data->name);
247         if (ret) {
248                 if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
249                         ida_free(&intel_uncore_ida, data->instance_id);
250         } else {
251                 data->control_cpu = cpu;
252                 data->valid = true;
253         }
254
255 uncore_unlock:
256         mutex_unlock(&uncore_lock);
257
258         return ret;
259 }
260 EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
261
262 void uncore_freq_remove_die_entry(struct uncore_data *data)
263 {
264         mutex_lock(&uncore_lock);
265         delete_attr_group(data, data->name);
266         data->control_cpu = -1;
267         data->valid = false;
268         if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
269                 ida_free(&intel_uncore_ida, data->instance_id);
270
271         mutex_unlock(&uncore_lock);
272 }
273 EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
274
275 int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value,
276                                         enum uncore_index index),
277                             int (*write)(struct uncore_data *data, unsigned int input,
278                                          enum uncore_index index))
279 {
280         mutex_lock(&uncore_lock);
281
282         uncore_read = read;
283         uncore_write = write;
284
285         if (!uncore_root_kobj) {
286                 struct device *dev_root = bus_get_dev_root(&cpu_subsys);
287
288                 if (dev_root) {
289                         uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
290                                                                   &dev_root->kobj);
291                         put_device(dev_root);
292                 }
293         }
294         if (uncore_root_kobj)
295                 ++uncore_instance_count;
296         mutex_unlock(&uncore_lock);
297
298         return uncore_root_kobj ? 0 : -ENOMEM;
299 }
300 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
301
302 void uncore_freq_common_exit(void)
303 {
304         mutex_lock(&uncore_lock);
305         --uncore_instance_count;
306         if (!uncore_instance_count) {
307                 kobject_put(uncore_root_kobj);
308                 uncore_root_kobj = NULL;
309         }
310         mutex_unlock(&uncore_lock);
311 }
312 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
313
314
315 MODULE_LICENSE("GPL v2");
316 MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");
This page took 0.04736 seconds and 4 git commands to generate.