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