Skip to content

Commit aa684c7

Browse files
committed
Merge pull-request openvelinux#48 -- 'velinux-kernel-intel/6.6-velinux-intel-uncore-freq-add-elc-support' into intel-6.6-velinux
backport Uncore freq Efficiency Latency Control (ELC) feature from 6.13. ELC description in kernel doc: https://www.kernel.org/doc/html/v6.14-rc5/admin-guide/pm/intel_uncore_frequency_scaling.html test: sysfs is added and worked as expected
2 parents ec0a967 + 8f88f99 commit aa684c7

File tree

3 files changed

+215
-9
lines changed

3 files changed

+215
-9
lines changed

drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,16 @@ static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index
6060
static ssize_t store_attr(struct uncore_data *data, const char *buf, ssize_t count,
6161
enum uncore_index index)
6262
{
63-
unsigned int input;
63+
unsigned int input = 0;
6464
int ret;
6565

66-
if (kstrtouint(buf, 10, &input))
67-
return -EINVAL;
66+
if (index == UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE) {
67+
if (kstrtobool(buf, (bool *)&input))
68+
return -EINVAL;
69+
} else {
70+
if (kstrtouint(buf, 10, &input))
71+
return -EINVAL;
72+
}
6873

6974
mutex_lock(&uncore_lock);
7075
ret = uncore_write(data, input, index);
@@ -103,6 +108,18 @@ show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);
103108

104109
show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ);
105110

111+
store_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
112+
store_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
113+
store_uncore_attr(elc_high_threshold_enable,
114+
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
115+
store_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);
116+
117+
show_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
118+
show_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
119+
show_uncore_attr(elc_high_threshold_enable,
120+
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
121+
show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);
122+
106123
#define show_uncore_data(member_name) \
107124
static ssize_t show_##member_name(struct kobject *kobj, \
108125
struct kobj_attribute *attr, char *buf)\
@@ -146,7 +163,8 @@ show_uncore_data(initial_max_freq_khz);
146163

