Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F172500058
D54881.id186626.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.id186626.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
@@ -262,6 +262,7 @@
${_imcsmb.4} \
inet.4 \
inet6.4 \
+ intel_pmc.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,83 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2026 Abdelkader Boudih <seuros@FreeBSD.org>
+.\"
+.Dd September 7, 2026
+.Dt INTEL_PMC 4
+.Os
+.Sh NAME
+.Nm intel_pmc
+.Nd Intel Performance Management Controller driver
+.Sh SYNOPSIS
+.Cd "device intel_pmc"
+.Sh DESCRIPTION
+The
+.Nm
+driver exposes information and controls from the Performance
+Management Controller (PMC) of Intel platforms.
+Presently, it supports the Intel Sunrise Point platform (Skylake CPU
+generation), providing access to debug information and controls
+related to S0ix (Modern Standby).
+.Pp
+The cumulative time spent in low power mode while in S0 is reported,
+and the administrator can force the platform to ignore IP blocks
+whose Latency Tolerance Reporting (LTR) prevents the platform from
+entering S0ix.
+.Sh HARDWARE
+The
+.Nm
+driver supports the PMC block found in the following Intel Platform
+Controller Hubs:
+.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.ltr_ignore Pq read-write
+Latency Tolerance Reporting (LTR) ignore mask.
+Each bit corresponds to one IP block (bits 0-16).
+Setting a bit tells the PMC to ignore that IP's LTR requirements,
+allowing S0ix entry even if the IP would otherwise block it.
+A clear bit means the IP's requirements are considered and can
+prevent S0ix.
+.Pp
+Sunrise Point bit assignments:
+SOUTHPORT_A, SOUTHPORT_B, SATA, GIGABIT_ETHERNET, XHCI, reserved,
+ME, EVA, SOUTHPORT_C, HD_AUDIO, LPSS, SOUTHPORT_D, SOUTHPORT_E,
+CAMERA, ESPI, SCC, ISH.
+.It Va dev.intel_pmc.%d.slp_s0_residency Pq read-only
+Cumulative time in microseconds that the SLP_S0 signal has been
+asserted (100\ us per counter step).
+Per the datasheet, SLP_S0 asserts when the PCH is idle and the
+processor is in C10 state.
+A value that never advances indicates S0ix transitions are not occurring.
+.Pp
+The counter is 32-bit and wraps after approximately 5 days of
+cumulative S0ix residency.
+.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.
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 16.0 .
+.Sh AUTHORS
+.An Abdelkader Boudih Aq Mt seuros@FreeBSD.org
+.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
@@ -159,6 +159,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,219 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Abdelkader Boudih <seuros@FreeBSD.org>
+ */
+
+/*
+ * intel_pmc -- Intel Performance Management Controller (PMC) driver
+ *
+ * Exposes information and controls from the PMC of Intel platforms.
+ * Only the Sunrise Point (SPT) platform, paired with Skylake
+ * generation processors, is currently supported; everything below
+ * describes that hardware only.
+ *
+ * The driver reports the cumulative time spent in low power mode
+ * (S0ix, Modern Standby) while in S0, and lets the administrator
+ * force the PMC to ignore IP blocks whose Latency Tolerance
+ * Reporting (LTR) prevents the platform from entering S0ix.
+ *
+ * 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. Per the datasheet, SLP_S0 asserts
+ * when the PCH is idle and the processor is in C10 state; in general
+ * this also requires ModPhy lanes power-gated and PLLs idle (Linux
+ * commit b740d2e9233cb). A counter that never advances indicates
+ * S0ix transitions are not occurring. The counter is 32-bit and
+ * wraps after approximately 5 days of cumulative S0ix residency.
+ *
+ * LTR_IGNORE (PWRM+0x30C) has one bit per IP block. Setting a bit
+ * tells the PMC to ignore that IP's LTR requirements, allowing S0ix
+ * entry even if the IP would otherwise block it. A clear bit means
+ * the IP's LTR requirements are considered and can prevent S0ix.
+ *
+ * SPT bit assignments (0-16):
+ * 0=SOUTHPORT_A 1=SOUTHPORT_B 2=SATA
+ * 3=GIGABIT_ETHERNET 4=XHCI 5=reserved
+ * 6=ME 7=EVA 8=SOUTHPORT_C
+ * 9=HD_AUDIO 10=LPSS 11=SOUTHPORT_D
+ * 12=SOUTHPORT_E 13=CAMERA 14=ESPI
+ * 15=SCC 16=ISH
+ *
+ * Ref: Intel 100 Series Chipset Family PCH Datasheet Vol 2, section 4.3
+ * Ref: Linux commit 9c2ee19987ef (initial SPT PMC support)
+ * Ref: Linux commit 2eb150558bb7 (LTR IP block documentation)
+ */
+
+#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 <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/pmap.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.
+ * LTR_IGNORE is not documented there; the offset comes from Linux
+ * commit 9c2ee19987ef (initial SPT PMC support).
+ */
+#define SPT_PMC_ACTL_OFFSET 0x44 /* ACPI Control */
+#define SPT_PMC_ACTL_PWRM_EN (1u << 8) /* PWRM decode enabled */
+#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
+#define SPT_PMC_LTR_IGNORE_BITS 17 /* bits 0-16 are valid IP blocks */
+
+struct intel_pmc_softc {
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+};
+
+/*
+ * Only Sunrise Point - other generations have different layouts.
+ * 0xa121 is documented in the Intel 100 Series Chipset Family PCH
+ * Datasheet Vol 2. Sunrise Point-LP has no public datasheet; 0x9d21
+ * comes from the pci_vendors database, where Linux also sourced it.
+ */
+static const struct pci_device_table intel_pmc_devices[] = {
+ { 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 inline void
+intel_pmc_write(struct intel_pmc_softc *sc, uint32_t offset, uint32_t val)
+{
+
+ bus_space_write_4(sc->bst, sc->bsh, offset, val);
+}
+
+static int
+intel_pmc_slp_s0_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct intel_pmc_softc *sc = oidp->oid_arg1;
+ uint64_t val, usec;
+
+ 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;
+ int error;
+
+ val = intel_pmc_read(sc, SPT_PMC_LTR_IGNORE_OFFSET);
+ error = sysctl_handle_32(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ /* Only bits 0-16 are valid IP blocks */
+ val &= (1u << SPT_PMC_LTR_IGNORE_BITS) - 1;
+ intel_pmc_write(sc, SPT_PMC_LTR_IGNORE_OFFSET, val);
+ return (0);
+}
+
+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;
+
+ if ((pci_read_config(dev, SPT_PMC_ACTL_OFFSET, 4) &
+ SPT_PMC_ACTL_PWRM_EN) == 0) {
+ device_printf(dev, "PWRM decode not enabled by firmware\n");
+ return (ENXIO);
+ }
+ pwrm_base = pci_read_config(dev, SPT_PMC_PWRM_BASE_OFFSET, 4) &
+ SPT_PMC_PWRM_BASE_MASK;
+
+ sc->bst = X86_BUS_SPACE_MEM;
+ sc->bsh = (bus_space_handle_t)pmap_mapdev(pwrm_base,
+ SPT_PMC_MMIO_SIZE);
+
+ ctx = device_get_sysctl_ctx(dev);
+ tree = device_get_sysctl_tree(dev);
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ltr_ignore",
+ CTLTYPE_U32 | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, intel_pmc_ltr_ignore_sysctl, "IU",
+ "LTR ignore mask: set bit = ignore IP, allowing S0ix");
+
+ 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");
+
+ 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
@@ -178,6 +178,7 @@
${_igc} \
imgact_binmisc \
${_imx} \
+ ${_intel_pmc} \
${_intelspi} \
${_io} \
${_ioat} \
@@ -831,6 +832,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
Sat, Sep 19, 9:29 PM (4 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39251472
Default Alt Text
D54881.id186626.diff (10 KB)
Attached To
Mode
D54881: intel/intelpmc: Add Intel PMC Core driver
Attached
Detach File
Event Timeline
Log In to Comment