summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/os/cpupm/cpupm_intel.c
blob: 04113a94859b89af32f3e56df0c6ce2c01fcee4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright (c) 2009, Intel Corporation.
 * All rights reserved.
 */

/*
 * Intel specific CPU power management support.
 */

#include <sys/x86_archext.h>
#include <sys/cpu_acpi.h>
#include <sys/speedstep.h>
#include <sys/cpupm_throttle.h>
#include <sys/cpu_idle.h>
#include <sys/archsystm.h>

/*
 * The Intel Processor Driver Capabilities (_PDC).
 * See Intel Processor Vendor-Specific ACPI Interface Specification
 * for details.
 */
#define	CPUPM_INTEL_PDC_REVISION	0x1
#define	CPUPM_INTEL_PDC_PS_MSR		0x0001
#define	CPUPM_INTEL_PDC_C1_HALT		0x0002
#define	CPUPM_INTEL_PDC_TS_MSR		0x0004
#define	CPUPM_INTEL_PDC_MP		0x0008
#define	CPUPM_INTEL_PDC_C2C3_MP		0x0010
#define	CPUPM_INTEL_PDC_SW_PSD		0x0020
#define	CPUPM_INTEL_PDC_TSD		0x0080
#define	CPUPM_INTEL_PDC_C1_FFH		0x0100
#define	CPUPM_INTEL_PDC_HW_PSD		0x0800

static uint32_t cpupm_intel_pdccap = 0;

/*
 * MSR for Intel ENERGY_PERF_BIAS feature.
 * The default processor power operation policy is max performance.
 * Power control unit drives to max performance at any energy cost.
 * This MSR is designed to be a power master control knob,
 * it provides 4-bit OS input to the HW for the logical CPU, based on
 * user power-policy preference(scale of 0 to 15). 0 is highest
 * performance, 15 is minimal energy consumption.
 * 7 is a good balance between performance and energy consumption.
 */
#define	IA32_ENERGY_PERF_BIAS_MSR	0x1B0
#define	EPB_MSR_MASK			0xF
#define	EPB_MAX_PERF			0
#define	EPB_BALANCE			7
#define	EPB_MAX_POWER_SAVE		15

/*
 * The value is used to initialize the user power policy preference
 * in IA32_ENERGY_PERF_BIAS_MSR. Variable is used here to allow tuning
 * from the /etc/system file.
 */
uint64_t cpupm_iepb_policy = EPB_MAX_PERF;

static void cpupm_iepb_set_policy(uint64_t power_policy);

boolean_t
cpupm_intel_init(cpu_t *cp)
{
	cpupm_mach_state_t *mach_state =
	    (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
	uint_t family;
	uint_t model;

	if (x86_vendor != X86_VENDOR_Intel)
		return (B_FALSE);

	family = cpuid_getfamily(CPU);
	model = cpuid_getmodel(CPU);

	cpupm_intel_pdccap = CPUPM_INTEL_PDC_MP;

	/*
	 * If we support SpeedStep on this processor, then set the
	 * correct cma_ops for the processor and enable appropriate
	 * _PDC bits.
	 */
	if (speedstep_supported(family, model)) {
		mach_state->ms_pstate.cma_ops = &speedstep_ops;
		cpupm_intel_pdccap |= CPUPM_INTEL_PDC_PS_MSR |
		    CPUPM_INTEL_PDC_C1_HALT | CPUPM_INTEL_PDC_SW_PSD |
		    CPUPM_INTEL_PDC_HW_PSD;
	} else {
		mach_state->ms_pstate.cma_ops = NULL;
	}

	/*
	 * Set the correct tstate_ops for the processor and
	 * enable appropriate _PDC bits.
	 */
	mach_state->ms_tstate.cma_ops = &cpupm_throttle_ops;
	cpupm_intel_pdccap |= CPUPM_INTEL_PDC_TS_MSR |
	    CPUPM_INTEL_PDC_TSD;

	/*
	 * If we support deep cstates on this processor, then set the
	 * correct cstate_ops for the processor and enable appropriate
	 * _PDC bits.
	 */
	mach_state->ms_cstate.cma_ops = &cpu_idle_ops;
	cpupm_intel_pdccap |= CPUPM_INTEL_PDC_C1_HALT |
	    CPUPM_INTEL_PDC_C2C3_MP | CPUPM_INTEL_PDC_C1_FFH;

	/*
	 * _PDC support is optional and the driver should
	 * function even if the _PDC write fails.
	 */
	(void) cpu_acpi_write_pdc(mach_state->ms_acpi_handle,
	    CPUPM_INTEL_PDC_REVISION, 1, &cpupm_intel_pdccap);

	/*
	 * If Intel ENERGY PERFORMANCE BIAS feature is supported,
	 * provides input to the HW, based on user power-policy.
	 */
	if (cpuid_iepb_supported(cp)) {
		cpupm_iepb_set_policy(cpupm_iepb_policy);
	}

	return (B_TRUE);
}

/*
 * ENERGY_PERF_BIAS setting,
 * A hint to HW, based on user power-policy
 */
static void
cpupm_iepb_set_policy(uint64_t iepb_policy)
{
	ulong_t		iflag;
	uint64_t	epb_value;

	epb_value = iepb_policy & EPB_MSR_MASK;

	iflag = intr_clear();
	wrmsr(IA32_ENERGY_PERF_BIAS_MSR, epb_value);
	intr_restore(iflag);
}