From a2c5d6feeb3d5d33491bd4c0bdadef9bfa7692ca Mon Sep 17 00:00:00 2001 From: Xingui Yang Date: Tue, 5 Sep 2023 02:48:33 +0000 Subject: [PATCH 01/25] seq_file: add helper macro to define attribute for rw file commit 9cba82bba500e3ce875381350f289cfb3aa633ba upstream. Patch series "Add helper macro DEFINE_SHOW_STORE_ATTRIBUTE() at seq_file.c", v6. We already own DEFINE_SHOW_ATTRIBUTE() helper macro for defining attribute for read-only file, but we found many of drivers also want a helper macro for read-write file too. So we add this helper macro to reduce duplicated code. This patch (of 3): We already own DEFINE_SHOW_ATTRIBUTE() helper macro for defining attribute for read-only file, but many of drivers want a helper macro for read-write file too. So we add DEFINE_SHOW_STORE_ATTRIBUTE() helper to reduce duplicated code. Intel-SIG: commit 9cba82bba500 seq_file: add helper macro to define attribute for rw file Backport PLR (Power Limit Reasons) TPMI driver Link: https://lkml.kernel.org/r/20230905024835.43219-1-yangxingui@huawei.com Link: https://lkml.kernel.org/r/20230905024835.43219-2-yangxingui@huawei.com Signed-off-by: Luo Jiaxing Co-developed-by: Xingui Yang Signed-off-by: Xingui Yang Reviewed-by: Andy Shevchenko Cc: Al Viro Cc: Animesh Manna Cc: Anshuman Gupta Cc: Damien Le Moal Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Himanshu Madhani Cc: James Bottomley Cc: John Garry Cc: Martin K. Petersen Cc: Uma Shankar Cc: Xiang Chen Cc: Zeng Tao Signed-off-by: Andrew Morton [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- include/linux/seq_file.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 386ab580b839b..234bcdb1fba45 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -207,6 +207,21 @@ static const struct file_operations __name ## _fops = { \ .release = single_release, \ } +#define DEFINE_SHOW_STORE_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __name ## _show, inode->i_private); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .write = __name ## _write, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + #define DEFINE_PROC_SHOW_ATTRIBUTE(__name) \ static int __name ## _open(struct inode *inode, struct file *file) \ { \ From 99d7ae0375cc183a6014bbb0d9ddb363b87e55c9 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Tue, 3 Oct 2023 14:59:53 +0300 Subject: [PATCH 02/25] kernel.h: Move ARRAY_SIZE() to a separate header commit 3cd39bc3b11b8d34b7d7c961a35fdfd18b0ebf75 upstream. Touching files so used for the kernel, forces 'make' to recompile most of the kernel. Having those definitions in more granular files helps avoid recompiling so much of the kernel. Intel-SIG: commit 3cd39bc3b11b kernel.h: Move ARRAY_SIZE() to a separate header Backport PLR (Power Limit Reasons) TPMI driver Signed-off-by: Alejandro Colomar Reviewed-by: Giovanni Cabiddu Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230817143352.132583-2-lucas.segarra.fernandez@intel.com [andy: reduced to cover only string.h for now] Signed-off-by: Andy Shevchenko [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- include/linux/array_size.h | 13 +++++++++++++ include/linux/kernel.h | 7 +------ include/linux/string.h | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 include/linux/array_size.h diff --git a/include/linux/array_size.h b/include/linux/array_size.h new file mode 100644 index 0000000000000..06d7d83196ca3 --- /dev/null +++ b/include/linux/array_size.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_ARRAY_SIZE_H +#define _LINUX_ARRAY_SIZE_H + +#include + +/** + * ARRAY_SIZE - get the number of elements in array @arr + * @arr: array to be sized + */ +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) + +#endif /* _LINUX_ARRAY_SIZE_H */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index cee8fe87e9f4f..d9ad21058eed9 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -50,12 +51,6 @@ #define READ 0 #define WRITE 1 -/** - * ARRAY_SIZE - get the number of elements in array @arr - * @arr: array to be sized - */ -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) - #define PTR_IF(cond, ptr) ((cond) ? (ptr) : NULL) #define u64_to_user_ptr(x) ( \ diff --git a/include/linux/string.h b/include/linux/string.h index 5077776e995e0..ce137830a0b99 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -2,6 +2,7 @@ #ifndef _LINUX_STRING_H_ #define _LINUX_STRING_H_ +#include #include /* for inline */ #include /* for size_t */ #include /* for NULL */ From d01d49fad679ab144c7680edeef5ae0b690f145a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 13 Nov 2023 16:27:45 +0100 Subject: [PATCH 03/25] batman-adv: Switch to linux/array_size.h commit c3ed16a64c0b0a5b116c9753bf48496d49daffb5 upstream. The commit 3cd39bc3b11b ("kernel.h: Move ARRAY_SIZE() to a separate header") introduced a new header for the ARRAY_SIZE macro which was previously exposed via linux/kernel.h. Intel-SIG: commit c3ed16a64c0b batman-adv: Switch to linux/array_size.h Backport PLR (Power Limit Reasons) TPMI driver Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- net/batman-adv/main.c | 2 +- net/batman-adv/netlink.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index e8a4499155667..357b3a6a3b4c9 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -6,6 +6,7 @@ #include "main.h" +#include #include #include #include @@ -20,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 0c64d81a77617..1f7ed9d4f6fdf 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -7,6 +7,7 @@ #include "netlink.h" #include "main.h" +#include #include #include #include @@ -20,7 +21,6 @@ #include #include #include -#include #include #include #include From 01b567e371a9daed207e1d38269750709df81b5d Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 May 2024 16:29:33 +0300 Subject: [PATCH 04/25] platform/x86/intel/tpmi: Add support for performance limit reasons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b44d79d6bad16c30978c2cee3421133d3f181494 upstream. Add TPMI ID 0x0C (Perf Limit Reasons) to the list of supported TPMI IDs. Intel-SIG: commit b44d79d6bad1 platform/x86/intel/tpmi: Add support for performance limit reasons Backport PLR (Power Limit Reasons) TPMI driver Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Signed-off-by: Tero Kristo Link: https://lore.kernel.org/r/20240527133400.483634-2-tero.kristo@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/tpmi.c | 2 ++ include/linux/intel_tpmi.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 060f9b86bc030..437c1a06d77f6 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -576,6 +576,8 @@ static const char *intel_tpmi_name(enum intel_tpmi_id id) return "uncore"; case TPMI_ID_SST: return "sst"; + case TPMI_ID_PLR: + return "plr"; default: return NULL; } diff --git a/include/linux/intel_tpmi.h b/include/linux/intel_tpmi.h index 1e880cb0f4541..a88ac937d2c29 100644 --- a/include/linux/intel_tpmi.h +++ b/include/linux/intel_tpmi.h @@ -21,6 +21,7 @@ enum intel_tpmi_id { TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */ TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */ TPMI_ID_SST = 5, /* Speed Select Technology */ + TPMI_ID_PLR = 0xc, /* Performance Limit Reasons */ TPMI_CONTROL_ID = 0x80, /* Special ID for getting feature status */ TPMI_INFO_ID = 0x81, /* Special ID for PCI BDF and Package ID information */ }; From 4735b52e791cf790aaff4ec0e3bf065a61e80beb Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 May 2024 16:29:34 +0300 Subject: [PATCH 05/25] platform/x86/intel/tpmi: Add API to get debugfs root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d36842bacf8e3491f555059f27de57b3436cc3ff upstream. Add new API to get the debugfs root directory for TPMI. This allows any TPMI devices to add their own debugfs items under the same directory structure. Intel-SIG: commit d36842bacf8e platform/x86/intel/tpmi: Add API to get debugfs root Backport PLR (Power Limit Reasons) TPMI driver Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Signed-off-by: Tero Kristo Link: https://lore.kernel.org/r/20240527133400.483634-3-tero.kristo@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/tpmi.c | 9 +++++++++ include/linux/intel_tpmi.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 437c1a06d77f6..a3430abeb9869 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -357,6 +357,15 @@ int tpmi_get_feature_status(struct auxiliary_device *auxdev, } EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI); +struct dentry *tpmi_get_debugfs_dir(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); + struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); + + return tpmi_info->dbgfs_dir; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_debugfs_dir, INTEL_TPMI); + static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused) { struct intel_tpmi_info *tpmi_info = s->private; diff --git a/include/linux/intel_tpmi.h b/include/linux/intel_tpmi.h index a88ac937d2c29..ff480b47ae642 100644 --- a/include/linux/intel_tpmi.h +++ b/include/linux/intel_tpmi.h @@ -54,4 +54,5 @@ struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int int tpmi_get_resource_count(struct auxiliary_device *auxdev); int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id, bool *read_blocked, bool *write_blocked); +struct dentry *tpmi_get_debugfs_dir(struct auxiliary_device *auxdev); #endif From e043d0c42992beaab7261ee3c5fbeec12770586f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 28 May 2024 10:34:57 +0300 Subject: [PATCH 06/25] platform/x86/intel: TPMI domain id and CPU mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 17ca2780458cdb0afc623e3432b1977847da3d15 upstream. Each TPMI power domain includes a group of CPUs. Several power management settings in this case applicable to a group of CPUs. There can be several power domains in a CPU package. So, provide interfaces for: - Get power domain id for a Linux CPU - Get mask of Linux CPUs in a power domain Hardware Punit uses different CPU numbering, which is not based on APIC (Advanced Programmable Interrupt Controller) CPU numbering. The Linux CPU numbering is based on APIC CPU numbering. Some PM features like Intel Speed Select, the CPU core mask provided by the hardware is based on the Punit CPU numbering. To use the core mask, this mask needs to be converted to a Linux CPUs mask. So, provide interfaces for: - Convert to a Linux CPU number from a Punit CPU number - Convert to a Punit CPU number from a Linux CPU number On each CPU online, MSR 0x54 is used to read the mapping and stores in a per cpu array. Create a hash for faster searching of a Linux CPU number from a Punit CPU number. Intel-SIG: commit 17ca2780458c platform/x86/intel: TPMI domain id and CPU mapping Backport PLR (Power Limit Reasons) TPMI driver Signed-off-by: Srinivas Pandruvada [tero.kristo: minor updates] Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Signed-off-by: Tero Kristo Link: https://lore.kernel.org/r/20240528073457.497816-1-tero.kristo@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/Kconfig | 4 + drivers/platform/x86/intel/Makefile | 3 + .../platform/x86/intel/tpmi_power_domains.c | 235 ++++++++++++++++++ .../platform/x86/intel/tpmi_power_domains.h | 18 ++ 4 files changed, 260 insertions(+) create mode 100644 drivers/platform/x86/intel/tpmi_power_domains.c create mode 100644 drivers/platform/x86/intel/tpmi_power_domains.h diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index e9dc0c0210299..e97a97355d5aa 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -192,10 +192,14 @@ config INTEL_SMARTCONNECT This driver checks to determine whether the device has Intel Smart Connect enabled, and if so disables it. +config INTEL_TPMI_POWER_DOMAINS + tristate + config INTEL_TPMI tristate "Intel Topology Aware Register and PM Capsule Interface (TPMI)" depends on INTEL_VSEC depends on X86_64 + select INTEL_TPMI_POWER_DOMAINS help The Intel Topology Aware Register and PM Capsule Interface (TPMI), provides enumerable MMIO interface for power management features. diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index c1d5fe05e3f30..10437e56027dd 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -53,6 +53,9 @@ obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o intel_vsec_tpmi-y := tpmi.o obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o +intel_tpmi_power_domains-y := tpmi_power_domains.o +obj-$(CONFIG_INTEL_TPMI_POWER_DOMAINS) += intel_tpmi_power_domains.o + # Intel Uncore drivers intel-rst-y := rst.o obj-$(CONFIG_INTEL_RST) += intel-rst.o diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c new file mode 100644 index 0000000000000..4eb02553957cf --- /dev/null +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Mapping of TPMI power domains CPU mapping + * + * Copyright (c) 2024, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tpmi_power_domains.h" + +#define MSR_PM_LOGICAL_ID 0x54 + +/* + * Struct of MSR 0x54 + * [15:11] PM_DOMAIN_ID + * [10:3] MODULE_ID (aka IDI_AGENT_ID) + * [2:0] LP_ID + * For Atom: + * [2] Always 0 + * [1:0] core ID within module + * For Core + * [2:1] Always 0 + * [0] thread ID + */ + +#define LP_ID_MASK GENMASK_ULL(2, 0) +#define MODULE_ID_MASK GENMASK_ULL(10, 3) +#define PM_DOMAIN_ID_MASK GENMASK_ULL(15, 11) + +/** + * struct tpmi_cpu_info - Mapping information for a CPU + * @hnode: Used to add mapping information to hash list + * @linux_cpu: Linux CPU number + * @pkg_id: Package ID of this CPU + * @punit_thread_id: Punit thread id of this CPU + * @punit_core_id: Punit core id + * @punit_domain_id: Power domain id from Punit + * + * Structure to store mapping information for a Linux CPU + * to a Punit core, thread and power domain. + */ +struct tpmi_cpu_info { + struct hlist_node hnode; + int linux_cpu; + u8 pkg_id; + u8 punit_thread_id; + u8 punit_core_id; + u8 punit_domain_id; +}; + +static DEFINE_PER_CPU(struct tpmi_cpu_info, tpmi_cpu_info); + +/* The dynamically assigned cpu hotplug state to free later */ +static enum cpuhp_state tpmi_hp_state __read_mostly; + +#define MAX_POWER_DOMAINS 8 + +static cpumask_t *tpmi_power_domain_mask; + +/* Lock to protect tpmi_power_domain_mask and tpmi_cpu_hash */ +static DEFINE_MUTEX(tpmi_lock); + +static const struct x86_cpu_id tpmi_cpu_ids[] = { + X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, NULL), + X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, NULL), + X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, NULL), + X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, NULL), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, tpmi_cpu_ids); + +static DECLARE_HASHTABLE(tpmi_cpu_hash, 8); + +static bool tpmi_domain_is_valid(struct tpmi_cpu_info *info) +{ + return info->pkg_id < topology_max_packages() && + info->punit_domain_id < MAX_POWER_DOMAINS; +} + +int tpmi_get_linux_cpu_number(int package_id, int domain_id, int punit_core_id) +{ + struct tpmi_cpu_info *info; + int ret = -EINVAL; + + guard(mutex)(&tpmi_lock); + hash_for_each_possible(tpmi_cpu_hash, info, hnode, punit_core_id) { + if (info->punit_domain_id == domain_id && info->pkg_id == package_id) { + ret = info->linux_cpu; + break; + } + } + + return ret; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_cpu_number, INTEL_TPMI_POWER_DOMAIN); + +int tpmi_get_punit_core_number(int cpu_no) +{ + if (cpu_no >= num_possible_cpus()) + return -EINVAL; + + return per_cpu(tpmi_cpu_info, cpu_no).punit_core_id; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_punit_core_number, INTEL_TPMI_POWER_DOMAIN); + +int tpmi_get_power_domain_id(int cpu_no) +{ + if (cpu_no >= num_possible_cpus()) + return -EINVAL; + + return per_cpu(tpmi_cpu_info, cpu_no).punit_domain_id; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_id, INTEL_TPMI_POWER_DOMAIN); + +cpumask_t *tpmi_get_power_domain_mask(int cpu_no) +{ + struct tpmi_cpu_info *info; + cpumask_t *mask; + int index; + + if (cpu_no >= num_possible_cpus()) + return NULL; + + info = &per_cpu(tpmi_cpu_info, cpu_no); + if (!tpmi_domain_is_valid(info)) + return NULL; + + index = info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id; + guard(mutex)(&tpmi_lock); + mask = &tpmi_power_domain_mask[index]; + + return mask; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, INTEL_TPMI_POWER_DOMAIN); + +static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) +{ + u64 data; + int ret; + + ret = rdmsrl_safe(MSR_PM_LOGICAL_ID, &data); + if (ret) + return ret; + + info->punit_domain_id = FIELD_GET(PM_DOMAIN_ID_MASK, data); + if (info->punit_domain_id >= MAX_POWER_DOMAINS) + return -EINVAL; + + info->punit_thread_id = FIELD_GET(LP_ID_MASK, data); + info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data); + info->pkg_id = topology_physical_package_id(cpu); + info->linux_cpu = cpu; + + return 0; +} + +static int tpmi_cpu_online(unsigned int cpu) +{ + struct tpmi_cpu_info *info = &per_cpu(tpmi_cpu_info, cpu); + int ret, index; + + /* Don't fail CPU online for some bad mapping of CPUs */ + ret = tpmi_get_logical_id(cpu, info); + if (ret) + return 0; + + index = info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id; + + guard(mutex)(&tpmi_lock); + cpumask_set_cpu(cpu, &tpmi_power_domain_mask[index]); + hash_add(tpmi_cpu_hash, &info->hnode, info->punit_core_id); + + return 0; +} + +static int __init tpmi_init(void) +{ + const struct x86_cpu_id *id; + u64 data; + int ret; + + id = x86_match_cpu(tpmi_cpu_ids); + if (!id) + return -ENODEV; + + /* Check for MSR 0x54 presence */ + ret = rdmsrl_safe(MSR_PM_LOGICAL_ID, &data); + if (ret) + return ret; + + tpmi_power_domain_mask = kcalloc(size_mul(topology_max_packages(), MAX_POWER_DOMAINS), + sizeof(*tpmi_power_domain_mask), GFP_KERNEL); + if (!tpmi_power_domain_mask) + return -ENOMEM; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "platform/x86/tpmi_power_domains:online", + tpmi_cpu_online, NULL); + if (ret < 0) { + kfree(tpmi_power_domain_mask); + return ret; + } + + tpmi_hp_state = ret; + + return 0; +} +module_init(tpmi_init) + +static void __exit tpmi_exit(void) +{ + cpuhp_remove_state(tpmi_hp_state); + kfree(tpmi_power_domain_mask); +} +module_exit(tpmi_exit) + +MODULE_DESCRIPTION("TPMI Power Domains Mapping"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/tpmi_power_domains.h b/drivers/platform/x86/intel/tpmi_power_domains.h new file mode 100644 index 0000000000000..e35750dd92736 --- /dev/null +++ b/drivers/platform/x86/intel/tpmi_power_domains.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Mapping of TPMI power domain and CPUs + * + * Copyright (c) 2024, Intel Corporation. + */ + +#ifndef _TPMI_POWER_DOMAINS_H_ +#define _TPMI_POWER_DOMAINS_H_ + +#include + +int tpmi_get_linux_cpu_number(int package_id, int die_id, int punit_core_id); +int tpmi_get_punit_core_number(int cpu_no); +int tpmi_get_power_domain_id(int cpu_no); +cpumask_t *tpmi_get_power_domain_mask(int cpu_no); + +#endif From 8b5eaa7548f49de73f20fecb5a5f346e8209aecb Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 May 2024 16:29:36 +0300 Subject: [PATCH 07/25] platform/x86/intel/tpmi: Add new auxiliary driver for performance limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 811f67c51636d43791995bf483c5c1904900b531 upstream. Add new auxiliary driver that exposes the SoC performance limit reasons via debugfs interface. Intel-SIG: commit 811f67c51636 platform/x86/intel/tpmi: Add new auxiliary driver for performance limits Backport PLR (Power Limit Reasons) TPMI driver Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Signed-off-by: Tero Kristo Link: https://lore.kernel.org/r/20240527133400.483634-5-tero.kristo@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/Kconfig | 7 + drivers/platform/x86/intel/Makefile | 1 + drivers/platform/x86/intel/intel_plr_tpmi.c | 204 ++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 drivers/platform/x86/intel/intel_plr_tpmi.c diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index e97a97355d5aa..ad50bbabec615 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -209,6 +209,13 @@ config INTEL_TPMI To compile this driver as a module, choose M here: the module will be called intel_vsec_tpmi. +config INTEL_PLR_TPMI + tristate "Intel SoC TPMI Power Limit Reasons driver" + depends on INTEL_TPMI + help + This driver provides the TPMI power limit reasons status information + via debugfs files. + config INTEL_TURBO_MAX_3 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" depends on X86_64 && SCHED_MC_PRIO diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 10437e56027dd..74db065c82d61 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o # TPMI drivers intel_vsec_tpmi-y := tpmi.o obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o +obj-$(CONFIG_INTEL_PLR_TPMI) += intel_plr_tpmi.o intel_tpmi_power_domains-y := tpmi_power_domains.o obj-$(CONFIG_INTEL_TPMI_POWER_DOMAINS) += intel_tpmi_power_domains.o diff --git a/drivers/platform/x86/intel/intel_plr_tpmi.c b/drivers/platform/x86/intel/intel_plr_tpmi.c new file mode 100644 index 0000000000000..3c51e50bd244f --- /dev/null +++ b/drivers/platform/x86/intel/intel_plr_tpmi.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Performance Limit Reasons via TPMI + * + * Copyright (c) 2024, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PLR_HEADER 0x00 +#define PLR_DIE_LEVEL 0x18 + +#define PLR_INVALID GENMASK_ULL(63, 0) + +struct tpmi_plr_die { + void __iomem *base; +}; + +struct tpmi_plr { + struct dentry *dbgfs_dir; + struct tpmi_plr_die *die_info; + int num_dies; +}; + +static const char * const plr_coarse_reasons[] = { + "FREQUENCY", + "CURRENT", + "POWER", + "THERMAL", + "PLATFORM", + "MCP", + "RAS", + "MISC", + "QOS", + "DFC", +}; + +static u64 plr_read(struct tpmi_plr_die *plr_die, int offset) +{ + return readq(plr_die->base + offset); +} + +static void plr_write(u64 val, struct tpmi_plr_die *plr_die, int offset) +{ + writeq(val, plr_die->base + offset); +} + +static void plr_print_bits(struct seq_file *s, u64 val, int bits) +{ + const unsigned long mask[] = { BITMAP_FROM_U64(val) }; + int bit; + + for_each_set_bit(bit, mask, bits) { + if (bit >= ARRAY_SIZE(plr_coarse_reasons)) + seq_printf(s, " UNKNOWN(%d)", bit); + else + seq_printf(s, " %s", plr_coarse_reasons[bit]); + } + + if (!val) + seq_puts(s, " none"); + + seq_putc(s, '\n'); +} + +static int plr_status_show(struct seq_file *s, void *unused) +{ + struct tpmi_plr_die *plr_die = s->private; + u64 val; + + val = plr_read(plr_die, PLR_DIE_LEVEL); + seq_puts(s, "cpus"); + plr_print_bits(s, val, 32); + + return 0; +} + +static ssize_t plr_status_write(struct file *filp, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = filp->private_data; + struct tpmi_plr_die *plr_die = s->private; + bool val; + int ret; + + ret = kstrtobool_from_user(ubuf, count, &val); + if (ret) + return ret; + + if (val != 0) + return -EINVAL; + + plr_write(0, plr_die, PLR_DIE_LEVEL); + + return count; +} +DEFINE_SHOW_STORE_ATTRIBUTE(plr_status); + +static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) +{ + struct intel_tpmi_plat_info *plat_info; + struct dentry *dentry; + int i, num_resources; + struct resource *res; + struct tpmi_plr *plr; + void __iomem *base; + char name[16]; + int err; + + plat_info = tpmi_get_platform_data(auxdev); + if (!plat_info) + return dev_err_probe(&auxdev->dev, -EINVAL, "No platform info\n"); + + dentry = tpmi_get_debugfs_dir(auxdev); + if (!dentry) + return dev_err_probe(&auxdev->dev, -ENODEV, "No TPMI debugfs directory.\n"); + + num_resources = tpmi_get_resource_count(auxdev); + if (!num_resources) + return -EINVAL; + + plr = devm_kzalloc(&auxdev->dev, sizeof(*plr), GFP_KERNEL); + if (!plr) + return -ENOMEM; + + plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info), + GFP_KERNEL); + if (!plr->die_info) + return -ENOMEM; + + plr->num_dies = num_resources; + plr->dbgfs_dir = debugfs_create_dir("plr", dentry); + + for (i = 0; i < num_resources; i++) { + res = tpmi_get_resource_at_index(auxdev, i); + if (!res) { + err = dev_err_probe(&auxdev->dev, -EINVAL, "No resource\n"); + goto err; + } + + base = devm_ioremap_resource(&auxdev->dev, res); + if (IS_ERR(base)) { + err = PTR_ERR(base); + goto err; + } + + plr->die_info[i].base = base; + + if (plr_read(&plr->die_info[i], PLR_HEADER) == PLR_INVALID) + continue; + + snprintf(name, sizeof(name), "domain%d", i); + + dentry = debugfs_create_dir(name, plr->dbgfs_dir); + debugfs_create_file("status", 0444, dentry, &plr->die_info[i], + &plr_status_fops); + } + + auxiliary_set_drvdata(auxdev, plr); + + return 0; + +err: + debugfs_remove_recursive(plr->dbgfs_dir); + return err; +} + +static void intel_plr_remove(struct auxiliary_device *auxdev) +{ + struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev); + + debugfs_remove_recursive(plr->dbgfs_dir); +} + +static const struct auxiliary_device_id intel_plr_id_table[] = { + { .name = "intel_vsec.tpmi-plr" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, intel_plr_id_table); + +static struct auxiliary_driver intel_plr_aux_driver = { + .id_table = intel_plr_id_table, + .remove = intel_plr_remove, + .probe = intel_plr_probe, +}; +module_auxiliary_driver(intel_plr_aux_driver); + +MODULE_IMPORT_NS(INTEL_TPMI); +MODULE_DESCRIPTION("Intel TPMI PLR Driver"); +MODULE_LICENSE("GPL"); From 6aef0c8e68fb5de7e48ca89110ccc54dfaa114c6 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 May 2024 16:29:37 +0300 Subject: [PATCH 08/25] platform/x86/intel/tpmi/plr: Add support for the plr mailbox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9e9397a41b7b1db10603edcb13913034bd41cce0 upstream. Add support for reading fine grained power limit reasons via the PLR mailbox. Intel-SIG: commit 9e9397a41b7b platform/x86/intel/tpmi/plr: Add support for the plr mailbox Backport PLR (Power Limit Reasons) TPMI driver Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Signed-off-by: Tero Kristo Link: https://lore.kernel.org/r/20240527133400.483634-6-tero.kristo@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/intel_plr_tpmi.c | 157 +++++++++++++++++++- 1 file changed, 153 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/intel_plr_tpmi.c b/drivers/platform/x86/intel/intel_plr_tpmi.c index 3c51e50bd244f..c1aa52c23d256 100644 --- a/drivers/platform/x86/intel/intel_plr_tpmi.c +++ b/drivers/platform/x86/intel/intel_plr_tpmi.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -14,26 +15,50 @@ #include #include #include +#include #include +#include #include #include +#include #include #include #include +#include "tpmi_power_domains.h" + #define PLR_HEADER 0x00 +#define PLR_MAILBOX_INTERFACE 0x08 +#define PLR_MAILBOX_DATA 0x10 #define PLR_DIE_LEVEL 0x18 +#define PLR_MODULE_ID_MASK GENMASK_ULL(19, 12) +#define PLR_RUN_BUSY BIT_ULL(63) + +#define PLR_COMMAND_WRITE 1 + #define PLR_INVALID GENMASK_ULL(63, 0) +#define PLR_TIMEOUT_US 5 +#define PLR_TIMEOUT_MAX_US 1000 + +#define PLR_COARSE_REASON_BITS 32 + +struct tpmi_plr; + struct tpmi_plr_die { void __iomem *base; + struct mutex lock; /* Protect access to PLR mailbox */ + int package_id; + int die_id; + struct tpmi_plr *plr; }; struct tpmi_plr { struct dentry *dbgfs_dir; struct tpmi_plr_die *die_info; int num_dies; + struct auxiliary_device *auxdev; }; static const char * const plr_coarse_reasons[] = { @@ -49,6 +74,39 @@ static const char * const plr_coarse_reasons[] = { "DFC", }; +static const char * const plr_fine_reasons[] = { + "FREQUENCY_CDYN0", + "FREQUENCY_CDYN1", + "FREQUENCY_CDYN2", + "FREQUENCY_CDYN3", + "FREQUENCY_CDYN4", + "FREQUENCY_CDYN5", + "FREQUENCY_FCT", + "FREQUENCY_PCS_TRL", + "CURRENT_MTPMAX", + "POWER_FAST_RAPL", + "POWER_PKG_PL1_MSR_TPMI", + "POWER_PKG_PL1_MMIO", + "POWER_PKG_PL1_PCS", + "POWER_PKG_PL2_MSR_TPMI", + "POWER_PKG_PL2_MMIO", + "POWER_PKG_PL2_PCS", + "POWER_PLATFORM_PL1_MSR_TPMI", + "POWER_PLATFORM_PL1_MMIO", + "POWER_PLATFORM_PL1_PCS", + "POWER_PLATFORM_PL2_MSR_TPMI", + "POWER_PLATFORM_PL2_MMIO", + "POWER_PLATFORM_PL2_PCS", + "UNKNOWN(22)", + "THERMAL_PER_CORE", + "DFC_UFS", + "PLATFORM_PROCHOT", + "PLATFORM_HOT_VR", + "UNKNOWN(27)", + "UNKNOWN(28)", + "MISC_PCS_PSTATE", +}; + static u64 plr_read(struct tpmi_plr_die *plr_die, int offset) { return readq(plr_die->base + offset); @@ -59,16 +117,68 @@ static void plr_write(u64 val, struct tpmi_plr_die *plr_die, int offset) writeq(val, plr_die->base + offset); } +static int plr_read_cpu_status(struct tpmi_plr_die *plr_die, int cpu, + u64 *status) +{ + u64 regval; + int ret; + + lockdep_assert_held(&plr_die->lock); + + regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); + regval |= PLR_RUN_BUSY; + + plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); + + ret = readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, + !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, + PLR_TIMEOUT_MAX_US); + if (ret) + return ret; + + *status = plr_read(plr_die, PLR_MAILBOX_DATA); + + return 0; +} + +static int plr_clear_cpu_status(struct tpmi_plr_die *plr_die, int cpu) +{ + u64 regval; + + lockdep_assert_held(&plr_die->lock); + + regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); + regval |= PLR_RUN_BUSY | PLR_COMMAND_WRITE; + + plr_write(0, plr_die, PLR_MAILBOX_DATA); + + plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); + + return readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, + !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, + PLR_TIMEOUT_MAX_US); +} + static void plr_print_bits(struct seq_file *s, u64 val, int bits) { const unsigned long mask[] = { BITMAP_FROM_U64(val) }; - int bit; + const char *str; + int bit, index; for_each_set_bit(bit, mask, bits) { - if (bit >= ARRAY_SIZE(plr_coarse_reasons)) - seq_printf(s, " UNKNOWN(%d)", bit); + if (bit < PLR_COARSE_REASON_BITS) { + if (bit < ARRAY_SIZE(plr_coarse_reasons)) + str = plr_coarse_reasons[bit]; + } else { + index = bit - PLR_COARSE_REASON_BITS; + if (index < ARRAY_SIZE(plr_fine_reasons)) + str = plr_fine_reasons[index]; + } + + if (str) + seq_printf(s, " %s", str); else - seq_printf(s, " %s", plr_coarse_reasons[bit]); + seq_printf(s, " UNKNOWN(%d)", bit); } if (!val) @@ -80,12 +190,33 @@ static void plr_print_bits(struct seq_file *s, u64 val, int bits) static int plr_status_show(struct seq_file *s, void *unused) { struct tpmi_plr_die *plr_die = s->private; + int ret; u64 val; val = plr_read(plr_die, PLR_DIE_LEVEL); seq_puts(s, "cpus"); plr_print_bits(s, val, 32); + guard(mutex)(&plr_die->lock); + + for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) + continue; + + if (plr_die->package_id != topology_physical_package_id(cpu)) + continue; + + seq_printf(s, "cpu%d", cpu); + ret = plr_read_cpu_status(plr_die, cpu, &val); + if (ret) { + dev_err(&plr_die->plr->auxdev->dev, "Failed to read PLR for cpu %d, ret=%d\n", + cpu, ret); + return ret; + } + + plr_print_bits(s, val, 64); + } + return 0; } @@ -106,6 +237,18 @@ static ssize_t plr_status_write(struct file *filp, const char __user *ubuf, plr_write(0, plr_die, PLR_DIE_LEVEL); + guard(mutex)(&plr_die->lock); + + for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) + continue; + + if (plr_die->package_id != topology_physical_package_id(cpu)) + continue; + + plr_clear_cpu_status(plr_die, cpu); + } + return count; } DEFINE_SHOW_STORE_ATTRIBUTE(plr_status); @@ -144,6 +287,7 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia plr->num_dies = num_resources; plr->dbgfs_dir = debugfs_create_dir("plr", dentry); + plr->auxdev = auxdev; for (i = 0; i < num_resources; i++) { res = tpmi_get_resource_at_index(auxdev, i); @@ -159,6 +303,10 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia } plr->die_info[i].base = base; + plr->die_info[i].package_id = plat_info->package_id; + plr->die_info[i].die_id = i; + plr->die_info[i].plr = plr; + mutex_init(&plr->die_info[i].lock); if (plr_read(&plr->die_info[i], PLR_HEADER) == PLR_INVALID) continue; @@ -200,5 +348,6 @@ static struct auxiliary_driver intel_plr_aux_driver = { module_auxiliary_driver(intel_plr_aux_driver); MODULE_IMPORT_NS(INTEL_TPMI); +MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); MODULE_DESCRIPTION("Intel TPMI PLR Driver"); MODULE_LICENSE("GPL"); From a7a3b6335e8a52d9572d7fb063d462b770d61506 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 15 Jul 2024 15:22:55 -0500 Subject: [PATCH 09/25] platform/x86/intel/tpmi/plr: Fix output in plr_print_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 182c6941c55347c735e70ffca77741cd000cbec7 upstream. Smatch complains that 'str' can be used without being initialized: drivers/platform/x86/intel/intel_plr_tpmi.c:178 plr_print_bits() error: uninitialized symbol 'str'. In this loop, we iterate over all the set bits and print the name of the bit. The intention is that if there is a bit which is between 0-31 we look for the name in the first array plr_coarse_reasons[] which has 10 elements. If the bit is in the 32-63 range we look for it in the plr_fine_reasons[] array which has 30 elements. If the bit is in the invalid ranges, 10-31 or 62-63, then we should print "UNKNOWN(%d)". The problem is that 'str' needs to be initialized at the start of each iteration, otherwise if we can't find the string then instead of printing "UNKNOWN(%d)", we will re-print whatever the previous bit was. Intel-SIG: commit 182c6941c553 platform/x86/intel/tpmi/plr: Fix output in plr_print_bits() Backport PLR (Power Limit Reasons) TPMI driver Fixes: 9e9397a41b7b ("platform/x86/intel/tpmi/plr: Add support for the plr mailbox") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/b0084e70-4144-445a-9b89-fb19f6b8336a@stanley.mountain Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/intel_plr_tpmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/intel_plr_tpmi.c b/drivers/platform/x86/intel/intel_plr_tpmi.c index c1aa52c23d256..69ace6a629bc7 100644 --- a/drivers/platform/x86/intel/intel_plr_tpmi.c +++ b/drivers/platform/x86/intel/intel_plr_tpmi.c @@ -162,10 +162,11 @@ static int plr_clear_cpu_status(struct tpmi_plr_die *plr_die, int cpu) static void plr_print_bits(struct seq_file *s, u64 val, int bits) { const unsigned long mask[] = { BITMAP_FROM_U64(val) }; - const char *str; int bit, index; for_each_set_bit(bit, mask, bits) { + const char *str = NULL; + if (bit < PLR_COARSE_REASON_BITS) { if (bit < ARRAY_SIZE(plr_coarse_reasons)) str = plr_coarse_reasons[bit]; From 0e36d40dda3715db13eed6cdb57eec982bd9bcfb Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 3 Jan 2025 07:52:53 -0800 Subject: [PATCH 10/25] platform/x86/intel: power-domains: Add Clearwater Forest support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bee9a0838fd223823e5a6d85c055ab1691dc738e upstream. Add Clearwater Forest support (INTEL_ATOM_DARKMONT_X) to tpmi_cpu_ids to support domaid id mappings. Intel-SIG: commit bee9a0838fd2 platform/x86/intel: power-domains: Add Clearwater Forest support Backport PLR (Power Limit Reasons) TPMI driver Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250103155255.1488139-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/tpmi_power_domains.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c index 4eb02553957cf..6b7933fab0f1f 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.c +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -81,6 +81,7 @@ static const struct x86_cpu_id tpmi_cpu_ids[] = { X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, NULL), X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, NULL), X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, NULL), + X86_MATCH_VFM(INTEL_ATOM_DARKMONT_X, NULL), X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, NULL), {} }; From e772ef3e28bec9fcaec44c81b0ae1ec32cd661e6 Mon Sep 17 00:00:00 2001 From: David Arcari Date: Fri, 29 Aug 2025 07:38:59 -0400 Subject: [PATCH 11/25] platform/x86/intel: power-domains: Use topology_logical_package_id() for package ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit aa28991fd5dc4c01a40caab2bd9af8c5e06f9899 upstream. Currently, tpmi_get_logical_id() calls topology_physical_package_id() to set the pkg_id of the info structure. Since some VM hosts assign non contiguous package IDs, topology_physical_package_id() can return a larger value than topology_max_packages(). This will result in an invalid reference into tpmi_power_domain_mask[] as that is allocatead based on topology_max_packages() as the maximum package ID. Intel-SIG: commit aa28991fd5dc platform/x86/intel: power-domains: Use topology_logical_package_id() for package ID Backport PLR (Power Limit Reasons) TPMI driver Fixes: 17ca2780458c ("platform/x86/intel: TPMI domain id and CPU mapping") Signed-off-by: David Arcari Acked-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250829113859.1772827-1-darcari@redhat.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/tpmi_power_domains.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c index 6b7933fab0f1f..e44d19b9db1b5 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.c +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -166,7 +166,7 @@ static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) info->punit_thread_id = FIELD_GET(LP_ID_MASK, data); info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data); - info->pkg_id = topology_physical_package_id(cpu); + info->pkg_id = topology_logical_package_id(cpu); info->linux_cpu = cpu; return 0; From 08b75c423990cc787ceaa86ef60d5c2fd332800e Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 4 Dec 2025 09:08:08 +0800 Subject: [PATCH 12/25] config: enable CONFIG_INTEL_PLR_TPMI Enable PLR (Perf Limit Reasons) driver. Signed-off-by: Zhang Rui --- config.x86_64 | 1 + 1 file changed, 1 insertion(+) diff --git a/config.x86_64 b/config.x86_64 index 6cd53619fa6c9..4c60c0e8e0e05 100644 --- a/config.x86_64 +++ b/config.x86_64 @@ -8196,6 +8196,7 @@ CONFIG_INTEL_OAKTRAIL=m CONFIG_INTEL_RST=m CONFIG_INTEL_SMARTCONNECT=m CONFIG_INTEL_TPMI=m +CONFIG_INTEL_PLR_TPMI=m # CONFIG_INTEL_TURBO_MAX_3 is not set CONFIG_INTEL_VSEC=m # CONFIG_MSI_EC is not set From 8e8f57c6243f2307c460c7f293e81cee7e018204 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 20 Aug 2024 13:45:58 -0700 Subject: [PATCH 13/25] platform/x86/intel-uncore-freq: Do not present separate package-die domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bb9a9bf2787fbe1a4e003daabc8f7a31c17740d6 upstream. The scope of uncore control is per power domain with TPMI. There are two types of processor topologies can be presented by CPUID extended topology leaf irrespective of the hardware architecture: 1. A die is not enumerated in CPUID. In this case there is only one die in a package is visible. In this case there can be multiple power domains in a single die. 2. A power domain in a package is enumerated as a die in CPUID. So there is one power domain per die. To allow die level controls, the current implementation creates a root domain and aggregates all information from power domains in it. This is well suited for configuration 1 above. But for configuration 2 above, the root domain will present the same information as present by power domain. So, no use of aggregating. To check the configuration, call topology_max_dies_per_package(). If it is more than one, avoid creating root domain. Intel-SIG: commit bb9a9bf2787f platform/x86/intel-uncore-freq: Do not present separate package-die domain. Backport Intel uncore-freq driver elc support and update Signed-off-by: Srinivas Pandruvada Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240820204558.1296319-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede [ Yingbao Jia: amend commit log ] Signed-off-by: Yingbao Jia --- .../x86/intel/uncore-frequency/uncore-frequency-tpmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index cd48bd4bf6461..9c77a6f1a2bd0 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -430,6 +430,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ auxiliary_set_drvdata(auxdev, tpmi_uncore); + if (topology_max_die_per_package() > 1) + return 0; + tpmi_uncore->root_cluster.root_domain = true; tpmi_uncore->root_cluster.uncore_root = tpmi_uncore; @@ -453,7 +456,9 @@ static void uncore_remove(struct auxiliary_device *auxdev) { struct tpmi_uncore_struct *tpmi_uncore = auxiliary_get_drvdata(auxdev); - uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data); + if (tpmi_uncore->root_cluster.root_domain) + uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data); + remove_cluster_entries(tpmi_uncore); uncore_freq_common_exit(); From 66cb7f87eb3f7c3b95f847c6c4d0ee3a84bb7dfc Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 28 Aug 2024 18:34:54 +0300 Subject: [PATCH 14/25] platform/x86/intel-uncore-freq: Add support for efficiency latency control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bb516dc79c4a6334d5ef6bdbd0d262cf8be9db8e upstream. Add efficiency latency control support to the TPMI uncore driver. This defines two new threshold values for controlling uncore frequency, low threshold and high threshold. When CPU utilization is below low threshold, the user configurable floor latency control frequency can be used by the system. When CPU utilization is above high threshold, the uncore frequency is increased in 100MHz steps until power limit is reached. Intel-SIG: commit bb516dc79c4a platform/x86/intel-uncore-freq: Add support for efficiency latency control. Backport Intel uncore-freq driver elc support and update Signed-off-by: Tero Kristo Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240828153657.1296410-3-tero.kristo@linux.intel.com Signed-off-by: Hans de Goede [ Yingbao Jia: amend commit log ] Signed-off-by: Yingbao Jia --- .../uncore-frequency-common.h | 4 + .../uncore-frequency/uncore-frequency-tpmi.c | 158 +++++++++++++++++- 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h index 4c245b945e4ea..b5c7311bfa058 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h @@ -70,6 +70,10 @@ enum uncore_index { UNCORE_INDEX_MIN_FREQ, UNCORE_INDEX_MAX_FREQ, UNCORE_INDEX_CURRENT_FREQ, + UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD, + UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD, + UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, + UNCORE_INDEX_EFF_LAT_CTRL_FREQ, }; int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value, diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 9c77a6f1a2bd0..23c44b82642aa 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -30,6 +30,7 @@ #define UNCORE_MAJOR_VERSION 0 #define UNCORE_MINOR_VERSION 2 +#define UNCORE_ELC_SUPPORTED_VERSION 2 #define UNCORE_HEADER_INDEX 0 #define UNCORE_FABRIC_CLUSTER_OFFSET 8 @@ -46,6 +47,7 @@ struct tpmi_uncore_struct; /* Information for each cluster */ struct tpmi_uncore_cluster_info { bool root_domain; + bool elc_supported; u8 __iomem *cluster_base; struct uncore_data uncore_data; struct tpmi_uncore_struct *uncore_root; @@ -75,6 +77,10 @@ struct tpmi_uncore_struct { /* Bit definitions for CONTROL register */ #define UNCORE_MAX_RATIO_MASK GENMASK_ULL(14, 8) #define UNCORE_MIN_RATIO_MASK GENMASK_ULL(21, 15) +#define UNCORE_EFF_LAT_CTRL_RATIO_MASK GENMASK_ULL(28, 22) +#define UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK GENMASK_ULL(38, 32) +#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE BIT(39) +#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK GENMASK_ULL(46, 40) /* Helper function to read MMIO offset for max/min control frequency */ static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info, @@ -89,6 +95,48 @@ static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info, *value = FIELD_GET(UNCORE_MIN_RATIO_MASK, control) * UNCORE_FREQ_KHZ_MULTIPLIER; } +/* Helper function to read efficiency latency control values over MMIO */ +static int read_eff_lat_ctrl(struct uncore_data *data, unsigned int *val, enum uncore_index index) +{ + struct tpmi_uncore_cluster_info *cluster_info; + u64 ctrl; + + cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data); + if (cluster_info->root_domain) + return -ENODATA; + + if (!cluster_info->elc_supported) + return -EOPNOTSUPP; + + ctrl = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX); + + switch (index) { + case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD: + *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, ctrl); + *val *= 100; + *val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK)); + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD: + *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, ctrl); + *val *= 100; + *val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK)); + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE: + *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, ctrl); + break; + case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: + *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_RATIO_MASK, ctrl) * UNCORE_FREQ_KHZ_MULTIPLIER; + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + #define UNCORE_MAX_RATIO FIELD_MAX(UNCORE_MAX_RATIO_MASK) /* Helper for sysfs read for max/min frequencies. Called under mutex locks */ @@ -137,6 +185,82 @@ static int uncore_read_control_freq(struct uncore_data *data, unsigned int *valu return 0; } +/* Helper function for writing efficiency latency control values over MMIO */ +static int write_eff_lat_ctrl(struct uncore_data *data, unsigned int val, enum uncore_index index) +{ + struct tpmi_uncore_cluster_info *cluster_info; + u64 control; + + cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data); + + if (cluster_info->root_domain) + return -ENODATA; + + if (!cluster_info->elc_supported) + return -EOPNOTSUPP; + + switch (index) { + case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD: + if (val > 100) + return -EINVAL; + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD: + if (val > 100) + return -EINVAL; + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE: + if (val > 1) + return -EINVAL; + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: + val /= UNCORE_FREQ_KHZ_MULTIPLIER; + if (val > FIELD_MAX(UNCORE_EFF_LAT_CTRL_RATIO_MASK)) + return -EINVAL; + break; + + default: + return -EOPNOTSUPP; + } + + control = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX); + + switch (index) { + case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD: + val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK); + val /= 100; + control &= ~UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK; + control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, val); + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD: + val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK); + val /= 100; + control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK; + control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, val); + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE: + control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE; + control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, val); + break; + + case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: + control &= ~UNCORE_EFF_LAT_CTRL_RATIO_MASK; + control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_RATIO_MASK, val); + break; + + default: + break; + } + + writeq(control, cluster_info->cluster_base + UNCORE_CONTROL_INDEX); + + return 0; +} + /* Helper function to write MMIO offset for max/min control frequency */ static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, unsigned int input, unsigned int index) @@ -156,7 +280,7 @@ static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, un writeq(control, (cluster_info->cluster_base + UNCORE_CONTROL_INDEX)); } -/* Callback for sysfs write for max/min frequencies. Called under mutex locks */ +/* Helper for sysfs write for max/min frequencies. Called under mutex locks */ static int uncore_write_control_freq(struct uncore_data *data, unsigned int input, enum uncore_index index) { @@ -234,6 +358,33 @@ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncor case UNCORE_INDEX_CURRENT_FREQ: return uncore_read_freq(data, value); + case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD: + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD: + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE: + case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: + return read_eff_lat_ctrl(data, value, index); + + default: + break; + } + + return -EOPNOTSUPP; +} + +/* Callback for sysfs write for TPMI uncore data. Called under mutex locks. */ +static int uncore_write(struct uncore_data *data, unsigned int value, enum uncore_index index) +{ + switch (index) { + case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD: + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD: + case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE: + case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: + return write_eff_lat_ctrl(data, value, index); + + case UNCORE_INDEX_MIN_FREQ: + case UNCORE_INDEX_MAX_FREQ: + return uncore_write_control_freq(data, value, index); + default: break; } @@ -291,7 +442,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ return -EINVAL; /* Register callbacks to uncore core */ - ret = uncore_freq_common_init(uncore_read, uncore_write_control_freq); + ret = uncore_freq_common_init(uncore_read, uncore_write); if (ret) return ret; @@ -412,6 +563,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ cluster_info->uncore_root = tpmi_uncore; + if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION) + cluster_info->elc_supported = true; + ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0); if (ret) { cluster_info->cluster_base = NULL; From 4af465d6f1eb9305fa19d7f7e1037faa0dde0120 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 28 Aug 2024 18:34:55 +0300 Subject: [PATCH 15/25] platform/x86/intel-uncore-freq: Add efficiency latency control to sysfs interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 24b6616355f7eb2a839776578b104a0348b4f77f upstream. Add the TPMI efficiency latency control fields to the sysfs interface. The sysfs files are mapped to the TPMI uncore driver via the registered uncore_read and uncore_write driver callbacks. These fields are not populated on older non TPMI hardware. Intel-SIG: commit 24b6616355f7 platform/x86/intel-uncore-freq: Add efficiency latency control to sysfs interface. Backport Intel uncore-freq driver elc support and update Signed-off-by: Tero Kristo Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240828153657.1296410-4-tero.kristo@linux.intel.com Signed-off-by: Hans de Goede [ Yingbao Jia: amend commit log ] Signed-off-by: Yingbao Jia --- .../uncore-frequency-common.c | 42 ++++++++++++++++--- .../uncore-frequency-common.h | 13 +++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c index 4e880585cbe4d..e22b683a7a434 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -60,11 +60,16 @@ static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index static ssize_t store_attr(struct uncore_data *data, const char *buf, ssize_t count, enum uncore_index index) { - unsigned int input; + unsigned int input = 0; int ret; - if (kstrtouint(buf, 10, &input)) - return -EINVAL; + if (index == UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE) { + if (kstrtobool(buf, (bool *)&input)) + return -EINVAL; + } else { + if (kstrtouint(buf, 10, &input)) + return -EINVAL; + } mutex_lock(&uncore_lock); ret = uncore_write(data, input, index); @@ -103,6 +108,18 @@ show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ); show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ); +store_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD); +store_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD); +store_uncore_attr(elc_high_threshold_enable, + UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE); +store_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ); + +show_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD); +show_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD); +show_uncore_attr(elc_high_threshold_enable, + UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE); +show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ); + #define show_uncore_data(member_name) \ static ssize_t show_##member_name(struct kobject *kobj, \ struct kobj_attribute *attr, char *buf)\ @@ -146,7 +163,8 @@ show_uncore_data(initial_max_freq_khz); static int create_attr_group(struct uncore_data *data, char *name) { - int ret, freq, index = 0; + int ret, index = 0; + unsigned int val; init_attribute_rw(max_freq_khz); init_attribute_rw(min_freq_khz); @@ -168,10 +186,24 @@ static int create_attr_group(struct uncore_data *data, char *name) data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr; data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr; - ret = uncore_read(data, &freq, UNCORE_INDEX_CURRENT_FREQ); + ret = uncore_read(data, &val, UNCORE_INDEX_CURRENT_FREQ); if (!ret) data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr; + ret = uncore_read(data, &val, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD); + if (!ret) { + init_attribute_rw(elc_low_threshold_percent); + init_attribute_rw(elc_high_threshold_percent); + init_attribute_rw(elc_high_threshold_enable); + init_attribute_rw(elc_floor_freq_khz); + + data->uncore_attrs[index++] = &data->elc_low_threshold_percent_kobj_attr.attr; + data->uncore_attrs[index++] = &data->elc_high_threshold_percent_kobj_attr.attr; + data->uncore_attrs[index++] = + &data->elc_high_threshold_enable_kobj_attr.attr; + data->uncore_attrs[index++] = &data->elc_floor_freq_khz_kobj_attr.attr; + } + data->uncore_attrs[index] = NULL; data->uncore_attr_group.name = name; diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h index b5c7311bfa058..26c854cd5d97f 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h @@ -34,6 +34,13 @@ * @domain_id_kobj_attr: Storage for kobject attribute domain_id * @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id * @package_id_kobj_attr: Storage for kobject attribute package_id + * @elc_low_threshold_percent_kobj_attr: + Storage for kobject attribute elc_low_threshold_percent + * @elc_high_threshold_percent_kobj_attr: + Storage for kobject attribute elc_high_threshold_percent + * @elc_high_threshold_enable_kobj_attr: + Storage for kobject attribute elc_high_threshold_enable + * @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs @@ -61,7 +68,11 @@ struct uncore_data { struct kobj_attribute domain_id_kobj_attr; struct kobj_attribute fabric_cluster_id_kobj_attr; struct kobj_attribute package_id_kobj_attr; - struct attribute *uncore_attrs[9]; + struct kobj_attribute elc_low_threshold_percent_kobj_attr; + struct kobj_attribute elc_high_threshold_percent_kobj_attr; + struct kobj_attribute elc_high_threshold_enable_kobj_attr; + struct kobj_attribute elc_floor_freq_khz_kobj_attr; + struct attribute *uncore_attrs[13]; }; #define UNCORE_DOMAIN_ID_INVALID -1 From ce7e0496eb5bef2969827b3f1484520603347028 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2025 16:02:38 -0700 Subject: [PATCH 16/25] platform/x86/intel-uncore-freq: Add attributes to show agent types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b98fa870fce2335433f20b2213e526b8d99e15dc upstream. Currently, users need detailed hardware information to understand the scope of controls within each uncore domain. Uncore frequency controls manage subsystems such as core, cache, memory, and I/O. The UFS TPMI provides this information, which can be used to present the scope more clearly. Each uncore domain consists of one or more agent types, with each agent type controlling one or more uncore hardware subsystems. For example, a single agent might control both the core and cache. Introduce a new attribute called "agent_types." This attribute displays a list of agents, separated by space character. The string representations for agent types are as follows: For core agent: core For cache agent: cache For memory agent: memory For I/O agent: io These agent types are read during probe time for each cluster and stored as part of the struct uncore_data. Intel-SIG: commit b98fa870fce2 platform/x86/intel-uncore-freq: Add attributes to show agent types Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250508230250.1186619-2-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- .../uncore-frequency-common.c | 27 +++++++++++++++++++ .../uncore-frequency-common.h | 18 ++++++++++++- .../uncore-frequency/uncore-frequency-tpmi.c | 21 +++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c index e22b683a7a434..d2612843a145b 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -43,6 +43,29 @@ static ssize_t show_package_id(struct kobject *kobj, struct kobj_attribute *attr return sprintf(buf, "%u\n", data->package_id); } +#define MAX_UNCORE_AGENT_TYPES 4 + +/* The order follows AGENT_TYPE_* defines */ +static const char *agent_name[MAX_UNCORE_AGENT_TYPES] = {"core", "cache", "memory", "io"}; + +static ssize_t show_agent_types(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct uncore_data *data = container_of(attr, struct uncore_data, agent_types_kobj_attr); + unsigned long agent_mask = data->agent_type_mask; + int agent, length = 0; + + for_each_set_bit(agent, &agent_mask, MAX_UNCORE_AGENT_TYPES) { + if (length) + length += sysfs_emit_at(buf, length, " "); + + length += sysfs_emit_at(buf, length, agent_name[agent]); + } + + length += sysfs_emit_at(buf, length, "\n"); + + return length; +} + static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index index) { unsigned int value; @@ -179,6 +202,10 @@ static int create_attr_group(struct uncore_data *data, char *name) data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr; init_attribute_root_ro(package_id); data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr; + if (data->agent_type_mask) { + init_attribute_ro(agent_types); + data->uncore_attrs[index++] = &data->agent_types_kobj_attr.attr; + } } data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr; diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h index 26c854cd5d97f..a638d2e1e83a7 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h @@ -11,6 +11,18 @@ #include +/* + * Define uncore agents, which are under uncore frequency control. + * Defined in the same order as specified in the TPMI UFS Specifications. + * It is possible that there are common uncore frequency control to more than + * one hardware agents. So, these defines are used as a bit mask. +*/ + +#define AGENT_TYPE_CORE 0x01 +#define AGENT_TYPE_CACHE 0x02 +#define AGENT_TYPE_MEMORY 0x04 +#define AGENT_TYPE_IO 0x08 + /** * struct uncore_data - Encapsulate all uncore data * @stored_uncore_data: Last user changed MSR 620 value, which will be restored @@ -25,6 +37,7 @@ * @cluster_id: cluster id in a domain * @instance_id: Unique instance id to append to directory name * @name: Sysfs entry name for this instance + * @agent_type_mask: Bit mask of all hardware agents for this domain * @uncore_attr_group: Attribute group storage * @max_freq_khz_kobj_attr: Storage for kobject attribute max_freq_khz * @mix_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz @@ -41,6 +54,7 @@ * @elc_high_threshold_enable_kobj_attr: Storage for kobject attribute elc_high_threshold_enable * @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz + * @agent_types_kobj_attr: Storage for kobject attribute agent_type * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs @@ -58,6 +72,7 @@ struct uncore_data { int cluster_id; int instance_id; char name[32]; + u16 agent_type_mask; struct attribute_group uncore_attr_group; struct kobj_attribute max_freq_khz_kobj_attr; @@ -72,7 +87,8 @@ struct uncore_data { struct kobj_attribute elc_high_threshold_percent_kobj_attr; struct kobj_attribute elc_high_threshold_enable_kobj_attr; struct kobj_attribute elc_floor_freq_khz_kobj_attr; - struct attribute *uncore_attrs[13]; + struct kobj_attribute agent_types_kobj_attr; + struct attribute *uncore_attrs[14]; }; #define UNCORE_DOMAIN_ID_INVALID -1 diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 23c44b82642aa..76745fd389e4d 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -347,6 +347,25 @@ static int uncore_read_freq(struct uncore_data *data, unsigned int *freq) return 0; } +/* + * Agent types as per the TPMI UFS Specification for UFS_STATUS + * Agent Type - Core Bit: 23 + * Agent Type - Cache Bit: 24 + * Agent Type - Memory Bit: 25 + * Agent Type - IO Bit: 26 + */ + +#define UNCORE_AGENT_TYPES GENMASK_ULL(26, 23) + +/* Helper function to read agent type over MMIO and set the agent type mask */ +static void uncore_set_agent_type(struct tpmi_uncore_cluster_info *cluster_info) +{ + u64 status; + + status = readq((u8 __iomem *)cluster_info->cluster_base + UNCORE_STATUS_INDEX); + cluster_info->uncore_data.agent_type_mask = FIELD_GET(UNCORE_AGENT_TYPES, status); +} + /* Callback for sysfs read for TPMI uncore values. Called under mutex locks. */ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) { @@ -555,6 +574,8 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ cluster_info->cluster_base = pd_info->uncore_base + mask; + uncore_set_agent_type(cluster_info); + cluster_info->uncore_data.package_id = pkg; /* There are no dies like Cascade Lake */ cluster_info->uncore_data.die_id = 0; From bacfaf159c6d48b98e7ad3d31c5a4cb3bfa61f3a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2025 16:02:39 -0700 Subject: [PATCH 17/25] Documentation: admin-guide: pm: Add documentation for agent_types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bfbe7729d6dd2e2c8ef44f9179ad11ab766150e6 upstream. Add documentation to describe agent_types attribute. Intel-SIG: commit bfbe7729d6dd Documentation: admin-guide: pm: Add documentation for agent_types Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20250508230250.1186619-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- .../admin-guide/pm/intel_uncore_frequency_scaling.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst b/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst index 5ab3440e6cee0..84554b87eae45 100644 --- a/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst +++ b/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst @@ -97,6 +97,11 @@ Attributes in each directory: ``package_id`` This attribute is used to get the package id of this instance. +``agent_types`` + This attribute displays all the hardware agents present within the + domain. Each agent has the capability to control one or more hardware + subsystems, which include: core, cache, memory, and I/O. + The other attributes are same as presented at package_*_die_* level. In most of current use cases, the "max_freq_khz" and "min_freq_khz" From 96a370efbdfb42cbfac539cac275e0cf663c4429 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2025 16:02:40 -0700 Subject: [PATCH 18/25] platform/x86/intel: power-domains: Add interface to get Linux die ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e37be5d85c602e07c1e2930c2cc98ebd46f9ecf7 upstream. The die ID in the Linux topology sysfs is a logical identifier that differs from the one presented in CPUID leaf 0x1F or via MSR 0x54. Introduce an interface that returns the Linux CPU die ID based on a given package ID and power domain ID. This mapping is stored during the CPU online callback in an array. Intel-SIG: commit e37be5d85c60 platform/x86/intel: power-domains: Add interface to get Linux die ID Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20250508230250.1186619-4-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: resolve conflict and amend commit log ] Signed-off-by: Zhang Rui --- .../platform/x86/intel/tpmi_power_domains.c | 34 ++++++++++++++++--- .../platform/x86/intel/tpmi_power_domains.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c index e44d19b9db1b5..68f160cfe2ccc 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.c +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -74,6 +74,8 @@ static enum cpuhp_state tpmi_hp_state __read_mostly; static cpumask_t *tpmi_power_domain_mask; +static u16 *domain_die_map; + /* Lock to protect tpmi_power_domain_mask and tpmi_cpu_hash */ static DEFINE_MUTEX(tpmi_lock); @@ -151,6 +153,15 @@ cpumask_t *tpmi_get_power_domain_mask(int cpu_no) } EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, INTEL_TPMI_POWER_DOMAIN); +int tpmi_get_linux_die_id(int pkg_id, int domain_id) +{ + if (pkg_id >= topology_max_packages() || domain_id >= MAX_POWER_DOMAINS) + return -EINVAL; + + return domain_die_map[pkg_id * MAX_POWER_DOMAINS + domain_id]; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_die_id, INTEL_TPMI_POWER_DOMAIN); + static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) { u64 data; @@ -188,6 +199,9 @@ static int tpmi_cpu_online(unsigned int cpu) cpumask_set_cpu(cpu, &tpmi_power_domain_mask[index]); hash_add(tpmi_cpu_hash, &info->hnode, info->punit_core_id); + domain_die_map[info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id] = + topology_die_id(cpu); + return 0; } @@ -211,17 +225,28 @@ static int __init tpmi_init(void) if (!tpmi_power_domain_mask) return -ENOMEM; + domain_die_map = kcalloc(size_mul(topology_max_packages(), MAX_POWER_DOMAINS), + sizeof(*domain_die_map), GFP_KERNEL); + if (!domain_die_map) + goto free_domain_mask; + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "platform/x86/tpmi_power_domains:online", tpmi_cpu_online, NULL); - if (ret < 0) { - kfree(tpmi_power_domain_mask); - return ret; - } + if (ret < 0) + goto free_domain_map; tpmi_hp_state = ret; return 0; + +free_domain_map: + kfree(domain_die_map); + +free_domain_mask: + kfree(tpmi_power_domain_mask); + + return ret; } module_init(tpmi_init) @@ -229,6 +254,7 @@ static void __exit tpmi_exit(void) { cpuhp_remove_state(tpmi_hp_state); kfree(tpmi_power_domain_mask); + kfree(domain_die_map); } module_exit(tpmi_exit) diff --git a/drivers/platform/x86/intel/tpmi_power_domains.h b/drivers/platform/x86/intel/tpmi_power_domains.h index e35750dd92736..2fd0dd7afbd22 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.h +++ b/drivers/platform/x86/intel/tpmi_power_domains.h @@ -14,5 +14,6 @@ int tpmi_get_linux_cpu_number(int package_id, int die_id, int punit_core_id); int tpmi_get_punit_core_number(int cpu_no); int tpmi_get_power_domain_id(int cpu_no); cpumask_t *tpmi_get_power_domain_mask(int cpu_no); +int tpmi_get_linux_die_id(int pkg_id, int domain_id); #endif From b13d2cfe608a5e326b30d10916b90015689fd247 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2025 16:02:41 -0700 Subject: [PATCH 19/25] platform/x86/intel-uncore-freq: Add attributes to show die_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 247b43fcd8722914282fbd432e9cc41cd3971e31 upstream. For domains with agents to control cores (compute dies) show matching Linux CPU die ID. Linux CPU ID is a logical die ID, so this may not match physical die ID or domain_id. So, a mapping is required to get Linux CPU die ID. This attribute is only presented when CPUID enumerates die ids. This attribute can be used by orchestration software like Kubernetes to target specific dies for uncore frequency control. Intel-SIG: commit 247b43fcd872 platform/x86/intel-uncore-freq: Add attributes to show die_id Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20250508230250.1186619-5-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: resolve conflict (use old x86 Macro) and amend commit log ] Signed-off-by: Zhang Rui --- .../uncore-frequency-common.c | 7 +++++ .../uncore-frequency-common.h | 4 ++- .../uncore-frequency/uncore-frequency-tpmi.c | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c index d2612843a145b..5e8a504099dad 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -143,6 +143,8 @@ show_uncore_attr(elc_high_threshold_enable, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE); show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ); +show_uncore_attr(die_id, UNCORE_INDEX_DIE_ID); + #define show_uncore_data(member_name) \ static ssize_t show_##member_name(struct kobject *kobj, \ struct kobj_attribute *attr, char *buf)\ @@ -206,6 +208,11 @@ static int create_attr_group(struct uncore_data *data, char *name) init_attribute_ro(agent_types); data->uncore_attrs[index++] = &data->agent_types_kobj_attr.attr; } + if (topology_max_die_per_package() > 1 && + data->agent_type_mask & AGENT_TYPE_CORE) { + init_attribute_ro(die_id); + data->uncore_attrs[index++] = &data->die_id_kobj_attr.attr; + } } data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr; diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h index a638d2e1e83a7..70ae11519837e 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h @@ -88,7 +88,8 @@ struct uncore_data { struct kobj_attribute elc_high_threshold_enable_kobj_attr; struct kobj_attribute elc_floor_freq_khz_kobj_attr; struct kobj_attribute agent_types_kobj_attr; - struct attribute *uncore_attrs[14]; + struct kobj_attribute die_id_kobj_attr; + struct attribute *uncore_attrs[15]; }; #define UNCORE_DOMAIN_ID_INVALID -1 @@ -101,6 +102,7 @@ enum uncore_index { UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, UNCORE_INDEX_EFF_LAT_CTRL_FREQ, + UNCORE_INDEX_DIE_ID, }; int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value, diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 76745fd389e4d..9d649094d255f 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -26,6 +26,7 @@ #include #include +#include "../tpmi_power_domains.h" #include "uncore-frequency-common.h" #define UNCORE_MAJOR_VERSION 0 @@ -49,6 +50,7 @@ struct tpmi_uncore_cluster_info { bool root_domain; bool elc_supported; u8 __iomem *cluster_base; + u16 cdie_id; struct uncore_data uncore_data; struct tpmi_uncore_struct *uncore_root; }; @@ -369,6 +371,9 @@ static void uncore_set_agent_type(struct tpmi_uncore_cluster_info *cluster_info) /* Callback for sysfs read for TPMI uncore values. Called under mutex locks. */ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) { + struct tpmi_uncore_cluster_info *cluster_info; + int ret; + switch (index) { case UNCORE_INDEX_MIN_FREQ: case UNCORE_INDEX_MAX_FREQ: @@ -383,6 +388,16 @@ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncor case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: return read_eff_lat_ctrl(data, value, index); + case UNCORE_INDEX_DIE_ID: + cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data); + ret = tpmi_get_linux_die_id(cluster_info->uncore_data.package_id, + cluster_info->cdie_id); + if (ret < 0) + return ret; + + *value = ret; + return 0; + default: break; } @@ -432,6 +447,16 @@ static void remove_cluster_entries(struct tpmi_uncore_struct *tpmi_uncore) } } +static void set_cdie_id(int domain_id, struct tpmi_uncore_cluster_info *cluster_info, + struct intel_tpmi_plat_info *plat_info) +{ + + cluster_info->cdie_id = domain_id; + + if (plat_info->cdie_mask && cluster_info->uncore_data.agent_type_mask & AGENT_TYPE_CORE) + cluster_info->cdie_id = domain_id + ffs(plat_info->cdie_mask) - 1; +} + #define UNCORE_VERSION_MASK GENMASK_ULL(7, 0) #define UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK GENMASK_ULL(15, 8) #define UNCORE_CLUSTER_OFF_MASK GENMASK_ULL(7, 0) @@ -582,6 +607,8 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ cluster_info->uncore_data.domain_id = i; cluster_info->uncore_data.cluster_id = j; + set_cdie_id(i, cluster_info, plat_info); + cluster_info->uncore_root = tpmi_uncore; if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION) @@ -655,5 +682,6 @@ module_auxiliary_driver(intel_uncore_aux_driver); MODULE_IMPORT_NS(INTEL_TPMI); MODULE_IMPORT_NS(INTEL_UNCORE_FREQUENCY); +MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); MODULE_DESCRIPTION("Intel TPMI UFS Driver"); MODULE_LICENSE("GPL"); From 53f3d9ec8fe9b22cba91529f53f8c7d4c3fec4b7 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2025 16:02:42 -0700 Subject: [PATCH 20/25] Documentation: admin-guide: pm: Add documentation for die_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e636e3f7421b2ff8e706a835f78f071cb0d8e197 upstream. Add documentation to describe die_id attribute. Intel-SIG: commit e636e3f7421b Documentation: admin-guide: pm: Add documentation for die_id Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20250508230250.1186619-6-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- .../admin-guide/pm/intel_uncore_frequency_scaling.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst b/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst index 84554b87eae45..4a36763cd1f3f 100644 --- a/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst +++ b/Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst @@ -91,6 +91,11 @@ Attributes in each directory: ``domain_id`` This attribute is used to get the power domain id of this instance. +``die_id`` + This attribute is used to get the Linux die id of this instance. + This attribute is only present for domains with core agents and + when the CPUID leaf 0x1f presents die ID. + ``fabric_cluster_id`` This attribute is used to get the fabric cluster id of this instance. From 67d45f4eac988582802f8a252c560e12fc007779 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Jun 2025 11:34:55 +0200 Subject: [PATCH 21/25] platform/x86/intel-uncore-freq: avoid non-literal format string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0c44b46f51a17baa7ab67de1464427116e9c4eaa upstream. Using a string variable in place of a format string causes a W=1 build warning: drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c:61:40: error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security] 61 | length += sysfs_emit_at(buf, length, agent_name[agent]); | ^~~~~~~~~~~~~~~~~ Use the safer "%s" format string to print it instead. Intel-SIG: commit 0c44b46f51a1 platform/x86/intel-uncore-freq: avoid non-literal format string Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Fixes: b98fa870fce2 ("platform/x86/intel-uncore-freq: Add attributes to show agent types") Signed-off-by: Arnd Bergmann Tested-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250610093459.2646337-1-arnd@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- .../x86/intel/uncore-frequency/uncore-frequency-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c index 5e8a504099dad..577da9867b213 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -58,7 +58,7 @@ static ssize_t show_agent_types(struct kobject *kobj, struct kobj_attribute *att if (length) length += sysfs_emit_at(buf, length, " "); - length += sysfs_emit_at(buf, length, agent_name[agent]); + length += sysfs_emit_at(buf, length, "%s", agent_name[agent]); } length += sysfs_emit_at(buf, length, "\n"); From 3c83ce359a1cf984575ca1bce458d39e7e319a8c Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 19 Aug 2025 14:10:34 -0700 Subject: [PATCH 22/25] platform/x86/intel-uncore-freq: Fix warning in partitioned system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6d47b4f08436cb682fb2644e6265a3897fd42a77 upstream. A partitioned system configured with only one package and one compute die, warning will be generated for duplicate sysfs entry. This typically occurs during the platform bring-up phase. Partitioned systems expose dies, equivalent to TPMI compute domains, through the CPUID. Each partitioned system must contains at least one compute die per partition, resulting in a minimum of two dies per package. Hence the function topology_max_dies_per_package() returns at least two, and the condition "topology_max_dies_per_package() > 1" prevents the creation of a root domain. In this case topology_max_dies_per_package() will return 1 and root domain will be created for partition 0 and a duplicate sysfs warning for partition 1 as both partitions have same package ID. To address this also check for non zero partition in addition to topology_max_dies_per_package() > 1. Intel-SIG: commit 6d47b4f08436 platform/x86/intel-uncore-freq: Fix warning in partitioned system Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250819211034.3776284-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen [ Zhang Rui: resolve conflict (use old topo Macro) and amend commit log ] Signed-off-by: Zhang Rui --- .../platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 9d649094d255f..cad562d289e48 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -632,7 +632,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ auxiliary_set_drvdata(auxdev, tpmi_uncore); - if (topology_max_die_per_package() > 1) + if (topology_max_die_per_package() > 1 || plat_info->partition) return 0; tpmi_uncore->root_cluster.root_domain = true; From 185c78474ed95523996ed6e747801c7124e1e287 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 3 Sep 2025 12:11:54 -0700 Subject: [PATCH 23/25] platform/x86/intel-uncore-freq: Present unique domain ID per package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a191224186ec16a4cb1775b2a647ea91f5c139e1 upstream. In partitioned systems, the domain ID is unique in the partition and a package can have multiple partitions. Some user-space tools, such as turbostat, assume the domain ID is unique per package. These tools map CPU power domains, which are unique to a package. However, this approach does not work in partitioned systems. There is no architectural definition of "partition" to present to user space. To support these tools, set the domain_id to be unique per package. For compute die IDs, uniqueness can be achieved using the platform info cdie_mask, mirroring the behavior observed in non-partitioned systems. For IO dies, which lack a direct CPU relationship, any unique logical ID can be assigned. Here domain IDs for IO dies are configured after all compute domain IDs. During the probe, keep the index of the next IO domain ID after the last IO domain ID of the current partition. Since CPU packages are symmetric, partition information is same for all packages. The Intel Speed Select driver has already implemented a similar change to make the domain ID unique, with compute dies listed first, followed by I/O dies. Intel-SIG: commit a191224186ec platform/x86/intel-uncore-freq: Present unique domain ID per package Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250903191154.1081159-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: resolve conflict (use old topo Macro) and amend commit log ] Signed-off-by: Zhang Rui --- .../uncore-frequency/uncore-frequency-tpmi.c | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index cad562d289e48..b03dbf5695b0f 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -368,6 +368,77 @@ static void uncore_set_agent_type(struct tpmi_uncore_cluster_info *cluster_info) cluster_info->uncore_data.agent_type_mask = FIELD_GET(UNCORE_AGENT_TYPES, status); } +#define MAX_PARTITIONS 2 + +/* IO domain ID start index for a partition */ +static u8 io_die_start[MAX_PARTITIONS]; + +/* Next IO domain ID index after the current partition IO die IDs */ +static u8 io_die_index_next; + +/* Lock to protect io_die_start, io_die_index_next */ +static DEFINE_MUTEX(domain_lock); + +static void set_domain_id(int id, int num_resources, + struct intel_tpmi_plat_info *plat_info, + struct tpmi_uncore_cluster_info *cluster_info) +{ + u8 part_io_index, cdie_range, pkg_io_index, max_dies; + + if (plat_info->partition >= MAX_PARTITIONS) { + cluster_info->uncore_data.domain_id = id; + return; + } + + if (cluster_info->uncore_data.agent_type_mask & AGENT_TYPE_CORE) { + cluster_info->uncore_data.domain_id = cluster_info->cdie_id; + return; + } + + /* Unlikely but cdie_mask may have holes, so take range */ + cdie_range = fls(plat_info->cdie_mask) - ffs(plat_info->cdie_mask) + 1; + max_dies = topology_max_die_per_package(); + + /* + * If the CPU doesn't enumerate dies, then use current cdie range + * as the max. + */ + if (cdie_range > max_dies) + max_dies = cdie_range; + + guard(mutex)(&domain_lock); + + if (!io_die_index_next) + io_die_index_next = max_dies; + + if (!io_die_start[plat_info->partition]) { + io_die_start[plat_info->partition] = io_die_index_next; + /* + * number of IO dies = num_resources - cdie_range. Hence + * next partition io_die_index_next is set after IO dies + * in the current partition. + */ + io_die_index_next += (num_resources - cdie_range); + } + + /* + * Index from IO die start within the partition: + * This is the first valid domain after the cdies. + * For example the current resource index 5 and cdies end at + * index 3 (cdie_cnt = 4). Then the IO only index 5 - 4 = 1. + */ + part_io_index = id - cdie_range; + + /* + * Add to the IO die start index for this partition in this package + * to make unique in the package. + */ + pkg_io_index = io_die_start[plat_info->partition] + part_io_index; + + /* Assign this to domain ID */ + cluster_info->uncore_data.domain_id = pkg_io_index; +} + /* Callback for sysfs read for TPMI uncore values. Called under mutex locks. */ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) { @@ -604,11 +675,12 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ cluster_info->uncore_data.package_id = pkg; /* There are no dies like Cascade Lake */ cluster_info->uncore_data.die_id = 0; - cluster_info->uncore_data.domain_id = i; cluster_info->uncore_data.cluster_id = j; set_cdie_id(i, cluster_info, plat_info); + set_domain_id(i, num_resources, plat_info, cluster_info); + cluster_info->uncore_root = tpmi_uncore; if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION) From 48c433fcd111000baa0b5f419d83322a0a8bc248 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Jun 2025 12:04:32 +0300 Subject: [PATCH 24/25] platform/x86/intel: power-domains: Fix error code in tpmi_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1d0a61940e22e165e6acc4a9c6fb26edbe69112e upstream. Return -ENOMEM instead of success if kcalloc() fails. Intel-SIG: commit 1d0a61940e22 platform/x86/intel: power-domains: Fix error code in tpmi_init() Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Fixes: e37be5d85c60 ("platform/x86/intel: power-domains: Add interface to get Linux die ID") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/aEKvIGCt6d8Gcx4S@stanley.mountain Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- drivers/platform/x86/intel/tpmi_power_domains.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c index 68f160cfe2ccc..1fc15a58657fd 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.c +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -227,8 +227,10 @@ static int __init tpmi_init(void) domain_die_map = kcalloc(size_mul(topology_max_packages(), MAX_POWER_DOMAINS), sizeof(*domain_die_map), GFP_KERNEL); - if (!domain_die_map) + if (!domain_die_map) { + ret = -ENOMEM; goto free_domain_mask; + } ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "platform/x86/tpmi_power_domains:online", From 70aba115afa3db1584fd79c38148cce29ef2b66f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 10 Nov 2025 22:09:34 -0800 Subject: [PATCH 25/25] platform/x86: intel-uncore-freq: fix all header kernel-doc warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit db30233361f94e1a84450c607989bdb671100fb6 upstream. In file uncore-frequency/uncore-frequency-common.h, correct all kernel-doc warnings by adding missing leading " *" to some lines, adding a missing kernel-doc entry, and fixing a name typo. Warning: uncore-frequency-common.h:50 bad line: Storage for kobject attribute elc_low_threshold_percent Warning: uncore-frequency-common.h:52 bad line: Storage for kobject attribute elc_high_threshold_percent Warning: uncore-frequency-common.h:54 bad line: Storage for kobject attribute elc_high_threshold_enable Warning: uncore-frequency-common.h:92 struct member 'min_freq_khz_kobj_attr' not described in 'uncore_data' Warning: uncore-frequency-common.h:92 struct member 'die_id_kobj_attr' not described in 'uncore_data' Intel-SIG: commit db30233361f9 platform/x86: intel-uncore-freq: fix all header kernel-doc warnings Backport uncore freq driver fixes and support for agent_types and die_id sysfs attributes Fixes: 24b6616355f7 ("platform/x86/intel-uncore-freq: Add efficiency latency control to sysfs interface") Fixes: 416de0246f35 ("platform/x86: intel-uncore-freq: Fix types in sysfs callbacks") Fixes: 247b43fcd872 ("platform/x86/intel-uncore-freq: Add attributes to show die_id") Signed-off-by: Randy Dunlap Link: https://patch.msgid.link/20251111060938.1998542-1-rdunlap@infradead.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen [ Zhang Rui: amend commit log ] Signed-off-by: Zhang Rui --- .../x86/intel/uncore-frequency/uncore-frequency-common.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h index 70ae11519837e..0abe850ef54ea 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h @@ -40,7 +40,7 @@ * @agent_type_mask: Bit mask of all hardware agents for this domain * @uncore_attr_group: Attribute group storage * @max_freq_khz_kobj_attr: Storage for kobject attribute max_freq_khz - * @mix_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz + * @min_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz * @initial_max_freq_khz_kobj_attr: Storage for kobject attribute initial_max_freq_khz * @initial_min_freq_khz_kobj_attr: Storage for kobject attribute initial_min_freq_khz * @current_freq_khz_kobj_attr: Storage for kobject attribute current_freq_khz @@ -48,13 +48,14 @@ * @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id * @package_id_kobj_attr: Storage for kobject attribute package_id * @elc_low_threshold_percent_kobj_attr: - Storage for kobject attribute elc_low_threshold_percent + * Storage for kobject attribute elc_low_threshold_percent * @elc_high_threshold_percent_kobj_attr: - Storage for kobject attribute elc_high_threshold_percent + * Storage for kobject attribute elc_high_threshold_percent * @elc_high_threshold_enable_kobj_attr: - Storage for kobject attribute elc_high_threshold_enable + * Storage for kobject attribute elc_high_threshold_enable * @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz * @agent_types_kobj_attr: Storage for kobject attribute agent_type + * @die_id_kobj_attr: Attribute storage for die_id information * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs