1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #if defined(__i386__) || defined(__x86_64__)
3*4882a593Smuzhiyun #include <unistd.h>
4*4882a593Smuzhiyun #include <errno.h>
5*4882a593Smuzhiyun #include <stdio.h>
6*4882a593Smuzhiyun #include <stdint.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <pci/pci.h>
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include "helpers/helpers.h"
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define MSR_AMD_PSTATE_STATUS 0xc0010063
13*4882a593Smuzhiyun #define MSR_AMD_PSTATE 0xc0010064
14*4882a593Smuzhiyun #define MSR_AMD_PSTATE_LIMIT 0xc0010061
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun union msr_pstate {
17*4882a593Smuzhiyun struct {
18*4882a593Smuzhiyun unsigned fid:6;
19*4882a593Smuzhiyun unsigned did:3;
20*4882a593Smuzhiyun unsigned vid:7;
21*4882a593Smuzhiyun unsigned res1:6;
22*4882a593Smuzhiyun unsigned nbdid:1;
23*4882a593Smuzhiyun unsigned res2:2;
24*4882a593Smuzhiyun unsigned nbvid:7;
25*4882a593Smuzhiyun unsigned iddval:8;
26*4882a593Smuzhiyun unsigned idddiv:2;
27*4882a593Smuzhiyun unsigned res3:21;
28*4882a593Smuzhiyun unsigned en:1;
29*4882a593Smuzhiyun } bits;
30*4882a593Smuzhiyun struct {
31*4882a593Smuzhiyun unsigned fid:8;
32*4882a593Smuzhiyun unsigned did:6;
33*4882a593Smuzhiyun unsigned vid:8;
34*4882a593Smuzhiyun unsigned iddval:8;
35*4882a593Smuzhiyun unsigned idddiv:2;
36*4882a593Smuzhiyun unsigned res1:31;
37*4882a593Smuzhiyun unsigned en:1;
38*4882a593Smuzhiyun } fam17h_bits;
39*4882a593Smuzhiyun unsigned long long val;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
get_did(int family,union msr_pstate pstate)42*4882a593Smuzhiyun static int get_did(int family, union msr_pstate pstate)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun int t;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun if (family == 0x12)
47*4882a593Smuzhiyun t = pstate.val & 0xf;
48*4882a593Smuzhiyun else if (family == 0x17 || family == 0x18)
49*4882a593Smuzhiyun t = pstate.fam17h_bits.did;
50*4882a593Smuzhiyun else
51*4882a593Smuzhiyun t = pstate.bits.did;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun return t;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
get_cof(int family,union msr_pstate pstate)56*4882a593Smuzhiyun static int get_cof(int family, union msr_pstate pstate)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun int t;
59*4882a593Smuzhiyun int fid, did, cof;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun did = get_did(family, pstate);
62*4882a593Smuzhiyun if (family == 0x17 || family == 0x18) {
63*4882a593Smuzhiyun fid = pstate.fam17h_bits.fid;
64*4882a593Smuzhiyun cof = 200 * fid / did;
65*4882a593Smuzhiyun } else {
66*4882a593Smuzhiyun t = 0x10;
67*4882a593Smuzhiyun fid = pstate.bits.fid;
68*4882a593Smuzhiyun if (family == 0x11)
69*4882a593Smuzhiyun t = 0x8;
70*4882a593Smuzhiyun cof = (100 * (fid + t)) >> did;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun return cof;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Needs:
76*4882a593Smuzhiyun * cpu -> the cpu that gets evaluated
77*4882a593Smuzhiyun * cpu_family -> The cpu's family (0x10, 0x12,...)
78*4882a593Smuzhiyun * boots_states -> how much boost states the machines support
79*4882a593Smuzhiyun *
80*4882a593Smuzhiyun * Fills up:
81*4882a593Smuzhiyun * pstates -> a pointer to an array of size MAX_HW_PSTATES
82*4882a593Smuzhiyun * must be initialized with zeros.
83*4882a593Smuzhiyun * All available HW pstates (including boost states)
84*4882a593Smuzhiyun * no -> amount of pstates above array got filled up with
85*4882a593Smuzhiyun *
86*4882a593Smuzhiyun * returns zero on success, -1 on failure
87*4882a593Smuzhiyun */
decode_pstates(unsigned int cpu,unsigned int cpu_family,int boost_states,unsigned long * pstates,int * no)88*4882a593Smuzhiyun int decode_pstates(unsigned int cpu, unsigned int cpu_family,
89*4882a593Smuzhiyun int boost_states, unsigned long *pstates, int *no)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun int i, psmax, pscur;
92*4882a593Smuzhiyun union msr_pstate pstate;
93*4882a593Smuzhiyun unsigned long long val;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Only read out frequencies from HW when CPU might be boostable
96*4882a593Smuzhiyun to keep the code as short and clean as possible.
97*4882a593Smuzhiyun Otherwise frequencies are exported via ACPI tables.
98*4882a593Smuzhiyun */
99*4882a593Smuzhiyun if (cpu_family < 0x10 || cpu_family == 0x14)
100*4882a593Smuzhiyun return -1;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
103*4882a593Smuzhiyun return -1;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun psmax = (val >> 4) & 0x7;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
108*4882a593Smuzhiyun return -1;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun pscur = val & 0x7;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun pscur += boost_states;
113*4882a593Smuzhiyun psmax += boost_states;
114*4882a593Smuzhiyun for (i = 0; i <= psmax; i++) {
115*4882a593Smuzhiyun if (i >= MAX_HW_PSTATES) {
116*4882a593Smuzhiyun fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
117*4882a593Smuzhiyun psmax, MAX_HW_PSTATES);
118*4882a593Smuzhiyun return -1;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
121*4882a593Smuzhiyun return -1;
122*4882a593Smuzhiyun if ((cpu_family == 0x17) && (!pstate.fam17h_bits.en))
123*4882a593Smuzhiyun continue;
124*4882a593Smuzhiyun else if (!pstate.bits.en)
125*4882a593Smuzhiyun continue;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun pstates[i] = get_cof(cpu_family, pstate);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun *no = i;
130*4882a593Smuzhiyun return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
amd_pci_get_num_boost_states(int * active,int * states)133*4882a593Smuzhiyun int amd_pci_get_num_boost_states(int *active, int *states)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun struct pci_access *pci_acc;
136*4882a593Smuzhiyun struct pci_dev *device;
137*4882a593Smuzhiyun uint8_t val = 0;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun *active = *states = 0;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun device = pci_slot_func_init(&pci_acc, 0x18, 4);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (device == NULL)
144*4882a593Smuzhiyun return -ENODEV;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun val = pci_read_byte(device, 0x15c);
147*4882a593Smuzhiyun if (val & 3)
148*4882a593Smuzhiyun *active = 1;
149*4882a593Smuzhiyun else
150*4882a593Smuzhiyun *active = 0;
151*4882a593Smuzhiyun *states = (val >> 2) & 7;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun pci_cleanup(pci_acc);
154*4882a593Smuzhiyun return 0;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun #endif /* defined(__i386__) || defined(__x86_64__) */
157