public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "David E. Box" <david.e.box@linux.intel.com>
To: thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com,
	irenic.rajneesh@gmail.com, ilpo.jarvinen@linux.intel.com,
	srinivas.pandruvada@linux.intel.com,
	intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
	xi.pardee@linux.intel.com
Cc: david.e.box@linux.intel.com, hansg@kernel.org,
	linux-kernel@vger.kernel.org,
	platform-driver-x86@vger.kernel.org
Subject: [PATCH 14/22] platform/x86/intel/pmc: Add ACPI PWRM telemetry driver for Nova Lake S
Date: Thu, 12 Mar 2026 18:51:53 -0700	[thread overview]
Message-ID: <20260313015202.3660072-15-david.e.box@linux.intel.com> (raw)
In-Reply-To: <20260313015202.3660072-1-david.e.box@linux.intel.com>

Add an ACPI-based PMC PWRM telemetry driver for Nova Lake S. The driver
locates PMT discovery data in _DSD under the Intel VSEC UUID, parses it,
and registers telemetry regions with the PMT/VSEC framework so PMC
telemetry is exposed via existing PMT interfaces.

Export pmc_parse_telem_dsd() and pmc_find_telem_guid() to support ACPI
discovery in other PMC drivers (e.g., ssram_telemetry) without duplicating
ACPI parsing logic. Also export acpi_disc_t typedef from core.h for callers
to properly declare discovery table arrays.

Selected by INTEL_PMC_CORE. Existing PCI functionality is preserved.

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
 drivers/platform/x86/intel/pmc/Kconfig        |  14 ++
 drivers/platform/x86/intel/pmc/Makefile       |   2 +
 drivers/platform/x86/intel/pmc/core.h         |  12 +
 .../platform/x86/intel/pmc/pwrm_telemetry.c   | 227 ++++++++++++++++++
 4 files changed, 255 insertions(+)
 create mode 100644 drivers/platform/x86/intel/pmc/pwrm_telemetry.c

diff --git a/drivers/platform/x86/intel/pmc/Kconfig b/drivers/platform/x86/intel/pmc/Kconfig
index 0f19dc7edcf9..937186b0b5dd 100644
--- a/drivers/platform/x86/intel/pmc/Kconfig
+++ b/drivers/platform/x86/intel/pmc/Kconfig
@@ -9,6 +9,7 @@ config INTEL_PMC_CORE
 	depends on ACPI
 	depends on INTEL_PMT_TELEMETRY
 	select INTEL_PMC_SSRAM_TELEMETRY
+	select INTEL_PMC_PWRM_TELEMETRY
 	help
 	  The Intel Platform Controller Hub for Intel Core SoCs provides access
 	  to Power Management Controller registers via various interfaces. This
@@ -39,3 +40,16 @@ config INTEL_PMC_SSRAM_TELEMETRY
 	  (including sysfs).
 
 	  This option is selected by INTEL_PMC_CORE.
+
+config INTEL_PMC_PWRM_TELEMETRY
+	tristate
+	help
+	  This driver discovers PMC PWRM telemetry regions described in ACPI
+	  _DSD and registers them with the Intel VSEC framework as Intel PMT
+	  telemetry devices.
+
+	  It validates the ACPI discovery data and publishes the discovered
+	  regions so they can be accessed through the Intel PMT telemetry
+	  interfaces (including sysfs).
+
+	  This option is selected by INTEL_PMC_CORE.
diff --git a/drivers/platform/x86/intel/pmc/Makefile b/drivers/platform/x86/intel/pmc/Makefile
index bb960c8721d7..fdbb768f7b09 100644
--- a/drivers/platform/x86/intel/pmc/Makefile
+++ b/drivers/platform/x86/intel/pmc/Makefile
@@ -12,3 +12,5 @@ obj-$(CONFIG_INTEL_PMC_CORE)		+= intel_pmc_core_pltdrv.o
 # Intel PMC SSRAM driver
 intel_pmc_ssram_telemetry-y		+= ssram_telemetry.o
 obj-$(CONFIG_INTEL_PMC_SSRAM_TELEMETRY)	+= intel_pmc_ssram_telemetry.o
