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