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
get_did(union core_pstate pstate)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
get_cof(union core_pstate pstate)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 */
decode_pstates(unsigned int cpu,int boost_states,unsigned long * pstates,int * no)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
amd_pci_get_num_boost_states(int * active,int * states)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