+intel_pmc_pwrm_telemetry-y		+= pwrm_telemetry.o
+obj-$(CONFIG_INTEL_PMC_PWRM_TELEMETRY)	+= intel_pmc_pwrm_telemetry.o
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 118c8740ad3a..284aced99f72 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -562,6 +562,8 @@ int pmc_core_pmt_get_blk_sub_req(struct pmc_dev *pmcdev, struct pmc *pmc,
 extern const struct file_operations pmc_core_substate_req_regs_fops;
 extern const struct file_operations pmc_core_substate_blk_req_fops;
 
+extern const guid_t intel_vsec_guid;
+
 #define pmc_for_each_mode(mode, pmc)						\
 	for (unsigned int __i = 0, __cond;					\
 	     __cond = __i < (pmc)->num_lpm_modes,				\
@@ -583,4 +585,14 @@ static const struct file_operations __name ## _fops = {			\
 	.release	= single_release,				\
 }
 
+struct intel_vsec_header;
+union acpi_object;
+
+/* Avoid checkpatch warning */
+typedef u32 (*acpi_disc_t)[4];
+
+int pmc_parse_telem_dsd(union acpi_object *obj,
+			struct intel_vsec_header *header,
+			acpi_disc_t *acpi_disc);
+union acpi_object *pmc_find_telem_guid(union acpi_object *dsd);
 #endif /* PMC_CORE_H */
diff --git a/drivers/platform/x86/intel/pmc/pwrm_telemetry.c b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c
new file mode 100644
index 000000000000..25ca6979c214
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel PMC PWRM ACPI driver
+ *
+ * Copyright (C) 2025, Intel Corporation
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/intel_vsec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uuid.h>
+
+#include "core.h"
+
+#define ENTRY_LEN		5
+
+/* DWORD2 */
+#define DVSEC_ID_MASK		GENMASK(15, 0)
+#define NUM_ENTRIES_MASK	GENMASK(23, 16)
+#define ENTRY_SIZE_MASK		GENMASK(31, 24)
+
+/* DWORD3 */
+#define TBIR_MASK		GENMASK(2, 0)
+#define DISC_TBL_OFF_MASK	GENMASK(31, 3)
+
+const guid_t intel_vsec_guid =
+	GUID_INIT(0x294903fb, 0x634d, 0x4fc7, 0xaf, 0x1f, 0x0f, 0xb9,
+		  0x56, 0xb0, 0x4f, 0xc1);
+
+static bool is_valid_entry(union acpi_object *pkg)
+{
+	int i;
+
+	if (!pkg || pkg->type != ACPI_TYPE_PACKAGE || pkg->package.count != ENTRY_LEN)
+		return false;
+
+	if (pkg->package.elements[0].type != ACPI_TYPE_STRING)
+		return false;
+
+	for (i = 1; i < ENTRY_LEN; i++)
+		if (pkg->package.elements[i].type != ACPI_TYPE_INTEGER)
+			return false;
+
+	return true;
+}
+
+int pmc_parse_telem_dsd(union acpi_object *obj,
+			struct intel_vsec_header *header,
+			u32 (**acpi_disc)[4])
+{
+	union acpi_object *vsec_pkg;
+	union acpi_object *disc_pkg;
+	u64 hdr0;
+	u64 hdr1;
+	int num_regions;
+	int i;
+
+	if (!header)
+		return -EINVAL;
+
+	if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2)
+		return -EINVAL;
+
+	/* First Package is DVSEC info */
+	vsec_pkg = &obj->package.elements[0];
+	if (!is_valid_entry(vsec_pkg))
+		return -EINVAL;
+
+	hdr0 = vsec_pkg->package.elements[3].integer.value;
+	hdr1 = vsec_pkg->package.elements[4].integer.value;
+
+	header->id          = FIELD_GET(DVSEC_ID_MASK, hdr0);
+	header->num_entries = FIELD_GET(NUM_ENTRIES_MASK, hdr0);
+	header->entry_size  = FIELD_GET(ENTRY_SIZE_MASK, hdr0);
+	header->tbir        = FIELD_GET(TBIR_MASK, hdr1);
+	header->offset      = FIELD_GET(DISC_TBL_OFF_MASK, hdr1);
+
+	/* Second Package contains the discovery tables */
+	disc_pkg = &obj->package.elements[1];
+	if (disc_pkg->type != ACPI_TYPE_PACKAGE || disc_pkg->package.count < 1)
+		return -EINVAL;
+
+	num_regions = disc_pkg->package.count;
+	if (header->num_entries != num_regions)
+		return -EINVAL;
+
+	*acpi_disc = kmalloc_array(num_regions, sizeof(**acpi_disc), GFP_KERNEL);
+	if (!*acpi_disc)
+		return -ENOMEM;
+
+	for (i = 0; i < num_regions; i++) {
+		union acpi_object *pkg;
+		u64 value;
+		int j;
+
+		pkg = &disc_pkg->package.elements[i];
+		if (!is_valid_entry(pkg)) {
+			kfree(*acpi_disc);
+			return -EINVAL;
+		}
+
+		/* Element 0 is a descriptive string; DWORD values start at index 1. */
+		for (j = 1; j < ENTRY_LEN; j++) {
+			value = pkg->package.elements[j].integer.value;
+			if (value > U32_MAX) {
+				kfree(*acpi_disc);
+				return -ERANGE;
+			}
+
+			(*acpi_disc)[i][j - 1] = value;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(pmc_parse_telem_dsd, "INTEL_PMC_CORE");
+
+union acpi_object *pmc_find_telem_guid(union acpi_object *dsd)
+{
+	int i;
+
+	if (!dsd || dsd->type != ACPI_TYPE_PACKAGE)
+		return NULL;
+
+	for (i = 0; i + 1 < dsd->package.count; i += 2) {
+		union acpi_object *uuid_obj, *data_obj;
+		guid_t uuid;
+
+		uuid_obj = &dsd->package.elements[i];
+		data_obj = &dsd->package.elements[i + 1];
+
+		if (uuid_obj->type != ACPI_TYPE_BUFFER ||
+		    uuid_obj->buffer.length != 16)
+			continue;
+
+		memcpy(&uuid, uuid_obj->buffer.pointer, 16);
+		if (guid_equal(&uuid, &intel_vsec_guid))
+			return data_obj;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(pmc_find_telem_guid, "INTEL_PMC_CORE");
+
+static int pmc_pwrm_acpi_probe(struct platform_device *pdev)
+{
+	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+	struct intel_vsec_header header;
+	struct intel_vsec_header *headers[2] = { &header, NULL };
+	struct intel_vsec_platform_info info = { };
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	u32 (*acpi_disc)[4];
+	union acpi_object *dsd;
+	acpi_status status;
+	int ret;
+
+	if (!handle)
+		return -ENODEV;
+
+	status = acpi_evaluate_object(handle, "_DSD", NULL, &buf);
+	if (ACPI_FAILURE(status))
+		return dev_err_probe(dev, -ENODEV, "Could not evaluate _DSD: %s\n",
+				     acpi_format_exception(status));
+
+	dsd = pmc_find_telem_guid(buf.pointer);
+	if (!dsd) {
+		ret = -ENODEV;
+		goto cleanup_acpi_buf;
+	}
+
+	ret = pmc_parse_telem_dsd(dsd, &header, &acpi_disc);
+	if (ret)
+		goto cleanup_acpi_buf;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, header.tbir);
+	if (!res) {
+		ret = -EINVAL;
+		goto cleanup_acpi_disc;
+	}
+
+	info.headers = headers;
+	info.caps = VSEC_CAP_TELEMETRY;
+	info.acpi_disc = acpi_disc;
+	info.src = INTEL_VSEC_DISC_ACPI;
+	info.base_addr = res->start;
+
+	ret = intel_vsec_register(&pdev->dev, &info);
+
+cleanup_acpi_disc:
+	kfree(acpi_disc);
+cleanup_acpi_buf:
+	ACPI_FREE(buf.pointer);
+
+	return ret;
+}
+
+static const struct acpi_device_id pmc_pwrm_acpi_ids[] = {
+	{ "INTC1122", 0 }, /* Nova Lake */
+	{ "INTC1129", 0 }, /* Nova Lake */
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, pmc_pwrm_acpi_ids);
+
+static struct platform_driver pmc_pwrm_acpi_driver = {
+	.probe = pmc_pwrm_acpi_probe,
+	.driver = {
+		.name = "intel_pmc_pwrm_acpi",
+		.acpi_match_table = ACPI_PTR(pmc_pwrm_acpi_ids),
+	},
+};
+module_platform_driver(pmc_pwrm_acpi_driver);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("Intel PMC PWRM ACPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("INTEL_VSEC");
-- 
2.43.0


  parent reply	other threads:[~2026-03-13  1:52 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-13  1:51 [PATCH 00/22] platform/x86/intel: Add ACPI PMT discovery support and enable NVL PMC telemetry David E. Box
2026-03-13  1:51 ` [PATCH 01/22] platform/x86/intel/vsec: Refactor base_addr handling David E. Box
2026-03-13  1:51 ` [PATCH 02/22] platform/x86/intel/vsec: Make driver_data info const David E. Box
2026-03-13  1:51 ` [PATCH 03/22] platform/x86/intel/vsec: Decouple add/link helpers from PCI David E. Box
2026-03-13  1:51 ` [PATCH 04/22] platform/x86/intel/vsec: Switch exported helpers from pci_dev to device David E. Box
2026-03-13  1:51 ` [PATCH 05/22] platform/x86/intel/vsec: Return real error codes from registration path David E. Box
2026-03-13  1:51 ` [PATCH 06/22] platform/x86/intel/vsec: Plumb ACPI PMT discovery tables through vsec David E. Box
2026-03-17 16:54   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 07/22] platform/x86/intel/pmt: Add pre/post decode hooks around header parsing David E. Box
2026-03-13  1:51 ` [PATCH 08/22] platform/x86/intel/pmt/crashlog: Split init into pre-decode David E. Box
2026-03-13  1:51 ` [PATCH 09/22] platform/x86/intel/pmt/telemetry: Move overlap check to post-decode hook David E. Box
2026-03-13  1:51 ` [PATCH 10/22] platform/x86/intel/pmt: Move header decode into common helper David E. Box
2026-03-17 15:42   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 11/22] platform/x86/intel/pmt: Pass discovery index instead of resource David E. Box
2026-03-13  1:51 ` [PATCH 12/22] platform/x86/intel/pmt: Unify header fetch and add ACPI source David E. Box
2026-03-17 15:57   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 13/22] platform/x86/intel/pmc: Add PMC SSRAM Kconfig description David E. Box
2026-03-13  1:51 ` David E. Box [this message]
2026-03-17 16:24   ` [PATCH 14/22] platform/x86/intel/pmc: Add ACPI PWRM telemetry driver for Nova Lake S Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 15/22] platform/x86/intel/pmc/ssram: Rename probe and PCI ID table for consistency David E. Box
2026-03-17 16:26   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 16/22] platform/x86/intel/pmc/ssram: Use fixed-size static pmc array David E. Box
2026-03-13  1:51 ` [PATCH 17/22] platform/x86/intel/pmc/ssram: Refactor DEVID/PWRMBASE extraction into helper David E. Box
2026-03-17 16:33   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 18/22] platform/x86/intel/pmc/ssram: Add PCI platform data David E. Box
2026-03-17 16:35   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 19/22] platform/x86/intel/pmc/ssram: Refactor memory barrier for reentrant probe David E. Box
2026-03-17 16:40   ` Ilpo Järvinen
2026-03-13  1:51 ` [PATCH 20/22] platform/x86/intel/pmc/ssram: Add ACPI discovery scaffolding David E. Box
2026-03-17 16:45   ` Ilpo Järvinen
2026-03-13  1:52 ` [PATCH 21/22] platform/x86/intel/pmc/ssram: Make PMT registration optional David E. Box
2026-03-17 16:48   ` Ilpo Järvinen
2026-03-13  1:52 ` [PATCH 22/22] platform/x86/intel/pmc: Add NVL PCI IDs for SSRAM telemetry discovery David E. Box
2026-03-13 15:03 ` [PATCH 00/22] platform/x86/intel: Add ACPI PMT discovery support and enable NVL PMC telemetry srinivas pandruvada

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260313015202.3660072-15-david.e.box@linux.intel.com \
    --to=david.e.box@linux.intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hansg@kernel.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=irenic.rajneesh@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=rodrigo.vivi@intel.com \
    --cc=srinivas.pandruvada@linux.intel.com \
    --cc=thomas.hellstrom@linux.intel.com \
    --cc=xi.pardee@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox