linux/drivers/platform/x86/intel/uncore-frequency.c
<<
>>
Prefs
   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");
 452