]> Git Repo - linux.git/blob - drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
Merge tag 'pm-6.4-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[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 /* callbacks for actual HW read/write */
20 static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max);
21 static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
22 static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
23
24 static ssize_t show_min_max_freq_khz(struct uncore_data *data,
25                                       char *buf, int min_max)
26 {
27         unsigned int min, max;
28         int ret;
29
30         mutex_lock(&uncore_lock);
31         ret = uncore_read(data, &min, &max);
32         mutex_unlock(&uncore_lock);
33         if (ret)
34                 return ret;
35
36         if (min_max)
37                 return sprintf(buf, "%u\n", max);
38
39         return sprintf(buf, "%u\n", min);
40 }
41
42 static ssize_t store_min_max_freq_khz(struct uncore_data *data,
43                                       const char *buf, ssize_t count,
44                                       int min_max)
45 {
46         unsigned int input;
47
48         if (kstrtouint(buf, 10, &input))
49                 return -EINVAL;
50
51         mutex_lock(&uncore_lock);
52         uncore_write(data, input, min_max);
53         mutex_unlock(&uncore_lock);
54
55         return count;
56 }
57
58 static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf)
59 {
60         unsigned int freq;
61         int ret;
62
63         mutex_lock(&uncore_lock);
64         ret = uncore_read_freq(data, &freq);
65         mutex_unlock(&uncore_lock);
66         if (ret)
67                 return ret;
68
69         return sprintf(buf, "%u\n", freq);
70 }
71
72 #define store_uncore_min_max(name, min_max)                             \
73         static ssize_t store_##name(struct device *dev,         \
74                                      struct device_attribute *attr,     \
75                                      const char *buf, size_t count)     \
76         {                                                               \
77                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
78                                                                         \
79                 return store_min_max_freq_khz(data, buf, count, \
80                                               min_max);         \
81         }
82
83 #define show_uncore_min_max(name, min_max)                              \
84         static ssize_t show_##name(struct device *dev,          \
85                                     struct device_attribute *attr, char *buf)\
86         {                                                               \
87                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
88                                                                         \
89                 return show_min_max_freq_khz(data, buf, min_max);       \
90         }
91
92 #define show_uncore_perf_status(name)                                   \
93         static ssize_t show_##name(struct device *dev,          \
94                                    struct device_attribute *attr, char *buf)\
95         {                                                               \
96                 struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
97                                                                         \
98                 return show_perf_status_freq_khz(data, buf); \
99         }
100
101 store_uncore_min_max(min_freq_khz, 0);
102 store_uncore_min_max(max_freq_khz, 1);
103
104 show_uncore_min_max(min_freq_khz, 0);
105 show_uncore_min_max(max_freq_khz, 1);
106
107 show_uncore_perf_status(current_freq_khz);
108
109 #define show_uncore_data(member_name)                                   \
110         static ssize_t show_##member_name(struct device *dev,   \
111                                            struct device_attribute *attr, char *buf)\
112         {                                                               \
113                 struct uncore_data *data = container_of(attr, struct uncore_data,\
114                                                           member_name##_dev_attr);\
115                                                                         \
116                 return sysfs_emit(buf, "%u\n",                          \
117                                  data->member_name);                    \
118         }                                                               \
119
120 show_uncore_data(initial_min_freq_khz);
121 show_uncore_data(initial_max_freq_khz);
122
123 #define init_attribute_rw(_name)                                        \
124         do {                                                            \
125                 sysfs_attr_init(&data->_name##_dev_attr.attr);  \
126                 data->_name##_dev_attr.show = show_##_name;             \
127                 data->_name##_dev_attr.store = store_##_name;           \
128                 data->_name##_dev_attr.attr.name = #_name;              \
129                 data->_name##_dev_attr.attr.mode = 0644;                \
130         } while (0)
131
132 #define init_attribute_ro(_name)                                        \
133         do {                                                            \
134                 sysfs_attr_init(&data->_name##_dev_attr.attr);  \
135                 data->_name##_dev_attr.show = show_##_name;             \
136                 data->_name##_dev_attr.store = NULL;                    \
137                 data->_name##_dev_attr.attr.name = #_name;              \
138                 data->_name##_dev_attr.attr.mode = 0444;                \
139         } while (0)
140
141 #define init_attribute_root_ro(_name)                                   \
142         do {                                                            \
143                 sysfs_attr_init(&data->_name##_dev_attr.attr);  \
144                 data->_name##_dev_attr.show = show_##_name;             \
145                 data->_name##_dev_attr.store = NULL;                    \
146                 data->_name##_dev_attr.attr.name = #_name;              \
147                 data->_name##_dev_attr.attr.mode = 0400;                \
148         } while (0)
149
150 static int create_attr_group(struct uncore_data *data, char *name)
151 {
152         int ret, index = 0;
153
154         init_attribute_rw(max_freq_khz);
155         init_attribute_rw(min_freq_khz);
156         init_attribute_ro(initial_min_freq_khz);
157         init_attribute_ro(initial_max_freq_khz);
158         init_attribute_root_ro(current_freq_khz);
159
160         data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr;
161         data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr;
162         data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr;
163         data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr;
164         data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr;
165         data->uncore_attrs[index] = NULL;
166
167         data->uncore_attr_group.name = name;
168         data->uncore_attr_group.attrs = data->uncore_attrs;
169         ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group);
170
171         return ret;
172 }
173
174 static void delete_attr_group(struct uncore_data *data, char *name)
175 {
176         sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
177 }
178
179 int uncore_freq_add_entry(struct uncore_data *data, int cpu)
180 {
181         int ret = 0;
182
183         mutex_lock(&uncore_lock);
184         if (data->valid) {
185                 /* control cpu changed */
186                 data->control_cpu = cpu;
187                 goto uncore_unlock;
188         }
189
190         sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
191
192         uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz);
193
194         ret = create_attr_group(data, data->name);
195         if (!ret) {
196                 data->control_cpu = cpu;
197                 data->valid = true;
198         }
199
200 uncore_unlock:
201         mutex_unlock(&uncore_lock);
202
203         return ret;
204 }
205 EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
206
207 void uncore_freq_remove_die_entry(struct uncore_data *data)
208 {
209         mutex_lock(&uncore_lock);
210         delete_attr_group(data, data->name);
211         data->control_cpu = -1;
212         data->valid = false;
213         mutex_unlock(&uncore_lock);
214 }
215 EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
216
217 int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max),
218                              int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max),
219                              int (*read_freq)(struct uncore_data *data, unsigned int *freq))
220 {
221         mutex_lock(&uncore_lock);
222
223         uncore_read = read_control_freq;
224         uncore_write = write_control_freq;
225         uncore_read_freq = read_freq;
226
227         if (!uncore_root_kobj) {
228                 struct device *dev_root = bus_get_dev_root(&cpu_subsys);
229
230                 if (dev_root) {
231                         uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
232                                                                   &dev_root->kobj);
233                         put_device(dev_root);
234                 }
235         }
236         if (uncore_root_kobj)
237                 ++uncore_instance_count;
238         mutex_unlock(&uncore_lock);
239
240         return uncore_root_kobj ? 0 : -ENOMEM;
241 }
242 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
243
244 void uncore_freq_common_exit(void)
245 {
246         mutex_lock(&uncore_lock);
247         --uncore_instance_count;
248         if (!uncore_instance_count) {
249                 kobject_put(uncore_root_kobj);
250                 uncore_root_kobj = NULL;
251         }
252         mutex_unlock(&uncore_lock);
253 }
254 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
255
256
257 MODULE_LICENSE("GPL v2");
258 MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");
This page took 0.05066 seconds and 4 git commands to generate.