Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,16 @@ static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index
static ssize_t store_attr(struct uncore_data *data, const char *buf, ssize_t count,
enum uncore_index index)
{
unsigned int input;
unsigned int input = 0;
int ret;

if (kstrtouint(buf, 10, &input))
return -EINVAL;
if (index == UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE) {
if (kstrtobool(buf, (bool *)&input))
return -EINVAL;
} else {
if (kstrtouint(buf, 10, &input))
return -EINVAL;
}

mutex_lock(&uncore_lock);
ret = uncore_write(data, input, index);
Expand Down Expand Up @@ -103,6 +108,18 @@ show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);

show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ);

store_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
store_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
store_uncore_attr(elc_high_threshold_enable,
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
store_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);

show_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
show_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
show_uncore_attr(elc_high_threshold_enable,
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);

#define show_uncore_data(member_name) \
static ssize_t show_##member_name(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf)\
Expand Down Expand Up @@ -146,7 +163,8 @@ show_uncore_data(initial_max_freq_khz);

static int create_attr_group(struct uncore_data *data, char *name)
{
int ret, freq, index = 0;
int ret, index = 0;
unsigned int val;

init_attribute_rw(max_freq_khz);
init_attribute_rw(min_freq_khz);
Expand All @@ -168,10 +186,24 @@ static int create_attr_group(struct uncore_data *data, char *name)
data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;

ret = uncore_read(data, &freq, UNCORE_INDEX_CURRENT_FREQ);
ret = uncore_read(data, &val, UNCORE_INDEX_CURRENT_FREQ);
if (!ret)
data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;

ret = uncore_read(data, &val, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
if (!ret) {
init_attribute_rw(elc_low_threshold_percent);
init_attribute_rw(elc_high_threshold_percent);
init_attribute_rw(elc_high_threshold_enable);
init_attribute_rw(elc_floor_freq_khz);

data->uncore_attrs[index++] = &data->elc_low_threshold_percent_kobj_attr.attr;
data->uncore_attrs[index++] = &data->elc_high_threshold_percent_kobj_attr.attr;
data->uncore_attrs[index++] =
&data->elc_high_threshold_enable_kobj_attr.attr;
data->uncore_attrs[index++] = &data->elc_floor_freq_khz_kobj_attr.attr;
}

data->uncore_attrs[index] = NULL;

data->uncore_attr_group.name = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
* @domain_id_kobj_attr: Storage for kobject attribute domain_id
* @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id
* @package_id_kobj_attr: Storage for kobject attribute package_id
* @elc_low_threshold_percent_kobj_attr:
Storage for kobject attribute elc_low_threshold_percent
* @elc_high_threshold_percent_kobj_attr:
Storage for kobject attribute elc_high_threshold_percent
* @elc_high_threshold_enable_kobj_attr:
Storage for kobject attribute elc_high_threshold_enable
* @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz
* @uncore_attrs: Attribute storage for group creation
*
* This structure is used to encapsulate all data related to uncore sysfs
Expand Down Expand Up @@ -61,7 +68,11 @@ struct uncore_data {
struct kobj_attribute domain_id_kobj_attr;
struct kobj_attribute fabric_cluster_id_kobj_attr;
struct kobj_attribute package_id_kobj_attr;
struct attribute *uncore_attrs[9];
struct kobj_attribute elc_low_threshold_percent_kobj_attr;
struct kobj_attribute elc_high_threshold_percent_kobj_attr;
struct kobj_attribute elc_high_threshold_enable_kobj_attr;
struct kobj_attribute elc_floor_freq_khz_kobj_attr;
struct attribute *uncore_attrs[13];
};

#define UNCORE_DOMAIN_ID_INVALID -1
Expand All @@ -70,6 +81,10 @@ enum uncore_index {
UNCORE_INDEX_MIN_FREQ,
UNCORE_INDEX_MAX_FREQ,
UNCORE_INDEX_CURRENT_FREQ,
UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD,
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD,
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE,
UNCORE_INDEX_EFF_LAT_CTRL_FREQ,
};

int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value,
Expand Down
165 changes: 162 additions & 3 deletions drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#define UNCORE_MAJOR_VERSION 0
#define UNCORE_MINOR_VERSION 2
#define UNCORE_ELC_SUPPORTED_VERSION 2
#define UNCORE_HEADER_INDEX 0
#define UNCORE_FABRIC_CLUSTER_OFFSET 8

Expand All @@ -46,6 +47,7 @@ struct tpmi_uncore_struct;
/* Information for each cluster */
struct tpmi_uncore_cluster_info {
bool root_domain;
bool elc_supported;
u8 __iomem *cluster_base;
struct uncore_data uncore_data;
struct tpmi_uncore_struct *uncore_root;
Expand Down Expand Up @@ -75,6 +77,10 @@ struct tpmi_uncore_struct {
/* Bit definitions for CONTROL register */
#define UNCORE_MAX_RATIO_MASK GENMASK_ULL(14, 8)
#define UNCORE_MIN_RATIO_MASK GENMASK_ULL(21, 15)
#define UNCORE_EFF_LAT_CTRL_RATIO_MASK GENMASK_ULL(28, 22)
#define UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK GENMASK_ULL(38, 32)
#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE BIT(39)
#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK GENMASK_ULL(46, 40)

/* Helper function to read MMIO offset for max/min control frequency */
static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info,
Expand All @@ -89,6 +95,48 @@ static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info,
*value = FIELD_GET(UNCORE_MIN_RATIO_MASK, control) * UNCORE_FREQ_KHZ_MULTIPLIER;
}

/* Helper function to read efficiency latency control values over MMIO */
static int read_eff_lat_ctrl(struct uncore_data *data, unsigned int *val, enum uncore_index index)
{
struct tpmi_uncore_cluster_info *cluster_info;
u64 ctrl;

cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data);
if (cluster_info->root_domain)
return -ENODATA;

if (!cluster_info->elc_supported)
return -EOPNOTSUPP;

ctrl = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX);

switch (index) {
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, ctrl);
*val *= 100;
*val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK));
break;

