Page MenuHomeFreeBSD

D54881.id186626.diff
No OneTemporary

D54881.id186626.diff

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

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)

Event Timeline