1*5951ced0SHans Rosenfeld /*
2*5951ced0SHans Rosenfeld * CDDL HEADER START
3*5951ced0SHans Rosenfeld *
4*5951ced0SHans Rosenfeld * The contents of this file are subject to the terms of the
5*5951ced0SHans Rosenfeld * Common Development and Distribution License (the "License").
6*5951ced0SHans Rosenfeld * You may not use this file except in compliance with the License.
7*5951ced0SHans Rosenfeld *
8*5951ced0SHans Rosenfeld * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5951ced0SHans Rosenfeld * or http://www.opensolaris.org/os/licensing.
10*5951ced0SHans Rosenfeld * See the License for the specific language governing permissions
11*5951ced0SHans Rosenfeld * and limitations under the License.
12*5951ced0SHans Rosenfeld *
13*5951ced0SHans Rosenfeld * When distributing Covered Code, include this CDDL HEADER in each
14*5951ced0SHans Rosenfeld * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5951ced0SHans Rosenfeld * If applicable, add the following below this CDDL HEADER, with the
16*5951ced0SHans Rosenfeld * fields enclosed by brackets "[]" replaced with your own identifying
17*5951ced0SHans Rosenfeld * information: Portions Copyright [yyyy] [name of copyright owner]
18*5951ced0SHans Rosenfeld *
19*5951ced0SHans Rosenfeld * CDDL HEADER END
20*5951ced0SHans Rosenfeld */
21*5951ced0SHans Rosenfeld /*
22*5951ced0SHans Rosenfeld * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*5951ced0SHans Rosenfeld */
24*5951ced0SHans Rosenfeld /*
25*5951ced0SHans Rosenfeld * Copyright (c) 2009, Intel Corporation.
26*5951ced0SHans Rosenfeld * All Rights Reserved.
27*5951ced0SHans Rosenfeld */
28*5951ced0SHans Rosenfeld
29*5951ced0SHans Rosenfeld #include <sys/x86_archext.h>
30*5951ced0SHans Rosenfeld #include <sys/machsystm.h>
31*5951ced0SHans Rosenfeld #include <sys/archsystm.h>
32*5951ced0SHans Rosenfeld #include <sys/x_call.h>
33*5951ced0SHans Rosenfeld #include <sys/acpi/acpi.h>
34*5951ced0SHans Rosenfeld #include <sys/acpica.h>
35*5951ced0SHans Rosenfeld #include <sys/speedstep.h>
36*5951ced0SHans Rosenfeld #include <sys/cpu_acpi.h>
37*5951ced0SHans Rosenfeld #include <sys/cpupm.h>
38*5951ced0SHans Rosenfeld #include <sys/dtrace.h>
39*5951ced0SHans Rosenfeld #include <sys/sdt.h>
40*5951ced0SHans Rosenfeld
41*5951ced0SHans Rosenfeld typedef struct turbo_kstat_s {
42*5951ced0SHans Rosenfeld struct kstat_named turbo_supported; /* turbo flag */
43*5951ced0SHans Rosenfeld struct kstat_named t_mcnt; /* IA32_MPERF_MSR */
44*5951ced0SHans Rosenfeld struct kstat_named t_acnt; /* IA32_APERF_MSR */
45*5951ced0SHans Rosenfeld } turbo_kstat_t;
46*5951ced0SHans Rosenfeld
47*5951ced0SHans Rosenfeld static int turbo_kstat_update(kstat_t *, int);
48*5951ced0SHans Rosenfeld static void get_turbo_info(cpupm_mach_turbo_info_t *);
49*5951ced0SHans Rosenfeld static void reset_turbo_info(void);
50*5951ced0SHans Rosenfeld static void record_turbo_info(cpupm_mach_turbo_info_t *, uint32_t, uint32_t);
51*5951ced0SHans Rosenfeld static void update_turbo_info(cpupm_mach_turbo_info_t *);
52*5951ced0SHans Rosenfeld
53*5951ced0SHans Rosenfeld static kmutex_t turbo_mutex;
54*5951ced0SHans Rosenfeld
55*5951ced0SHans Rosenfeld turbo_kstat_t turbo_kstat = {
56*5951ced0SHans Rosenfeld { "turbo_supported", KSTAT_DATA_UINT32 },
57*5951ced0SHans Rosenfeld { "turbo_mcnt", KSTAT_DATA_UINT64 },
58*5951ced0SHans Rosenfeld { "turbo_acnt", KSTAT_DATA_UINT64 },
59*5951ced0SHans Rosenfeld };
60*5951ced0SHans Rosenfeld
61*5951ced0SHans Rosenfeld #define CPU_ACPI_P0 0
62*5951ced0SHans Rosenfeld #define CPU_IN_TURBO 1
63*5951ced0SHans Rosenfeld
64*5951ced0SHans Rosenfeld /*
65*5951ced0SHans Rosenfeld * MSR for hardware coordination feedback mechanism
66*5951ced0SHans Rosenfeld * - IA32_MPERF: increments in proportion to a fixed frequency
67*5951ced0SHans Rosenfeld * - IA32_APERF: increments in proportion to actual performance
68*5951ced0SHans Rosenfeld */
69*5951ced0SHans Rosenfeld #define IA32_MPERF_MSR 0xE7
70*5951ced0SHans Rosenfeld #define IA32_APERF_MSR 0xE8
71*5951ced0SHans Rosenfeld
72*5951ced0SHans Rosenfeld /*
73*5951ced0SHans Rosenfeld * kstat update function of the turbo mode info
74*5951ced0SHans Rosenfeld */
75*5951ced0SHans Rosenfeld static int
turbo_kstat_update(kstat_t * ksp,int flag)76*5951ced0SHans Rosenfeld turbo_kstat_update(kstat_t *ksp, int flag)
77*5951ced0SHans Rosenfeld {
78*5951ced0SHans Rosenfeld cpupm_mach_turbo_info_t *turbo_info = ksp->ks_private;
79*5951ced0SHans Rosenfeld
80*5951ced0SHans Rosenfeld if (flag == KSTAT_WRITE) {
81*5951ced0SHans Rosenfeld return (EACCES);
82*5951ced0SHans Rosenfeld }
83*5951ced0SHans Rosenfeld
84*5951ced0SHans Rosenfeld /*
85*5951ced0SHans Rosenfeld * update the count in case CPU is in the turbo
86*5951ced0SHans Rosenfeld * mode for a long time
87*5951ced0SHans Rosenfeld */
88*5951ced0SHans Rosenfeld if (turbo_info->in_turbo == CPU_IN_TURBO)
89*5951ced0SHans Rosenfeld update_turbo_info(turbo_info);
90*5951ced0SHans Rosenfeld
91*5951ced0SHans Rosenfeld turbo_kstat.turbo_supported.value.ui32 =
92*5951ced0SHans Rosenfeld turbo_info->turbo_supported;
93*5951ced0SHans Rosenfeld turbo_kstat.t_mcnt.value.ui64 = turbo_info->t_mcnt;
94*5951ced0SHans Rosenfeld turbo_kstat.t_acnt.value.ui64 = turbo_info->t_acnt;
95*5951ced0SHans Rosenfeld
96*5951ced0SHans Rosenfeld return (0);
97*5951ced0SHans Rosenfeld }
98*5951ced0SHans Rosenfeld
99*5951ced0SHans Rosenfeld /*
100*5951ced0SHans Rosenfeld * update the sum of counts and clear MSRs
101*5951ced0SHans Rosenfeld */
102*5951ced0SHans Rosenfeld static void
update_turbo_info(cpupm_mach_turbo_info_t * turbo_info)103*5951ced0SHans Rosenfeld update_turbo_info(cpupm_mach_turbo_info_t *turbo_info)
104*5951ced0SHans Rosenfeld {
105*5951ced0SHans Rosenfeld ulong_t iflag;
106*5951ced0SHans Rosenfeld uint64_t mcnt, acnt;
107*5951ced0SHans Rosenfeld
108*5951ced0SHans Rosenfeld iflag = intr_clear();
109*5951ced0SHans Rosenfeld mcnt = rdmsr(IA32_MPERF_MSR);
110*5951ced0SHans Rosenfeld acnt = rdmsr(IA32_APERF_MSR);
111*5951ced0SHans Rosenfeld wrmsr(IA32_MPERF_MSR, 0);
112*5951ced0SHans Rosenfeld wrmsr(IA32_APERF_MSR, 0);
113*5951ced0SHans Rosenfeld turbo_info->t_mcnt += mcnt;
114*5951ced0SHans Rosenfeld turbo_info->t_acnt += acnt;
115*5951ced0SHans Rosenfeld intr_restore(iflag);
116*5951ced0SHans Rosenfeld }
117*5951ced0SHans Rosenfeld
118*5951ced0SHans Rosenfeld /*
119*5951ced0SHans Rosenfeld * Get count of MPERF/APERF MSR
120*5951ced0SHans Rosenfeld */
121*5951ced0SHans Rosenfeld static void
get_turbo_info(cpupm_mach_turbo_info_t * turbo_info)122*5951ced0SHans Rosenfeld get_turbo_info(cpupm_mach_turbo_info_t *turbo_info)
123*5951ced0SHans Rosenfeld {
124*5951ced0SHans Rosenfeld ulong_t iflag;
125*5951ced0SHans Rosenfeld uint64_t mcnt, acnt;
126*5951ced0SHans Rosenfeld
127*5951ced0SHans Rosenfeld iflag = intr_clear();
128*5951ced0SHans Rosenfeld mcnt = rdmsr(IA32_MPERF_MSR);
129*5951ced0SHans Rosenfeld acnt = rdmsr(IA32_APERF_MSR);
130*5951ced0SHans Rosenfeld turbo_info->t_mcnt += mcnt;
131*5951ced0SHans Rosenfeld turbo_info->t_acnt += acnt;
132*5951ced0SHans Rosenfeld intr_restore(iflag);
133*5951ced0SHans Rosenfeld }
134*5951ced0SHans Rosenfeld
135*5951ced0SHans Rosenfeld /*
136*5951ced0SHans Rosenfeld * Clear MPERF/APERF MSR
137*5951ced0SHans Rosenfeld */
138*5951ced0SHans Rosenfeld static void
reset_turbo_info(void)139*5951ced0SHans Rosenfeld reset_turbo_info(void)
140*5951ced0SHans Rosenfeld {
141*5951ced0SHans Rosenfeld ulong_t iflag;
142*5951ced0SHans Rosenfeld
143*5951ced0SHans Rosenfeld iflag = intr_clear();
144*5951ced0SHans Rosenfeld wrmsr(IA32_MPERF_MSR, 0);
145*5951ced0SHans Rosenfeld wrmsr(IA32_APERF_MSR, 0);
146*5951ced0SHans Rosenfeld intr_restore(iflag);
147*5951ced0SHans Rosenfeld }
148*5951ced0SHans Rosenfeld
149*5951ced0SHans Rosenfeld /*
150*5951ced0SHans Rosenfeld * sum up the count of one CPU_ACPI_P0 transition
151*5951ced0SHans Rosenfeld */
152*5951ced0SHans Rosenfeld void
cpupm_record_turbo_info(cpupm_mach_turbo_info_t * turbo_info,uint32_t cur_state,uint32_t req_state)153*5951ced0SHans Rosenfeld cpupm_record_turbo_info(cpupm_mach_turbo_info_t *turbo_info,
154*5951ced0SHans Rosenfeld uint32_t cur_state, uint32_t req_state)
155*5951ced0SHans Rosenfeld {
156*5951ced0SHans Rosenfeld if (!turbo_info->turbo_supported)
157*5951ced0SHans Rosenfeld return;
158*5951ced0SHans Rosenfeld /*
159*5951ced0SHans Rosenfeld * enter P0 state
160*5951ced0SHans Rosenfeld */
161*5951ced0SHans Rosenfeld if (req_state == CPU_ACPI_P0) {
162*5951ced0SHans Rosenfeld reset_turbo_info();
163*5951ced0SHans Rosenfeld turbo_info->in_turbo = CPU_IN_TURBO;
164*5951ced0SHans Rosenfeld }
165*5951ced0SHans Rosenfeld /*
166*5951ced0SHans Rosenfeld * Leave P0 state
167*5951ced0SHans Rosenfeld */
168*5951ced0SHans Rosenfeld else if (cur_state == CPU_ACPI_P0) {
169*5951ced0SHans Rosenfeld turbo_info->in_turbo = 0;
170*5951ced0SHans Rosenfeld get_turbo_info(turbo_info);
171*5951ced0SHans Rosenfeld }
172*5951ced0SHans Rosenfeld }
173*5951ced0SHans Rosenfeld
174*5951ced0SHans Rosenfeld cpupm_mach_turbo_info_t *
cpupm_turbo_init(cpu_t * cp)175*5951ced0SHans Rosenfeld cpupm_turbo_init(cpu_t *cp)
176*5951ced0SHans Rosenfeld {
177*5951ced0SHans Rosenfeld cpupm_mach_turbo_info_t *turbo_info;
178*5951ced0SHans Rosenfeld
179*5951ced0SHans Rosenfeld turbo_info = kmem_zalloc(sizeof (cpupm_mach_turbo_info_t), KM_SLEEP);
180*5951ced0SHans Rosenfeld
181*5951ced0SHans Rosenfeld turbo_info->turbo_supported = 1;
182*5951ced0SHans Rosenfeld turbo_info->turbo_ksp = kstat_create("turbo", cp->cpu_id,
183*5951ced0SHans Rosenfeld "turbo", "misc", KSTAT_TYPE_NAMED,
184*5951ced0SHans Rosenfeld sizeof (turbo_kstat) / sizeof (kstat_named_t),
185*5951ced0SHans Rosenfeld KSTAT_FLAG_VIRTUAL);
186*5951ced0SHans Rosenfeld
187*5951ced0SHans Rosenfeld if (turbo_info->turbo_ksp == NULL) {
188*5951ced0SHans Rosenfeld cmn_err(CE_NOTE, "kstat_create(turbo) fail");
189*5951ced0SHans Rosenfeld } else {
190*5951ced0SHans Rosenfeld turbo_info->turbo_ksp->ks_data = &turbo_kstat;
191*5951ced0SHans Rosenfeld turbo_info->turbo_ksp->ks_lock = &turbo_mutex;
192*5951ced0SHans Rosenfeld turbo_info->turbo_ksp->ks_update = turbo_kstat_update;
193*5951ced0SHans Rosenfeld turbo_info->turbo_ksp->ks_data_size += MAXNAMELEN;
194*5951ced0SHans Rosenfeld turbo_info->turbo_ksp->ks_private = turbo_info;
195*5951ced0SHans Rosenfeld
196*5951ced0SHans Rosenfeld kstat_install(turbo_info->turbo_ksp);
197*5951ced0SHans Rosenfeld }
198*5951ced0SHans Rosenfeld
199*5951ced0SHans Rosenfeld return (turbo_info);
200*5951ced0SHans Rosenfeld }
201*5951ced0SHans Rosenfeld
202*5951ced0SHans Rosenfeld void
cpupm_turbo_fini(cpupm_mach_turbo_info_t * turbo_info)203*5951ced0SHans Rosenfeld cpupm_turbo_fini(cpupm_mach_turbo_info_t *turbo_info)
204*5951ced0SHans Rosenfeld {
205*5951ced0SHans Rosenfeld if (turbo_info->turbo_ksp != NULL)
206*5951ced0SHans Rosenfeld kstat_delete(turbo_info->turbo_ksp);
207*5951ced0SHans Rosenfeld kmem_free(turbo_info, sizeof (cpupm_mach_turbo_info_t));
208*5951ced0SHans Rosenfeld }
209