147164
static int create_attr_group(struct uncore_data *data, char *name)
148165
{
149-
int ret, freq, index = 0;
166+
int ret, index = 0;
167+
unsigned int val;
150168

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

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

193+
ret = uncore_read(data, &val, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
194+
if (!ret) {
195+
init_attribute_rw(elc_low_threshold_percent);
196+
init_attribute_rw(elc_high_threshold_percent);
197+
init_attribute_rw(elc_high_threshold_enable);
198+
init_attribute_rw(elc_floor_freq_khz);
199+
200+
data->uncore_attrs[index++] = &data->elc_low_threshold_percent_kobj_attr.attr;
201+
data->uncore_attrs[index++] = &data->elc_high_threshold_percent_kobj_attr.attr;
202+
data->uncore_attrs[index++] =
203+
&data->elc_high_threshold_enable_kobj_attr.attr;
204+
data->uncore_attrs[index++] = &data->elc_floor_freq_khz_kobj_attr.attr;
205+
}
206+
175207
data->uncore_attrs[index] = NULL;
176208

177209
data->uncore_attr_group.name = name;

drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
* @domain_id_kobj_attr: Storage for kobject attribute domain_id
3535
* @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id
3636
* @package_id_kobj_attr: Storage for kobject attribute package_id
37+
* @elc_low_threshold_percent_kobj_attr:
38+
Storage for kobject attribute elc_low_threshold_percent
39+
* @elc_high_threshold_percent_kobj_attr:
40+
Storage for kobject attribute elc_high_threshold_percent
41+
* @elc_high_threshold_enable_kobj_attr:
42+
Storage for kobject attribute elc_high_threshold_enable
43+
* @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz
3744
* @uncore_attrs: Attribute storage for group creation
3845
*
3946
* This structure is used to encapsulate all data related to uncore sysfs
@@ -61,7 +68,11 @@ struct uncore_data {
6168
struct kobj_attribute domain_id_kobj_attr;
6269
struct kobj_attribute fabric_cluster_id_kobj_attr;
6370
struct kobj_attribute package_id_kobj_attr;
64-
struct attribute *uncore_attrs[9];
71+
struct kobj_attribute elc_low_threshold_percent_kobj_attr;
72+
struct kobj_attribute elc_high_threshold_percent_kobj_attr;
73+
struct kobj_attribute elc_high_threshold_enable_kobj_attr;
74+
struct kobj_attribute elc_floor_freq_khz_kobj_attr;
75+
struct attribute *uncore_attrs[13];
6576
};
6677

6778
#define UNCORE_DOMAIN_ID_INVALID -1
@@ -70,6 +81,10 @@ enum uncore_index {
7081
UNCORE_INDEX_MIN_FREQ,
7182
UNCORE_INDEX_MAX_FREQ,
7283
UNCORE_INDEX_CURRENT_FREQ,
84+
UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD,
85+
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD,
86+
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE,
87+
UNCORE_INDEX_EFF_LAT_CTRL_FREQ,
7388
};
7489

7590
int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value,

drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c

Lines changed: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#define UNCORE_MAJOR_VERSION 0
3232
#define UNCORE_MINOR_VERSION 2
33+
#define UNCORE_ELC_SUPPORTED_VERSION 2
3334
#define UNCORE_HEADER_INDEX 0
3435
#define UNCORE_FABRIC_CLUSTER_OFFSET 8
3536

@@ -46,6 +47,7 @@ struct tpmi_uncore_struct;
4647
/* Information for each cluster */
4748
struct tpmi_uncore_cluster_info {
4849
bool root_domain;
50+
bool elc_supported;
4951
u8 __iomem *cluster_base;
5052
struct uncore_data uncore_data;
5153
struct tpmi_uncore_struct *uncore_root;
@@ -75,6 +77,10 @@ struct tpmi_uncore_struct {
7577
/* Bit definitions for CONTROL register */
7678
#define UNCORE_MAX_RATIO_MASK GENMASK_ULL(14, 8)
7779
#define UNCORE_MIN_RATIO_MASK GENMASK_ULL(21, 15)
80+
#define UNCORE_EFF_LAT_CTRL_RATIO_MASK GENMASK_ULL(28, 22)
81+
#define UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK GENMASK_ULL(38, 32)
82+
#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE BIT(39)
83+
#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK GENMASK_ULL(46, 40)
7884

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

98+
/* Helper function to read efficiency latency control values over MMIO */
99+
static int read_eff_lat_ctrl(struct uncore_data *data, unsigned int *val, enum uncore_index index)
100+
{
101+
struct tpmi_uncore_cluster_info *cluster_info;
102+
u64 ctrl;
103+
104+
cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data);
105+
if (cluster_info->root_domain)
106+
return -ENODATA;
107+
108+
if (!cluster_info->elc_supported)
109+
return -EOPNOTSUPP;
110+
111+
ctrl = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX);
112+
113+
switch (index) {
114+
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
115+
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, ctrl);
116+
*val *= 100;
117+
*val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK));
118+
break;
119+
120+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
121+
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, ctrl);
122+
*val *= 100;
123+
*val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK));
124+
break;
125+
126+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
127+
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, ctrl);
128+
break;
129+
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
130+
*val = FIELD_GET(UNCORE_EFF_LAT_CTRL_RATIO_MASK, ctrl) * UNCORE_FREQ_KHZ_MULTIPLIER;
131+
break;
132+
133+
default:
134+
return -EOPNOTSUPP;
135+
}
136+
137+
return 0;
138+
}
139+
92140
#define UNCORE_MAX_RATIO FIELD_MAX(UNCORE_MAX_RATIO_MASK)
93141

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

