1dbce412aSSrinivas Pandruvada // SPDX-License-Identifier: GPL-2.0
2dbce412aSSrinivas Pandruvada /*
3dbce412aSSrinivas Pandruvada  * Intel Uncore Frequency Control: Common code implementation
4dbce412aSSrinivas Pandruvada  * Copyright (c) 2022, Intel Corporation.
5dbce412aSSrinivas Pandruvada  * All rights reserved.
6dbce412aSSrinivas Pandruvada  *
7dbce412aSSrinivas Pandruvada  */
8dbce412aSSrinivas Pandruvada #include <linux/cpu.h>
9dbce412aSSrinivas Pandruvada #include <linux/module.h>
10dbce412aSSrinivas Pandruvada #include "uncore-frequency-common.h"
11dbce412aSSrinivas Pandruvada 
12dbce412aSSrinivas Pandruvada /* Mutex to control all mutual exclusions */
13dbce412aSSrinivas Pandruvada static DEFINE_MUTEX(uncore_lock);
14dbce412aSSrinivas Pandruvada /* Root of the all uncore sysfs kobjs */
15dbce412aSSrinivas Pandruvada static struct kobject *uncore_root_kobj;
16dbce412aSSrinivas Pandruvada /* uncore instance count */
17dbce412aSSrinivas Pandruvada static int uncore_instance_count;
18dbce412aSSrinivas Pandruvada 
199b8dea80SSrinivas Pandruvada static DEFINE_IDA(intel_uncore_ida);
209b8dea80SSrinivas Pandruvada 
21dbce412aSSrinivas Pandruvada /* callbacks for actual HW read/write */
22dbce412aSSrinivas Pandruvada static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max);
23dbce412aSSrinivas Pandruvada static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
24dbce412aSSrinivas Pandruvada static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
25dbce412aSSrinivas Pandruvada 
show_domain_id(struct kobject * kobj,struct kobj_attribute * attr,char * buf)26*ace6fb9dSNathan Chancellor static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
279b8dea80SSrinivas Pandruvada {
28*ace6fb9dSNathan Chancellor 	struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_kobj_attr);
299b8dea80SSrinivas Pandruvada 
309b8dea80SSrinivas Pandruvada 	return sprintf(buf, "%u\n", data->domain_id);
319b8dea80SSrinivas Pandruvada }
329b8dea80SSrinivas Pandruvada 
show_fabric_cluster_id(struct kobject * kobj,struct kobj_attribute * attr,char * buf)33*ace6fb9dSNathan Chancellor static ssize_t show_fabric_cluster_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
349b8dea80SSrinivas Pandruvada {
35*ace6fb9dSNathan Chancellor 	struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr);
369b8dea80SSrinivas Pandruvada 
379b8dea80SSrinivas Pandruvada 	return sprintf(buf, "%u\n", data->cluster_id);
389b8dea80SSrinivas Pandruvada }
399b8dea80SSrinivas Pandruvada 
show_package_id(struct kobject * kobj,struct kobj_attribute * attr,char * buf)40*ace6fb9dSNathan Chancellor static ssize_t show_package_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
419b8dea80SSrinivas Pandruvada {
42*ace6fb9dSNathan Chancellor 	struct uncore_data *data = container_of(attr, struct uncore_data, package_id_kobj_attr);
439b8dea80SSrinivas Pandruvada 
449b8dea80SSrinivas Pandruvada 	return sprintf(buf, "%u\n", data->package_id);
459b8dea80SSrinivas Pandruvada }
469b8dea80SSrinivas Pandruvada 
show_min_max_freq_khz(struct uncore_data * data,char * buf,int min_max)47dbce412aSSrinivas Pandruvada static ssize_t show_min_max_freq_khz(struct uncore_data *data,
48dbce412aSSrinivas Pandruvada 				      char *buf, int min_max)
49dbce412aSSrinivas Pandruvada {
50dbce412aSSrinivas Pandruvada 	unsigned int min, max;
51dbce412aSSrinivas Pandruvada 	int ret;
52dbce412aSSrinivas Pandruvada 
53dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
54dbce412aSSrinivas Pandruvada 	ret = uncore_read(data, &min, &max);
55dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
56dbce412aSSrinivas Pandruvada 	if (ret)
57dbce412aSSrinivas Pandruvada 		return ret;
58dbce412aSSrinivas Pandruvada 
59dbce412aSSrinivas Pandruvada 	if (min_max)
60dbce412aSSrinivas Pandruvada 		return sprintf(buf, "%u\n", max);
61dbce412aSSrinivas Pandruvada 
62dbce412aSSrinivas Pandruvada 	return sprintf(buf, "%u\n", min);
63dbce412aSSrinivas Pandruvada }
64dbce412aSSrinivas Pandruvada 
store_min_max_freq_khz(struct uncore_data * data,const char * buf,ssize_t count,int min_max)65dbce412aSSrinivas Pandruvada static ssize_t store_min_max_freq_khz(struct uncore_data *data,
66dbce412aSSrinivas Pandruvada 				      const char *buf, ssize_t count,
67dbce412aSSrinivas Pandruvada 				      int min_max)
68dbce412aSSrinivas Pandruvada {
69dbce412aSSrinivas Pandruvada 	unsigned int input;
7075e406b5SSrinivas Pandruvada 	int ret;
71dbce412aSSrinivas Pandruvada 
72dbce412aSSrinivas Pandruvada 	if (kstrtouint(buf, 10, &input))
73dbce412aSSrinivas Pandruvada 		return -EINVAL;
74dbce412aSSrinivas Pandruvada 
75dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
7675e406b5SSrinivas Pandruvada 	ret = uncore_write(data, input, min_max);
77dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
78dbce412aSSrinivas Pandruvada 
7975e406b5SSrinivas Pandruvada 	if (ret)
8075e406b5SSrinivas Pandruvada 		return ret;
8175e406b5SSrinivas Pandruvada 
82dbce412aSSrinivas Pandruvada 	return count;
83dbce412aSSrinivas Pandruvada }
84dbce412aSSrinivas Pandruvada 
show_perf_status_freq_khz(struct uncore_data * data,char * buf)85dbce412aSSrinivas Pandruvada static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf)
86dbce412aSSrinivas Pandruvada {
87dbce412aSSrinivas Pandruvada 	unsigned int freq;
88dbce412aSSrinivas Pandruvada 	int ret;
89dbce412aSSrinivas Pandruvada 
90dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
91dbce412aSSrinivas Pandruvada 	ret = uncore_read_freq(data, &freq);
92dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
93dbce412aSSrinivas Pandruvada 	if (ret)
94dbce412aSSrinivas Pandruvada 		return ret;
95dbce412aSSrinivas Pandruvada 
96dbce412aSSrinivas Pandruvada 	return sprintf(buf, "%u\n", freq);
97dbce412aSSrinivas Pandruvada }
98dbce412aSSrinivas Pandruvada 
99dbce412aSSrinivas Pandruvada #define store_uncore_min_max(name, min_max)				\
100*ace6fb9dSNathan Chancellor 	static ssize_t store_##name(struct kobject *kobj,		\
101*ace6fb9dSNathan Chancellor 				     struct kobj_attribute *attr,	\
102dbce412aSSrinivas Pandruvada 				     const char *buf, size_t count)	\
103dbce412aSSrinivas Pandruvada 	{								\
104*ace6fb9dSNathan Chancellor 		struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
105dbce412aSSrinivas Pandruvada 									\
106dbce412aSSrinivas Pandruvada 		return store_min_max_freq_khz(data, buf, count,	\
107dbce412aSSrinivas Pandruvada 					      min_max);		\
108dbce412aSSrinivas Pandruvada 	}
109dbce412aSSrinivas Pandruvada 
110dbce412aSSrinivas Pandruvada #define show_uncore_min_max(name, min_max)				\
111*ace6fb9dSNathan Chancellor 	static ssize_t show_##name(struct kobject *kobj,		\
112*ace6fb9dSNathan Chancellor 				    struct kobj_attribute *attr, char *buf)\
113dbce412aSSrinivas Pandruvada 	{                                                               \
114*ace6fb9dSNathan Chancellor 		struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
115dbce412aSSrinivas Pandruvada 									\
116dbce412aSSrinivas Pandruvada 		return show_min_max_freq_khz(data, buf, min_max);	\
117dbce412aSSrinivas Pandruvada 	}
118dbce412aSSrinivas Pandruvada 
119dbce412aSSrinivas Pandruvada #define show_uncore_perf_status(name)					\
120*ace6fb9dSNathan Chancellor 	static ssize_t show_##name(struct kobject *kobj,		\
121*ace6fb9dSNathan Chancellor 				   struct kobj_attribute *attr, char *buf)\
122dbce412aSSrinivas Pandruvada 	{                                                               \
123*ace6fb9dSNathan Chancellor 		struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
124dbce412aSSrinivas Pandruvada 									\
125dbce412aSSrinivas Pandruvada 		return show_perf_status_freq_khz(data, buf); \
126dbce412aSSrinivas Pandruvada 	}
127dbce412aSSrinivas Pandruvada 
128dbce412aSSrinivas Pandruvada store_uncore_min_max(min_freq_khz, 0);
129dbce412aSSrinivas Pandruvada store_uncore_min_max(max_freq_khz, 1);
130dbce412aSSrinivas Pandruvada 
131dbce412aSSrinivas Pandruvada show_uncore_min_max(min_freq_khz, 0);
132dbce412aSSrinivas Pandruvada show_uncore_min_max(max_freq_khz, 1);
133dbce412aSSrinivas Pandruvada 
134dbce412aSSrinivas Pandruvada show_uncore_perf_status(current_freq_khz);
135dbce412aSSrinivas Pandruvada 
136dbce412aSSrinivas Pandruvada #define show_uncore_data(member_name)					\
137*ace6fb9dSNathan Chancellor 	static ssize_t show_##member_name(struct kobject *kobj,	\
138*ace6fb9dSNathan Chancellor 					   struct kobj_attribute *attr, char *buf)\
139dbce412aSSrinivas Pandruvada 	{                                                               \
140dbce412aSSrinivas Pandruvada 		struct uncore_data *data = container_of(attr, struct uncore_data,\
141*ace6fb9dSNathan Chancellor 							  member_name##_kobj_attr);\
142dbce412aSSrinivas Pandruvada 									\
14376a13da7Sye xingchen 		return sysfs_emit(buf, "%u\n",				\
144dbce412aSSrinivas Pandruvada 				 data->member_name);			\
145dbce412aSSrinivas Pandruvada 	}								\
146dbce412aSSrinivas Pandruvada 
147dbce412aSSrinivas Pandruvada show_uncore_data(initial_min_freq_khz);
148dbce412aSSrinivas Pandruvada show_uncore_data(initial_max_freq_khz);
149dbce412aSSrinivas Pandruvada 
150dbce412aSSrinivas Pandruvada #define init_attribute_rw(_name)					\
151dbce412aSSrinivas Pandruvada 	do {								\
152*ace6fb9dSNathan Chancellor 		sysfs_attr_init(&data->_name##_kobj_attr.attr);	\
153*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.show = show_##_name;		\
154*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.store = store_##_name;		\
155*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.attr.name = #_name;		\
156*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.attr.mode = 0644;		\
157dbce412aSSrinivas Pandruvada 	} while (0)
158dbce412aSSrinivas Pandruvada 
159dbce412aSSrinivas Pandruvada #define init_attribute_ro(_name)					\
160dbce412aSSrinivas Pandruvada 	do {								\
161*ace6fb9dSNathan Chancellor 		sysfs_attr_init(&data->_name##_kobj_attr.attr);	\
162*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.show = show_##_name;		\
163*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.store = NULL;			\
164*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.attr.name = #_name;		\
165*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.attr.mode = 0444;		\
166dbce412aSSrinivas Pandruvada 	} while (0)
167dbce412aSSrinivas Pandruvada 
168dbce412aSSrinivas Pandruvada #define init_attribute_root_ro(_name)					\
169dbce412aSSrinivas Pandruvada 	do {								\
170*ace6fb9dSNathan Chancellor 		sysfs_attr_init(&data->_name##_kobj_attr.attr);	\
171*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.show = show_##_name;		\
172*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.store = NULL;			\
173*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.attr.name = #_name;		\
174*ace6fb9dSNathan Chancellor 		data->_name##_kobj_attr.attr.mode = 0400;		\
175dbce412aSSrinivas Pandruvada 	} while (0)
176dbce412aSSrinivas Pandruvada 
create_attr_group(struct uncore_data * data,char * name)177dbce412aSSrinivas Pandruvada static int create_attr_group(struct uncore_data *data, char *name)
178dbce412aSSrinivas Pandruvada {
1794d73c677SSrinivas Pandruvada 	int ret, freq, index = 0;
180dbce412aSSrinivas Pandruvada 
181dbce412aSSrinivas Pandruvada 	init_attribute_rw(max_freq_khz);
182dbce412aSSrinivas Pandruvada 	init_attribute_rw(min_freq_khz);
183dbce412aSSrinivas Pandruvada 	init_attribute_ro(initial_min_freq_khz);
184dbce412aSSrinivas Pandruvada 	init_attribute_ro(initial_max_freq_khz);
185dbce412aSSrinivas Pandruvada 	init_attribute_root_ro(current_freq_khz);
186dbce412aSSrinivas Pandruvada 
1879b8dea80SSrinivas Pandruvada 	if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
1889b8dea80SSrinivas Pandruvada 		init_attribute_root_ro(domain_id);
189*ace6fb9dSNathan Chancellor 		data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;
1909b8dea80SSrinivas Pandruvada 		init_attribute_root_ro(fabric_cluster_id);
191*ace6fb9dSNathan Chancellor 		data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;
1929b8dea80SSrinivas Pandruvada 		init_attribute_root_ro(package_id);
193*ace6fb9dSNathan Chancellor 		data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr;
1949b8dea80SSrinivas Pandruvada 	}
1959b8dea80SSrinivas Pandruvada 
196*ace6fb9dSNathan Chancellor 	data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr;
197*ace6fb9dSNathan Chancellor 	data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr;
198*ace6fb9dSNathan Chancellor 	data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
199*ace6fb9dSNathan Chancellor 	data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;
2004d73c677SSrinivas Pandruvada 
2014d73c677SSrinivas Pandruvada 	ret = uncore_read_freq(data, &freq);
2024d73c677SSrinivas Pandruvada 	if (!ret)
203*ace6fb9dSNathan Chancellor 		data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;
2044d73c677SSrinivas Pandruvada 
205dbce412aSSrinivas Pandruvada 	data->uncore_attrs[index] = NULL;
206dbce412aSSrinivas Pandruvada 
207dbce412aSSrinivas Pandruvada 	data->uncore_attr_group.name = name;
208dbce412aSSrinivas Pandruvada 	data->uncore_attr_group.attrs = data->uncore_attrs;
209dbce412aSSrinivas Pandruvada 	ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group);
210dbce412aSSrinivas Pandruvada 
211dbce412aSSrinivas Pandruvada 	return ret;
212dbce412aSSrinivas Pandruvada }
213dbce412aSSrinivas Pandruvada 
delete_attr_group(struct uncore_data * data,char * name)214dbce412aSSrinivas Pandruvada static void delete_attr_group(struct uncore_data *data, char *name)
215dbce412aSSrinivas Pandruvada {
216dbce412aSSrinivas Pandruvada 	sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
217dbce412aSSrinivas Pandruvada }
218dbce412aSSrinivas Pandruvada 
uncore_freq_add_entry(struct uncore_data * data,int cpu)219dbce412aSSrinivas Pandruvada int uncore_freq_add_entry(struct uncore_data *data, int cpu)
220dbce412aSSrinivas Pandruvada {
221dbce412aSSrinivas Pandruvada 	int ret = 0;
222dbce412aSSrinivas Pandruvada 
223dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
224dbce412aSSrinivas Pandruvada 	if (data->valid) {
225dbce412aSSrinivas Pandruvada 		/* control cpu changed */
226dbce412aSSrinivas Pandruvada 		data->control_cpu = cpu;
227dbce412aSSrinivas Pandruvada 		goto uncore_unlock;
228dbce412aSSrinivas Pandruvada 	}
229dbce412aSSrinivas Pandruvada 
2309b8dea80SSrinivas Pandruvada 	if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
2319b8dea80SSrinivas Pandruvada 		ret = ida_alloc(&intel_uncore_ida, GFP_KERNEL);
2329b8dea80SSrinivas Pandruvada 		if (ret < 0)
2339b8dea80SSrinivas Pandruvada 			goto uncore_unlock;
2349b8dea80SSrinivas Pandruvada 
2359b8dea80SSrinivas Pandruvada 		data->instance_id = ret;
2369b8dea80SSrinivas Pandruvada 		sprintf(data->name, "uncore%02d", ret);
2379b8dea80SSrinivas Pandruvada 	} else {
238dbce412aSSrinivas Pandruvada 		sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
2399b8dea80SSrinivas Pandruvada 	}
240dbce412aSSrinivas Pandruvada 
241dbce412aSSrinivas Pandruvada 	uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz);
242dbce412aSSrinivas Pandruvada 
243dbce412aSSrinivas Pandruvada 	ret = create_attr_group(data, data->name);
2449b8dea80SSrinivas Pandruvada 	if (ret) {
2459b8dea80SSrinivas Pandruvada 		if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
2469b8dea80SSrinivas Pandruvada 			ida_free(&intel_uncore_ida, data->instance_id);
2479b8dea80SSrinivas Pandruvada 	} else {
248dbce412aSSrinivas Pandruvada 		data->control_cpu = cpu;
249dbce412aSSrinivas Pandruvada 		data->valid = true;
250dbce412aSSrinivas Pandruvada 	}
251dbce412aSSrinivas Pandruvada 
252dbce412aSSrinivas Pandruvada uncore_unlock:
253dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
254dbce412aSSrinivas Pandruvada 
255dbce412aSSrinivas Pandruvada 	return ret;
256dbce412aSSrinivas Pandruvada }
257dbce412aSSrinivas Pandruvada EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
258dbce412aSSrinivas Pandruvada 
uncore_freq_remove_die_entry(struct uncore_data * data)259dbce412aSSrinivas Pandruvada void uncore_freq_remove_die_entry(struct uncore_data *data)
260dbce412aSSrinivas Pandruvada {
261dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
262dbce412aSSrinivas Pandruvada 	delete_attr_group(data, data->name);
263dbce412aSSrinivas Pandruvada 	data->control_cpu = -1;
264dbce412aSSrinivas Pandruvada 	data->valid = false;
2659b8dea80SSrinivas Pandruvada 	if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
2669b8dea80SSrinivas Pandruvada 		ida_free(&intel_uncore_ida, data->instance_id);
2679b8dea80SSrinivas Pandruvada 
268dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
269dbce412aSSrinivas Pandruvada }
270dbce412aSSrinivas Pandruvada EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
271dbce412aSSrinivas Pandruvada 
uncore_freq_common_init(int (* read_control_freq)(struct uncore_data * data,unsigned int * min,unsigned int * max),int (* write_control_freq)(struct uncore_data * data,unsigned int input,unsigned int set_max),int (* read_freq)(struct uncore_data * data,unsigned int * freq))272dbce412aSSrinivas Pandruvada int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max),
273dbce412aSSrinivas Pandruvada 			     int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max),
274dbce412aSSrinivas Pandruvada 			     int (*read_freq)(struct uncore_data *data, unsigned int *freq))
275dbce412aSSrinivas Pandruvada {
276dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
277dbce412aSSrinivas Pandruvada 
278dbce412aSSrinivas Pandruvada 	uncore_read = read_control_freq;
279dbce412aSSrinivas Pandruvada 	uncore_write = write_control_freq;
280dbce412aSSrinivas Pandruvada 	uncore_read_freq = read_freq;
281dbce412aSSrinivas Pandruvada 
282c8e15075SGreg Kroah-Hartman 	if (!uncore_root_kobj) {
283c8e15075SGreg Kroah-Hartman 		struct device *dev_root = bus_get_dev_root(&cpu_subsys);
284c8e15075SGreg Kroah-Hartman 
285c8e15075SGreg Kroah-Hartman 		if (dev_root) {
286dbce412aSSrinivas Pandruvada 			uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
287c8e15075SGreg Kroah-Hartman 								  &dev_root->kobj);
288c8e15075SGreg Kroah-Hartman 			put_device(dev_root);
289c8e15075SGreg Kroah-Hartman 		}
290c8e15075SGreg Kroah-Hartman 	}
291dbce412aSSrinivas Pandruvada 	if (uncore_root_kobj)
292dbce412aSSrinivas Pandruvada 		++uncore_instance_count;
293dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
294dbce412aSSrinivas Pandruvada 
295f2a6c7e7SDan Carpenter 	return uncore_root_kobj ? 0 : -ENOMEM;
296dbce412aSSrinivas Pandruvada }
297dbce412aSSrinivas Pandruvada EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
298dbce412aSSrinivas Pandruvada 
uncore_freq_common_exit(void)299dbce412aSSrinivas Pandruvada void uncore_freq_common_exit(void)
300dbce412aSSrinivas Pandruvada {
301dbce412aSSrinivas Pandruvada 	mutex_lock(&uncore_lock);
302dbce412aSSrinivas Pandruvada 	--uncore_instance_count;
303dbce412aSSrinivas Pandruvada 	if (!uncore_instance_count) {
304dbce412aSSrinivas Pandruvada 		kobject_put(uncore_root_kobj);
305dbce412aSSrinivas Pandruvada 		uncore_root_kobj = NULL;
306dbce412aSSrinivas Pandruvada 	}
307dbce412aSSrinivas Pandruvada 	mutex_unlock(&uncore_lock);
308dbce412aSSrinivas Pandruvada }
309dbce412aSSrinivas Pandruvada EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
310dbce412aSSrinivas Pandruvada 
311dbce412aSSrinivas Pandruvada 
312dbce412aSSrinivas Pandruvada MODULE_LICENSE("GPL v2");
313dbce412aSSrinivas Pandruvada MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");
314