Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F161916908
D54881.id175952.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D54881.id175952.diff
View Options
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -254,6 +254,8 @@
${_imcsmb.4} \
inet.4 \
inet6.4 \
+ intel_pmc.4 \
+ intelthermal.4 \
intpm.4 \
intro.4 \
${_io.4} \
diff --git a/share/man/man4/intel_pmc.4 b/share/man/man4/intel_pmc.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/intel_pmc.4
@@ -0,0 +1,98 @@
+.\"
+.\" Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd February 23, 2026
+.Dt INTEL_PMC 4
+.Os
+.Sh NAME
+.Nm intel_pmc
+.Nd Intel PCH Power Management Controller driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device intel_pmc"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+intel_pmc_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver exposes sleep state residency counters and LTR block status
+for Intel Sunrise Point PCH (Platform Controller Hub) via
+.Xr sysctl 8 .
+.Pp
+The driver supports debugging S0ix (Modern Standby) power states by
+providing the cumulative time the system has spent in S0ix and
+identifying which IP blocks are preventing deeper sleep states.
+.Pp
+If firmware has locked access to the PMC registers, the driver detects
+this condition at attach time and reports it via the
+.Va access_denied
+sysctl.
+All register reads return zero when access is denied.
+.Sh HARDWARE
+The
+.Nm
+driver supports the following devices:
+.Pp
+.Bl -bullet -compact
+.It
+Intel Sunrise Point-LP PMC (6th/7th Gen Core mobile, PCI ID 0x8086:0x9d21)
+.It
+Intel Sunrise Point-H PMC (6th/7th Gen Core desktop/server,
+PCI ID 0x8086:0xa121)
+.El
+.Sh SYSCTLS
+The following
+.Xr sysctl 8
+variables are available:
+.Bl -tag -width indent
+.It Va dev.intel_pmc.%d.access_denied
+Set to 1 if firmware has denied access to PMC registers.
+.It Va dev.intel_pmc.%d.slp_s0_residency
+Cumulative time the PCH SLP_S0 signal was asserted, in microseconds
+(100\ us per step).
+SLP_S0 is asserted only when all of the following conditions are
+met simultaneously: CPU in Package C10, PCH in low power mode,
+ModPhy lanes power-gated, and PLLs idle.
+This represents the deepest achievable S0ix platform state.
+A value that never advances indicates S0ix transitions are not occurring.
+.Pp
+The counter is 32-bit and wraps after approximately 4.97 days of
+cumulative S0ix residency.
+.It Va dev.intel_pmc.%d.ltr_ignore
+Latency Tolerance Reporting (LTR) ignore mask.
+Each bit corresponds to one IP block; a
+.Em clear
+bit means that agent is asserting LTR requirements that can prevent S0ix
+entry.
+Sunrise Point bit assignments (bits 0-17):
+SPA, SPB, SATA, GBE, XHCI, reserved, ME, EVA, SPC, HDA, LPSS,
+SPD, SPE, CAM, ESPI, SCC, ISH, AGG.
+.El
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr pci 4 ,
+.Xr sysctl 8
+.Pp
+Intel 100 Series Chipset Family PCH Datasheet, Volume 2, Section 4.3.53.
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 16.0 .
+.Sh AUTHORS
+.An Abdelkader Boudih Aq Mt freebsd@seuros.com
+.Sh CAVEATS
+Only Sunrise Point PCH is supported.
+Other PCH generations (Cannon Point, Tiger Lake, etc.) have different
+register layouts and are not handled by this driver.
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -150,6 +150,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.c optional intel_pmc 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.c b/sys/dev/intel/intel_pmc.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/intel/intel_pmc.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * intel_pmc -- Intel PCH Power Management Controller driver
+ *
+ * Exposes sleep state residency counters and LTR block status
+ * for debugging S0ix (Modern Standby) power states.
+ *
+ * The PMC register space (PWRM) is mapped via the PWRM_BASE register
+ * at PCI config offset 0x48, not through BAR0. See Intel 100 Series
+ * Chipset Family PCH Datasheet Vol 2, section 4.3.53.
+ *
+ * The SLP_S0_RESIDENCY counter increments (100 us per step) while the
+ * PCH SLP_S0 signal is asserted. SLP_S0 is asserted only when all of
+ * the following conditions are met simultaneously:
+ * - CPU in Package C10 (deepest package C-state)
+ * - PCH in low power mode
+ * - ModPhy lanes power-gated
+ * - PLLs idle
+ * A counter that never advances indicates S0ix transitions are not
+ * occurring. The counter is 32-bit and wraps after approximately
+ * 4.97 days of cumulative S0ix residency.
+ *
+ * LTR_IGNORE (PWRM+0x30C) has one bit per IP block. A clear bit means
+ * that agent is asserting LTR requirements that can prevent S0ix entry.
+ * SPT bit assignments (0-17):
+ * 0=SPA 1=SPB 2=SATA 3=GBE 4=XHCI 5=reserved
+ * 6=ME 7=EVA 8=SPC 9=HDA 10=LPSS 11=SPD
+ * 12=SPE 13=CAM 14=ESPI 15=SCC 16=ISH 17=AGG
+ *
+ * Ref: https://patchwork.kernel.org/project/platform-driver-x86/patch/\
+ * 1462891545-24060-1-git-send-email-rajneesh.bhardwaj@intel.com/
+ * Ref: Intel 100 Series Chipset Family PCH Datasheet Vol 2, section 4.3.53
+ */
+
+#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/pmap.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_PWRM_BASE_OFFSET 0x48 /* PCI config offset for PWRM */
+#define SPT_PMC_PWRM_BASE_MASK 0xfffff000
+#define SPT_PMC_MMIO_SIZE 0x1000
+
+#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_softc {
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ int access_denied;
+};
+
+static const struct pci_device_table intel_pmc_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
+intel_pmc_read(struct intel_pmc_softc *sc, uint32_t offset)
+{
+ return (bus_space_read_4(sc->bst, sc->bsh, offset));
+}
+
+static int
+intel_pmc_slp_s0_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_softc *sc = oidp->oid_arg1;
+ uint64_t val, usec;
+
+ if (sc->access_denied)
+ return (EACCES);
+ val = intel_pmc_read(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
+intel_pmc_ltr_ignore_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_softc *sc = oidp->oid_arg1;
+ uint32_t val;
+
+ if (sc->access_denied)
+ return (EACCES);
+ val = intel_pmc_read(sc, SPT_PMC_LTR_IGNORE_OFFSET);
+ return (sysctl_handle_32(oidp, &val, 0, req));
+}
+
+static int
+intel_pmc_probe(device_t dev)
+{
+ const struct pci_device_table *tbl;
+
+ tbl = PCI_MATCH(dev, intel_pmc_devices);
+ if (tbl == NULL)
+ return (ENXIO);
+ device_set_desc(dev, tbl->descr);
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+intel_pmc_attach(device_t dev)
+{
+ struct intel_pmc_softc *sc = device_get_softc(dev);
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+ vm_paddr_t pwrm_base;
+ uint32_t slp_s0, ltr_ign;
+
+ pwrm_base = pci_read_config(dev, SPT_PMC_PWRM_BASE_OFFSET, 4) &
+ SPT_PMC_PWRM_BASE_MASK;
+ if (pwrm_base == 0) {
+ device_printf(dev, "PWRM base not configured by firmware\n");
+ return (ENXIO);
+ }
+
+ sc->bst = X86_BUS_SPACE_MEM;
+ sc->bsh = (bus_space_handle_t)pmap_mapdev(pwrm_base,
+ SPT_PMC_MMIO_SIZE);
+
+ /*
+ * Detect firmware access lock: both key registers returning
+ * 0xFFFFFFFF indicates PMC registers are inaccessible.
+ */
+ slp_s0 = intel_pmc_read(sc, SPT_PMC_SLP_S0_RES_OFFSET);
+ ltr_ign = intel_pmc_read(sc, SPT_PMC_LTR_IGNORE_OFFSET);
+
+ if (slp_s0 == 0xFFFFFFFF && ltr_ign == 0xFFFFFFFF) {
+ sc->access_denied = 1;
+ device_printf(dev, "PMC registers inaccessible "
+ "(locked by firmware)\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 locked PMC registers");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "slp_s0_residency",
+ CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, intel_pmc_slp_s0_sysctl, "QU",
+ "SLP_S0 residency time in microseconds");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ltr_ignore", CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, intel_pmc_ltr_ignore_sysctl, "IU",
+ "LTR ignore mask: clear bit = agent blocking S0ix entry");
+
+ return (0);
+}
+
+static int
+intel_pmc_detach(device_t dev)
+{
+ struct intel_pmc_softc *sc = device_get_softc(dev);
+
+ pmap_unmapdev((void *)sc->bsh, SPT_PMC_MMIO_SIZE);
+ return (0);
+}
+
+static device_method_t intel_pmc_methods[] = {
+ DEVMETHOD(device_probe, intel_pmc_probe),
+ DEVMETHOD(device_attach, intel_pmc_attach),
+ DEVMETHOD(device_detach, intel_pmc_detach),
+ DEVMETHOD_END
+};
+
+static driver_t intel_pmc_driver = {
+ "intel_pmc",
+ intel_pmc_methods,
+ sizeof(struct intel_pmc_softc)
+};
+
+DRIVER_MODULE(intel_pmc, pci, intel_pmc_driver, 0, 0);
+PCI_PNP_INFO(intel_pmc_devices);
+MODULE_VERSION(intel_pmc, 1);
+MODULE_DEPEND(intel_pmc, pci, 1, 1, 1);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -175,6 +175,7 @@
${_igc} \
imgact_binmisc \
${_imx} \
+ ${_intel_pmc} \
${_intelspi} \
${_io} \
${_ioat} \
@@ -822,6 +823,7 @@
_hyperv= hyperv
_ichwd= ichwd
_ida= ida
+_intel_pmc= intel_pmc
_intelspi= intelspi
_ips= ips
_isci= isci
diff --git a/sys/modules/intel_pmc/Makefile b/sys/modules/intel_pmc/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/intel_pmc/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/intel
+KMOD= intel_pmc
+SRCS= intel_pmc.c
+SRCS+= device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jul 9, 12:21 AM (17 h, 13 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34865686
Default Alt Text
D54881.id175952.diff (10 KB)
Attached To
Mode
D54881: intel/intelpmc: Add Intel PMC Core driver
Attached
Detach File
Event Timeline
Log In to Comment