1/**
2 * \file
3 * \brief AMD performance monitoring infrastructure.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2013, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <kernel.h>
16#include <stdio.h>
17#include <stdint.h>
18#include <stdbool.h>
19#include <string.h>
20#include <capabilities.h>
21#include <arch/x86/perfmon_amd.h>
22#include <arch/x86/perfmon_intel.h>
23#include <arch/x86/perfmon.h>
24#include <arch/x86/apic.h>
25
26static bool perfmon_amd = false, perfmon_intel = false;
27/* static bool perfmon_measurement_running = false; */
28/* static bool perfmon_apic_activated = false; */
29static uint64_t perfmon_cntr_init = 0;
30struct capability perfmon_callback_ep = {
31    .type = ObjType_Null,
32};
33
34void perfmon_init(void)
35{
36    // Return if init already done ..
37    if(perfmon_amd || perfmon_intel) {
38        return;
39    }
40
41    // Try to initialize on intel.
42    if(err_is_fail(perfmon_intel_init())) {
43        // Try amd
44        perfmon_amd_init();
45        // Check amd
46        perfmon_amd = perfmon_amd_supported();
47    } else {
48        perfmon_intel = true;
49    }
50
51    // Debug output
52    if(perfmon_intel) {
53        printf("Activated perfmon for Intel!\n");
54    } else if(perfmon_amd) {
55        printf("Activated perfmon for AMD!\n");
56    } else {
57        printf("Perfmon activation failed. "
58               "Neither Intel nor AMD support detected\n");
59    }
60}
61
62/*
63 * \brief Initialize measuring for performance analysis.
64 *
65 * An overflow will be registered and the counter will set such that this
66 * overflow occures every ctr counter steps.
67 */
68void perfmon_measure_start(uint8_t event, uint8_t umask,
69                           uint8_t counter_id, bool kernel, uint64_t ctr)
70{
71    // Activate APIC interrupts for overflow if init successful
72    if(ctr!=0) {
73        if(perfmon_amd || perfmon_intel) {
74            apic_perfcnt_init();
75        }
76    }
77
78    if(perfmon_amd) {
79        perfmon_amd_measure_write(ctr*-1, 0);
80        perfmon_amd_measure_start(event, umask, kernel, counter_id, ctr!=0);
81    }
82
83    // Activate performance measurement for Intel
84    if(perfmon_intel) {
85        perfmon_intel_measure_write(ctr*-1);
86        perfmon_intel_measure_start(event, umask, kernel, counter_id, ctr!=0);
87    }
88
89    perfmon_cntr_init = ctr;
90}
91
92/*
93 * Re-Initialize counter after overflow.
94 * This function is called from the interrupt processing.
95 */
96void perfmon_measure_reset(void)
97{
98    if(perfmon_amd) {
99        perfmon_amd_measure_write(perfmon_cntr_init*-1, 0);
100    }
101    if(perfmon_intel) {
102        perfmon_intel_reset();
103        perfmon_intel_measure_write(perfmon_cntr_init*-1);
104    }
105}
106
107uint64_t perfmon_measure_read(void)
108{
109    if(perfmon_amd) {
110        return perfmon_amd_measure_read(0);
111    }
112
113    if(perfmon_intel) {
114        return perfmon_intel_measure_read();
115    }
116
117    return 0;
118
119}
120
121void perfmon_measure_write(uint8_t counter_id, uint64_t val)
122{
123
124    if(perfmon_amd) {
125        perfmon_amd_measure_write(val, counter_id);
126    }
127
128    if(perfmon_intel) {
129        perfmon_intel_measure_write(val);
130    }
131
132}
133
134/*
135 * \brief Deactivate performance measuring
136 */
137void perfmon_measure_stop(void)
138{
139    if(perfmon_amd) {
140        perfmon_amd_measure_stop(0);
141    }
142
143    // Mask out performance counter overflow interrupts on APIC
144    apic_perfcnt_stop();
145}
146