Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.15-rc3 451 lines 11 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Intel Uncore Frequency Setting 4 * Copyright (c) 2019, Intel Corporation. 5 * All rights reserved. 6 * 7 * Provide interface to set MSR 620 at a granularity of per die. On CPU online, 8 * one control CPU is identified per die to read/write limit. This control CPU 9 * is changed, if the CPU state is changed to offline. When the last CPU is 10 * offline in a die then remove the sysfs object for that die. 11 * The majority of actual code is related to sysfs create and read/write 12 * attributes. 13 * 14 * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 15 */ 16 17#include <linux/cpu.h> 18#include <linux/module.h> 19#include <linux/slab.h> 20#include <linux/suspend.h> 21#include <asm/cpu_device_id.h> 22#include <asm/intel-family.h> 23 24#define MSR_UNCORE_RATIO_LIMIT 0x620 25#define UNCORE_FREQ_KHZ_MULTIPLIER 100000 26 27/** 28 * struct uncore_data - Encapsulate all uncore data 29 * @stored_uncore_data: Last user changed MSR 620 value, which will be restored 30 * on system resume. 31 * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init 32 * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init 33 * @control_cpu: Designated CPU for a die to read/write 34 * @valid: Mark the data valid/invalid 35 * 36 * This structure is used to encapsulate all data related to uncore sysfs 37 * settings for a die/package. 38 */ 39struct uncore_data { 40 struct kobject kobj; 41 struct completion kobj_unregister; 42 u64 stored_uncore_data; 43 u32 initial_min_freq_khz; 44 u32 initial_max_freq_khz; 45 int control_cpu; 46 bool valid; 47}; 48 49#define to_uncore_data(a) container_of(a, struct uncore_data, kobj) 50 51/* Max instances for uncore data, one for each die */ 52static int uncore_max_entries __read_mostly; 53/* Storage for uncore data for all instances */ 54static struct uncore_data *uncore_instances; 55/* Root of the all uncore sysfs kobjs */ 56static struct kobject *uncore_root_kobj; 57/* Stores the CPU mask of the target CPUs to use during uncore read/write */ 58static cpumask_t uncore_cpu_mask; 59/* CPU online callback register instance */ 60static enum cpuhp_state uncore_hp_state __read_mostly; 61/* Mutex to control all mutual exclusions */ 62static DEFINE_MUTEX(uncore_lock); 63 64struct uncore_attr { 65 struct attribute attr; 66 ssize_t (*show)(struct kobject *kobj, 67 struct attribute *attr, char *buf); 68 ssize_t (*store)(struct kobject *kobj, 69 struct attribute *attr, const char *c, ssize_t count); 70}; 71 72#define define_one_uncore_ro(_name) \ 73static struct uncore_attr _name = \ 74__ATTR(_name, 0444, show_##_name, NULL) 75 76#define define_one_uncore_rw(_name) \ 77static struct uncore_attr _name = \ 78__ATTR(_name, 0644, show_##_name, store_##_name) 79 80#define show_uncore_data(member_name) \ 81 static ssize_t show_##member_name(struct kobject *kobj, \ 82 struct attribute *attr, \ 83 char *buf) \ 84 { \ 85 struct uncore_data *data = to_uncore_data(kobj); \ 86 return scnprintf(buf, PAGE_SIZE, "%u\n", \ 87 data->member_name); \ 88 } \ 89 define_one_uncore_ro(member_name) 90 91show_uncore_data(initial_min_freq_khz); 92show_uncore_data(initial_max_freq_khz); 93 94/* Common function to read MSR 0x620 and read min/max */ 95static int uncore_read_ratio(struct uncore_data *data, unsigned int *min, 96 unsigned int *max) 97{ 98 u64 cap; 99 int ret; 100 101 if (data->control_cpu < 0) 102 return -ENXIO; 103 104 ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); 105 if (ret) 106 return ret; 107 108 *max = (cap & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; 109 *min = ((cap & GENMASK(14, 8)) >> 8) * UNCORE_FREQ_KHZ_MULTIPLIER; 110 111 return 0; 112} 113 114/* Common function to set min/max ratios to be used by sysfs callbacks */ 115static int uncore_write_ratio(struct uncore_data *data, unsigned int input, 116 int set_max) 117{ 118 int ret; 119 u64 cap; 120 121 mutex_lock(&uncore_lock); 122 123 if (data->control_cpu < 0) { 124 ret = -ENXIO; 125 goto finish_write; 126 } 127 128 input /= UNCORE_FREQ_KHZ_MULTIPLIER; 129 if (!input || input > 0x7F) { 130 ret = -EINVAL; 131 goto finish_write; 132 } 133 134 ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); 135 if (ret) 136 goto finish_write; 137 138 if (set_max) { 139 cap &= ~0x7F; 140 cap |= input; 141 } else { 142 cap &= ~GENMASK(14, 8); 143 cap |= (input << 8); 144 } 145 146 ret = wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap); 147 if (ret) 148 goto finish_write; 149 150 data->stored_uncore_data = cap; 151 152finish_write: 153 mutex_unlock(&uncore_lock); 154 155 return ret; 156} 157 158static ssize_t store_min_max_freq_khz(struct kobject *kobj, 159 struct attribute *attr, 160 const char *buf, ssize_t count, 161 int min_max) 162{ 163 struct uncore_data *data = to_uncore_data(kobj); 164 unsigned int input; 165 166 if (kstrtouint(buf, 10, &input)) 167 return -EINVAL; 168 169 uncore_write_ratio(data, input, min_max); 170 171 return count; 172} 173 174static ssize_t show_min_max_freq_khz(struct kobject *kobj, 175 struct attribute *attr, 176 char *buf, int min_max) 177{ 178 struct uncore_data *data = to_uncore_data(kobj); 179 unsigned int min, max; 180 int ret; 181 182 mutex_lock(&uncore_lock); 183 ret = uncore_read_ratio(data, &min, &max); 184 mutex_unlock(&uncore_lock); 185 if (ret) 186 return ret; 187 188 if (min_max) 189 return sprintf(buf, "%u\n", max); 190 191 return sprintf(buf, "%u\n", min); 192} 193 194#define store_uncore_min_max(name, min_max) \ 195 static ssize_t store_##name(struct kobject *kobj, \ 196 struct attribute *attr, \ 197 const char *buf, ssize_t count) \ 198 { \ 199 \ 200 return store_min_max_freq_khz(kobj, attr, buf, count, \ 201 min_max); \ 202 } 203 204#define show_uncore_min_max(name, min_max) \ 205 static ssize_t show_##name(struct kobject *kobj, \ 206 struct attribute *attr, char *buf) \ 207 { \ 208 \ 209 return show_min_max_freq_khz(kobj, attr, buf, min_max); \ 210 } 211 212store_uncore_min_max(min_freq_khz, 0); 213store_uncore_min_max(max_freq_khz, 1); 214 215show_uncore_min_max(min_freq_khz, 0); 216show_uncore_min_max(max_freq_khz, 1); 217 218define_one_uncore_rw(min_freq_khz); 219define_one_uncore_rw(max_freq_khz); 220 221static struct attribute *uncore_attrs[] = { 222 &initial_min_freq_khz.attr, 223 &initial_max_freq_khz.attr, 224 &max_freq_khz.attr, 225 &min_freq_khz.attr, 226 NULL 227}; 228 229static void uncore_sysfs_entry_release(struct kobject *kobj) 230{ 231 struct uncore_data *data = to_uncore_data(kobj); 232 233 complete(&data->kobj_unregister); 234} 235 236static struct kobj_type uncore_ktype = { 237 .release = uncore_sysfs_entry_release, 238 .sysfs_ops = &kobj_sysfs_ops, 239 .default_attrs = uncore_attrs, 240}; 241 242/* Caller provides protection */ 243static struct uncore_data *uncore_get_instance(unsigned int cpu) 244{ 245 int id = topology_logical_die_id(cpu); 246 247 if (id >= 0 && id < uncore_max_entries) 248 return &uncore_instances[id]; 249 250 return NULL; 251} 252 253static void uncore_add_die_entry(int cpu) 254{ 255 struct uncore_data *data; 256 257 mutex_lock(&uncore_lock); 258 data = uncore_get_instance(cpu); 259 if (!data) { 260 mutex_unlock(&uncore_lock); 261 return; 262 } 263 264 if (data->valid) { 265 /* control cpu changed */ 266 data->control_cpu = cpu; 267 } else { 268 char str[64]; 269 int ret; 270 271 memset(data, 0, sizeof(*data)); 272 sprintf(str, "package_%02d_die_%02d", 273 topology_physical_package_id(cpu), 274 topology_die_id(cpu)); 275 276 uncore_read_ratio(data, &data->initial_min_freq_khz, 277 &data->initial_max_freq_khz); 278 279 init_completion(&data->kobj_unregister); 280 281 ret = kobject_init_and_add(&data->kobj, &uncore_ktype, 282 uncore_root_kobj, str); 283 if (!ret) { 284 data->control_cpu = cpu; 285 data->valid = true; 286 } 287 } 288 mutex_unlock(&uncore_lock); 289} 290 291/* Last CPU in this die is offline, make control cpu invalid */ 292static void uncore_remove_die_entry(int cpu) 293{ 294 struct uncore_data *data; 295 296 mutex_lock(&uncore_lock); 297 data = uncore_get_instance(cpu); 298 if (data) 299 data->control_cpu = -1; 300 mutex_unlock(&uncore_lock); 301} 302 303static int uncore_event_cpu_online(unsigned int cpu) 304{ 305 int target; 306 307 /* Check if there is an online cpu in the package for uncore MSR */ 308 target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); 309 if (target < nr_cpu_ids) 310 return 0; 311 312 /* Use this CPU on this die as a control CPU */ 313 cpumask_set_cpu(cpu, &uncore_cpu_mask); 314 uncore_add_die_entry(cpu); 315 316 return 0; 317} 318 319static int uncore_event_cpu_offline(unsigned int cpu) 320{ 321 int target; 322 323 /* Check if existing cpu is used for uncore MSRs */ 324 if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) 325 return 0; 326 327 /* Find a new cpu to set uncore MSR */ 328 target = cpumask_any_but(topology_die_cpumask(cpu), cpu); 329 330 if (target < nr_cpu_ids) { 331 cpumask_set_cpu(target, &uncore_cpu_mask); 332 uncore_add_die_entry(target); 333 } else { 334 uncore_remove_die_entry(cpu); 335 } 336 337 return 0; 338} 339 340static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode, 341 void *_unused) 342{ 343 int cpu; 344 345 switch (mode) { 346 case PM_POST_HIBERNATION: 347 case PM_POST_RESTORE: 348 case PM_POST_SUSPEND: 349 for_each_cpu(cpu, &uncore_cpu_mask) { 350 struct uncore_data *data; 351 int ret; 352 353 data = uncore_get_instance(cpu); 354 if (!data || !data->valid || !data->stored_uncore_data) 355 continue; 356 357 ret = wrmsrl_on_cpu(cpu, MSR_UNCORE_RATIO_LIMIT, 358 data->stored_uncore_data); 359 if (ret) 360 return ret; 361 } 362 break; 363 default: 364 break; 365 } 366 return 0; 367} 368 369static struct notifier_block uncore_pm_nb = { 370 .notifier_call = uncore_pm_notify, 371}; 372 373static const struct x86_cpu_id intel_uncore_cpu_ids[] = { 374 X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, NULL), 375 X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL), 376 X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, NULL), 377 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL), 378 X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), 379 X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), 380 X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), 381 {} 382}; 383 384static int __init intel_uncore_init(void) 385{ 386 const struct x86_cpu_id *id; 387 int ret; 388 389 id = x86_match_cpu(intel_uncore_cpu_ids); 390 if (!id) 391 return -ENODEV; 392 393 uncore_max_entries = topology_max_packages() * 394 topology_max_die_per_package(); 395 uncore_instances = kcalloc(uncore_max_entries, 396 sizeof(*uncore_instances), GFP_KERNEL); 397 if (!uncore_instances) 398 return -ENOMEM; 399 400 uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency", 401 &cpu_subsys.dev_root->kobj); 402 if (!uncore_root_kobj) { 403 ret = -ENOMEM; 404 goto err_free; 405 } 406 407 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 408 "platform/x86/uncore-freq:online", 409 uncore_event_cpu_online, 410 uncore_event_cpu_offline); 411 if (ret < 0) 412 goto err_rem_kobj; 413 414 uncore_hp_state = ret; 415 416 ret = register_pm_notifier(&uncore_pm_nb); 417 if (ret) 418 goto err_rem_state; 419 420 return 0; 421 422err_rem_state: 423 cpuhp_remove_state(uncore_hp_state); 424err_rem_kobj: 425 kobject_put(uncore_root_kobj); 426err_free: 427 kfree(uncore_instances); 428 429 return ret; 430} 431module_init(intel_uncore_init) 432 433static void __exit intel_uncore_exit(void) 434{ 435 int i; 436 437 unregister_pm_notifier(&uncore_pm_nb); 438 cpuhp_remove_state(uncore_hp_state); 439 for (i = 0; i < uncore_max_entries; ++i) { 440 if (uncore_instances[i].valid) { 441 kobject_put(&uncore_instances[i].kobj); 442 wait_for_completion(&uncore_instances[i].kobj_unregister); 443 } 444 } 445 kobject_put(uncore_root_kobj); 446 kfree(uncore_instances); 447} 448module_exit(intel_uncore_exit) 449 450MODULE_LICENSE("GPL v2"); 451MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver");