brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 0609a83 Raw
237 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Mapping of TPMI power domains CPU mapping4 *5 * Copyright (c) 2024, Intel Corporation.6 */7 8#include <linux/bitfield.h>9#include <linux/cleanup.h>10#include <linux/cpuhotplug.h>11#include <linux/cpumask.h>12#include <linux/errno.h>13#include <linux/export.h>14#include <linux/hashtable.h>15#include <linux/module.h>16#include <linux/mutex.h>17#include <linux/overflow.h>18#include <linux/slab.h>19#include <linux/topology.h>20#include <linux/types.h>21 22#include <asm/cpu_device_id.h>23#include <asm/intel-family.h>24#include <asm/msr.h>25 26#include "tpmi_power_domains.h"27 28#define MSR_PM_LOGICAL_ID       0x5429 30/*31 * Struct of MSR 0x5432 * [15:11] PM_DOMAIN_ID33 * [10:3] MODULE_ID (aka IDI_AGENT_ID)34 * [2:0] LP_ID35 * For Atom:36 *   [2] Always 037 *   [1:0] core ID within module38 * For Core39 *   [2:1] Always 040 *   [0] thread ID41 */42 43#define LP_ID_MASK		GENMASK_ULL(2, 0)44#define MODULE_ID_MASK		GENMASK_ULL(10, 3)45#define PM_DOMAIN_ID_MASK	GENMASK_ULL(15, 11)46 47/**48 * struct tpmi_cpu_info - Mapping information for a CPU49 * @hnode: Used to add mapping information to hash list50 * @linux_cpu:	Linux CPU number51 * @pkg_id: Package ID of this CPU52 * @punit_thread_id: Punit thread id of this CPU53 * @punit_core_id: Punit core id54 * @punit_domain_id: Power domain id from Punit55 *56 * Structure to store mapping information for a Linux CPU57 * to a Punit core, thread and power domain.58 */59struct tpmi_cpu_info {60	struct hlist_node hnode;61	int linux_cpu;62	u8 pkg_id;63	u8 punit_thread_id;64	u8 punit_core_id;65	u8 punit_domain_id;66};67 68static DEFINE_PER_CPU(struct tpmi_cpu_info, tpmi_cpu_info);69 70/* The dynamically assigned cpu hotplug state to free later */71static enum cpuhp_state tpmi_hp_state __read_mostly;72 73#define MAX_POWER_DOMAINS	874 75static cpumask_t *tpmi_power_domain_mask;76 77/* Lock to protect tpmi_power_domain_mask and tpmi_cpu_hash */78static DEFINE_MUTEX(tpmi_lock);79 80static const struct x86_cpu_id tpmi_cpu_ids[] = {81	X86_MATCH_VFM(INTEL_GRANITERAPIDS_X,	NULL),82	X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X,	NULL),83	X86_MATCH_VFM(INTEL_ATOM_CRESTMONT,	NULL),84	X86_MATCH_VFM(INTEL_GRANITERAPIDS_D,	NULL),85	X86_MATCH_VFM(INTEL_PANTHERCOVE_X,	NULL),86	{}87};88MODULE_DEVICE_TABLE(x86cpu, tpmi_cpu_ids);89 90static DECLARE_HASHTABLE(tpmi_cpu_hash, 8);91 92static bool tpmi_domain_is_valid(struct tpmi_cpu_info *info)93{94	return info->pkg_id < topology_max_packages() &&95		info->punit_domain_id < MAX_POWER_DOMAINS;96}97 98int tpmi_get_linux_cpu_number(int package_id, int domain_id, int punit_core_id)99{100	struct tpmi_cpu_info *info;101	int ret = -EINVAL;102 103	guard(mutex)(&tpmi_lock);104	hash_for_each_possible(tpmi_cpu_hash, info, hnode, punit_core_id) {105		if (info->punit_domain_id == domain_id && info->pkg_id == package_id) {106			ret = info->linux_cpu;107			break;108		}109	}110 111	return ret;112}113EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_cpu_number, INTEL_TPMI_POWER_DOMAIN);114 115int tpmi_get_punit_core_number(int cpu_no)116{117	if (cpu_no >= num_possible_cpus())118		return -EINVAL;119 120	return per_cpu(tpmi_cpu_info, cpu_no).punit_core_id;121}122EXPORT_SYMBOL_NS_GPL(tpmi_get_punit_core_number, INTEL_TPMI_POWER_DOMAIN);123 124int tpmi_get_power_domain_id(int cpu_no)125{126	if (cpu_no >= num_possible_cpus())127		return -EINVAL;128 129	return per_cpu(tpmi_cpu_info, cpu_no).punit_domain_id;130}131EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_id, INTEL_TPMI_POWER_DOMAIN);132 133cpumask_t *tpmi_get_power_domain_mask(int cpu_no)134{135	struct tpmi_cpu_info *info;136	cpumask_t *mask;137	int index;138 139	if (cpu_no >= num_possible_cpus())140		return NULL;141 142	info = &per_cpu(tpmi_cpu_info, cpu_no);143	if (!tpmi_domain_is_valid(info))144		return NULL;145 146	index = info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id;147	guard(mutex)(&tpmi_lock);148	mask = &tpmi_power_domain_mask[index];149 150	return mask;151}152EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, INTEL_TPMI_POWER_DOMAIN);153 154static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info)155{156	u64 data;157	int ret;158 159	ret = rdmsrl_safe(MSR_PM_LOGICAL_ID, &data);160	if (ret)161		return ret;162 163	info->punit_domain_id = FIELD_GET(PM_DOMAIN_ID_MASK, data);164	if (info->punit_domain_id >= MAX_POWER_DOMAINS)165		return -EINVAL;166 167	info->punit_thread_id = FIELD_GET(LP_ID_MASK, data);168	info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data);169	info->pkg_id = topology_physical_package_id(cpu);170	info->linux_cpu = cpu;171 172	return 0;173}174 175static int tpmi_cpu_online(unsigned int cpu)176{177	struct tpmi_cpu_info *info = &per_cpu(tpmi_cpu_info, cpu);178	int ret, index;179 180	/* Don't fail CPU online for some bad mapping of CPUs */181	ret = tpmi_get_logical_id(cpu, info);182	if (ret)183		return 0;184 185	index = info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id;186 187	guard(mutex)(&tpmi_lock);188	cpumask_set_cpu(cpu, &tpmi_power_domain_mask[index]);189	hash_add(tpmi_cpu_hash, &info->hnode, info->punit_core_id);190 191	return 0;192}193 194static int __init tpmi_init(void)195{196	const struct x86_cpu_id *id;197	u64 data;198	int ret;199 200	id = x86_match_cpu(tpmi_cpu_ids);201	if (!id)202		return -ENODEV;203 204	/* Check for MSR 0x54 presence */205	ret = rdmsrl_safe(MSR_PM_LOGICAL_ID, &data);206	if (ret)207		return ret;208 209	tpmi_power_domain_mask = kcalloc(size_mul(topology_max_packages(), MAX_POWER_DOMAINS),210					 sizeof(*tpmi_power_domain_mask), GFP_KERNEL);211	if (!tpmi_power_domain_mask)212		return -ENOMEM;213 214	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,215				"platform/x86/tpmi_power_domains:online",216				tpmi_cpu_online, NULL);217	if (ret < 0) {218		kfree(tpmi_power_domain_mask);219		return ret;220	}221 222	tpmi_hp_state = ret;223 224	return 0;225}226module_init(tpmi_init)227 228static void __exit tpmi_exit(void)229{230	cpuhp_remove_state(tpmi_hp_state);231	kfree(tpmi_power_domain_mask);232}233module_exit(tpmi_exit)234 235MODULE_DESCRIPTION("TPMI Power Domains Mapping");236MODULE_LICENSE("GPL");237