188+
/* Helper function for writing efficiency latency control values over MMIO */
189+
static int write_eff_lat_ctrl(struct uncore_data *data, unsigned int val, enum uncore_index index)
190+
{
191+
struct tpmi_uncore_cluster_info *cluster_info;
192+
u64 control;
193+
194+
cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data);
195+
196+
if (cluster_info->root_domain)
197+
return -ENODATA;
198+
199+
if (!cluster_info->elc_supported)
200+
return -EOPNOTSUPP;
201+
202+
switch (index) {
203+
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
204+
if (val > 100)
205+
return -EINVAL;
206+
break;
207+
208+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
209+
if (val > 100)
210+
return -EINVAL;
211+
break;
212+
213+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
214+
if (val > 1)
215+
return -EINVAL;
216+
break;
217+
218+
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
219+
val /= UNCORE_FREQ_KHZ_MULTIPLIER;
220+
if (val > FIELD_MAX(UNCORE_EFF_LAT_CTRL_RATIO_MASK))
221+
return -EINVAL;
222+
break;
223+
224+
default:
225+
return -EOPNOTSUPP;
226+
}
227+
228+
control = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX);
229+
230+
switch (index) {
231+
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
232+
val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK);
233+
val /= 100;
234+
control &= ~UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK;
235+
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, val);
236+
break;
237+
238+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
239+
val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK);
240+
val /= 100;
241+
control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK;
242+
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, val);
243+
break;
244+
245+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
246+
control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE;
247+
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, val);
248+
break;
249+
250+
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
251+
control &= ~UNCORE_EFF_LAT_CTRL_RATIO_MASK;
252+
control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_RATIO_MASK, val);
253+
break;
254+
255+
default:
256+
break;
257+
}
258+
259+
writeq(control, cluster_info->cluster_base + UNCORE_CONTROL_INDEX);
260+
261+
return 0;
262+
}
263+
140264
/* Helper function to write MMIO offset for max/min control frequency */
141265
static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, unsigned int input,
142266
unsigned int index)
@@ -156,7 +280,7 @@ static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, un
156280
writeq(control, (cluster_info->cluster_base + UNCORE_CONTROL_INDEX));
157281
}
158282

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

361+
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
362+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
363+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
364+
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
365+
return read_eff_lat_ctrl(data, value, index);
366+
367+
default:
368+
break;
369+
}
370+
371+
return -EOPNOTSUPP;
372+
}
373+
374+
/* Callback for sysfs write for TPMI uncore data. Called under mutex locks. */
375+
static int uncore_write(struct uncore_data *data, unsigned int value, enum uncore_index index)
376+
{
377+
switch (index) {
378+
case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
379+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
380+
case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
381+
case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
382+
return write_eff_lat_ctrl(data, value, index);
383+
384+
case UNCORE_INDEX_MIN_FREQ:
385+
case UNCORE_INDEX_MAX_FREQ:
386+
return uncore_write_control_freq(data, value, index);
387+
237388
default:
238389
break;
239390
}
@@ -291,7 +442,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
291442
return -EINVAL;
292443

293444
/* Register callbacks to uncore core */
294-
ret = uncore_freq_common_init(uncore_read, uncore_write_control_freq);
445+
ret = uncore_freq_common_init(uncore_read, uncore_write);
295446
if (ret)
296447
return ret;
297448

@@ -412,6 +563,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
412563

413564
cluster_info->uncore_root = tpmi_uncore;
414565

566+
if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION)
567+
cluster_info->elc_supported = true;
568+
415569
ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0);
416570
if (ret) {
417571
cluster_info->cluster_base = NULL;
@@ -430,6 +584,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
430584

431585
auxiliary_set_drvdata(auxdev, tpmi_uncore);
432586

587+
if (topology_max_die_per_package() > 1)
588+
return 0;
589+
433590
tpmi_uncore->root_cluster.root_domain = true;
434591
tpmi_uncore->root_cluster.uncore_root = tpmi_uncore;
435592

@@ -453,7 +610,9 @@ static void uncore_remove(struct auxiliary_device *auxdev)
453610
{
454611
struct tpmi_uncore_struct *tpmi_uncore = auxiliary_get_drvdata(auxdev);
455612

456-
uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data);
613+
if (tpmi_uncore->root_cluster.root_domain)
614+
uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data);
615+
457616
remove_cluster_entries(tpmi_uncore);
458617

459618
uncore_freq_common_exit();

0 commit comments

Comments
 (0)