xref: /illumos-gate/usr/src/uts/i86pc/os/cpupm/turbo.c (revision 5951ced0ac070feedc4707fba3149df0b5b406f8)
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