diff options
-rw-r--r-- | drivers/platform/x86/amd/hfi/hfi.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/platform/x86/amd/hfi/hfi.c b/drivers/platform/x86/amd/hfi/hfi.c index b10bd96c5920..28ef7212d339 100644 --- a/drivers/platform/x86/amd/hfi/hfi.c +++ b/drivers/platform/x86/amd/hfi/hfi.c @@ -92,6 +92,7 @@ struct amd_hfi_classes { * struct amd_hfi_cpuinfo - HFI workload class info per CPU * @cpu: CPU index * @apic_id: APIC id of the current CPU + * @cpus: mask of CPUs associated with amd_hfi_cpuinfo * @class_index: workload class ID index * @nr_class: max number of workload class supported * @ipcc_scores: ipcc scores for each class @@ -102,6 +103,7 @@ struct amd_hfi_classes { struct amd_hfi_cpuinfo { int cpu; u32 apic_id; + cpumask_var_t cpus; s16 class_index; u8 nr_class; int *ipcc_scores; @@ -110,6 +112,8 @@ struct amd_hfi_cpuinfo { static DEFINE_PER_CPU(struct amd_hfi_cpuinfo, amd_hfi_cpuinfo) = {.class_index = -1}; +static DEFINE_MUTEX(hfi_cpuinfo_lock); + static int find_cpu_index_by_apicid(unsigned int target_apicid) { int cpu_index; @@ -237,6 +241,81 @@ static int amd_set_hfi_ipcc_score(struct amd_hfi_cpuinfo *hfi_cpuinfo, int cpu) return 0; } +static int amd_hfi_set_state(unsigned int cpu, bool state) +{ + int ret; + + ret = wrmsrq_on_cpu(cpu, MSR_AMD_WORKLOAD_CLASS_CONFIG, state ? 1 : 0); + if (ret) + return ret; + + return wrmsrq_on_cpu(cpu, MSR_AMD_WORKLOAD_HRST, 0x1); +} + +/** + * amd_hfi_online() - Enable workload classification on @cpu + * @cpu: CPU in which the workload classification will be enabled + * + * Return: 0 on success, negative error code on failure. + */ +static int amd_hfi_online(unsigned int cpu) +{ + struct amd_hfi_cpuinfo *hfi_info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu); + struct amd_hfi_classes *hfi_classes; + int ret; + + if (WARN_ON_ONCE(!hfi_info)) + return -EINVAL; + + /* + * Check if @cpu as an associated, initialized and ranking data must + * be filled. + */ + hfi_classes = hfi_info->amd_hfi_classes; + if (!hfi_classes) + return -EINVAL; + + guard(mutex)(&hfi_cpuinfo_lock); + + if (!zalloc_cpumask_var(&hfi_info->cpus, GFP_KERNEL)) + return -ENOMEM; + + cpumask_set_cpu(cpu, hfi_info->cpus); + + ret = amd_hfi_set_state(cpu, true); + if (ret) + pr_err("WCT enable failed for CPU %u\n", cpu); + + return ret; +} + +/** + * amd_hfi_offline() - Disable workload classification on @cpu + * @cpu: CPU in which the workload classification will be disabled + * + * Remove @cpu from those covered by its HFI instance. + * + * Return: 0 on success, negative error code on failure + */ +static int amd_hfi_offline(unsigned int cpu) +{ + struct amd_hfi_cpuinfo *hfi_info = &per_cpu(amd_hfi_cpuinfo, cpu); + int ret; + + if (WARN_ON_ONCE(!hfi_info)) + return -EINVAL; + + guard(mutex)(&hfi_cpuinfo_lock); + + ret = amd_hfi_set_state(cpu, false); + if (ret) + pr_err("WCT disable failed for CPU %u\n", cpu); + + free_cpumask_var(hfi_info->cpus); + + return ret; +} + static int update_hfi_ipcc_scores(void) { int cpu; @@ -339,6 +418,15 @@ static int amd_hfi_probe(struct platform_device *pdev) if (ret) return ret; + /* + * Tasks will already be running at the time this happens. This is + * OK because rankings will be adjusted by the callbacks. + */ + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/amd_hfi:online", + amd_hfi_online, amd_hfi_offline); + if (ret < 0) + return ret; + return 0; } |