Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145867241
D55477.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D55477.diff
View Options
diff --git a/sys/x86/cpufreq/hwpstate_amd.c b/sys/x86/cpufreq/hwpstate_amd.c
--- a/sys/x86/cpufreq/hwpstate_amd.c
+++ b/sys/x86/cpufreq/hwpstate_amd.c
@@ -73,13 +73,13 @@
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h>
+#include <dev/acpica/acpi_cppc_lib.h>
#include <x86/cpufreq/hwpstate_common.h>
#include "acpi_if.h"
#include "cpufreq_if.h"
-
#define MSR_AMD_10H_11H_LIMIT 0xc0010061
#define MSR_AMD_10H_11H_CONTROL 0xc0010062
#define MSR_AMD_10H_11H_STATUS 0xc0010063
@@ -150,6 +150,7 @@
};
#define HWPFL_USE_CPPC (1 << 0)
+#define HWPFL_CPPC_CPUFREQ_WRITE (1 << 1)
/*
* Atomicity is achieved by only modifying a given softc on its associated CPU
@@ -168,6 +169,8 @@
};
struct {
uint64_t request;
+ uint32_t caps1;
+ struct acpi_cppc_ctx *acpi_ctx;
} cppc;
};
};
@@ -286,6 +289,42 @@
#define HWP_ERROR_CPPC_REQUEST (1 << 2)
#define HWP_ERROR_CPPC_REQUEST_WRITE (1 << 3)
+static int
+upscale_cppc_freq(struct hwpstate_softc *sc, uint32_t perf)
+{
+ struct acpi_cppc_ctx *ctx = sc->cppc.acpi_ctx;
+ uint32_t low_freq, nominal_freq, low_perf, nominal_perf;
+
+ low_freq = acpi_cppc_read_reg(ctx, ACPI_CPPC_LOWEST_FREQ);
+ nominal_freq = acpi_cppc_read_reg(ctx, ACPI_CPPC_NOMINAL_FREQ);
+ low_perf = BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, sc->cppc.caps1);
+ nominal_perf = BITS_VALUE(AMD_CPPC_CAPS_1_NOMINAL_PERF_BITS,
+ sc->cppc.caps1);
+ if (nominal_perf == low_perf)
+ nominal_perf = low_perf + 1;
+ return (low_freq +
+ (nominal_freq - low_freq) * (perf - low_perf) /
+ (nominal_perf - low_perf));
+}
+
+static int
+downscale_cppc_freq(struct hwpstate_softc *sc, uint32_t freq)
+{
+ struct acpi_cppc_ctx *ctx = sc->cppc.acpi_ctx;
+ uint32_t low_freq, nominal_freq, low_perf, nominal_perf;
+
+ low_freq = acpi_cppc_read_reg(ctx, ACPI_CPPC_LOWEST_FREQ);
+ nominal_freq = acpi_cppc_read_reg(ctx, ACPI_CPPC_NOMINAL_FREQ);
+ low_perf = BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, sc->cppc.caps1);
+ nominal_perf = BITS_VALUE(AMD_CPPC_CAPS_1_NOMINAL_PERF_BITS,
+ sc->cppc.caps1);
+ if (nominal_freq == low_freq)
+ nominal_freq = low_freq + 1;
+ return (low_perf +
+ (nominal_perf - low_perf) * (freq - low_freq) /
+ (nominal_freq - low_freq));
+}
+
static inline bool
hwp_has_error(u_int res, u_int err)
{
@@ -294,7 +333,6 @@
struct get_cppc_regs_data {
uint64_t enable;
- uint64_t caps;
uint64_t req;
/* HWP_ERROR_CPPC_* except HWP_ERROR_*_WRITE */
u_int res;
@@ -312,10 +350,6 @@
if (error != 0)
data->res |= HWP_ERROR_CPPC_ENABLE;
- error = rdmsr_safe(MSR_AMD_CPPC_CAPS_1, &data->caps);
- if (error != 0)
- data->res |= HWP_ERROR_CPPC_CAPS;
-
error = rdmsr_safe(MSR_AMD_CPPC_REQUEST, &data->req);
if (error != 0)
data->res |= HWP_ERROR_CPPC_REQUEST;
@@ -351,7 +385,7 @@
if (hwp_has_error(data.res, HWP_ERROR_CPPC_CAPS))
print_cppc_no_caps_1(sb);
else
- print_cppc_caps_1(sb, data.caps);
+ print_cppc_caps_1(sb, sc->cppc.caps1);
if (hwp_has_error(data.res, HWP_ERROR_CPPC_REQUEST))
print_cppc_no_request(sb);
@@ -562,15 +596,24 @@
if (cf == NULL)
return (EINVAL);
sc = device_get_softc(dev);
- if ((sc->flags & HWPFL_USE_CPPC) != 0)
- return (EOPNOTSUPP);
+ if ((sc->flags & HWPFL_USE_CPPC) != 0) {
+ if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
+ return (ENOTSUP);
+
+ SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_DES_PERF_BITS,
+ downscale_cppc_freq(sc, cf->freq));
+ return (x86_msr_op(MSR_AMD_CPPC_REQUEST,
+ MSR_OP_RENDEZVOUS_ONE | MSR_OP_READ |
+ MSR_OP_CPUID(cpu_get_pcpu(dev)->pc_cpuid),
+ sc->cppc.request, NULL));
+ }
+
set = sc->hwpstate_settings;
for (i = 0; i < sc->cfnum; i++)
if (CPUFREQ_CMP(cf->freq, set[i].freq))
break;
if (i == sc->cfnum)
return (EINVAL);
-
return (hwpstate_goto_pstate(dev, set[i].pstate_id));
}
@@ -614,30 +657,59 @@
return (0);
}
+#define AMD_CPPC_STEPS 10
+#define AMD_CPPC_COUNT_LEVELS(l, r) ((r - l) / AMD_CPPC_STEPS + 1)
+
static int
hwpstate_settings(device_t dev, struct cf_setting *sets, int *count)
{
struct hwpstate_softc *sc;
struct hwpstate_setting set;
int i;
+ int levels;
+ int cur_level;
if (sets == NULL || count == NULL)
return (EINVAL);
sc = device_get_softc(dev);
- if ((sc->flags & HWPFL_USE_CPPC) != 0)
- return (EOPNOTSUPP);
-
- if (*count < sc->cfnum)
- return (E2BIG);
- for (i = 0; i < sc->cfnum; i++, sets++) {
- set = sc->hwpstate_settings[i];
- sets->freq = set.freq;
- sets->volts = set.volts;
- sets->power = set.power;
- sets->lat = set.lat;
- sets->dev = dev;
+
+ if ((sc->flags & HWPFL_USE_CPPC) != 0) {
+ if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
+ return (ENOTSUP);
+ levels = AMD_CPPC_COUNT_LEVELS(
+ BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS,
+ sc->cppc.caps1),
+ BITS_VALUE(AMD_CPPC_CAPS_1_HIGHEST_PERF_BITS,
+ sc->cppc.caps1));
+ if (*count < levels)
+ return (E2BIG);
+ *count = levels;
+ cur_level = BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS,
+ sc->cppc.caps1);
+ for (i = 0; i < levels; i++, sets++) {
+ sets->freq = upscale_cppc_freq(sc, cur_level);
+ sets->volts = CPUFREQ_VAL_UNKNOWN;
+ sets->power = CPUFREQ_VAL_UNKNOWN;
+ sets->lat = CPUFREQ_VAL_UNKNOWN;
+ sets->dev = dev;
+ cur_level += AMD_CPPC_STEPS;
+ cur_level = MIN(cur_level,
+ BITS_VALUE(AMD_CPPC_CAPS_1_HIGHEST_PERF_BITS,
+ sc->cppc.caps1));
+ }
+ } else {
+ if (*count < sc->cfnum)
+ return (E2BIG);
+ for (i = 0; i < sc->cfnum; i++, sets++) {
+ set = sc->hwpstate_settings[i];
+ sets->freq = set.freq;
+ sets->volts = set.volts;
+ sets->power = set.power;
+ sets->lat = set.lat;
+ sets->dev = dev;
+ }
+ *count = sc->cfnum;
}
- *count = sc->cfnum;
return (0);
}
@@ -649,12 +721,14 @@
if (type == NULL)
return (EINVAL);
+ *type = CPUFREQ_TYPE_ABSOLUTE;
+
sc = device_get_softc(dev);
+ if ((sc->flags & HWPFL_USE_CPPC)) {
+ if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
+ *type |= CPUFREQ_FLAG_INFO_ONLY | CPUFREQ_FLAG_UNCACHED;
+ }
- *type = CPUFREQ_TYPE_ABSOLUTE;
- *type |= (sc->flags & HWPFL_USE_CPPC) != 0 ?
- CPUFREQ_FLAG_INFO_ONLY | CPUFREQ_FLAG_UNCACHED :
- 0;
return (0);
}
@@ -752,6 +826,7 @@
lowest_perf = 0;
highest_perf = -1;
}
+ sc->cppc.caps1 = data->caps;
SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_MIN_PERF_BITS,
lowest_perf);
SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_MAX_PERF_BITS,
@@ -905,6 +980,7 @@
{
struct hwpstate_softc *sc;
int res;
+ uint32_t flag;
sc = device_get_softc(dev);
if ((sc->flags & HWPFL_USE_CPPC) != 0) {
@@ -954,6 +1030,19 @@
"0 enables autonomous mode, otherwise value should be "
"between 'minimum_performance' and 'maximum_performance' "
"inclusive)");
+ sc->cppc.acpi_ctx = acpi_cppc_ctx_init(dev);
+ if (sc->cppc.acpi_ctx) {
+ if (hwpstate_verbose)
+ device_printf(dev, "Found ACPI _CPC object");
+ flag = acpi_cppc_get_features(sc->cppc.acpi_ctx);
+ if ((flag & ACPI_CPPC_HAS_LOW_FREQ) &&
+ (flag & ACPI_CPPC_HAS_NOMINAL_FREQ)) {
+ if (hwpstate_verbose)
+ device_printf(dev,
+ "ACPI CPPC is writable in cpufreq");
+ sc->flags |= HWPFL_CPPC_CPUFREQ_WRITE;
+ }
+ }
}
return (cpufreq_register(dev));
}
@@ -1103,6 +1192,8 @@
sc = device_get_softc(dev);
if ((sc->flags & HWPFL_USE_CPPC) == 0)
hwpstate_goto_pstate(dev, 0);
+ else if (sc->cppc.acpi_ctx)
+ acpi_cppc_ctx_free(dev, sc->cppc.acpi_ctx);
return (cpufreq_unregister(dev));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Feb 26, 10:46 AM (30 m, 26 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29003764
Default Alt Text
D55477.diff (7 KB)
Attached To
Mode
D55477: hwpstate_amd: Support writable cpufreq interface in CPPC mode
Attached
Detach File
Event Timeline
Log In to Comment