]> Git Repo - linux.git/blob - drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
i2c: Fix conditional for substituting empty ACPI functions
[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;
64         int ret;
65
66         if (kstrtouint(buf, 10, &input))
67                 return -EINVAL;
68
69         mutex_lock(&uncore_lock);
70         ret = uncore_write(data, input, index);
71         mutex_unlock(&uncore_lock);
72
73         if (ret)
74                 return ret;
75
76         return count;
77 }
78
79 #define store_uncore_attr(name, index)                                  \
80         static ssize_t store_##name(struct kobject *kobj,               \
81                                      struct kobj_attribute *attr,       \
82                                      const char *buf, size_t count)     \
83         {                                                               \
84                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
85                                                                         \
86                 return store_attr(data, buf, count, index);             \
87         }
88
89 #define show_uncore_attr(name, index)                                   \
90         static ssize_t show_##name(struct kobject *kobj,                \
91                                     struct kobj_attribute *attr, char *buf)\
92         {                                                               \
93                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
94                                                                         \
95                 return show_attr(data, buf, index);                     \
96         }
97
98 store_uncore_attr(min_freq_khz, UNCORE_INDEX_MIN_FREQ);
99 store_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);
100
101 show_uncore_attr(min_freq_khz, UNCORE_INDEX_MIN_FREQ);
102 show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);
103
104 show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ);
105
106 #define show_uncore_data(member_name)                                   \
107         static ssize_t show_##member_name(struct kobject *kobj, \
108                                            struct kobj_attribute *attr, char *buf)\
109         {                                                               \
110                 struct uncore_data *data = container_of(attr, struct uncore_data,\
111                                                           member_name##_kobj_attr);\
112                                                                         \
113                 return sysfs_emit(buf, "%u\n",                          \
114                                  data->member_name);                    \
115         }                                                               \
116
117 show_uncore_data(initial_min_freq_khz);
118 show_uncore_data(initial_max_freq_khz);
119
120 #define init_attribute_rw(_name)                                        \
121         do {                                                            \
122                 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
123                 data->_name##_kobj_attr.show = show_##_name;            \
124                 data->_name##_kobj_attr.store = store_##_name;          \
125                 data->_name##_kobj_attr.attr.name = #_name;             \
126                 data->_name##_kobj_attr.attr.mode = 0644;               \
127         } while (0)
128
129 #define init_attribute_ro(_name)                                        \
130         do {                                                            \
131                 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
132                 data->_name##_kobj_attr.show = show_##_name;            \
133                 data->_name##_kobj_attr.store = NULL;                   \
134                 data->_name##_kobj_attr.attr.name = #_name;             \
135                 data->_name##_kobj_attr.attr.mode = 0444;               \
136         } while (0)
137
138 #define init_attribute_root_ro(_name)                                   \
139         do {                                                            \
140                 sysfs_attr_init(&data->_name##_kobj_attr.attr); \
141                 data->_name##_kobj_attr.show = show_##_name;            \
142                 data->_name##_kobj_attr.store = NULL;                   \
143                 data->_name##_kobj_attr.attr.name = #_name;             \
144                 data->_name##_kobj_attr.attr.mode = 0400;               \
145         } while (0)
146
147 static int create_attr_group(struct uncore_data *data, char *name)
148 {
149         int ret, freq, index = 0;
150
151         init_attribute_rw(max_freq_khz);
152         init_attribute_rw(min_freq_khz);
153         init_attribute_ro(initial_min_freq_khz);
154         init_attribute_ro(initial_max_freq_khz);
155         init_attribute_root_ro(current_freq_khz);
156
157         if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
158                 init_attribute_root_ro(domain_id);
159                 data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;
160                 init_attribute_root_ro(fabric_cluster_id);
161                 data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;
162                 init_attribute_root_ro(package_id);
163                 data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr;
164         }
165
166         data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr;
167         data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr;
168         data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
169         data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;
170
171         ret = uncore_read(data, &freq, UNCORE_INDEX_CURRENT_FREQ);
172         if (!ret)
173                 data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;
174
175         data->uncore_attrs[index] = NULL;
176
177         data->uncore_attr_group.name = name;
178         data->uncore_attr_group.attrs = data->uncore_attrs;
179         ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group);
180
181         return ret;
182 }
183
184 static void delete_attr_group(struct uncore_data *data, char *name)
185 {
186         sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
187 }
188
189 int uncore_freq_add_entry(struct uncore_data *data, int cpu)
190 {
191         int ret = 0;
192
193         mutex_lock(&uncore_lock);
194         if (data->valid) {
195                 /* control cpu changed */
196                 data->control_cpu = cpu;
197                 goto uncore_unlock;
198         }
199
200         if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
201                 ret = ida_alloc(&intel_uncore_ida, GFP_KERNEL);
202                 if (ret < 0)
203                         goto uncore_unlock;
204
205                 data->instance_id = ret;
206                 sprintf(data->name, "uncore%02d", ret);
207         } else {
208                 sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
209         }
210
211         uncore_read(data, &data->initial_min_freq_khz, UNCORE_INDEX_MIN_FREQ);
212         uncore_read(data, &data->initial_max_freq_khz, UNCORE_INDEX_MAX_FREQ);
213
214         ret = create_attr_group(data, data->name);
215         if (ret) {
216                 if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
217                         ida_free(&intel_uncore_ida, data->instance_id);
218         } else {
219                 data->control_cpu = cpu;
220                 data->valid = true;
221         }
222
223 uncore_unlock:
224         mutex_unlock(&uncore_lock);
225
226         return ret;
227 }
228 EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
229
230 void uncore_freq_remove_die_entry(struct uncore_data *data)
231 {
232         mutex_lock(&uncore_lock);
233         delete_attr_group(data, data->name);
234         data->control_cpu = -1;
235         data->valid = false;
236         if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
237                 ida_free(&intel_uncore_ida, data->instance_id);
238
239         mutex_unlock(&uncore_lock);
240 }
241 EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
242
243 int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value,
244                                         enum uncore_index index),
245                             int (*write)(struct uncore_data *data, unsigned int input,
246                                          enum uncore_index index))
247 {
248         mutex_lock(&uncore_lock);
249
250         uncore_read = read;
251         uncore_write = write;
252
253         if (!uncore_root_kobj) {
254                 struct device *dev_root = bus_get_dev_root(&cpu_subsys);
255
256                 if (dev_root) {
257                         uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
258                                                                   &dev_root->kobj);
259                         put_device(dev_root);
260                 }
261         }
262         if (uncore_root_kobj)
263                 ++uncore_instance_count;
264         mutex_unlock(&uncore_lock);
265
266         return uncore_root_kobj ? 0 : -ENOMEM;
267 }
268 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
269
270 void uncore_freq_common_exit(void)
271 {
272         mutex_lock(&uncore_lock);
273         --uncore_instance_count;
274         if (!uncore_instance_count) {
275                 kobject_put(uncore_root_kobj);
276                 uncore_root_kobj = NULL;
277         }
278         mutex_unlock(&uncore_lock);
279 }
280 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
281
282
283 MODULE_LICENSE("GPL v2");
284 MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");
This page took 0.052392 seconds and 4 git commands to generate.