1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * Copyright (c) 2009,  Intel Corporation.
27 * All Rights Reserved.
28 */
29
30#ifndef	_CPUPM_MACH_H
31#define	_CPUPM_MACH_H
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37#include <sys/ddi.h>
38#include <sys/sunddi.h>
39#include <sys/cpuvar.h>
40#include <sys/ksynch.h>
41#include <sys/cpu_pm.h>
42
43/*
44 * CPU power domains
45 */
46typedef struct cpupm_state_domains {
47	struct cpupm_state_domains	*pm_next;
48	uint32_t			pm_domain;
49	uint32_t			pm_type;
50	cpuset_t			pm_cpus;
51	kmutex_t			pm_lock;
52} cpupm_state_domains_t;
53
54extern cpupm_state_domains_t *cpupm_pstate_domains;
55extern cpupm_state_domains_t *cpupm_tstate_domains;
56extern cpupm_state_domains_t *cpupm_cstate_domains;
57
58/*
59 * Different processor families have their own technologies for supporting
60 * CPU power management (i.e., Intel has Enhanced SpeedStep for some of its
61 * processors and AMD has PowerNow! for some of its processors). We support
62 * these different technologies via modules that export the interfaces
63 * described below.
64 *
65 * If a module implements the technology that should be used to manage
66 * the current CPU device, then the cpus_init() module should return
67 * succesfully (i.e., return code of 0) and perform any initialization
68 * such that future power transistions can be performed by calling
69 * the cpus_change() interface. And the cpups_fini() interface can be
70 * used to free any resources allocated by cpus_init().
71 */
72typedef struct cpupm_state_ops {
73	char	*cpups_label;
74	int	(*cpus_init)(cpu_t *);
75	void	(*cpus_fini)(cpu_t *);
76	void	(*cpus_change)(cpuset_t, uint32_t);
77	void	(*cpus_stop)(cpu_t *);
78} cpupm_state_ops_t;
79
80/*
81 * Data kept for each C-state power-domain.
82 */
83typedef struct cma_c_state {
84	uint32_t	cs_next_cstate;	/* computed best C-state */
85
86	uint32_t	cs_cnt;		/* times accessed */
87	uint32_t	cs_type;	/* current ACPI idle type */
88
89	hrtime_t	cs_idle_enter;	/* entered idle */
90	hrtime_t	cs_idle_exit;	/* left idle */
91
92	hrtime_t	cs_smpl_start;	/* accounting sample began */
93	hrtime_t	cs_idle;	/* time idle */
94	hrtime_t	cs_smpl_len;	/* sample duration */
95	hrtime_t	cs_smpl_idle;	/* idle time in last sample */
96	uint64_t	cs_smpl_idle_pct;	/* % idle time in last smpl */
97} cma_c_state_t;
98
99typedef union cma_state {
100	cma_c_state_t	*cstate;
101	uint32_t	pstate;
102} cma_state_t;
103
104typedef struct cpupm_mach_acpi_state {
105	cpupm_state_ops_t	*cma_ops;
106	cpupm_state_domains_t   *cma_domain;
107	cma_state_t		cma_state;
108} cpupm_mach_acpi_state_t;
109
110typedef struct cpupm_mach_turbo_info {
111	kstat_t		*turbo_ksp;		/* turbo kstat */
112	int		in_turbo;		/* in turbo? */
113	int		turbo_supported;	/* turbo flag */
114	uint64_t	t_mcnt;			/* turbo mcnt */
115	uint64_t	t_acnt;			/* turbo acnt */
116} cpupm_mach_turbo_info_t;
117
118typedef struct cpupm_mach_state {
119	void			*ms_acpi_handle;
120	cpupm_mach_acpi_state_t	ms_pstate;
121	cpupm_mach_acpi_state_t	ms_cstate;
122	cpupm_mach_acpi_state_t	ms_tstate;
123	uint32_t		ms_caps;
124	dev_info_t		*ms_dip;
125	kmutex_t		ms_lock;
126	cpupm_mach_turbo_info_t	*ms_turbo;
127	struct cpupm_notification *ms_handlers;
128} cpupm_mach_state_t;
129
130/*
131 * Constants used by the Processor Device Notification handler
132 * that identify what kind of change has occurred.
133 */
134#define	CPUPM_PPC_CHANGE_NOTIFICATION 0x80
135#define	CPUPM_CST_CHANGE_NOTIFICATION 0x81
136#define	CPUPM_TPC_CHANGE_NOTIFICATION 0x82
137
138typedef void (*CPUPM_NOTIFY_HANDLER)(void *handle, uint32_t val,
139    void *ctx);
140
141typedef struct cpupm_notification {
142	struct cpupm_notification	*nq_next;
143	CPUPM_NOTIFY_HANDLER		nq_handler;
144	void				*nq_ctx;
145} cpupm_notification_t;
146
147/*
148 * If any states are added, then make sure to add them to
149 * CPUPM_ALL_STATES.
150 */
151#define	CPUPM_NO_STATES		0x00
152#define	CPUPM_P_STATES		0x01
153#define	CPUPM_T_STATES		0x02
154#define	CPUPM_C_STATES		0x04
155#define	CPUPM_ALL_STATES	(CPUPM_P_STATES \
156				| CPUPM_T_STATES \
157				| CPUPM_C_STATES)
158
159/*
160 * An error in initializing any of the CPU PM results in disabling
161 * CPU power management.
162 */
163#define	CPUPM_DISABLE() cpupm_disable(CPUPM_ALL_STATES)
164
165#define	CPUPM_SPEED_HZ(unused, mhz) ((uint64_t)mhz * 1000000)
166
167/*
168 * Callbacks used for CPU power management.
169 */
170extern void (*cpupm_ppm_alloc_pstate_domains)(cpu_t *);
171extern void (*cpupm_ppm_free_pstate_domains)(cpu_t *);
172extern void (*cpupm_redefine_topspeed)(void *);
173extern int (*cpupm_get_topspeed_callb)(void *);
174extern void (*cpupm_set_topspeed_callb)(void *, int);
175
176extern void cpupm_init(cpu_t *);
177extern void cpupm_fini(cpu_t *);
178extern void cpupm_start(cpu_t *);
179extern void cpupm_stop(cpu_t *);
180extern boolean_t cpupm_is_ready(cpu_t *);
181extern boolean_t cpupm_is_enabled(uint32_t);
182extern void cpupm_disable(uint32_t);
183extern void cpupm_alloc_domains(cpu_t *, int);
184extern void cpupm_free_domains(cpupm_state_domains_t **);
185extern void cpupm_remove_domains(cpu_t *, int, cpupm_state_domains_t **);
186extern void cpupm_alloc_ms_cstate(cpu_t *cp);
187extern void cpupm_free_ms_cstate(cpu_t *cp);
188extern void cpupm_state_change(cpu_t *, int, int);
189extern id_t cpupm_plat_domain_id(cpu_t *cp, cpupm_dtype_t type);
190extern uint_t cpupm_plat_state_enumerate(cpu_t *, cpupm_dtype_t,
191    cpupm_state_t *);
192extern int cpupm_plat_change_state(cpu_t *, cpupm_state_t *);
193extern uint_t cpupm_get_speeds(cpu_t *, int **);
194extern void cpupm_free_speeds(int *, uint_t);
195extern boolean_t cpupm_power_ready(cpu_t *);
196extern boolean_t cpupm_throttle_ready(cpu_t *);
197extern boolean_t cpupm_cstate_ready(cpu_t *);
198extern void cpupm_add_notify_handler(cpu_t *, CPUPM_NOTIFY_HANDLER, void *);
199extern int cpupm_get_top_speed(cpu_t *);
200extern void cpupm_idle_cstate_data(cma_c_state_t *, int);
201extern void cpupm_wakeup_cstate_data(cma_c_state_t *, hrtime_t);
202extern void cpupm_record_turbo_info(cpupm_mach_turbo_info_t *, uint32_t,
203    uint32_t);
204extern cpupm_mach_turbo_info_t *cpupm_turbo_init(cpu_t *);
205extern void cpupm_turbo_fini(cpupm_mach_turbo_info_t *);
206
207#ifdef __cplusplus
208}
209#endif
210
211#endif	/* _CPUPM_MACH_H */
212