Page MenuHomeFreeBSD

D55604.id172966.diff
No OneTemporary

D55604.id172966.diff

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
@@ -154,6 +154,13 @@
#define HWPFL_CPPC_REQUEST_NOT_READ (1 << 1)
#define HWPFL_CPPC_CPUFREQ_WRITE (1 << 2)
+struct hwpstate_cpufreq_methods {
+ int (*get)(device_t dev, struct cf_setting *cf);
+ int (*set)(device_t dev, const struct cf_setting *cf);
+ int (*settings)(device_t dev, struct cf_setting *sets, int *count);
+ int (*type)(device_t dev, int *type);
+};
+
/*
* Atomicity is achieved by only modifying a given softc on its associated CPU
* and with interrupts disabled.
@@ -163,6 +170,7 @@
struct hwpstate_softc {
device_t dev;
u_int flags;
+ struct hwpstate_cpufreq_methods *cpufreq_methods;
union {
struct {
struct hwpstate_setting
@@ -656,33 +664,36 @@
}
static int
-hwpstate_set(device_t dev, const struct cf_setting *cf)
+hwpstate_set_cppc(device_t dev, const struct cf_setting *cf)
{
struct hwpstate_softc *sc;
- struct hwpstate_setting *set;
uint32_t des_perf;
- int i;
- if (cf == NULL)
- return (EINVAL);
sc = device_get_softc(dev);
- if ((sc->flags & HWPFL_USE_CPPC) != 0) {
- if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
- return (EOPNOTSUPP);
- des_perf = downscale_cppc_freq(sc, cf->freq);
- if (des_perf < BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS,
- sc->cppc.caps1) ||
- des_perf > BITS_VALUE(AMD_CPPC_CAPS_1_HIGHEST_PERF_BITS,
- sc->cppc.caps1))
- return (ENXIO);
- SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_DES_PERF_BITS,
- des_perf);
- return (x86_msr_op(MSR_AMD_CPPC_REQUEST,
- MSR_OP_RENDEZVOUS_ONE | MSR_OP_WRITE |
- MSR_OP_CPUID(cpu_get_pcpu(dev)->pc_cpuid),
- sc->cppc.request, NULL));
- }
+ if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
+ return (EOPNOTSUPP);
+ des_perf = downscale_cppc_freq(sc, cf->freq);
+ if (des_perf <
+ BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, sc->cppc.caps1) ||
+ des_perf >
+ BITS_VALUE(AMD_CPPC_CAPS_1_HIGHEST_PERF_BITS, sc->cppc.caps1))
+ return (ENXIO);
+ SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_DES_PERF_BITS,
+ des_perf);
+ return (x86_msr_op(MSR_AMD_CPPC_REQUEST,
+ MSR_OP_RENDEZVOUS_ONE | MSR_OP_WRITE |
+ MSR_OP_CPUID(cpu_get_pcpu(dev)->pc_cpuid),
+ sc->cppc.request, NULL));
+}
+
+static int
+hwpstate_set_pstate(device_t dev, const struct cf_setting *cf)
+{
+ struct hwpstate_softc *sc;
+ struct hwpstate_setting *set;
+ int i;
+ sc = device_get_softc(dev);
set = sc->hwpstate_settings;
for (i = 0; i < sc->cfnum; i++)
if (CPUFREQ_CMP(cf->freq, set[i].freq))
@@ -693,121 +704,170 @@
}
static int
-hwpstate_get(device_t dev, struct cf_setting *cf)
+hwpstate_set(device_t dev, const struct cf_setting *cf)
+{
+ struct hwpstate_softc *sc = device_get_softc(dev);
+
+ if (cf == NULL)
+ return (EINVAL);
+ return (sc->cpufreq_methods->set(dev, cf));
+}
+
+static int
+hwpstate_get_cppc(device_t dev, struct cf_setting *cf)
{
- struct hwpstate_softc *sc;
- struct hwpstate_setting set;
struct pcpu *pc;
- uint64_t msr;
uint64_t rate;
int ret;
+ pc = cpu_get_pcpu(dev);
+ if (pc == NULL)
+ return (ENXIO);
+
+ memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
+ cf->dev = dev;
+ if ((ret = cpu_est_clockrate(pc->pc_cpuid, &rate)))
+ return (ret);
+ cf->freq = rate / 1000000;
+ return (0);
+}
+
+static int
+hwpstate_get_pstate(device_t dev, struct cf_setting *cf)
+{
+ struct hwpstate_softc *sc;
+ struct hwpstate_setting set;
+ uint64_t msr;
+
sc = device_get_softc(dev);
- if (cf == NULL)
+ msr = rdmsr(MSR_AMD_10H_11H_STATUS);
+ if (msr >= sc->cfnum)
return (EINVAL);
+ set = sc->hwpstate_settings[msr];
- if ((sc->flags & HWPFL_USE_CPPC) != 0) {
- pc = cpu_get_pcpu(dev);
- if (pc == NULL)
- return (ENXIO);
-
- memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
- cf->dev = dev;
- if ((ret = cpu_est_clockrate(pc->pc_cpuid, &rate)))
- return (ret);
- cf->freq = rate / 1000000;
- } else {
- msr = rdmsr(MSR_AMD_10H_11H_STATUS);
- if (msr >= sc->cfnum)
- return (EINVAL);
- set = sc->hwpstate_settings[msr];
-
- cf->freq = set.freq;
- cf->volts = set.volts;
- cf->power = set.power;
- cf->lat = set.lat;
- cf->dev = dev;
- }
+ cf->freq = set.freq;
+ cf->volts = set.volts;
+ cf->power = set.power;
+ cf->lat = set.lat;
+ cf->dev = dev;
return (0);
}
+static int
+hwpstate_get(device_t dev, struct cf_setting *cf)
+{
+ struct hwpstate_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (cf == NULL)
+ return (EINVAL);
+ return (sc->cpufreq_methods->get(dev, cf));
+}
+
#define AMD_CPPC_STEPS 10
#define AMD_CPPC_COUNT_LEVELS(l, r) \
(roundup(r - l + 1, AMD_CPPC_STEPS) / AMD_CPPC_STEPS)
static int
-hwpstate_settings(device_t dev, struct cf_setting *sets, int *count)
+hwpstate_settings_cppc(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) {
- if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
- return (EOPNOTSUPP);
- levels = AMD_CPPC_COUNT_LEVELS(
- BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS,
- sc->cppc.caps1),
+ if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
+ return (EOPNOTSUPP);
+ 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));
- 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;
}
return (0);
}
static int
-hwpstate_type(device_t dev, int *type)
+hwpstate_settings_pstate(device_t dev, struct cf_setting *sets, int *count)
+{
+ struct hwpstate_setting set;
+ struct hwpstate_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+ 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;
+
+ return (0);
+}
+
+static int
+hwpstate_settings(device_t dev, struct cf_setting *sets, int *count)
{
struct hwpstate_softc *sc;
- if (type == NULL)
+ if (sets == NULL || count == NULL)
return (EINVAL);
+ sc = device_get_softc(dev);
+ return (sc->cpufreq_methods->settings(dev, sets, count));
+}
+
+static int
+hwpstate_type_cppc(device_t dev, int *type)
+{
+ struct hwpstate_softc *sc;
+
*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;
- }
+ if ((sc->flags & HWPFL_CPPC_CPUFREQ_WRITE) == 0)
+ *type |= CPUFREQ_FLAG_INFO_ONLY | CPUFREQ_FLAG_UNCACHED;
+
+ return (0);
+}
+static int
+hwpstate_type_pstate(device_t dev, int *type)
+{
+ *type = CPUFREQ_TYPE_ABSOLUTE;
return (0);
}
+static int
+hwpstate_type(device_t dev, int *type)
+{
+ struct hwpstate_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->cpufreq_methods->type(dev, type));
+}
+
static void
hwpstate_identify(driver_t *driver, device_t parent)
{
@@ -994,34 +1054,14 @@
}
static int
-hwpstate_probe(device_t dev)
+hwpstate_probe_pstate(device_t dev)
{
struct hwpstate_softc *sc;
device_t perf_dev;
- uint64_t msr;
int error, type;
+ uint64_t msr;
sc = device_get_softc(dev);
-
- if (hwpstate_amd_cppc_enable &&
- (amd_extended_feature_extensions & AMDFEID_CPPC)) {
- sc->flags |= HWPFL_USE_CPPC;
- device_set_desc(dev,
- "AMD Collaborative Processor Performance Control (CPPC)");
- } else {
- /*
- * No CPPC support. Only keep hwpstate0, it goes well with
- * acpi_throttle.
- */
- if (device_get_unit(dev) != 0)
- return (ENXIO);
- device_set_desc(dev, "Cool`n'Quiet 2.0");
- }
-
- sc->dev = dev;
- if ((sc->flags & HWPFL_USE_CPPC) != 0)
- return (0);
-
/*
* Check if acpi_perf has INFO only flag.
*/
@@ -1069,10 +1109,47 @@
*/
if (error)
error = hwpstate_get_info_from_msr(dev);
- if (error)
- return (error);
+ return (error);
+}
- return (0);
+struct hwpstate_cpufreq_methods cppc_methods = { .get = hwpstate_get_cppc,
+ .set = hwpstate_set_cppc,
+ .settings = hwpstate_settings_cppc,
+ .type = hwpstate_type_cppc };
+
+struct hwpstate_cpufreq_methods pstate_methods = { .get = hwpstate_get_pstate,
+ .set = hwpstate_set_pstate,
+ .settings = hwpstate_settings_pstate,
+ .type = hwpstate_type_pstate };
+
+static int
+hwpstate_probe(device_t dev)
+{
+ struct hwpstate_softc *sc;
+ sc = device_get_softc(dev);
+
+ if (hwpstate_amd_cppc_enable &&
+ (amd_extended_feature_extensions & AMDFEID_CPPC)) {
+ sc->flags |= HWPFL_USE_CPPC;
+ device_set_desc(dev,
+ "AMD Collaborative Processor Performance Control (CPPC)");
+ } else {
+ /*
+ * No CPPC support. Only keep hwpstate0, it goes well with
+ * acpi_throttle.
+ */
+ if (device_get_unit(dev) != 0)
+ return (ENXIO);
+ device_set_desc(dev, "Cool`n'Quiet 2.0");
+ }
+
+ sc->dev = dev;
+ if ((sc->flags & HWPFL_USE_CPPC) != 0) {
+ sc->cpufreq_methods = &cppc_methods;
+ return (0);
+ }
+ sc->cpufreq_methods = &pstate_methods;
+ return (hwpstate_probe_pstate(dev));
}
static int

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 15, 3:07 PM (1 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29160784
Default Alt Text
D55604.id172966.diff (10 KB)

Event Timeline