Page MenuHomeFreeBSD

D61195.1794309082.diff
No OneTemporary

Authored By
Unknown
Size
20 KB
Referenced Files
None
Subscribers
None

D61195.1794309082.diff

diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -267,6 +267,7 @@
inet.4 \
inet6.4 \
intel_pmc.4 \
+ ${_intel_cpu_cstate.4} \
intpm.4 \
intro.4 \
${_io.4} \
@@ -957,6 +958,7 @@
.if ${MACHINE_CPUARCH} == "amd64"
_acpi_apple.4= acpi_apple.4
+_intel_cpu_cstate.4= intel_cpu_cstate.4
_ioat.4= ioat.4
_iwx.4= iwx.4
_nvdimm.4= nvdimm.4
diff --git a/share/man/man4/intel_cpu_cstate.4 b/share/man/man4/intel_cpu_cstate.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/intel_cpu_cstate.4
@@ -0,0 +1,90 @@
+.\"
+.\" Copyright (c) 2026 The FreeBSD Foundation
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" This documentation was written by Olivier Certner <olce@FreeBSD.org> at
+.\" Kumacom SARL under sponsorship from the FreeBSD Foundation.
+.\"
+.Dd October 22, 2026
+.Dt INTEL_CPU_CSTATE 4
+.Os
+.Sh NAME
+.Nm intel_cpu_cstate
+.Nd Intel CPU-specific power states driver
+.Sh SYNOPSIS
+.Cd "device intel_cpu_cstate"
+.Sh DESCRIPTION
+The
+.Nm
+driver exposes CPU-specific C-state residency counters for Intel CPUs supporting
+them.
+.Pp
+Each residency counter applies to a scope among
+.Ql core ,
+.Ql module
+or
+.Ql package ,
+meaning it reports for how long all logical processors in that scope could reach
+at least its associated C-state.
+Scope
+.Ql module
+includes part of cores in a package, e.g., those sharing an L2 cache, but its
+exact definition is model-specific.
+.Pp
+The information is exposed in the form of sysctl knobs as described in the
+.Sx SYSCTL VARIABLES
+section.
+.Sh HARDWARE
+The
+.Nm
+driver supports available residency counters on Intel CPUs in the form of
+Model-Specific Registers (MSRs).
+Each CPU or CPU family has its own MSRs.
+The driver tries to autodetect those that are available.
+All CPUs up to at least the Lunar Lake microarchitecture are supported
+.Pq e.g., Intel Core Ultra Series 2
+and it is expected that CPUs with Panther Lake or Wildcat Lake
+.Pq e.g., Intel Core (Ultra) Series 3
+or Grand Ridge or Cleanwater Forest microarchitectures also work.
+.Sh SYSCTL VARIABLES
+All information exposed by the
+.Nm
+driver hangs from the
+.Va dev.cpu.N.cstate
+nodes.
+Under them, nodes are created per available counter scopes.
+In turn, under them, a knob is created for each C-state having a residency
+counter.
+As an example, the knob for a package C3 state residency counter on CPU 0 is
+.Va dev.cpu.0.cstate.package.c3 .
+.Pp
+All values are reported in microseconds (μs).
+.Pp
+A counter that stays at 0 may indicate that the corresponding C-state was never
+entered or that the CPU does not actually report residency for that case and the
+corresponding MSR, although present, is wired to 0.
+.Sh AUTHORS
+.An Olivier Certner Aq Mt olce@FreeBSD.org
+.Sh CAVEATS
+Note that the referred C-states differ from ACPI ones or those passed as a hint
+to the
+.Ql MWAIT
+instruction when the MWAIT Power Management Extension is supported.
+.Pp
+This driver is based on the Intel Software Developer Manual Volume 4 as of
+September 2026.
+.Pp
+Residency counters are accessed through non-architectural Model-Specific
+Registers (MSRs), meaning the latter's indices can vary depending on the CPU
+model.
+Barring quirks for specific models, this driver uses a default MSR index for
+each counter which was manually derived by looking up the most frequently and
+recently used index across all models for that counter.
+Newer processors may introduce a different index per counter, in which case they
+will not be supported automatically and will require a driver update.
+If an MSR is present at the default index, it is assumed to be the expected
+residency counter.
+Wrong information would be displayed if newer processors or some specific older
+models reuse that index for another register, which also requires a driver
+update to fix.
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -220,6 +220,7 @@
clean "ice_ddp.fw"
dev/intel/hfsts.c optional hfsts pci
dev/intel/hfsts_isa.c optional hfsts isa pci
+dev/intel/intel_cpu_cstate.c optional intel_cpu_cstate
dev/ioat/ioat.c optional ioat pci
dev/ioat/ioat_test.c optional ioat pci
dev/ixl/if_ixl.c optional ixl pci \
diff --git a/sys/dev/intel/intel_cpu_cstate.c b/sys/dev/intel/intel_cpu_cstate.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/intel/intel_cpu_cstate.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2026 The FreeBSD Foundation
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * This software was developed by Olivier Certner <olce@FreeBSD.org> at Kumacom
+ * SARL under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/ctype.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include <machine/_stdint.h>
+#include <x86/clock.h>
+#include <machine/cpufunc.h>
+#include <x86/cputypes.h>
+#include <machine/specialreg.h>
+#include <x86/x86_var.h>
+
+
+/*
+ * Full 64-bit multiplication and 64-bit shifted inverse. Used to convert
+ * counters in TSC units to μs. '__uint128_t' cannot be used in the kernel
+ * (support functions are not present).
+ */
+
+static void
+mul_64_64_128(const uint64_t a, const uint64_t b, uint64_t *const hi,
+ uint64_t *const lo)
+{
+ const uint64_t a_hi = a >> 32;
+ const uint64_t a_lo = a & UINT32_MAX;
+ const uint64_t b_hi = b >> 32;
+ const uint64_t b_lo = b & UINT32_MAX;
+ uint64_t mid, tmp;
+
+ /*
+ * Decompose the 64-bit numbers in two halves, which leads to products
+ * between 32-bit quantities only, fitting into a 64-bit integer type.
+ */
+ *hi = a_hi * b_hi;
+ *lo = a_lo * b_lo;
+ mid = a_hi * b_lo;
+ *hi += mid >> 32;
+ tmp = (mid & UINT32_MAX) << 32;
+ *lo += tmp;
+ if (tmp > *lo)
+ /* Carry. */
+ (*hi)++;
+ mid = a_lo * b_hi;
+ *hi += mid >> 32;
+ tmp = (mid & UINT32_MAX) << 32;
+ *lo += tmp;
+ if (tmp > *lo)
+ /* Carry. */
+ (*hi)++;
+}
+
+static uint64_t
+compute_2_64_inv(const uint64_t val)
+{
+ uint64_t lower, greater;
+ int ls;
+
+ if (val <= 1)
+ return (UINT64_MAX);
+
+ ls = flsll(val);
+ greater = 1ULL << (64 - ls + 1);
+ if (ls == ffsll(val))
+ return (greater);
+ lower = greater >> 1;
+
+ while (lower != greater - 1) {
+ const uint64_t cand = (lower + greater) / 2;
+ uint64_t hi, lo;
+
+ mul_64_64_128(cand, val, &hi, &lo);
+ if (hi != 0) {
+ MPASS(hi == 1);
+ if (lo == 0)
+ return (cand);
+ greater = cand;
+ } else
+ lower = cand;
+ }
+
+ return (lower);
+}
+
+static void intel_cpu_cstate_identify(driver_t *driver, device_t parent);
+static int intel_cpu_cstate_probe(device_t dev);
+static int intel_cpu_cstate_attach(device_t dev);
+static int intel_cpu_cstate_detach(device_t dev);
+
+static SYSCTL_NODE(_debug, OID_AUTO, intel_cpu_cstate, CTLFLAG_MPSAFE, NULL,
+ "intel_cpu_cstate(4) debug controls");
+
+static bool raw_counters;
+SYSCTL_BOOL(_debug_intel_cpu_cstate, OID_AUTO, raw_counters, CTLFLAG_RDTUN,
+ &raw_counters, 0,
+ "If true, reported residency values are always raw MSR values.");
+
+enum intel_cpu_cstate_residency_type {
+ CORE_C1,
+ CORE_C3,
+ CORE_C6,
+ CORE_C7,
+ MOD_C0,
+ MOD_C6,
+ PKG_C2,
+ PKG_C3,
+ PKG_C4,
+ PKG_C6,
+ PKG_C7,
+ PKG_C8,
+ PKG_C9,
+ PKG_C10,
+ RESIDENCY_TYPE_NB,
+};
+
+struct intel_cpu_cstate_residency_type_info {
+ const char *scope;
+ const char *level;
+};
+
+static const struct intel_cpu_cstate_residency_type_info
+cst_residency_type_info[RESIDENCY_TYPE_NB] = {
+ [CORE_C1] = { "core", "c1" },
+ [CORE_C3] = { "core", "c3" },
+ [CORE_C6] = { "core", "c6" },
+ [CORE_C7] = { "core", "c7" },
+ [MOD_C0] = { "module", "c0" },
+ [MOD_C6] = { "module", "c6" },
+ [PKG_C2] = { "package", "c2" },
+ [PKG_C3] = { "package", "c3" },
+ [PKG_C4] = { "package", "c4" },
+ [PKG_C6] = { "package", "c6" },
+ [PKG_C7] = { "package", "c7" },
+ [PKG_C8] = { "package", "c8" },
+ [PKG_C9] = { "package", "c9" },
+ [PKG_C10] = { "package", "c10" },
+};
+
+enum intel_cpu_cstate_residency_frequency {
+ CST_TSC = 0,
+ CST_1MHZ,
+};
+
+struct intel_cpu_cstate_residency_info {
+ /* 0 when the info is not available. */
+ uint32_t msr_index;
+ enum intel_cpu_cstate_residency_frequency frequency;
+};
+
+const struct intel_cpu_cstate_residency_info
+common_cst_residency_info[RESIDENCY_TYPE_NB] = {
+ [CORE_C1] = { .msr_index = MSR_CORE_C1_RESIDENCY },
+ [CORE_C3] = { .msr_index = MSR_CORE_C3_RESIDENCY },
+ [CORE_C6] = { .msr_index = MSR_CORE_C6_RESIDENCY },
+ [CORE_C7] = { .msr_index = MSR_CORE_C7_RESIDENCY },
+ /* Does not exist except on Phi. */
+ [MOD_C0] = { .msr_index = 0 },
+ [MOD_C6] = { .msr_index = MSR_MC6_RESIDENCY },
+ [PKG_C2] = { .msr_index = MSR_PKG_C2_RESIDENCY },
+ [PKG_C3] = { .msr_index = MSR_PKG_C3_RESIDENCY },
+ /* Does not exist except on Atom 06_27h. */
+ [PKG_C4] = { .msr_index = 0 },
+ [PKG_C6] = { .msr_index = MSR_PKG_C6_RESIDENCY },
+ [PKG_C7] = { .msr_index = MSR_PKG_C7_RESIDENCY },
+ [PKG_C8] = { .msr_index = MSR_PKG_C8_RESIDENCY },
+ [PKG_C9] = { .msr_index = MSR_PKG_C9_RESIDENCY },
+ [PKG_C10] = { .msr_index = MSR_PKG_C10_RESIDENCY },
+};
+
+struct intel_cpu_cstate_softc {
+ uint64_t tsc_inv; /* 2^64 / tsc_freq, or 0 on no conversion. */
+ struct intel_cpu_cstate_residency_info info[RESIDENCY_TYPE_NB];
+};
+
+static int
+sysctl_residency_counter(SYSCTL_HANDLER_ARGS)
+{
+ /*
+ * Frequency of reported residency counters.
+ *
+ * Currently, counters we report increment once per μs. If changing
+ * that, do not forget to also change the sysctl knob descriptions (they
+ * mention the unit).
+ */
+ const uint64_t F = 1000000;
+ const device_t dev = arg1;
+ struct intel_cpu_cstate_softc *const sc = device_get_softc(dev);
+ const size_t type = arg2;
+ const uint32_t msr = sc->info[type].msr_index;
+ uint64_t val, Fv_hi, Fv_lo, hi, lo;
+
+ KASSERT(msr != 0,
+ ("%s: Knob registered for non-existent MSR for type %zu",
+ __func__, type));
+ x86_msr_op(msr, MSR_OP_READ | MSR_OP_RENDEZVOUS_ONE |
+ MSR_OP_CPUID(device_get_unit(dev)), 0, &val);
+
+ /* Convert to μs. */
+ switch (sc->info[type].frequency) {
+ case CST_TSC:
+ /*
+ * Report the raw value when not enough resolution or precision,
+ * or explicitly requested to.
+ */
+ if (sc->tsc_inv == 0)
+ break;
+
+ /*
+ * Since 'val' is 64-bit without restrictions, multiplying it
+ * with our unit (here, C = 10^6, for microseconds) can overflow
+ * 2^64, so we use our full multiplication routine.
+ */
+ mul_64_64_128(F, val, &Fv_hi, &Fv_lo);
+ /*
+ * Division by 'tsc_freq' through multiplication by
+ * 2^64/'tsc_freq'. We need a 128-bit result for the 'Fv_lo'
+ * limb multiplication, as we are only concerned with the high
+ * 64 bits of the result (the low 64 bits are after the comma in
+ * the final result).
+ */
+ mul_64_64_128(Fv_lo, sc->tsc_inv, &hi, &lo);
+ /*
+ * We do not need the high 64 bits for the 'Fv_hi'
+ * multiplication, as we report only a 64-bit counter which
+ * naturally wraps around.
+ */
+ val = Fv_hi * sc->tsc_inv + hi;
+ break;
+
+ case CST_1MHZ:
+ /* No conversion needed. */
+ break;
+
+ default:
+ __assert_unreachable();
+ }
+
+ return (sysctl_handle_64(oidp, &val, 0, req));
+}
+
+static void
+intel_cpu_cstate_identify(driver_t *driver, device_t parent)
+{
+ const int unit = device_get_unit(parent);
+
+ /*
+ * Models with non-invariant TSC are not supposed to export residency
+ * MSRs. We leverage invariance to precompute an inverse of the TSC
+ * frequency to then ease conversion to μs.
+ */
+ if (cpu_vendor_id != CPU_VENDOR_INTEL || (!raw_counters &&
+ (!tsc_is_invariant || tsc_freq == 0)))
+ return;
+ if (resource_disabled("intel_cpu_cstate", 0))
+ return;
+ if (device_find_child(parent, "intel_cpu_cstate", unit) != NULL)
+ return;
+
+ if (BUS_ADD_CHILD(parent, 0, "intel_cpu_cstate", unit) == NULL)
+ device_printf(parent, "Cannot add driver under %s!\n",
+ device_get_nameunit(parent));
+}
+
+static int
+intel_cpu_cstate_probe(device_t dev)
+{
+ device_set_desc(dev, "Intel CPU internal C-states residency");
+
+ return (BUS_PROBE_NOWILDCARD);
+}
+
+/*
+ * Quirks for specific models.
+ *
+ * The attach() routine will probe declared MSRs and stop referencing
+ * those that do not exist. Also, specific MSRs installed here will be
+ * removed from other info types.
+ */
+static bool
+intel_cpu_cstate_set_infos_quirk(struct intel_cpu_cstate_softc *const sc)
+{
+ if (CPUID_TO_FAMILY(cpu_id) != 0x6)
+ /*
+ * Using the most frequent values is the most future-proof
+ * strategy.
+ */
+ return (false);
+
+ switch (CPUID_TO_MODEL(cpu_id)) {
+ case 0x57:
+ case 0x85:
+ /* Xeon Phi */
+ sc->info[CORE_C6].msr_index = MSR_CORE_C6_RESIDENCY_PHI;
+ sc->info[MOD_C0].msr_index = MSR_MC0_RESIDENCY_PHI;
+ sc->info[MOD_C6].msr_index = MSR_MC6_RESIDENCY_PHI;
+ return (true);
+
+ case 0x27:
+ /* Atom 45nm and 32nm */
+ sc->info[PKG_C2].msr_index = MSR_PKG_C2_RESIDENCY_ATOM;
+ sc->info[PKG_C2].frequency = CST_1MHZ;
+ sc->info[PKG_C4].msr_index = MSR_PKG_C4_RESIDENCY_ATOM;
+ sc->info[PKG_C4].frequency = CST_1MHZ;
+ sc->info[PKG_C6].msr_index = MSR_PKG_C6_RESIDENCY_ATOM;
+ sc->info[PKG_C6].frequency = CST_1MHZ;
+ return (true);
+
+ case 0x37:
+ case 0x4a:
+ case 0x4d:
+ case 0x5a:
+ case 0x5d:
+ /* Atom Silvermont, Airmont */
+ sc->info[MOD_C6].frequency = CST_1MHZ;
+ sc->info[PKG_C6].msr_index = MSR_PKG_C6_RESIDENCY_ATOM;
+ return (true);
+
+ case 0x97: /* Gen 12 */
+ case 0x9a: /* Gen 12 */
+ case 0xba: /* Gen 13 */
+ case 0xb7: /* Gen 13 */
+ case 0xbf: /* Gen 13 */
+ sc->info[MOD_C6].frequency = CST_1MHZ;
+ return (true);
+ }
+
+ return (false);
+}
+
+/*
+ * Remove MSRs introduced by quirks from the set of default/inherited MSRs
+ * (because a single MSR cannot convey different residency information at once;
+ * we might want to alias several C-states to the same counter though).
+ */
+static void
+intel_cpu_cstate_remove_duplicate_msrs(struct intel_cpu_cstate_softc *const sc)
+{
+ for (size_t i = 0; i < RESIDENCY_TYPE_NB; i++) {
+ const uint32_t msr_idx = sc->info[i].msr_index;
+
+ /* Was the index changed by quirks? */
+ if (msr_idx == common_cst_residency_info[i].msr_index)
+ continue;
+
+ for (size_t j = 0; j < RESIDENCY_TYPE_NB; j++)
+ /*
+ * If the new index was present in the defaults and was
+ * not changed, remove it.
+ */
+ if (common_cst_residency_info[j].msr_index == msr_idx &&
+ sc->info[j].msr_index == msr_idx)
+ sc->info[j].msr_index = 0;
+ }
+}
+
+static int
+intel_cpu_cstate_attach(device_t dev)
+{
+ /*
+ * Frequency of TSC under which residency counters are reported raw
+ * instead of converting them to μs (see sysctl_residency_counter()).
+ */
+ const uint64_t min_resolution = 1000000;
+ /*
+ * Minimum of the (shifted) inverse of the TSC, corresponding to the
+ * inverse of the maximum error caused by multiplying by the TSC
+ * inverse.
+ */
+ const uint64_t max_inverse_error = 1000000;
+ struct intel_cpu_cstate_softc *const sc = device_get_softc(dev);
+ const size_t all_infos_size = sizeof(common_cst_residency_info);
+ struct sysctl_ctx_list *const sysctl_ctx = device_get_sysctl_ctx(dev);
+ struct sysctl_oid *sysctl_top = NULL;
+
+ /*
+ * Precompute the TSC inverse (shifted by 64-bit) used to output
+ * residency values in duration with SI units. We impose a minimum
+ * resolution, else we just report the raw counters. We also impose
+ * a minimum (shifted) inverse resolution, to limit the conversion error
+ * to μs. We should never hit these bounds with the current values, as
+ * the TSC is expected to be in the order of magnitude of GHz (and up to
+ * 3 order of magnitudes below and above this also work).
+ */
+ if (raw_counters || tsc_freq < min_resolution)
+ sc->tsc_inv = 0;
+ else {
+ sc->tsc_inv = compute_2_64_inv(tsc_freq);
+ if (sc->tsc_inv < max_inverse_error)
+ sc->tsc_inv = 0;
+ }
+
+ /* Copy the common configuration. */
+ memcpy(sc->info, common_cst_residency_info, all_infos_size);
+
+ /* Apply quirks as necessary. */
+ if (intel_cpu_cstate_set_infos_quirk(sc))
+ intel_cpu_cstate_remove_duplicate_msrs(sc);
+
+ /*
+ * Check that MSRs actually exist, and for these create sysctl knobs.
+ */
+ for (size_t i = 0; i < RESIDENCY_TYPE_NB; i++) {
+ uint32_t *const msr_idx = &sc->info[i].msr_index;
+ const struct intel_cpu_cstate_residency_type_info *const
+ type_info = &cst_residency_type_info[i];
+ char buf[128];
+ char buf2[8];
+ struct sysctl_oid *node;
+ uint64_t val;
+ int error;
+
+ if (*msr_idx == 0)
+ continue;
+
+ error = rdmsr_safe(*msr_idx, &val);
+ if (error != 0) {
+ *msr_idx = 0;
+ continue;
+ }
+
+ if (sysctl_top == NULL) {
+ sysctl_top = SYSCTL_ADD_NODE(sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(
+ device_get_parent(dev))), OID_AUTO, "cstate",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
+ "CPU-specific C-states");
+ KASSERT(sysctl_top != NULL,
+ ("%s: Error creating top sysctl node",
+ device_get_nameunit(dev)));
+ }
+
+ snprintf(buf, sizeof(buf), "C-state knobs with %s scope",
+ type_info->scope);
+ node = SYSCTL_ADD_NODE(sysctl_ctx, SYSCTL_CHILDREN(sysctl_top),
+ OID_AUTO, type_info->scope, CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, buf);
+ KASSERT(node != NULL,
+ ("%s: Error creating scope '%s' sysctl node",
+ device_get_nameunit(dev), type_info->scope));
+
+ /* Capitalize the level in the description. */
+ strlcpy(buf2, type_info->level, sizeof(buf2));
+ buf2[0] = toupper(buf2[0]);
+ snprintf(buf, sizeof(buf), "Per-%s %s residency counter (%s)",
+ type_info->scope, buf2, sc->tsc_inv != 0 ||
+ sc->info[i].frequency == CST_1MHZ ? "μs" : "TSC ticks");
+ node = SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(node),
+ OID_AUTO, type_info->level, CTLTYPE_U64 | CTLFLAG_RD |
+ CTLFLAG_MPSAFE, dev, i, sysctl_residency_counter, "QU",
+ buf);
+ KASSERT(node != NULL,
+ ("%s: Error creating '%s' sysctl node for scope '%s'",
+ device_get_nameunit(dev), type_info->level,
+ type_info->scope));
+ }
+
+ return (0);
+}
+
+static int
+intel_cpu_cstate_detach(device_t dev)
+{
+ return (0);
+}
+
+static device_method_t intel_cpu_cstate_methods[] = {
+ DEVMETHOD(device_identify, intel_cpu_cstate_identify),
+ DEVMETHOD(device_probe, intel_cpu_cstate_probe),
+ DEVMETHOD(device_attach, intel_cpu_cstate_attach),
+ DEVMETHOD(device_detach, intel_cpu_cstate_detach),
+ DEVMETHOD_END
+};
+
+static driver_t intel_cpu_cstate_driver = {
+ "intel_cpu_cstate",
+ intel_cpu_cstate_methods,
+ sizeof(struct intel_cpu_cstate_softc),
+};
+
+DRIVER_MODULE(intel_cpu_cstate, cpu, intel_cpu_cstate_driver, NULL, NULL);
+MODULE_VERSION(intel_cpu_cstate, 1);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -179,6 +179,7 @@
${_igc} \
imgact_binmisc \
${_imx} \
+ ${_intel_cpu_cstate} \
${_intel_pmc} \
${_intelspi} \
${_io} \
@@ -879,6 +880,7 @@
_enic= enic
_hfsts= hfsts
_iavf= iavf
+_intel_cpu_cstate= intel_cpu_cstate
_ioat= ioat
_iwx= iwx
_ixl= ixl
diff --git a/sys/modules/intel_cpu_cstate/Makefile b/sys/modules/intel_cpu_cstate/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/intel_cpu_cstate/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/intel
+KMOD= intel_cpu_cstate
+SRCS= intel_cpu_cstate.c
+SRCS+= bus_if.h device_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h
--- a/sys/x86/include/specialreg.h
+++ b/sys/x86/include/specialreg.h
@@ -750,6 +750,41 @@
#define MSR_IA32_HWP_REQUEST 0x774
#define MSR_IA32_HWP_STATUS 0x777
+/*
+ * C-state MSRs
+ *
+ * Grouped by applicable scope and ordered by C-states, the common value being
+ * listed first in the case of differing MSR indexes for different CPUs. Only
+ * a single name is not suffixed with a particular CPU model for a given MSR
+ * index.
+ */
+/* Core scope. */
+#define MSR_CORE_C1_RESIDENCY 0x660
+#define MSR_CORE_C3_RESIDENCY 0x3fc
+#define MSR_CORE_C6_RESIDENCY 0x3fd
+#define MSR_CORE_C6_RESIDENCY_PHI 0x3ff
+#define MSR_CORE_C7_RESIDENCY 0x3fe
+
+/* Module (cores sharing cache) scope. */
+#define MSR_MC0_RESIDENCY_PHI 0x3fc
+/* Atom Silvermont, Airmont, and Gen12 and Gen13: 1Mhz frequency, else TSC. */
+#define MSR_MC6_RESIDENCY 0x664
+#define MSR_MC6_RESIDENCY_PHI 0x3fd
+
+/* Package scope. */
+#define MSR_PKG_CST_CONFIG_CONTROL 0x0e2
+#define MSR_PKG_C2_RESIDENCY 0x60d
+#define MSR_PKG_C2_RESIDENCY_ATOM 0x3f8 /* Atom 06_27h */
+#define MSR_PKG_C3_RESIDENCY 0x3f8
+#define MSR_PKG_C4_RESIDENCY_ATOM 0x3f9 /* Atom 06_27h */
+#define MSR_PKG_C6_RESIDENCY 0x3f9
+/* Atom 06_27h, Silvermont, Airmont */
+#define MSR_PKG_C6_RESIDENCY_ATOM 0x3fa
+#define MSR_PKG_C7_RESIDENCY 0x3fa
+#define MSR_PKG_C8_RESIDENCY 0x630
+#define MSR_PKG_C9_RESIDENCY 0x631
+#define MSR_PKG_C10_RESIDENCY 0x632
+
/*
* VMX MSRs
*/

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 10, 11:11 AM (2 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41637556
Default Alt Text
D61195.1794309082.diff (20 KB)

Event Timeline