From: Xi Pardee <xi.pardee@linux.intel.com>
To: xi.pardee@linux.intel.com, irenic.rajneesh@gmail.com,
david.e.box@linux.intel.com, hdegoede@redhat.com,
ilpo.jarvinen@linux.intel.com,
platform-driver-x86@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 6/7] platform/x86:intel/pmc: Add support to Retrieve LPM information
Date: Fri, 9 Aug 2024 13:46:35 -0700 [thread overview]
Message-ID: <20240809204648.1124545-7-xi.pardee@linux.intel.com> (raw)
In-Reply-To: <20240809204648.1124545-1-xi.pardee@linux.intel.com>
On supported platforms, the low power mode (LPM) requirements for entering
each idle substate are described in Platform Monitoring Technology (PMT)
telemetry entries. Add support to find and read the requirements from the
telemetry entries.
Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
---
drivers/platform/x86/intel/pmc/Kconfig | 2 +-
drivers/platform/x86/intel/pmc/core.c | 146 +++++++++++++++++++++++++
drivers/platform/x86/intel/pmc/core.h | 6 +
3 files changed, 153 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/intel/pmc/Kconfig b/drivers/platform/x86/intel/pmc/Kconfig
index 56c6d3650bf7..b77f1fb84b4d 100644
--- a/drivers/platform/x86/intel/pmc/Kconfig
+++ b/drivers/platform/x86/intel/pmc/Kconfig
@@ -8,7 +8,7 @@ config INTEL_PMC_CORE
depends on PCI
depends on ACPI
depends on INTEL_PMC_SSRAM_TELEMETRY || !INTEL_PMC_SSRAM_TELEMETRY
- depends on INTEL_PMT_TELEMETRY
+ depends on INTEL_PMT_TELEMETRY || !INTEL_PMT_TELEMETRY
help
The Intel Platform Controller Hub for Intel Core SoCs provides access
to Power Management Controller registers via various interfaces. This
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index 634b4d939ed2..379676d08136 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -785,6 +785,152 @@ static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs);
+static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
+{
+ for (; list->map; ++list)
+ if (list->map == map)
+ return list->guid;
+
+ return 0;
+}
+
+static int pmc_core_pmt_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, int func)
+{
+ struct telem_endpoint *ep;
+ const u8 *lpm_indices;
+ int num_maps, mode_offset = 0;
+ struct pci_dev *pcidev;
+ int ret, mode, i;
+ int lpm_size;
+ u32 guid;
+
+ lpm_indices = pmc->map->lpm_reg_index;
+ num_maps = pmc->map->lpm_num_maps;
+ lpm_size = LPM_MAX_NUM_MODES * num_maps;
+
+ guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map);
+ if (!guid)
+ return -ENXIO;
+
+ pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, func));
+ if (!pcidev)
+ return -ENODEV;
+
+ ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0);
+ if (IS_ERR(ep)) {
+ dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %ld",
+ PTR_ERR(ep));
+ ret = -EPROBE_DEFER;
+ goto release_dev;
+ }
+
+ pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev,
+ lpm_size * sizeof(u32),
+ GFP_KERNEL);
+ if (!pmc->lpm_req_regs) {
+ ret = -ENOMEM;
+ goto unregister_ep;
+ }
+
+ /*
+ * PMC Low Power Mode (LPM) table
+ *
+ * In telemetry space, the LPM table contains a 4 byte header followed
+ * by 8 consecutive mode blocks (one for each LPM mode). Each block
+ * has a 4 byte header followed by a set of registers that describe the
+ * IP state requirements for the given mode. The IP mapping is platform
+ * specific but the same for each block, making for easy analysis.
+ * Platforms only use a subset of the space to track the requirements
+ * for their IPs. Callers provide the requirement registers they use as
+ * a list of indices. Each requirement register is associated with an
+ * IP map that's maintained by the caller.
+ *
+ * Header
+ * +----+----------------------------+----------------------------+
+ * | 0 | REVISION | ENABLED MODES |
+ * +----+--------------+-------------+-------------+--------------+
+ *
+ * Low Power Mode 0 Block
+ * +----+--------------+-------------+-------------+--------------+
+ * | 1 | SUB ID | SIZE | MAJOR | MINOR |
+ * +----+--------------+-------------+-------------+--------------+
+ * | 2 | LPM0 Requirements 0 |
+ * +----+---------------------------------------------------------+
+ * | | ... |
+ * +----+---------------------------------------------------------+
+ * | 29 | LPM0 Requirements 27 |
+ * +----+---------------------------------------------------------+
+ *
+ * ...
+ *
+ * Low Power Mode 7 Block
+ * +----+--------------+-------------+-------------+--------------+
+ * | | SUB ID | SIZE | MAJOR | MINOR |
+ * +----+--------------+-------------+-------------+--------------+
+ * | 60 | LPM7 Requirements 0 |
+ * +----+---------------------------------------------------------+
+ * | | ... |
+ * +----+---------------------------------------------------------+
+ * | 87 | LPM7 Requirements 27 |
+ * +----+---------------------------------------------------------+
+ *
+ */
+ mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET;
+ pmc_for_each_mode(i, mode, pmcdev) {
+ u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps);
+ int m;
+
+ for (m = 0; m < num_maps; m++) {
+ u8 sample_id = lpm_indices[m] + mode_offset;
+
+ ret = pmt_telem_read32(ep, sample_id, req_offset, 1);
+ if (ret) {
+ dev_err(&pmcdev->pdev->dev,
+ "couldn't read Low Power Mode requirements: %d\n", ret);
+ devm_kfree(&pmcdev->pdev->dev, pmc->lpm_req_regs);
+ pmc->lpm_req_regs = NULL;
+ goto unregister_ep;
+ }
+ ++req_offset;
+ }
+ mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET;
+ }
+
+unregister_ep:
+ pmt_telem_unregister_endpoint(ep);
+release_dev:
+ pci_dev_put(pcidev);
+
+ return ret;
+}
+
+int pmc_core_get_lpm_reqs(struct pmc_dev *pmcdev, int func)
+{
+ unsigned int i;
+ int ret;
+
+ if (!IS_REACHABLE(CONFIG_INTEL_PMC_SSRAM_TELEMETRY)) {
+ dev_dbg(&pmcdev->pdev->dev, "INTEL PMC SSRAM device driver is not reachable");
+ return 0;
+ }
+
+ if (!IS_REACHABLE(CONFIG_INTEL_PMT_TELEMETRY)) {
+ dev_dbg(&pmcdev->pdev->dev, "INTEL PMT TELEMETRY driver is not reachable");
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
+ if (!pmcdev->pmcs[i])
+ continue;
+
+ ret = pmc_core_pmt_get_lpm_req(pmcdev, pmcdev->pmcs[i], func);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static void pmc_core_substate_req_header_show(struct seq_file *s, int pmc_index)
{
struct pmc_dev *pmcdev = s->private;
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 07f8c3070ab9..3dc640405590 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -24,6 +24,11 @@ struct telem_endpoint;
#define MAX_NUM_PMC 3
#define S0IX_BLK_SIZE 4
+/* PCH query */
+#define LPM_HEADER_OFFSET 1
+#define LPM_REG_COUNT 28
+#define LPM_MODE_OFFSET 1
+
/* Sunrise Point Power Management Controller PCI Device ID */
#define SPT_PMC_PCI_DEVICE_ID 0x9d21
#define SPT_PMC_BASE_ADDR_OFFSET 0x48
@@ -590,6 +595,7 @@ extern const struct pmc_bit_map *arl_pchs_lpm_maps[];
extern const struct pmc_reg_map arl_pchs_reg_map;
extern void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
+extern int pmc_core_get_lpm_reqs(struct pmc_dev *pmcdev, int func);
int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
int pmc_core_resume_common(struct pmc_dev *pmcdev);
--
2.43.0
next prev parent reply other threads:[~2024-08-09 20:46 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-09 20:46 [PATCH 0/7] Create Intel PMC SSRAM Telemetry driver Xi Pardee
2024-08-09 20:46 ` [PATCH 1/7] platform/x86:intel/pmc: Remove SSRAM support from PMC Core Xi Pardee
2024-08-09 20:46 ` [PATCH 2/7] platform/x86:intel/pmc: Create Intel PMC SSRAM Telemetry driver Xi Pardee
2024-08-09 20:46 ` [PATCH 3/7] platform/x86:intel/pmc: Add support to get PMC information from SSRAM Xi Pardee
2024-08-09 20:46 ` [PATCH 4/7] platform/x86:intel/pmt: Get PMC from SSRAM for available platforms Xi Pardee
2024-08-09 20:46 ` [PATCH 5/7] platform/x86:intel/pmt: Create inline version for telemetry functions Xi Pardee
2024-08-09 20:46 ` Xi Pardee [this message]
2024-08-09 20:46 ` [PATCH 7/7] platform/x86:intel/pmc: Get LPM information for available platforms Xi Pardee
2024-08-13 16:01 ` [PATCH 0/7] Create Intel PMC SSRAM Telemetry driver Ilpo Järvinen
2024-08-13 23:01 ` Xi Pardee
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=20240809204648.1124545-7-xi.pardee@linux.intel.com \
--to=xi.pardee@linux.intel.com \
--cc=david.e.box@linux.intel.com \
--cc=hdegoede@redhat.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=irenic.rajneesh@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=platform-driver-x86@vger.kernel.org \
/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