Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Intel Uncore Frequency Control: Common code implementation
0004  * Copyright (c) 2022, Intel Corporation.
0005  * All rights reserved.
0006  *
0007  */
0008 #include <linux/cpu.h>
0009 #include <linux/module.h>
0010 #include "uncore-frequency-common.h"
0011 
0012 /* Mutex to control all mutual exclusions */
0013 static DEFINE_MUTEX(uncore_lock);
0014 /* Root of the all uncore sysfs kobjs */
0015 static struct kobject *uncore_root_kobj;
0016 /* uncore instance count */
0017 static int uncore_instance_count;
0018 
0019 /* callbacks for actual HW read/write */
0020 static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max);
0021 static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
0022 static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
0023 
0024 static ssize_t show_min_max_freq_khz(struct uncore_data *data,
0025                       char *buf, int min_max)
0026 {
0027     unsigned int min, max;
0028     int ret;
0029 
0030     mutex_lock(&uncore_lock);
0031     ret = uncore_read(data, &min, &max);
0032     mutex_unlock(&uncore_lock);
0033     if (ret)
0034         return ret;
0035 
0036     if (min_max)
0037         return sprintf(buf, "%u\n", max);
0038 
0039     return sprintf(buf, "%u\n", min);
0040 }
0041 
0042 static ssize_t store_min_max_freq_khz(struct uncore_data *data,
0043                       const char *buf, ssize_t count,
0044                       int min_max)
0045 {
0046     unsigned int input;
0047 
0048     if (kstrtouint(buf, 10, &input))
0049         return -EINVAL;
0050 
0051     mutex_lock(&uncore_lock);
0052     uncore_write(data, input, min_max);
0053     mutex_unlock(&uncore_lock);
0054 
0055     return count;
0056 }
0057 
0058 static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf)
0059 {
0060     unsigned int freq;
0061     int ret;
0062 
0063     mutex_lock(&uncore_lock);
0064     ret = uncore_read_freq(data, &freq);
0065     mutex_unlock(&uncore_lock);
0066     if (ret)
0067         return ret;
0068 
0069     return sprintf(buf, "%u\n", freq);
0070 }
0071 
0072 #define store_uncore_min_max(name, min_max)             \
0073     static ssize_t store_##name(struct device *dev,     \
0074                      struct device_attribute *attr, \
0075                      const char *buf, size_t count) \
0076     {                               \
0077         struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
0078                                     \
0079         return store_min_max_freq_khz(data, buf, count, \
0080                           min_max);     \
0081     }
0082 
0083 #define show_uncore_min_max(name, min_max)              \
0084     static ssize_t show_##name(struct device *dev,      \
0085                     struct device_attribute *attr, char *buf)\
0086     {                                                               \
0087         struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
0088                                     \
0089         return show_min_max_freq_khz(data, buf, min_max);   \
0090     }
0091 
0092 #define show_uncore_perf_status(name)                   \
0093     static ssize_t show_##name(struct device *dev,      \
0094                    struct device_attribute *attr, char *buf)\
0095     {                                                               \
0096         struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
0097                                     \
0098         return show_perf_status_freq_khz(data, buf); \
0099     }
0100 
0101 store_uncore_min_max(min_freq_khz, 0);
0102 store_uncore_min_max(max_freq_khz, 1);
0103 
0104 show_uncore_min_max(min_freq_khz, 0);
0105 show_uncore_min_max(max_freq_khz, 1);
0106 
0107 show_uncore_perf_status(current_freq_khz);
0108 
0109 #define show_uncore_data(member_name)                   \
0110     static ssize_t show_##member_name(struct device *dev,   \
0111                        struct device_attribute *attr, char *buf)\
0112     {                                                               \
0113         struct uncore_data *data = container_of(attr, struct uncore_data,\
0114                               member_name##_dev_attr);\
0115                                     \
0116         return scnprintf(buf, PAGE_SIZE, "%u\n",        \
0117                  data->member_name);            \
0118     }                               \
0119 
0120 show_uncore_data(initial_min_freq_khz);
0121 show_uncore_data(initial_max_freq_khz);
0122 
0123 #define init_attribute_rw(_name)                    \
0124     do {                                \
0125         sysfs_attr_init(&data->_name##_dev_attr.attr);  \
0126         data->_name##_dev_attr.show = show_##_name;     \
0127         data->_name##_dev_attr.store = store_##_name;       \
0128         data->_name##_dev_attr.attr.name = #_name;      \
0129         data->_name##_dev_attr.attr.mode = 0644;        \
0130     } while (0)
0131 
0132 #define init_attribute_ro(_name)                    \
0133     do {                                \
0134         sysfs_attr_init(&data->_name##_dev_attr.attr);  \
0135         data->_name##_dev_attr.show = show_##_name;     \
0136         data->_name##_dev_attr.store = NULL;            \
0137         data->_name##_dev_attr.attr.name = #_name;      \
0138         data->_name##_dev_attr.attr.mode = 0444;        \
0139     } while (0)
0140 
0141 #define init_attribute_root_ro(_name)                   \
0142     do {                                \
0143         sysfs_attr_init(&data->_name##_dev_attr.attr);  \
0144         data->_name##_dev_attr.show = show_##_name;     \
0145         data->_name##_dev_attr.store = NULL;            \
0146         data->_name##_dev_attr.attr.name = #_name;      \
0147         data->_name##_dev_attr.attr.mode = 0400;        \
0148     } while (0)
0149 
0150 static int create_attr_group(struct uncore_data *data, char *name)
0151 {
0152     int ret, index = 0;
0153 
0154     init_attribute_rw(max_freq_khz);
0155     init_attribute_rw(min_freq_khz);
0156     init_attribute_ro(initial_min_freq_khz);
0157     init_attribute_ro(initial_max_freq_khz);
0158     init_attribute_root_ro(current_freq_khz);
0159 
0160     data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr;
0161     data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr;
0162     data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr;
0163     data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr;
0164     data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr;
0165     data->uncore_attrs[index] = NULL;
0166 
0167     data->uncore_attr_group.name = name;
0168     data->uncore_attr_group.attrs = data->uncore_attrs;
0169     ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group);
0170 
0171     return ret;
0172 }
0173 
0174 static void delete_attr_group(struct uncore_data *data, char *name)
0175 {
0176     sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
0177 }
0178 
0179 int uncore_freq_add_entry(struct uncore_data *data, int cpu)
0180 {
0181     int ret = 0;
0182 
0183     mutex_lock(&uncore_lock);
0184     if (data->valid) {
0185         /* control cpu changed */
0186         data->control_cpu = cpu;
0187         goto uncore_unlock;
0188     }
0189 
0190     sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
0191 
0192     uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz);
0193 
0194     ret = create_attr_group(data, data->name);
0195     if (!ret) {
0196         data->control_cpu = cpu;
0197         data->valid = true;
0198     }
0199 
0200 uncore_unlock:
0201     mutex_unlock(&uncore_lock);
0202 
0203     return ret;
0204 }
0205 EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
0206 
0207 void uncore_freq_remove_die_entry(struct uncore_data *data)
0208 {
0209     mutex_lock(&uncore_lock);
0210     delete_attr_group(data, data->name);
0211     data->control_cpu = -1;
0212     data->valid = false;
0213     mutex_unlock(&uncore_lock);
0214 }
0215 EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
0216 
0217 int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max),
0218                  int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max),
0219                  int (*read_freq)(struct uncore_data *data, unsigned int *freq))
0220 {
0221     mutex_lock(&uncore_lock);
0222 
0223     uncore_read = read_control_freq;
0224     uncore_write = write_control_freq;
0225     uncore_read_freq = read_freq;
0226 
0227     if (!uncore_root_kobj)
0228         uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
0229                                 &cpu_subsys.dev_root->kobj);
0230     if (uncore_root_kobj)
0231         ++uncore_instance_count;
0232     mutex_unlock(&uncore_lock);
0233 
0234     return uncore_root_kobj ? 0 : -ENOMEM;
0235 }
0236 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
0237 
0238 void uncore_freq_common_exit(void)
0239 {
0240     mutex_lock(&uncore_lock);
0241     --uncore_instance_count;
0242     if (!uncore_instance_count) {
0243         kobject_put(uncore_root_kobj);
0244         uncore_root_kobj = NULL;
0245     }
0246     mutex_unlock(&uncore_lock);
0247 }
0248 EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
0249 
0250 
0251 MODULE_LICENSE("GPL v2");
0252 MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");