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

amd.c (5828B)


      1// SPDX-License-Identifier: GPL-2.0
      2#if defined(__i386__) || defined(__x86_64__)
      3#include <unistd.h>
      4#include <errno.h>
      5#include <stdio.h>
      6#include <stdint.h>
      7
      8#include <pci/pci.h>
      9
     10#include "helpers/helpers.h"
     11#include "cpufreq.h"
     12#include "acpi_cppc.h"
     13
     14/* ACPI P-States Helper Functions for AMD Processors ***************/
     15#define MSR_AMD_PSTATE_STATUS	0xc0010063
     16#define MSR_AMD_PSTATE		0xc0010064
     17#define MSR_AMD_PSTATE_LIMIT	0xc0010061
     18
     19union core_pstate {
     20	/* pre fam 17h: */
     21	struct {
     22		unsigned fid:6;
     23		unsigned did:3;
     24		unsigned vid:7;
     25		unsigned res1:6;
     26		unsigned nbdid:1;
     27		unsigned res2:2;
     28		unsigned nbvid:7;
     29		unsigned iddval:8;
     30		unsigned idddiv:2;
     31		unsigned res3:21;
     32		unsigned en:1;
     33	} pstate;
     34	/* since fam 17h: */
     35	struct {
     36		unsigned fid:8;
     37		unsigned did:6;
     38		unsigned vid:8;
     39		unsigned iddval:8;
     40		unsigned idddiv:2;
     41		unsigned res1:31;
     42		unsigned en:1;
     43	} pstatedef;
     44	unsigned long long val;
     45};
     46
     47static int get_did(union core_pstate pstate)
     48{
     49	int t;
     50
     51	if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATEDEF)
     52		t = pstate.pstatedef.did;
     53	else if (cpupower_cpu_info.family == 0x12)
     54		t = pstate.val & 0xf;
     55	else
     56		t = pstate.pstate.did;
     57
     58	return t;
     59}
     60
     61static int get_cof(union core_pstate pstate)
     62{
     63	int t;
     64	int fid, did, cof;
     65
     66	did = get_did(pstate);
     67	if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATEDEF) {
     68		fid = pstate.pstatedef.fid;
     69		cof = 200 * fid / did;
     70	} else {
     71		t = 0x10;
     72		fid = pstate.pstate.fid;
     73		if (cpupower_cpu_info.family == 0x11)
     74			t = 0x8;
     75		cof = (100 * (fid + t)) >> did;
     76	}
     77	return cof;
     78}
     79
     80/* Needs:
     81 * cpu          -> the cpu that gets evaluated
     82 * boost_states -> how much boost states the machines support
     83 *
     84 * Fills up:
     85 * pstates -> a pointer to an array of size MAX_HW_PSTATES
     86 *            must be initialized with zeros.
     87 *            All available  HW pstates (including boost states)
     88 * no      -> amount of pstates above array got filled up with
     89 *
     90 * returns zero on success, -1 on failure
     91 */
     92int decode_pstates(unsigned int cpu, int boost_states,
     93		   unsigned long *pstates, int *no)
     94{
     95	int i, psmax;
     96	union core_pstate pstate;
     97	unsigned long long val;
     98
     99	/* Only read out frequencies from HW if HW Pstate is supported,
    100	 * otherwise frequencies are exported via ACPI tables.
    101	 */
    102	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_HW_PSTATE))
    103		return -1;
    104
    105	if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
    106		return -1;
    107
    108	psmax = (val >> 4) & 0x7;
    109	psmax += boost_states;
    110	for (i = 0; i <= psmax; i++) {
    111		if (i >= MAX_HW_PSTATES) {
    112			fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
    113				psmax, MAX_HW_PSTATES);
    114			return -1;
    115		}
    116		if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
    117			return -1;
    118
    119		/* The enabled bit (bit 63) is common for all families */
    120		if (!pstate.pstatedef.en)
    121			continue;
    122
    123		pstates[i] = get_cof(pstate);
    124	}
    125	*no = i;
    126	return 0;
    127}
    128
    129int amd_pci_get_num_boost_states(int *active, int *states)
    130{
    131	struct pci_access *pci_acc;
    132	struct pci_dev *device;
    133	uint8_t val = 0;
    134
    135	*active = *states = 0;
    136
    137	device = pci_slot_func_init(&pci_acc, 0x18, 4);
    138
    139	if (device == NULL)
    140		return -ENODEV;
    141
    142	val = pci_read_byte(device, 0x15c);
    143	if (val & 3)
    144		*active = 1;
    145	else
    146		*active = 0;
    147	*states = (val >> 2) & 7;
    148
    149	pci_cleanup(pci_acc);
    150	return 0;
    151}
    152
    153/* ACPI P-States Helper Functions for AMD Processors ***************/
    154
    155/* AMD P-State Helper Functions ************************************/
    156enum amd_pstate_value {
    157	AMD_PSTATE_HIGHEST_PERF,
    158	AMD_PSTATE_MAX_FREQ,
    159	AMD_PSTATE_LOWEST_NONLINEAR_FREQ,
    160	MAX_AMD_PSTATE_VALUE_READ_FILES,
    161};
    162
    163static const char *amd_pstate_value_files[MAX_AMD_PSTATE_VALUE_READ_FILES] = {
    164	[AMD_PSTATE_HIGHEST_PERF] = "amd_pstate_highest_perf",
    165	[AMD_PSTATE_MAX_FREQ] = "amd_pstate_max_freq",
    166	[AMD_PSTATE_LOWEST_NONLINEAR_FREQ] = "amd_pstate_lowest_nonlinear_freq",
    167};
    168
    169static unsigned long amd_pstate_get_data(unsigned int cpu,
    170					 enum amd_pstate_value value)
    171{
    172	return cpufreq_get_sysfs_value_from_table(cpu,
    173						  amd_pstate_value_files,
    174						  value,
    175						  MAX_AMD_PSTATE_VALUE_READ_FILES);
    176}
    177
    178void amd_pstate_boost_init(unsigned int cpu, int *support, int *active)
    179{
    180	unsigned long highest_perf, nominal_perf, cpuinfo_min,
    181		      cpuinfo_max, amd_pstate_max;
    182
    183	highest_perf = amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF);
    184	nominal_perf = acpi_cppc_get_data(cpu, NOMINAL_PERF);
    185
    186	*support = highest_perf > nominal_perf ? 1 : 0;
    187	if (!(*support))
    188		return;
    189
    190	cpufreq_get_hardware_limits(cpu, &cpuinfo_min, &cpuinfo_max);
    191	amd_pstate_max = amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ);
    192
    193	*active = cpuinfo_max == amd_pstate_max ? 1 : 0;
    194}
    195
    196void amd_pstate_show_perf_and_freq(unsigned int cpu, int no_rounding)
    197{
    198	printf(_("    AMD PSTATE Highest Performance: %lu. Maximum Frequency: "),
    199	       amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF));
    200	/*
    201	 * If boost isn't active, the cpuinfo_max doesn't indicate real max
    202	 * frequency. So we read it back from amd-pstate sysfs entry.
    203	 */
    204	print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ), no_rounding);
    205	printf(".\n");
    206
    207	printf(_("    AMD PSTATE Nominal Performance: %lu. Nominal Frequency: "),
    208	       acpi_cppc_get_data(cpu, NOMINAL_PERF));
    209	print_speed(acpi_cppc_get_data(cpu, NOMINAL_FREQ) * 1000,
    210		    no_rounding);
    211	printf(".\n");
    212
    213	printf(_("    AMD PSTATE Lowest Non-linear Performance: %lu. Lowest Non-linear Frequency: "),
    214	       acpi_cppc_get_data(cpu, LOWEST_NONLINEAR_PERF));
    215	print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_LOWEST_NONLINEAR_FREQ),
    216		    no_rounding);
    217	printf(".\n");
    218
    219	printf(_("    AMD PSTATE Lowest Performance: %lu. Lowest Frequency: "),
    220	       acpi_cppc_get_data(cpu, LOWEST_PERF));
    221	print_speed(acpi_cppc_get_data(cpu, LOWEST_FREQ) * 1000, no_rounding);
    222	printf(".\n");
    223}
    224
    225/* AMD P-State Helper Functions ************************************/
    226#endif /* defined(__i386__) || defined(__x86_64__) */