123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /*
- * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
- *
- * Licensed under the terms of the GNU GPL License version 2.
- *
- * PCI initialization based on example code from:
- * Andreas Herrmann <andreas.herrmann3@amd.com>
- */
- #if defined(__i386__) || defined(__x86_64__)
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <time.h>
- #include <string.h>
- #include <pci/pci.h>
- #include "idle_monitor/cpupower-monitor.h"
- #include "helpers/helpers.h"
- #define PCI_NON_PC0_OFFSET 0xb0
- #define PCI_PC1_OFFSET 0xb4
- #define PCI_PC6_OFFSET 0xb8
- #define PCI_MONITOR_ENABLE_REG 0xe0
- #define PCI_NON_PC0_ENABLE_BIT 0
- #define PCI_PC1_ENABLE_BIT 1
- #define PCI_PC6_ENABLE_BIT 2
- #define PCI_NBP1_STAT_OFFSET 0x98
- #define PCI_NBP1_ACTIVE_BIT 2
- #define PCI_NBP1_ENTERED_BIT 1
- #define PCI_NBP1_CAP_OFFSET 0x90
- #define PCI_NBP1_CAPABLE_BIT 31
- #define OVERFLOW_MS 343597 /* 32 bit register filled at 12500 HZ
- (1 tick per 80ns) */
- enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1,
- AMD_FAM14H_STATE_NUM};
- static int fam14h_get_count_percent(unsigned int self_id, double *percent,
- unsigned int cpu);
- static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
- unsigned int cpu);
- static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = {
- {
- .name = "!PC0",
- .desc = N_("Package in sleep state (PC1 or deeper)"),
- .id = NON_PC0,
- .range = RANGE_PACKAGE,
- .get_count_percent = fam14h_get_count_percent,
- },
- {
- .name = "PC1",
- .desc = N_("Processor Package C1"),
- .id = PC1,
- .range = RANGE_PACKAGE,
- .get_count_percent = fam14h_get_count_percent,
- },
- {
- .name = "PC6",
- .desc = N_("Processor Package C6"),
- .id = PC6,
- .range = RANGE_PACKAGE,
- .get_count_percent = fam14h_get_count_percent,
- },
- {
- .name = "NBP1",
- .desc = N_("North Bridge P1 boolean counter (returns 0 or 1)"),
- .id = NBP1,
- .range = RANGE_PACKAGE,
- .get_count = fam14h_nbp1_count,
- },
- };
- static struct pci_access *pci_acc;
- static struct pci_dev *amd_fam14h_pci_dev;
- static int nbp1_entered;
- static struct timespec start_time;
- static unsigned long long timediff;
- #ifdef DEBUG
- struct timespec dbg_time;
- long dbg_timediff;
- #endif
- static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM];
- static unsigned long long *current_count[AMD_FAM14H_STATE_NUM];
- static int amd_fam14h_get_pci_info(struct cstate *state,
- unsigned int *pci_offset,
- unsigned int *enable_bit,
- unsigned int cpu)
- {
- switch (state->id) {
- case NON_PC0:
- *enable_bit = PCI_NON_PC0_ENABLE_BIT;
- *pci_offset = PCI_NON_PC0_OFFSET;
- break;
- case PC1:
- *enable_bit = PCI_PC1_ENABLE_BIT;
- *pci_offset = PCI_PC1_OFFSET;
- break;
- case PC6:
- *enable_bit = PCI_PC6_ENABLE_BIT;
- *pci_offset = PCI_PC6_OFFSET;
- break;
- case NBP1:
- *enable_bit = PCI_NBP1_ENTERED_BIT;
- *pci_offset = PCI_NBP1_STAT_OFFSET;
- break;
- default:
- return -1;
- };
- return 0;
- }
- static int amd_fam14h_init(cstate_t *state, unsigned int cpu)
- {
- int enable_bit, pci_offset, ret;
- uint32_t val;
- ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
- if (ret)
- return ret;
- /* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */
- if (state->id == NBP1) {
- val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
- val |= 1 << enable_bit;
- val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val);
- return ret;
- }
- /* Enable monitor */
- val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
- dprint("Init %s: read at offset: 0x%x val: %u\n", state->name,
- PCI_MONITOR_ENABLE_REG, (unsigned int) val);
- val |= 1 << enable_bit;
- pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
- dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n",
- state->name, PCI_MONITOR_ENABLE_REG, enable_bit,
- (unsigned int) val, cpu);
- /* Set counter to zero */
- pci_write_long(amd_fam14h_pci_dev, pci_offset, 0);
- previous_count[state->id][cpu] = 0;
- return 0;
- }
- static int amd_fam14h_disable(cstate_t *state, unsigned int cpu)
- {
- int enable_bit, pci_offset, ret;
- uint32_t val;
- ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
- if (ret)
- return ret;
- val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
- dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val);
- if (state->id == NBP1) {
- /* was the bit whether NBP1 got entered set? */
- nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) |
- (val & (1 << PCI_NBP1_ENTERED_BIT));
- dprint("NBP1 was %sentered - 0x%x - enable_bit: "
- "%d - pci_offset: 0x%x\n",
- nbp1_entered ? "" : "not ",
- val, enable_bit, pci_offset);
- return ret;
- }
- current_count[state->id][cpu] = val;
- dprint("%s: Current - %llu (%u)\n", state->name,
- current_count[state->id][cpu], cpu);
- dprint("%s: Previous - %llu (%u)\n", state->name,
- previous_count[state->id][cpu], cpu);
- val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
- val &= ~(1 << enable_bit);
- pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
- return 0;
- }
- static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
- unsigned int cpu)
- {
- if (id == NBP1) {
- if (nbp1_entered)
- *count = 1;
- else
- *count = 0;
- return 0;
- }
- return -1;
- }
- static int fam14h_get_count_percent(unsigned int id, double *percent,
- unsigned int cpu)
- {
- unsigned long diff;
- if (id >= AMD_FAM14H_STATE_NUM)
- return -1;
- /* residency count in 80ns -> divide through 12.5 to get us residency */
- diff = current_count[id][cpu] - previous_count[id][cpu];
- if (timediff == 0)
- *percent = 0.0;
- else
- *percent = 100.0 * diff / timediff / 12.5;
- dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n",
- timediff, diff * 10 / 125, *percent);
- return 0;
- }
- static int amd_fam14h_start(void)
- {
- int num, cpu;
- clock_gettime(CLOCK_REALTIME, &start_time);
- for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
- for (cpu = 0; cpu < cpu_count; cpu++)
- amd_fam14h_init(&amd_fam14h_cstates[num], cpu);
- }
- #ifdef DEBUG
- clock_gettime(CLOCK_REALTIME, &dbg_time);
- dbg_timediff = timespec_diff_us(start_time, dbg_time);
- dprint("Enabling counters took: %lu us\n",
- dbg_timediff);
- #endif
- return 0;
- }
- static int amd_fam14h_stop(void)
- {
- int num, cpu;
- struct timespec end_time;
- clock_gettime(CLOCK_REALTIME, &end_time);
- for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
- for (cpu = 0; cpu < cpu_count; cpu++)
- amd_fam14h_disable(&amd_fam14h_cstates[num], cpu);
- }
- #ifdef DEBUG
- clock_gettime(CLOCK_REALTIME, &dbg_time);
- dbg_timediff = timespec_diff_us(end_time, dbg_time);
- dprint("Disabling counters took: %lu ns\n", dbg_timediff);
- #endif
- timediff = timespec_diff_us(start_time, end_time);
- if (timediff / 1000 > OVERFLOW_MS)
- print_overflow_err((unsigned int)timediff / 1000000,
- OVERFLOW_MS / 1000);
- return 0;
- }
- static int is_nbp1_capable(void)
- {
- uint32_t val;
- val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET);
- return val & (1 << 31);
- }
- struct cpuidle_monitor *amd_fam14h_register(void)
- {
- int num;
- if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
- return NULL;
- if (cpupower_cpu_info.family == 0x14)
- strncpy(amd_fam14h_monitor.name, "Fam_14h",
- MONITOR_NAME_LEN - 1);
- else if (cpupower_cpu_info.family == 0x12)
- strncpy(amd_fam14h_monitor.name, "Fam_12h",
- MONITOR_NAME_LEN - 1);
- else
- return NULL;
- /* We do not alloc for nbp1 machine wide counter */
- for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
- previous_count[num] = calloc(cpu_count,
- sizeof(unsigned long long));
- current_count[num] = calloc(cpu_count,
- sizeof(unsigned long long));
- }
- /* We need PCI device: Slot 18, Func 6, compare with BKDG
- for fam 12h/14h */
- amd_fam14h_pci_dev = pci_slot_func_init(&pci_acc, 0x18, 6);
- if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
- return NULL;
- if (!is_nbp1_capable())
- amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1;
- amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name);
- return &amd_fam14h_monitor;
- }
- static void amd_fam14h_unregister(void)
- {
- int num;
- for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
- free(previous_count[num]);
- free(current_count[num]);
- }
- pci_cleanup(pci_acc);
- }
- struct cpuidle_monitor amd_fam14h_monitor = {
- .name = "",
- .hw_states = amd_fam14h_cstates,
- .hw_states_num = AMD_FAM14H_STATE_NUM,
- .start = amd_fam14h_start,
- .stop = amd_fam14h_stop,
- .do_register = amd_fam14h_register,
- .unregister = amd_fam14h_unregister,
- .needs_root = 1,
- .overflow_s = OVERFLOW_MS / 1000,
- };
- #endif /* #if defined(__i386__) || defined(__x86_64__) */
|