Skip to content

Commit bb516dc

Browse files
Tero Kristojwrdegoede
authored andcommitted
platform/x86/intel-uncore-freq: Add support for efficiency latency control
Add efficiency latency control support to the TPMI uncore driver. This defines two new threshold values for controlling uncore frequency, low threshold and high threshold. When CPU utilization is below low threshold, the user configurable floor latency control frequency can be used by the system. When CPU utilization is above high threshold, the uncore frequency is increased in 100MHz steps until power limit is reached. Signed-off-by: Tero Kristo <[email protected]> Reviewed-by: Ilpo Järvinen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Hans de Goede <[email protected]>
1 parent 8022ae2 commit bb516dc

File tree

2 files changed

+160
-2
lines changed

2 files changed

+160
-2
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ enum uncore_index {
7070
UNCORE_INDEX_MIN_FREQ,
7171
UNCORE_INDEX_MAX_FREQ,
7272
UNCORE_INDEX_CURRENT_FREQ,
73+
UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD,
74+
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD,
75+
UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE,
76+
UNCORE_INDEX_EFF_LAT_CTRL_FREQ,
7377
};
7478

7579
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: 156 additions & 2 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

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

410561
cluster_info->uncore_root = tpmi_uncore;
411562

563+
if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION)
564+
cluster_info->elc_supported = true;
565+
412566
ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0);
413567
if (ret) {
414568
cluster_info->cluster_base = NULL;

0 commit comments

Comments
 (0)