Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 22 Mar 2026 02:35:44 +0000
From:      ShengYi Hung <aokblast@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 191f47bcd650 - main - hwpstate_amd: Refactor the cpufreq code by using delegation pattenr
Message-ID:  <69bf5580.462ae.4b8ad64e@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by aokblast:

URL: https://cgit.FreeBSD.org/src/commit/?id=191f47bcd65097599a962b46ae293e5ebe4e5b67

commit 191f47bcd65097599a962b46ae293e5ebe4e5b67
Author:     ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2026-02-24 07:22:52 +0000
Commit:     ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2026-03-22 02:35:36 +0000

    hwpstate_amd: Refactor the cpufreq code by using delegation pattenr
    
    We separate the code of CPPC and legacy pstate driver to make it easier
    to read.
    
    Reviewed by:    olce
    Approved by:    markj (mentor)
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D55604
---
 sys/x86/cpufreq/hwpstate_amd.c | 213 +++++++++++++++++++++++++++--------------
 1 file changed, 142 insertions(+), 71 deletions(-)

diff --git a/sys/x86/cpufreq/hwpstate_amd.c b/sys/x86/cpufreq/hwpstate_amd.c
index 2649fcc5779f..ccf13f06a6d1 100644
--- a/sys/x86/cpufreq/hwpstate_amd.c
+++ b/sys/x86/cpufreq/hwpstate_amd.c
@@ -152,6 +152,13 @@ struct hwpstate_setting {
 #define HWPFL_USE_CPPC			(1 << 0)
 #define HWPFL_CPPC_REQUEST_NOT_READ	(1 << 1)
 
+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.
@@ -161,6 +168,7 @@ struct hwpstate_setting {
 struct hwpstate_softc {
 	device_t	dev;
 	u_int		flags;
+	const struct hwpstate_cpufreq_methods *cpufreq_methods;
 	union {
 		struct {
 			struct hwpstate_setting
@@ -620,80 +628,105 @@ hwpstate_goto_pstate(device_t dev, int id)
 }
 
 static int
-hwpstate_set(device_t dev, const struct cf_setting *cf)
+hwpstate_set_cppc(device_t dev __unused, const struct cf_setting *cf __unused)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+hwpstate_set_pstate(device_t dev, const struct cf_setting *cf)
 {
 	struct hwpstate_softc *sc;
 	struct hwpstate_setting *set;
 	int i;
 
-	if (cf == NULL)
-		return (EINVAL);
 	sc = device_get_softc(dev);
-	if ((sc->flags & HWPFL_USE_CPPC) != 0)
-		return (EOPNOTSUPP);
 	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));
 }
 
 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_settings(device_t dev, struct cf_setting *sets, int *count)
+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));
+}
+
+static int
+hwpstate_settings_cppc(device_t dev __unused, struct cf_setting *sets __unused,
+    int *count __unused)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+hwpstate_settings_pstate(device_t dev, struct cf_setting *sets, int *count)
+{
 	struct hwpstate_setting set;
+	struct hwpstate_softc *sc;
 	int i;
 
-	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++) {
@@ -710,21 +743,40 @@ hwpstate_settings(device_t dev, struct cf_setting *sets, int *count)
 }
 
 static int
-hwpstate_type(device_t dev, int *type)
+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)
+{
+	*type |= CPUFREQ_TYPE_ABSOLUTE | CPUFREQ_FLAG_INFO_ONLY |
+	    CPUFREQ_FLAG_UNCACHED;
+	return (0);
+}
+
+static int
+hwpstate_type_pstate(device_t dev, int *type)
+{
 	*type = CPUFREQ_TYPE_ABSOLUTE;
-	*type |= (sc->flags & HWPFL_USE_CPPC) != 0 ?
-	    CPUFREQ_FLAG_INFO_ONLY | CPUFREQ_FLAG_UNCACHED :
-	    0;
 	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)
 {
@@ -909,34 +961,14 @@ enable_cppc(struct hwpstate_softc *sc)
 }
 
 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.
 	 */
@@ -984,10 +1016,49 @@ hwpstate_probe(device_t dev)
 	 */
 	if (error)
 		error = hwpstate_get_info_from_msr(dev);
-	if (error)
-		return (error);
+	return (error);
+}
 
-	return (0);
+static const struct hwpstate_cpufreq_methods cppc_methods = {
+	.get = hwpstate_get_cppc,
+	.set = hwpstate_set_cppc,
+	.settings = hwpstate_settings_cppc,
+	.type = hwpstate_type_cppc };
+
+static const 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
@@ -1037,8 +1108,8 @@ hwpstate_attach(device_t dev)
 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
 		    "desired_performance",
-		    CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
-		    dev, AMD_CPPC_REQUEST_DES_PERF_BITS,
+		    CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, dev,
+		    AMD_CPPC_REQUEST_DES_PERF_BITS,
 		    sysctl_cppc_request_field_handler, "IU",
 		    "Desired performance level (from 0 to 255; "
 		    "0 enables autonomous mode, otherwise value should be "


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69bf5580.462ae.4b8ad64e>