case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, ctrl);
*val *= 100;
*val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK));
break;

case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, ctrl);
break;
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_RATIO_MASK, ctrl) * UNCORE_FREQ_KHZ_MULTIPLIER;
break;

default:
return -EOPNOTSUPP;
}

return 0;
}

#define UNCORE_MAX_RATIO FIELD_MAX(UNCORE_MAX_RATIO_MASK)

/* Helper for sysfs read for max/min frequencies. Called under mutex locks */
Expand Down Expand Up @@ -137,6 +185,82 @@ static int uncore_read_control_freq(struct uncore_data *data, unsigned int *valu
return 0;
}

/* Helper function for writing efficiency latency control values over MMIO */
static int write_eff_lat_ctrl(struct uncore_data *data, unsigned int val, enum uncore_index index)
{
struct tpmi_uncore_cluster_info *cluster_info;
u64 control;

cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data);

if (cluster_info->root_domain)
return -ENODATA;

if (!cluster_info->elc_supported)
return -EOPNOTSUPP;

switch (index) {
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
if (val > 100)
return -EINVAL;
break;

case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
if (val > 100)
return -EINVAL;
break;

case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
if (val > 1)
return -EINVAL;
break;

case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
val /= UNCORE_FREQ_KHZ_MULTIPLIER;
if (val > FIELD_MAX(UNCORE_EFF_LAT_CTRL_RATIO_MASK))
return -EINVAL;
break;

default:
return -EOPNOTSUPP;
}

control = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX);

switch (index) {
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK);
val /= 100;
control &= ~UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK;
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, val);
break;

case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK);
val /= 100;
control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK;
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, val);
break;

case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE;
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, val);
break;

case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
control &= ~UNCORE_EFF_LAT_CTRL_RATIO_MASK;
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_RATIO_MASK, val);
break;

default:
break;
}

writeq(control, cluster_info->cluster_base + UNCORE_CONTROL_INDEX);

return 0;
}

/* Helper function to write MMIO offset for max/min control frequency */
static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, unsigned int input,
unsigned int index)
Expand All @@ -156,7 +280,7 @@ static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, un
writeq(control, (cluster_info->cluster_base + UNCORE_CONTROL_INDEX));
}

/* Callback for sysfs write for max/min frequencies. Called under mutex locks */
/* Helper for sysfs write for max/min frequencies. Called under mutex locks */
static int uncore_write_control_freq(struct uncore_data *data, unsigned int input,
enum uncore_index index)
{
Expand Down Expand Up @@ -234,6 +358,33 @@ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncor
case UNCORE_INDEX_CURRENT_FREQ:
return uncore_read_freq(data, value);

case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
return read_eff_lat_ctrl(data, value, index);

default:
break;
}

return -EOPNOTSUPP;
}

/* Callback for sysfs write for TPMI uncore data. Called under mutex locks. */
static int uncore_write(struct uncore_data *data, unsigned int value, enum uncore_index index)
{
switch (index) {
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
return write_eff_lat_ctrl(data, value, index);

case UNCORE_INDEX_MIN_FREQ:
case UNCORE_INDEX_MAX_FREQ:
return uncore_write_control_freq(data, value, index);

default:
break;
}
Expand Down Expand Up @@ -291,7 +442,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
return -EINVAL;

/* Register callbacks to uncore core */
ret = uncore_freq_common_init(uncore_read, uncore_write_control_freq);
ret = uncore_freq_common_init(uncore_read, uncore_write);
if (ret)
return ret;

Expand Down Expand Up @@ -409,6 +560,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_

cluster_info->uncore_root = tpmi_uncore;

if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION)
cluster_info->elc_supported = true;

ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0);
if (ret) {
cluster_info->cluster_base = NULL;
Expand All @@ -427,6 +581,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_

auxiliary_set_drvdata(auxdev, tpmi_uncore);

if (topology_max_die_per_package() > 1)
return 0;

tpmi_uncore->root_cluster.root_domain = true;
tpmi_uncore->root_cluster.uncore_root = tpmi_uncore;

Expand All @@ -450,7 +607,9 @@ static void uncore_remove(struct auxiliary_device *auxdev)
{
struct tpmi_uncore_struct *tpmi_uncore = auxiliary_get_drvdata(auxdev);

uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data);
if (tpmi_uncore->root_cluster.root_domain)
uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data);

remove_cluster_entries(tpmi_uncore);

uncore_freq_common_exit();
Expand Down