xref: /linux/tools/power/cpupower/utils/helpers/amd.c (revision a4eb44a6435d6d8f9e642407a4a06f65eb90ca04)
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 
12 #define MSR_AMD_PSTATE_STATUS	0xc0010063
13 #define MSR_AMD_PSTATE		0xc0010064
14 #define MSR_AMD_PSTATE_LIMIT	0xc0010061
15 
16 union core_pstate {
17 	/* pre fam 17h: */
18 	struct {
19 		unsigned fid:6;
20 		unsigned did:3;
21 		unsigned vid:7;
22 		unsigned res1:6;
23 		unsigned nbdid:1;
24 		unsigned res2:2;
25 		unsigned nbvid:7;
26 		unsigned iddval:8;
27 		unsigned idddiv:2;
28 		unsigned res3:21;
29 		unsigned en:1;
30 	} pstate;
31 	/* since fam 17h: */
32 	struct {
33 		unsigned fid:8;
34 		unsigned did:6;
35 		unsigned vid:8;
36 		unsigned iddval:8;
37 		unsigned idddiv:2;
38 		unsigned res1:31;
39 		unsigned en:1;
40 	} pstatedef;
41 	unsigned long long val;
42 };
43 
44 static int get_did(union core_pstate pstate)
45 {
46 	int t;
47 
48 	if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATEDEF)
49 		t = pstate.pstatedef.did;
50 	else if (cpupower_cpu_info.family == 0x12)
51 		t = pstate.val & 0xf;
52 	else
53 		t = pstate.pstate.did;
54 
55 	return t;
56 }
57 
58 static int get_cof(union core_pstate pstate)
59 {
60 	int t;
61 	int fid, did, cof;
62 
63 	did = get_did(pstate);
64 	if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATEDEF) {
65 		fid = pstate.pstatedef.fid;
66 		cof = 200 * fid / did;
67 	} else {
68 		t = 0x10;
69 		fid = pstate.pstate.fid;
70 		if (cpupower_cpu_info.family == 0x11)
71 			t = 0x8;
72 		cof = (100 * (fid + t)) >> did;
73 	}
74 	return cof;
75 }
76 
77 /* Needs:
78  * cpu          -> the cpu that gets evaluated
79  * boost_states -> how much boost states the machines support
80  *
81  * Fills up:
82  * pstates -> a pointer to an array of size MAX_HW_PSTATES
83  *            must be initialized with zeros.
84  *            All available  HW pstates (including boost states)
85  * no      -> amount of pstates above array got filled up with
86  *
87  * returns zero on success, -1 on failure
88  */
89 int decode_pstates(unsigned int cpu, int boost_states,
90 		   unsigned long *pstates, int *no)
91 {
92 	int i, psmax;
93 	union core_pstate pstate;
94 	unsigned long long val;
95 
96 	/* Only read out frequencies from HW if HW Pstate is supported,
97 	 * otherwise frequencies are exported via ACPI tables.
98 	 */
99 	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_HW_PSTATE))
100 		return -1;
101 
102 	if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
103 		return -1;
104 
105 	psmax = (val >> 4) & 0x7;
106 	psmax += boost_states;
107 	for (i = 0; i <= psmax; i++) {
108 		if (i >= MAX_HW_PSTATES) {
109 			fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
110 				psmax, MAX_HW_PSTATES);
111 			return -1;
112 		}
113 		if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
114 			return -1;
115 
116 		/* The enabled bit (bit 63) is common for all families */
117 		if (!pstate.pstatedef.en)
118 			continue;
119 
120 		pstates[i] = get_cof(pstate);
121 	}
122 	*no = i;
123 	return 0;
124 }
125 
126 int amd_pci_get_num_boost_states(int *active, int *states)
127 {
128 	struct pci_access *pci_acc;
129 	struct pci_dev *device;
130 	uint8_t val = 0;
131 
132 	*active = *states = 0;
133 
134 	device = pci_slot_func_init(&pci_acc, 0x18, 4);
135 
136 	if (device == NULL)
137 		return -ENODEV;
138 
139 	val = pci_read_byte(device, 0x15c);
140 	if (val & 3)
141 		*active = 1;
142 	else
143 		*active = 0;
144 	*states = (val >> 2) & 7;
145 
146 	pci_cleanup(pci_acc);
147 	return 0;
148 }
149 #endif /* defined(__i386__) || defined(__x86_64__) */
150