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