cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cppc.c (2397B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * cppc.c: CPPC Interface for x86
      4 * Copyright (c) 2016, Intel Corporation.
      5 */
      6
      7#include <acpi/cppc_acpi.h>
      8#include <asm/msr.h>
      9#include <asm/processor.h>
     10#include <asm/topology.h>
     11
     12/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
     13
     14bool cpc_supported_by_cpu(void)
     15{
     16	switch (boot_cpu_data.x86_vendor) {
     17	case X86_VENDOR_AMD:
     18	case X86_VENDOR_HYGON:
     19		return boot_cpu_has(X86_FEATURE_CPPC);
     20	}
     21	return false;
     22}
     23
     24bool cpc_ffh_supported(void)
     25{
     26	return true;
     27}
     28
     29int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
     30{
     31	int err;
     32
     33	err = rdmsrl_safe_on_cpu(cpunum, reg->address, val);
     34	if (!err) {
     35		u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
     36				       reg->bit_offset);
     37
     38		*val &= mask;
     39		*val >>= reg->bit_offset;
     40	}
     41	return err;
     42}
     43
     44int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
     45{
     46	u64 rd_val;
     47	int err;
     48
     49	err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val);
     50	if (!err) {
     51		u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
     52				       reg->bit_offset);
     53
     54		val <<= reg->bit_offset;
     55		val &= mask;
     56		rd_val &= ~mask;
     57		rd_val |= val;
     58		err = wrmsrl_safe_on_cpu(cpunum, reg->address, rd_val);
     59	}
     60	return err;
     61}
     62
     63static void amd_set_max_freq_ratio(void)
     64{
     65	struct cppc_perf_caps perf_caps;
     66	u64 highest_perf, nominal_perf;
     67	u64 perf_ratio;
     68	int rc;
     69
     70	rc = cppc_get_perf_caps(0, &perf_caps);
     71	if (rc) {
     72		pr_debug("Could not retrieve perf counters (%d)\n", rc);
     73		return;
     74	}
     75
     76	highest_perf = amd_get_highest_perf();
     77	nominal_perf = perf_caps.nominal_perf;
     78
     79	if (!highest_perf || !nominal_perf) {
     80		pr_debug("Could not retrieve highest or nominal performance\n");
     81		return;
     82	}
     83
     84	perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf);
     85	/* midpoint between max_boost and max_P */
     86	perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1;
     87	if (!perf_ratio) {
     88		pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n");
     89		return;
     90	}
     91
     92	freq_invariance_set_perf_ratio(perf_ratio, false);
     93}
     94
     95static DEFINE_MUTEX(freq_invariance_lock);
     96
     97void init_freq_invariance_cppc(void)
     98{
     99	static bool init_done;
    100
    101	if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF))
    102		return;
    103
    104	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
    105		return;
    106
    107	mutex_lock(&freq_invariance_lock);
    108	if (!init_done)
    109		amd_set_max_freq_ratio();
    110	init_done = true;
    111	mutex_unlock(&freq_invariance_lock);
    112}