Linux 4.16-rc1
[cris-mirror.git] / tools / power / cpupower / utils / idle_monitor / amd_fam14h_idle.c
blob2116df9ad83254eb0a7a37246b83f959e669b7f5
1 /*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
4 * Licensed under the terms of the GNU GPL License version 2.
6 * PCI initialization based on example code from:
7 * Andreas Herrmann <andreas.herrmann3@amd.com>
8 */
10 #if defined(__i386__) || defined(__x86_64__)
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <time.h>
16 #include <string.h>
18 #include <pci/pci.h>
20 #include "idle_monitor/cpupower-monitor.h"
21 #include "helpers/helpers.h"
23 #define PCI_NON_PC0_OFFSET 0xb0
24 #define PCI_PC1_OFFSET 0xb4
25 #define PCI_PC6_OFFSET 0xb8
27 #define PCI_MONITOR_ENABLE_REG 0xe0
29 #define PCI_NON_PC0_ENABLE_BIT 0
30 #define PCI_PC1_ENABLE_BIT 1
31 #define PCI_PC6_ENABLE_BIT 2
33 #define PCI_NBP1_STAT_OFFSET 0x98
34 #define PCI_NBP1_ACTIVE_BIT 2
35 #define PCI_NBP1_ENTERED_BIT 1
37 #define PCI_NBP1_CAP_OFFSET 0x90
38 #define PCI_NBP1_CAPABLE_BIT 31
40 #define OVERFLOW_MS 343597 /* 32 bit register filled at 12500 HZ
41 (1 tick per 80ns) */
43 enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1,
44 AMD_FAM14H_STATE_NUM};
46 static int fam14h_get_count_percent(unsigned int self_id, double *percent,
47 unsigned int cpu);
48 static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
49 unsigned int cpu);
51 static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = {
53 .name = "!PC0",
54 .desc = N_("Package in sleep state (PC1 or deeper)"),
55 .id = NON_PC0,
56 .range = RANGE_PACKAGE,
57 .get_count_percent = fam14h_get_count_percent,
60 .name = "PC1",
61 .desc = N_("Processor Package C1"),
62 .id = PC1,
63 .range = RANGE_PACKAGE,
64 .get_count_percent = fam14h_get_count_percent,
67 .name = "PC6",
68 .desc = N_("Processor Package C6"),
69 .id = PC6,
70 .range = RANGE_PACKAGE,
71 .get_count_percent = fam14h_get_count_percent,
74 .name = "NBP1",
75 .desc = N_("North Bridge P1 boolean counter (returns 0 or 1)"),
76 .id = NBP1,
77 .range = RANGE_PACKAGE,
78 .get_count = fam14h_nbp1_count,
82 static struct pci_access *pci_acc;
83 static struct pci_dev *amd_fam14h_pci_dev;
84 static int nbp1_entered;
86 struct timespec start_time;
87 static unsigned long long timediff;
89 #ifdef DEBUG
90 struct timespec dbg_time;
91 long dbg_timediff;
92 #endif
94 static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM];
95 static unsigned long long *current_count[AMD_FAM14H_STATE_NUM];
97 static int amd_fam14h_get_pci_info(struct cstate *state,
98 unsigned int *pci_offset,
99 unsigned int *enable_bit,
100 unsigned int cpu)
102 switch (state->id) {
103 case NON_PC0:
104 *enable_bit = PCI_NON_PC0_ENABLE_BIT;
105 *pci_offset = PCI_NON_PC0_OFFSET;
106 break;
107 case PC1:
108 *enable_bit = PCI_PC1_ENABLE_BIT;
109 *pci_offset = PCI_PC1_OFFSET;
110 break;
111 case PC6:
112 *enable_bit = PCI_PC6_ENABLE_BIT;
113 *pci_offset = PCI_PC6_OFFSET;
114 break;
115 case NBP1:
116 *enable_bit = PCI_NBP1_ENTERED_BIT;
117 *pci_offset = PCI_NBP1_STAT_OFFSET;
118 break;
119 default:
120 return -1;
122 return 0;
125 static int amd_fam14h_init(cstate_t *state, unsigned int cpu)
127 int enable_bit, pci_offset, ret;
128 uint32_t val;
130 ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
131 if (ret)
132 return ret;
134 /* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */
135 if (state->id == NBP1) {
136 val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
137 val |= 1 << enable_bit;
138 val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val);
139 return ret;
142 /* Enable monitor */
143 val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
144 dprint("Init %s: read at offset: 0x%x val: %u\n", state->name,
145 PCI_MONITOR_ENABLE_REG, (unsigned int) val);
146 val |= 1 << enable_bit;
147 pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
149 dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n",
150 state->name, PCI_MONITOR_ENABLE_REG, enable_bit,
151 (unsigned int) val, cpu);
153 /* Set counter to zero */
154 pci_write_long(amd_fam14h_pci_dev, pci_offset, 0);
155 previous_count[state->id][cpu] = 0;
157 return 0;
160 static int amd_fam14h_disable(cstate_t *state, unsigned int cpu)
162 int enable_bit, pci_offset, ret;
163 uint32_t val;
165 ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
166 if (ret)
167 return ret;
169 val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
170 dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val);
171 if (state->id == NBP1) {
172 /* was the bit whether NBP1 got entered set? */
173 nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) |
174 (val & (1 << PCI_NBP1_ENTERED_BIT));
176 dprint("NBP1 was %sentered - 0x%x - enable_bit: "
177 "%d - pci_offset: 0x%x\n",
178 nbp1_entered ? "" : "not ",
179 val, enable_bit, pci_offset);
180 return ret;
182 current_count[state->id][cpu] = val;
184 dprint("%s: Current - %llu (%u)\n", state->name,
185 current_count[state->id][cpu], cpu);
186 dprint("%s: Previous - %llu (%u)\n", state->name,
187 previous_count[state->id][cpu], cpu);
189 val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
190 val &= ~(1 << enable_bit);
191 pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
193 return 0;
196 static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
197 unsigned int cpu)
199 if (id == NBP1) {
200 if (nbp1_entered)
201 *count = 1;
202 else
203 *count = 0;
204 return 0;
206 return -1;
208 static int fam14h_get_count_percent(unsigned int id, double *percent,
209 unsigned int cpu)
211 unsigned long diff;
213 if (id >= AMD_FAM14H_STATE_NUM)
214 return -1;
215 /* residency count in 80ns -> divide through 12.5 to get us residency */
216 diff = current_count[id][cpu] - previous_count[id][cpu];
218 if (timediff == 0)
219 *percent = 0.0;
220 else
221 *percent = 100.0 * diff / timediff / 12.5;
223 dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n",
224 timediff, diff * 10 / 125, *percent);
226 return 0;
229 static int amd_fam14h_start(void)
231 int num, cpu;
232 clock_gettime(CLOCK_REALTIME, &start_time);
233 for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
234 for (cpu = 0; cpu < cpu_count; cpu++)
235 amd_fam14h_init(&amd_fam14h_cstates[num], cpu);
237 #ifdef DEBUG
238 clock_gettime(CLOCK_REALTIME, &dbg_time);
239 dbg_timediff = timespec_diff_us(start_time, dbg_time);
240 dprint("Enabling counters took: %lu us\n",
241 dbg_timediff);
242 #endif
243 return 0;
246 static int amd_fam14h_stop(void)
248 int num, cpu;
249 struct timespec end_time;
251 clock_gettime(CLOCK_REALTIME, &end_time);
253 for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
254 for (cpu = 0; cpu < cpu_count; cpu++)
255 amd_fam14h_disable(&amd_fam14h_cstates[num], cpu);
257 #ifdef DEBUG
258 clock_gettime(CLOCK_REALTIME, &dbg_time);
259 dbg_timediff = timespec_diff_us(end_time, dbg_time);
260 dprint("Disabling counters took: %lu ns\n", dbg_timediff);
261 #endif
262 timediff = timespec_diff_us(start_time, end_time);
263 if (timediff / 1000 > OVERFLOW_MS)
264 print_overflow_err((unsigned int)timediff / 1000000,
265 OVERFLOW_MS / 1000);
267 return 0;
270 static int is_nbp1_capable(void)
272 uint32_t val;
273 val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET);
274 return val & (1 << 31);
277 struct cpuidle_monitor *amd_fam14h_register(void)
279 int num;
281 if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
282 return NULL;
284 if (cpupower_cpu_info.family == 0x14)
285 strncpy(amd_fam14h_monitor.name, "Fam_14h",
286 MONITOR_NAME_LEN - 1);
287 else if (cpupower_cpu_info.family == 0x12)
288 strncpy(amd_fam14h_monitor.name, "Fam_12h",
289 MONITOR_NAME_LEN - 1);
290 else
291 return NULL;
293 /* We do not alloc for nbp1 machine wide counter */
294 for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
295 previous_count[num] = calloc(cpu_count,
296 sizeof(unsigned long long));
297 current_count[num] = calloc(cpu_count,
298 sizeof(unsigned long long));
301 /* We need PCI device: Slot 18, Func 6, compare with BKDG
302 for fam 12h/14h */
303 amd_fam14h_pci_dev = pci_slot_func_init(&pci_acc, 0x18, 6);
304 if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
305 return NULL;
307 if (!is_nbp1_capable())
308 amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1;
310 amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name);
311 return &amd_fam14h_monitor;
314 static void amd_fam14h_unregister(void)
316 int num;
317 for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
318 free(previous_count[num]);
319 free(current_count[num]);
321 pci_cleanup(pci_acc);
324 struct cpuidle_monitor amd_fam14h_monitor = {
325 .name = "",
326 .hw_states = amd_fam14h_cstates,
327 .hw_states_num = AMD_FAM14H_STATE_NUM,
328 .start = amd_fam14h_start,
329 .stop = amd_fam14h_stop,
330 .do_register = amd_fam14h_register,
331 .unregister = amd_fam14h_unregister,
332 .needs_root = 1,
333 .overflow_s = OVERFLOW_MS / 1000,
335 #endif /* #if defined(__i386__) || defined(__x86_64__) */