Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144357793
D54881.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
D54881.diff
View Options
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -149,6 +149,7 @@
dev/ichwd/ichwd.c optional ichwd
dev/imcsmb/imcsmb.c optional imcsmb
dev/imcsmb/imcsmb_pci.c optional imcsmb pci
+dev/intel/intel_pmc_core.c optional intel_pmc_core pci
dev/intel/pchtherm.c optional pchtherm
dev/intel/spi.c optional intelspi
dev/intel/spi_pci.c optional intelspi pci
diff --git a/sys/dev/intel/intel_pmc_core.c b/sys/dev/intel/intel_pmc_core.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/intel/intel_pmc_core.c
@@ -0,0 +1,224 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ */
+
+/*
+ * Intel PMC (Power Management Controller) Core driver
+ *
+ * Exposes sleep state residency counters and power gating status
+ * for debugging S0ix (Modern Standby) power states.
+ *
+ * Register offsets from Intel 100 Series Chipset Family PCH Datasheet Vol 2
+ * Section 4.3.53 describes the SLP_S0_RESIDENCY_COUNTER (offset 0x13C).
+ *
+ * The residency counter tracks cumulative time spent in any S0ix sub-state
+ * (S0i1, S0i2, S0i3), not specifically the deepest sleep state.
+ *
+ * Counter increment: The datasheet specifies 100us granularity. Linux uses
+ * 104us (0x68), probably a hardware quirk on untested vendors/revisions.
+ *
+ * NOTE: This driver only supports Sunrise Point (different PCH generations
+ * have different register layouts). Some firmware/BIOS implementations
+ * lock PMC access - if registers read as 0xFFFFFFFF, access is denied.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+/*
+ * Sunrise Point (SPT) PMC Register Definitions
+ * Reference: Intel 100 Series Chipset Family PCH Datasheet Vol 2
+ */
+#define SPT_PMC_PM_CFG_OFFSET 0x18
+#define SPT_PMC_PM_STS_OFFSET 0x1C
+#define SPT_PMC_SLP_S0_RES_OFFSET 0x13C
+#define SPT_PMC_SLP_S0_RES_STEP 100 /* 100us per datasheet */
+#define SPT_PMC_LTR_IGNORE_OFFSET 0x30C
+
+struct intel_pmc_core_softc {
+ int rid;
+ struct resource *res;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ int access_denied;
+};
+
+static const struct pci_device_table intel_pmc_core_devices[] = {
+ /* Only Sunrise Point - other generations have different layouts */
+ { PCI_DEV(0x8086, 0x9d21), PCI_DESCR("Sunrise Point-LP PMC")},
+ { PCI_DEV(0x8086, 0xa121), PCI_DESCR("Sunrise Point-H PMC")},
+};
+
+static inline uint32_t
+pmc_read(struct intel_pmc_core_softc *sc, uint32_t offset)
+{
+ return (bus_space_read_4(sc->bst, sc->bsh, offset));
+}
+
+static inline uint32_t
+pmc_read_safe(struct intel_pmc_core_softc *sc, uint32_t offset)
+{
+ if (sc->access_denied)
+ return (0);
+ return (pmc_read(sc, offset));
+}
+
+static int
+pmc_core_slp_s0_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_core_softc *sc = oidp->oid_arg1;
+ uint64_t val, usec;
+
+ val = pmc_read_safe(sc, SPT_PMC_SLP_S0_RES_OFFSET);
+ usec = val * SPT_PMC_SLP_S0_RES_STEP;
+ return (sysctl_handle_64(oidp, &usec, 0, req));
+}
+
+static int
+pmc_core_ltr_ignore_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_core_softc *sc = oidp->oid_arg1;
+ uint32_t val;
+
+ val = pmc_read_safe(sc, SPT_PMC_LTR_IGNORE_OFFSET);
+ return (sysctl_handle_32(oidp, &val, 0, req));
+}
+
+static int
+pmc_core_pm_cfg_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_core_softc *sc = oidp->oid_arg1;
+ uint32_t val;
+
+ val = pmc_read_safe(sc, SPT_PMC_PM_CFG_OFFSET);
+ return (sysctl_handle_32(oidp, &val, 0, req));
+}
+
+static int
+pmc_core_pm_sts_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_core_softc *sc = oidp->oid_arg1;
+ uint32_t val;
+
+ val = pmc_read_safe(sc, SPT_PMC_PM_STS_OFFSET);
+ return (sysctl_handle_32(oidp, &val, 0, req));
+}
+
+static int
+intel_pmc_core_probe(device_t dev)
+{
+ const struct pci_device_table *tbl;
+
+ tbl = PCI_MATCH(dev, intel_pmc_core_devices);
+ if (tbl == NULL)
+ return (ENXIO);
+ device_set_desc(dev, tbl->descr);
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+intel_pmc_core_attach(device_t dev)
+{
+ struct intel_pmc_core_softc *sc = device_get_softc(dev);
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+ uint32_t pm_cfg, pm_sts, ltr_ign, slp_s0;
+
+ sc->rid = PCIR_BAR(0);
+ sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->rid, RF_ACTIVE);
+ if (sc->res == NULL) {
+ device_printf(dev, "cannot allocate PMC BAR0\n");
+ return (ENOMEM);
+ }
+
+ sc->bst = rman_get_bustag(sc->res);
+ sc->bsh = rman_get_bushandle(sc->res);
+
+ /*
+ * Check multiple registers to detect firmware lock.
+ * All reading 0xFFFFFFFF indicates access denied.
+ */
+ pm_cfg = pmc_read(sc, SPT_PMC_PM_CFG_OFFSET);
+ pm_sts = pmc_read(sc, SPT_PMC_PM_STS_OFFSET);
+ ltr_ign = pmc_read(sc, SPT_PMC_LTR_IGNORE_OFFSET);
+ slp_s0 = pmc_read(sc, SPT_PMC_SLP_S0_RES_OFFSET);
+
+ if (pm_cfg == 0xFFFFFFFF && pm_sts == 0xFFFFFFFF &&
+ ltr_ign == 0xFFFFFFFF && slp_s0 == 0xFFFFFFFF) {
+ sc->access_denied = 1;
+ device_printf(dev,
+ "PMC access denied by firmware (S0ix not supported)\n");
+ } else
+ sc->access_denied = 0;
+
+ ctx = device_get_sysctl_ctx(dev);
+ tree = device_get_sysctl_tree(dev);
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "access_denied", CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->access_denied, 0,
+ "Firmware denied access to PMC registers");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "slp_s0_residency", CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, pmc_core_slp_s0_sysctl, "QU",
+ "Cumulative time in any S0ix sub-state (microseconds)");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ltr_ignore", CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, pmc_core_ltr_ignore_sysctl, "IU",
+ "LTR ignore mask");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "pm_cfg", CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, pmc_core_pm_cfg_sysctl, "IU",
+ "Power Management configuration");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "pm_sts", CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, pmc_core_pm_sts_sysctl, "IU",
+ "Power Management status");
+
+ return (0);
+}
+
+static int
+intel_pmc_core_detach(device_t dev)
+{
+ struct intel_pmc_core_softc *sc = device_get_softc(dev);
+
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
+ return (0);
+}
+
+static device_method_t intel_pmc_core_methods[] = {
+ DEVMETHOD(device_probe, intel_pmc_core_probe),
+ DEVMETHOD(device_attach, intel_pmc_core_attach),
+ DEVMETHOD(device_detach, intel_pmc_core_detach),
+ DEVMETHOD_END
+};
+
+static driver_t intel_pmc_core_driver = {
+ "intel_pmc_core",
+ intel_pmc_core_methods,
+ sizeof(struct intel_pmc_core_softc)
+};
+
+DRIVER_MODULE(intel_pmc_core, pci, intel_pmc_core_driver, 0, 0);
+PCI_PNP_INFO(intel_pmc_core_devices);
+MODULE_VERSION(intel_pmc_core, 1);
+MODULE_DEPEND(intel_pmc_core, pci, 1, 1, 1);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -174,6 +174,7 @@
${_igc} \
imgact_binmisc \
${_imx} \
+ ${_intel_pmc_core} \
${_intelspi} \
${_io} \
${_ioat} \
@@ -814,6 +815,7 @@
_hyperv= hyperv
_ichwd= ichwd
_ida= ida
+_intel_pmc_core= intel_pmc_core
_intelspi= intelspi
_ips= ips
_isci= isci
diff --git a/sys/modules/intel_pmc_core/Makefile b/sys/modules/intel_pmc_core/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/intel_pmc_core/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/intel
+KMOD= intel_pmc_core
+SRCS= intel_pmc_core.c
+SRCS+= device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 12:59 AM (2 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28517957
Default Alt Text
D54881.diff (7 KB)
Attached To
Mode
D54881: intel/intel_pmc_core: Add Intel PMC Core driver
Attached
Detach File
Event Timeline
Log In to Comment