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