cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

uncore-frequency-common.c (7467B)


      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 */
     13static DEFINE_MUTEX(uncore_lock);
     14/* Root of the all uncore sysfs kobjs */
     15static struct kobject *uncore_root_kobj;
     16/* uncore instance count */
     17static int uncore_instance_count;
     18
     19/* callbacks for actual HW read/write */
     20static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max);
     21static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
     22static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
     23
     24static 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
     42static 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
     58static 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
    101store_uncore_min_max(min_freq_khz, 0);
    102store_uncore_min_max(max_freq_khz, 1);
    103
    104show_uncore_min_max(min_freq_khz, 0);
    105show_uncore_min_max(max_freq_khz, 1);
    106
    107show_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 scnprintf(buf, PAGE_SIZE, "%u\n",		\
    117				 data->member_name);			\
    118	}								\
    119
    120show_uncore_data(initial_min_freq_khz);
    121show_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
    150static 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
    174static void delete_attr_group(struct uncore_data *data, char *name)
    175{
    176	sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group);
    177}
    178
    179int 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
    200uncore_unlock:
    201	mutex_unlock(&uncore_lock);
    202
    203	return ret;
    204}
    205EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY);
    206
    207void 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}
    215EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY);
    216
    217int 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		uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency",
    229							    &cpu_subsys.dev_root->kobj);
    230	if (uncore_root_kobj)
    231		++uncore_instance_count;
    232	mutex_unlock(&uncore_lock);
    233
    234	return uncore_root_kobj ? 0 : -ENOMEM;
    235}
    236EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY);
    237
    238void uncore_freq_common_exit(void)
    239{
    240	mutex_lock(&uncore_lock);
    241	--uncore_instance_count;
    242	if (!uncore_instance_count) {
    243		kobject_put(uncore_root_kobj);
    244		uncore_root_kobj = NULL;
    245	}
    246	mutex_unlock(&uncore_lock);
    247}
    248EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY);
    249
    250
    251MODULE_LICENSE("GPL v2");
    252MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");