The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: "David E. Box" <david.e.box@linux.intel.com>
Cc: irenic.rajneesh@gmail.com, srinivas.pandruvada@linux.intel.com,
	 xi.pardee@linux.intel.com, Hans de Goede <hansg@kernel.org>,
	 LKML <linux-kernel@vger.kernel.org>,
	platform-driver-x86@vger.kernel.org
Subject: Re: [PATCH V3 08/16] platform/x86/intel/pmc: Add ACPI PWRM telemetry driver for Nova Lake S
Date: Mon, 11 May 2026 20:16:10 +0300 (EEST)	[thread overview]
Message-ID: <735caf70-e9e9-444b-4549-ae9db80cc377@linux.intel.com> (raw)
In-Reply-To: <20260501231054.3890305-9-david.e.box@linux.intel.com>

On Fri, 1 May 2026, David E. Box wrote:

> 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>
> ---
> V3 changes:
>   - Updated pmc_parse_telem_dsd() in pwrm_telemetry.c to use acpi_disc_t
>     in the function return type for consistency with the exported typedef
>   - Moved acpi_disc_t allocation to the allocation site with cleanup
>     annotation (__free(kfree)), as now specified by cleanup.h

I wonder if you posted an old version of this patch as I don't see these
in the patch?

>   - Style, readability and cleanup-path refinement based on review
>     feedback
> 
> V2 changes:
>   - Added explicit <linux/uuid.h> include for guid_t type availability in
>     core.h
>   - Added explicit <linux/bits.h> include in pwrm_telemetry.c for GENMASK()
>   - Added <linux/cleanup.h> and converted goto based cleanup to __free()
>     attributes per Ilpo's feedback
>   - Combined u64 hdr0 and u64 hdr1 into single declaration
>   - Converted pmc_parse_telem_dsd() to return acpi_disc directly with
>     ERR_PTR() for failures
>   - Added braces around _DSD evaluation failure path
> 
>  drivers/platform/x86/intel/pmc/Kconfig        |  14 ++
>  drivers/platform/x86/intel/pmc/Makefile       |   2 +
>  drivers/platform/x86/intel/pmc/core.h         |  15 ++
>  .../platform/x86/intel/pmc/pwrm_telemetry.c   | 214 ++++++++++++++++++
>  4 files changed, 245 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..24406534c7fc 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -14,10 +14,14 @@
>  
>  #include <linux/acpi.h>
>  #include <linux/bits.h>
> +#include <linux/cleanup.h>
>  #include <linux/platform_device.h>
> +#include <linux/uuid.h>
>  
>  struct telem_endpoint;
>  
> +DEFINE_FREE(pmc_acpi_free, void *, if (_T) ACPI_FREE(_T))
> +
>  #define SLP_S0_RES_COUNTER_MASK			GENMASK(31, 0)
>  
>  #define PMC_BASE_ADDR_DEFAULT			0xFE000000
> @@ -562,6 +566,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 +589,13 @@ 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];
> +
> +acpi_disc_t pmc_parse_telem_dsd(union acpi_object *obj,
> +				struct intel_vsec_header *header);
> +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..e852ee2d6d9f
> --- /dev/null
> +++ b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c
> @@ -0,0 +1,214 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Intel PMC PWRM ACPI driver
> + *
> + * Copyright (C) 2025, Intel Corporation
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/bits.h>
> +#include <linux/bitfield.h>
> +#include <linux/cleanup.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;
> +}
> +
> +u32 (*pmc_parse_telem_dsd(union acpi_object *obj,
> +			  struct intel_vsec_header *header))[4]
> +{
> +	acpi_disc_t disc __free(kfree) = NULL;
> +	union acpi_object *vsec_pkg;
> +	union acpi_object *disc_pkg;
> +	u64 hdr0, hdr1;
> +	int num_regions;
> +	int i;
> +
> +	if (!header)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* First Package is DVSEC info */
> +	vsec_pkg = &obj->package.elements[0];
> +	if (!is_valid_entry(vsec_pkg))
> +		return ERR_PTR(-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 ERR_PTR(-EINVAL);
> +
> +	num_regions = disc_pkg->package.count;
> +	if (header->num_entries != num_regions)
> +		return ERR_PTR(-EINVAL);
> +
> +	disc = kmalloc_array(num_regions, sizeof(*disc), GFP_KERNEL);
> +	if (!disc)
> +		return ERR_PTR(-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))
> +			return ERR_PTR(-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)
> +				return ERR_PTR(-ERANGE);
> +
> +			disc[i][j - 1] = value;
> +		}
> +	}
> +
> +	return no_free_ptr(disc);
> +}
> +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;
> +	union acpi_object *dsd;
> +	acpi_status status;
> +
> +	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));
> +	}
> +
> +	void *dsd_buf __free(pmc_acpi_free) = buf.pointer;
> +
> +	dsd = pmc_find_telem_guid(dsd_buf);
> +	if (!dsd)
> +		return -ENODEV;
> +
> +	acpi_disc_t acpi_disc __free(kfree) = pmc_parse_telem_dsd(dsd, &header);
> +	if (IS_ERR(acpi_disc))
> +		return PTR_ERR(acpi_disc);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, header.tbir);
> +	if (!res)
> +		return -EINVAL;
> +
> +	info.headers = headers;
> +	info.caps = VSEC_CAP_TELEMETRY;
> +	info.acpi_disc = acpi_disc;
> +	info.src = INTEL_VSEC_DISC_ACPI;
> +	info.base_addr = res->start;
> +
> +	return intel_vsec_register(&pdev->dev, &info);
> +}
> +
> +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");
> 

-- 
 i.


      parent reply	other threads:[~2026-05-11 17:16 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260501231054.3890305-1-david.e.box@linux.intel.com>
     [not found] ` <20260501231054.3890305-7-david.e.box@linux.intel.com>
2026-05-11 17:12   ` [PATCH V3 06/16] platform/x86/intel/pmt: Unify header fetch and add ACPI source Ilpo Järvinen
     [not found] ` <20260501231054.3890305-9-david.e.box@linux.intel.com>
2026-05-11 17:16   ` Ilpo Järvinen [this message]

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=735caf70-e9e9-444b-4549-ae9db80cc377@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=david.e.box@linux.intel.com \
    --cc=hansg@kernel.org \
    --cc=irenic.rajneesh@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=srinivas.pandruvada@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