diff options
Diffstat (limited to 'tools/power/cpupower/utils/helpers/amd.c')
| -rw-r--r-- | tools/power/cpupower/utils/helpers/amd.c | 135 | 
1 files changed, 135 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c new file mode 100644 index 00000000000..6437ef39aee --- /dev/null +++ b/tools/power/cpupower/utils/helpers/amd.c @@ -0,0 +1,135 @@ +#if defined(__i386__) || defined(__x86_64__) +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdint.h> + +#include <pci/pci.h> + +#include "helpers/helpers.h" + +#define MSR_AMD_PSTATE_STATUS	0xc0010063 +#define MSR_AMD_PSTATE		0xc0010064 +#define MSR_AMD_PSTATE_LIMIT	0xc0010061 + +union msr_pstate { +	struct { +		unsigned fid:6; +		unsigned did:3; +		unsigned vid:7; +		unsigned res1:6; +		unsigned nbdid:1; +		unsigned res2:2; +		unsigned nbvid:7; +		unsigned iddval:8; +		unsigned idddiv:2; +		unsigned res3:21; +		unsigned en:1; +	} bits; +	unsigned long long val; +}; + +static int get_did(int family, union msr_pstate pstate) +{ +	int t; + +	if (family == 0x12) +		t = pstate.val & 0xf; +	else +		t = pstate.bits.did; + +	return t; +} + +static int get_cof(int family, union msr_pstate pstate) +{ +	int t; +	int fid, did; + +	did = get_did(family, pstate); + +	t = 0x10; +	fid = pstate.bits.fid; +	if (family == 0x11) +		t = 0x8; + +	return (100 * (fid + t)) >> did; +} + +/* Needs: + * cpu          -> the cpu that gets evaluated + * cpu_family   -> The cpu's family (0x10, 0x12,...) + * boots_states -> how much boost states the machines support + * + * Fills up: + * pstates -> a pointer to an array of size MAX_HW_PSTATES + *            must be initialized with zeros. + *            All available  HW pstates (including boost states) + * no      -> amount of pstates above array got filled up with + * + * returns zero on success, -1 on failure + */ +int decode_pstates(unsigned int cpu, unsigned int cpu_family, +		   int boost_states, unsigned long *pstates, int *no) +{ +	int i, psmax, pscur; +	union msr_pstate pstate; +	unsigned long long val; + +	/* Only read out frequencies from HW when CPU might be boostable +	   to keep the code as short and clean as possible. +	   Otherwise frequencies are exported via ACPI tables. +	*/ +	if (cpu_family < 0x10 || cpu_family == 0x14) +		return -1; + +	if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val)) +		return -1; + +	psmax = (val >> 4) & 0x7; + +	if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val)) +		return -1; + +	pscur = val & 0x7; + +	pscur += boost_states; +	psmax += boost_states; +	for (i = 0; i <= psmax; i++) { +		if (i >= MAX_HW_PSTATES) { +			fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n", +				psmax, MAX_HW_PSTATES); +			return -1; +		} +		if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val)) +			return -1; +		pstates[i] = get_cof(cpu_family, pstate); +	} +	*no = i; +	return 0; +} + +int amd_pci_get_num_boost_states(int *active, int *states) +{ +	struct pci_access *pci_acc; +	struct pci_dev *device; +	uint8_t val = 0; + +	*active = *states = 0; + +	device = pci_slot_func_init(&pci_acc, 0x18, 4); + +	if (device == NULL) +		return -ENODEV; + +	val = pci_read_byte(device, 0x15c); +	if (val & 3) +		*active = 1; +	else +		*active = 0; +	*states = (val >> 2) & 7; + +	pci_cleanup(pci_acc); +	return 0; +} +#endif /* defined(__i386__) || defined(__x86_64__) */  | 
