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