From a441643cb427b8600bfb5ae3313522765a6f6521 Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Sun, 29 Apr 2018 17:15:03 +0200 Subject: Minor changes --- arch/x86/machine/cpu.c | 13 ++++---- arch/x86/machine/cpu.h | 8 ++--- arch/x86/machine/lapic.c | 4 ++- arch/x86/machine/pmu.h | 7 ++-- arch/x86/machine/pmu_amd.c | 52 ++++++++++++++---------------- arch/x86/machine/pmu_intel.c | 76 ++++++++++++++++++++++++-------------------- 6 files changed, 81 insertions(+), 79 deletions(-) (limited to 'arch/x86/machine') diff --git a/arch/x86/machine/cpu.c b/arch/x86/machine/cpu.c index 54a2676..b60bea9 100644 --- a/arch/x86/machine/cpu.c +++ b/arch/x86/machine/cpu.c @@ -180,7 +180,7 @@ cpu_delay(unsigned long usecs) static const struct cpu_vendor cpu_vendors[] = { { CPU_VENDOR_INTEL, "GenuineIntel" }, - { CPU_VENDOR_AMD, "AuthenticAMD" }, + { CPU_VENDOR_AMD, "AuthenticAMD" }, }; void * __init @@ -442,11 +442,11 @@ cpu_load_idt(const void *idt, size_t size) static const struct cpu_vendor * cpu_vendor_lookup(const char *str) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(cpu_vendors); i++) - if (strcmp(str, cpu_vendors[i].str) == 0) + for (size_t i = 0; i < ARRAY_SIZE(cpu_vendors); i++) { + if (strcmp(str, cpu_vendors[i].str) == 0) { return &cpu_vendors[i]; + } + } return NULL; } @@ -458,8 +458,9 @@ cpu_init_vendor_id(struct cpu *cpu) vendor = cpu_vendor_lookup(cpu->vendor_str); - if (vendor == NULL) + if (vendor == NULL) { return; + } cpu->vendor_id = vendor->id; } diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h index eebacc6..334a51c 100644 --- a/arch/x86/machine/cpu.h +++ b/arch/x86/machine/cpu.h @@ -554,7 +554,7 @@ cpu_get_msr(uint32_t msr, uint32_t *high, uint32_t *low) } /* - * uint64 version of cpu_get_msr. + * Implies a compiler barrier. */ static __always_inline uint64_t cpu_get_msr64(uint32_t msr) @@ -562,7 +562,6 @@ cpu_get_msr64(uint32_t msr) uint32_t high, low; cpu_get_msr(msr, &high, &low); - return (((uint64_t)high << 32) | low); } @@ -574,15 +573,16 @@ cpu_set_msr(uint32_t msr, uint32_t high, uint32_t low) { asm volatile("wrmsr" : : "c" (msr), "a" (low), "d" (high) : "memory"); } + /* - * uint64 version of cpu_set_msr. + * Implies a full memory barrier. */ static inline void cpu_set_msr64(uint32_t msr, uint64_t value) { uint32_t low, high; - low = value & 0xffffffff; + low = value & 0xffffffff; high = value >> 32; cpu_set_msr(msr, high, low); diff --git a/arch/x86/machine/lapic.c b/arch/x86/machine/lapic.c index 7e8299e..6ba3ddd 100644 --- a/arch/x86/machine/lapic.c +++ b/arch/x86/machine/lapic.c @@ -339,9 +339,11 @@ void lapic_pmc_of_intr(struct trap_frame *frame) { (void)frame; + #ifdef CONFIG_PERFMON - perfmon_handle_of_intr(frame); + perfmon_of_intr(); #endif + lapic_eoi(); } diff --git a/arch/x86/machine/pmu.h b/arch/x86/machine/pmu.h index fdd79e7..009aac5 100644 --- a/arch/x86/machine/pmu.h +++ b/arch/x86/machine/pmu.h @@ -17,8 +17,8 @@ * Pmu driver modules. */ -#ifndef _X86_PMU_H -#define _X86_PMU_H +#ifndef X86_PMU_H +#define X86_PMU_H #include @@ -29,5 +29,4 @@ INIT_OP_DECLARE(pmu_intel_setup); INIT_OP_DECLARE(pmu_amd_setup); -#endif /* _X86_PMU_H */ - +#endif /* X86_PMU_H */ diff --git a/arch/x86/machine/pmu_amd.c b/arch/x86/machine/pmu_amd.c index 4d2a4f8..105ba50 100644 --- a/arch/x86/machine/pmu_amd.c +++ b/arch/x86/machine/pmu_amd.c @@ -14,14 +14,12 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * AMD PMU driver module. */ +#include +#include #include -#include -#include #include #include #include @@ -40,7 +38,7 @@ #define PMU_AMD_RE_DCACHE_REF 6 #define PMU_AMD_RE_DCACHE_MISS 7 #define PMU_AMD_RE_IFETCH_STALL 8 - +#define PMU_AMD_RE_INVALID ((unsigned int)-1) /* * PMU MSR addresses @@ -57,23 +55,29 @@ #define PMU_AMD_EVTSEL_EN 0x00400000 /* - * AMD PMU properties seem to be identical across all processors despite - * many of them being implementation-specific. + * XXX These properties have the minimum values required by the architecture. + * TODO Per-family/model event availability database. */ #define PMU_AMD_NR_PMCS 4 #define PMU_AMD_PMC_WIDTH 48 +/* + * Global PMU properties. + * + * The bitmap is used to implement counter allocation, where each bit denotes + * whether a counter is available or not. + */ struct pmu_amd { unsigned int pmc_bm; }; +static struct pmu_amd pmu_amd; + struct pmu_amd_event_code { unsigned short event_select; unsigned short umask; }; -static struct pmu_amd pmu_amd; - /* * TODO Per-family/model event availability database. */ @@ -89,8 +93,6 @@ static const struct pmu_amd_event_code pmu_amd_event_codes[] = { [PMU_AMD_RE_IFETCH_STALL] = { 0x87, 0x00 }, }; -#define PMU_AMD_RE_INVALID ((unsigned int)-1) - static const unsigned int pmu_amd_generic_events[] = { [PERFMON_EV_CYCLE] = PMU_AMD_RE_CYCLE, [PERFMON_EV_REF_CYCLE] = PMU_AMD_RE_INVALID, @@ -120,7 +122,6 @@ pmu_amd_translate(unsigned int *raw_event_idp, unsigned int event_id) assert(event_id < ARRAY_SIZE(pmu_amd_generic_events)); *raw_event_idp = pmu_amd_generic_events[event_id]; - return 0; } @@ -130,7 +131,7 @@ pmu_amd_alloc(unsigned int *pmc_idp, unsigned int raw_event_id) struct pmu_amd *pmu; unsigned int pmc_id; - /* TODO Check raw event availability */ + /* TODO Per-family/model event availability database */ (void)raw_event_id; pmu = pmu_amd_get(); @@ -156,9 +157,7 @@ pmu_amd_free(unsigned int pmc_id) pmu = pmu_amd_get(); mask = (1U << pmc_id); - assert(!(pmu->pmc_bm & mask)); - pmu->pmc_bm |= mask; } @@ -200,37 +199,35 @@ pmu_amd_read(unsigned int pmc_id) return cpu_get_msr64(PMU_AMD_MSR_PERCTR0 + pmc_id); } -#ifdef CONFIG_PERFMON_TEST - static void pmu_amd_write(unsigned int pmc_id, uint64_t value) { cpu_set_msr64(PMU_AMD_MSR_PERCTR0 + pmc_id, value); } -#endif /* CONFIG_PERFMON_TEST */ - +/* + * TODO Make the perfmon module handle basic overflow handling by polling + * counters. + */ static void -pmu_amd_handle_of_intr_v1(struct trap_frame *frame) +pmu_amd_handle_of_intr_v1(void) { struct pmu_amd *pmu; + uint64_t value, prev; unsigned int mask; - uint64_t value; - uint64_t prev; - - (void)frame; pmu = pmu_amd_get(); for (unsigned int pmc_id = 0; pmc_id != PMU_AMD_NR_PMCS; pmc_id++) { mask = (1U << pmc_id); + if (pmu->pmc_bm & mask) { - /* counter not enabled: can't overflow. */ continue; } value = pmu_amd_read(pmc_id); prev = perfmon_cpu_pmc_get_prev(pmc_id); + if (prev > value) { /* Overflow */ perfmon_cpu_pmc_inc_of(pmc_id); @@ -274,11 +271,9 @@ pmu_amd_setup(void) pmu_driver.start = pmu_amd_start; pmu_driver.stop = pmu_amd_stop; pmu_driver.read = pmu_amd_read; + pmu_driver.write = pmu_amd_write; pmu_driver.get_pmc_width = pmu_amd_get_pmc_width; pmu_driver.handle_of_intr = pmu_amd_handle_of_intr_v1; -#ifdef CONFIG_PERFMON_TEST - pmu_driver.write = pmu_amd_write; -#endif return perfmon_pmu_register(&pmu_driver); } @@ -287,4 +282,3 @@ INIT_OP_DEFINE(pmu_amd_setup, INIT_OP_DEP(perfmon_bootstrap, true), INIT_OP_DEP(cpu_setup, true), INIT_OP_DEP(log_setup, true)); - diff --git a/arch/x86/machine/pmu_intel.c b/arch/x86/machine/pmu_intel.c index 0833a71..f8168bb 100644 --- a/arch/x86/machine/pmu_intel.c +++ b/arch/x86/machine/pmu_intel.c @@ -14,14 +14,12 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * INTEL PMU driver module. */ +#include +#include #include -#include -#include #include #include #include @@ -76,6 +74,12 @@ #define PMU_INTEL_ID_EVLEN_OFFSET 24 #define PMU_INTEL_ID_EVLEN_MAX 7 +/* + * Global PMU properties. + * + * The bitmap is used to implement counter allocation, where each bit denotes + * whether a counter is available or not. + */ struct pmu_intel { unsigned int version; unsigned int nr_pmcs; @@ -84,12 +88,6 @@ struct pmu_intel { unsigned int events; }; -struct pmu_intel_event_code { - unsigned int hw_event_id; - unsigned short event_select; - unsigned short umask; -}; - static struct pmu_intel pmu_intel; /* @@ -103,6 +101,12 @@ static struct pmu_intel pmu_intel; #define PMU_INTEL_EVENT_BRANCH 0x20 #define PMU_INTEL_EVENT_BRANCH_MISS 0x40 +struct pmu_intel_event_code { + unsigned int hw_event_id; + unsigned short event_select; + unsigned short umask; +}; + static const unsigned int pmu_intel_raw_events[] = { [PERFMON_EV_CYCLE] = PMU_INTEL_RE_CYCLE, [PERFMON_EV_REF_CYCLE] = PMU_INTEL_RE_REF_CYCLE, @@ -141,20 +145,24 @@ pmu_intel_ack_status(uint64_t status) return cpu_set_msr64(PMU_INTEL_MSR_GLOBAL_OVF_CTRL, status); } +/* + * TODO use the compiler built-in once libgcc is linked again. + */ static unsigned int pmu_popcount(unsigned int bits) { - unsigned int count = 0; + unsigned int count; + + count = 0; - /* XXX: Dummy version of popcount. We should implement a faster one if it - * gets needed somewhere else. - */ while (bits) { if (bits & 1) { count++; } + bits >>= 1; } + return count; } @@ -167,8 +175,8 @@ pmu_intel_info(void) pmu = pmu_intel_get(); nr_events = pmu_popcount(pmu->events); log_info("pmu: driver: intel, architectural v1\n" - "pmu: nr_pmcs: %u, pmc_width: %u, events: %#x, nr_events: %u\n", - pmu->nr_pmcs, pmu->pmc_width, pmu->events, nr_events); + "pmu: nr_pmcs: %u, pmc_width: %u, events: %#x, nr_events: %u\n", + pmu->nr_pmcs, pmu->pmc_width, pmu->events, nr_events); } static int @@ -179,7 +187,6 @@ pmu_intel_translate(unsigned int *raw_event_idp, unsigned event_id) } *raw_event_idp = pmu_intel_raw_events[event_id]; - return 0; } @@ -217,9 +224,7 @@ pmu_intel_free(unsigned int pmc_id) pmu = pmu_intel_get(); mask = (1U << pmc_id); - assert(!(pmu->pmc_bm & mask)); - pmu->pmc_bm |= mask; } @@ -255,26 +260,24 @@ pmu_intel_read(unsigned int pmc_id) return cpu_get_msr64(PMU_INTEL_MSR_PMC0 + pmc_id); } -#ifdef CONFIG_PERFMON_TEST - static void pmu_intel_write(unsigned int pmc_id, uint64_t value) { cpu_set_msr64(PMU_INTEL_MSR_PMC0 + pmc_id, value); } -#endif /* CONFIG_PERFMON_TEST */ - +/* + * TODO Make the perfmon module handle basic overflow handling by polling + * counters. + */ static void -pmu_intel_handle_of_intr_v1(struct trap_frame *frame) +pmu_intel_handle_of_intr_v1(void) { struct pmu_intel *pmu; unsigned int mask; uint64_t value; uint64_t prev; - (void)frame; - pmu = pmu_intel_get(); for (unsigned int pmc_id = 0; pmc_id != pmu->nr_pmcs; pmc_id++) { @@ -301,37 +304,40 @@ pmu_intel_consume_bits(uint64_t *bits) int bit; bit = __builtin_ffsll(*bits) - 1; + if (bit < 0) { return bit; } - *bits &= ~(1U << bit); + *bits &= ~(1U << bit); return bit; } static void -pmu_intel_handle_of_intr_v2(struct trap_frame *frame) +pmu_intel_handle_of_intr_v2(void) { struct pmu_intel *pmu; uint64_t status; int pmc_id; - (void)frame; - status = pmu_intel_get_status(); + if (status == 0) { return; } + pmu_intel_ack_status(status); pmu = pmu_intel_get(); - /* XXX: Mask on all PMCs (we do not check FIXED counters status */ status &= ((1U << pmu->pmc_width) - 1); - for(;;) { + + for (;;) { pmc_id = pmu_intel_consume_bits(&status); + if (pmc_id < 0) { break; } + perfmon_cpu_pmc_inc_of(pmc_id); } } @@ -369,6 +375,7 @@ pmu_intel_setup(void) cpu_cpuid(&eax, &ebx, &ecx, &edx); pmu->version = eax & PMU_INTEL_ID_VERSION_MASK; + /* TODO Check this */ if ((pmu->version == 0) || (pmu->version > 3)) { return ENODEV; } @@ -391,15 +398,14 @@ pmu_intel_setup(void) pmu_driver.start = pmu_intel_start; pmu_driver.stop = pmu_intel_stop; pmu_driver.read = pmu_intel_read; + pmu_driver.write = pmu_intel_write; pmu_driver.get_pmc_width = pmu_intel_get_pmc_width; + if (pmu->version > 2) { pmu_driver.handle_of_intr = pmu_intel_handle_of_intr_v1; } else { pmu_driver.handle_of_intr = pmu_intel_handle_of_intr_v2; } -#ifdef CONFIG_PERFMON_TEST - pmu_driver.write = pmu_intel_write; -#endif return perfmon_pmu_register(&pmu_driver); } -- cgit v1.2.3