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");
259