1141236Snjl/*-
2167905Snjl * Copyright (c) 2005-2007 Nate Lawson (SDG)
3141236Snjl * All rights reserved.
4141236Snjl *
5141236Snjl * Redistribution and use in source and binary forms, with or without
6141236Snjl * modification, are permitted provided that the following conditions
7141236Snjl * are met:
8141236Snjl * 1. Redistributions of source code must retain the above copyright
9141236Snjl *    notice, this list of conditions and the following disclaimer.
10141236Snjl * 2. Redistributions in binary form must reproduce the above copyright
11141236Snjl *    notice, this list of conditions and the following disclaimer in the
12141236Snjl *    documentation and/or other materials provided with the distribution.
13141236Snjl *
14141236Snjl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15141236Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16141236Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17141236Snjl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18141236Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19141236Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20141236Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21141236Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22141236Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23141236Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24141236Snjl * SUCH DAMAGE.
25141236Snjl *
26141236Snjl * $FreeBSD$
27141236Snjl */
28141236Snjl
29141236Snjl#ifndef _SYS_CPU_H_
30141236Snjl#define _SYS_CPU_H_
31141236Snjl
32167905Snjl#include <sys/eventhandler.h>
33167905Snjl
34141236Snjl/*
35141236Snjl * CPU device support.
36141236Snjl */
37141236Snjl
38141236Snjl#define CPU_IVAR_PCPU		1
39193155Snwhitehorn#define CPU_IVAR_NOMINAL_MHZ	2
40141236Snjl
41141236Snjlstatic __inline struct pcpu *cpu_get_pcpu(device_t dev)
42141236Snjl{
43141236Snjl	uintptr_t v = 0;
44141236Snjl	BUS_READ_IVAR(device_get_parent(dev), dev, CPU_IVAR_PCPU, &v);
45141236Snjl	return ((struct pcpu *)v);
46141236Snjl}
47141236Snjl
48193155Snwhitehornstatic __inline int32_t cpu_get_nominal_mhz(device_t dev)
49193155Snwhitehorn{
50193155Snwhitehorn	uintptr_t v = 0;
51193155Snwhitehorn	if (BUS_READ_IVAR(device_get_parent(dev), dev,
52193155Snwhitehorn	    CPU_IVAR_NOMINAL_MHZ, &v) != 0)
53193155Snwhitehorn		return (-1);
54193155Snwhitehorn	return ((int32_t)v);
55193155Snwhitehorn}
56193155Snwhitehorn
57141236Snjl/*
58141236Snjl * CPU frequency control interface.
59141236Snjl */
60141236Snjl
61141236Snjl/* Each driver's CPU frequency setting is exported in this format. */
62141236Snjlstruct cf_setting {
63141781Snjl	int	freq;	/* CPU clock in Mhz or 100ths of a percent. */
64141236Snjl	int	volts;	/* Voltage in mV. */
65141236Snjl	int	power;	/* Power consumed in mW. */
66141236Snjl	int	lat;	/* Transition latency in us. */
67141236Snjl	device_t dev;	/* Driver providing this setting. */
68142073Snjl	int	spec[4];/* Driver-specific storage for non-standard info. */
69141236Snjl};
70141236Snjl
71141236Snjl/* Maximum number of settings a given driver can have. */
72141236Snjl#define MAX_SETTINGS		24
73141236Snjl
74141236Snjl/* A combination of settings is a level. */
75141236Snjlstruct cf_level {
76141236Snjl	struct cf_setting	total_set;
77141236Snjl	struct cf_setting	abs_set;
78141236Snjl	struct cf_setting	rel_set[MAX_SETTINGS];
79141236Snjl	int			rel_count;
80141236Snjl	TAILQ_ENTRY(cf_level)	link;
81141236Snjl};
82141236Snjl
83141236SnjlTAILQ_HEAD(cf_level_lst, cf_level);
84141236Snjl
85141236Snjl/* Drivers should set all unknown values to this. */
86141236Snjl#define CPUFREQ_VAL_UNKNOWN	(-1)
87141236Snjl
88141236Snjl/*
89141236Snjl * Every driver offers a type of CPU control.  Absolute levels are mutually
90141236Snjl * exclusive while relative levels modify the current absolute level.  There
91141236Snjl * may be multiple absolute and relative drivers available on a given
92141236Snjl * system.
93141236Snjl *
94141236Snjl * For example, consider a system with two absolute drivers that provide
95141236Snjl * frequency settings of 100, 200 and 300, 400 and a relative driver that
96141236Snjl * provides settings of 50%, 100%.  The cpufreq core would export frequency
97141236Snjl * levels of 50, 100, 150, 200, 300, 400.
98141781Snjl *
99141781Snjl * The "info only" flag signifies that settings returned by
100141781Snjl * CPUFREQ_DRV_SETTINGS cannot be passed to the CPUFREQ_DRV_SET method and
101141781Snjl * are only informational.  This is for some drivers that can return
102141781Snjl * information about settings but rely on another machine-dependent driver
103141781Snjl * for actually performing the frequency transition (e.g., ACPI performance
104141781Snjl * states of type "functional fixed hardware.")
105141236Snjl */
106141781Snjl#define CPUFREQ_TYPE_MASK	0xffff
107141236Snjl#define CPUFREQ_TYPE_RELATIVE	(1<<0)
108141236Snjl#define CPUFREQ_TYPE_ABSOLUTE	(1<<1)
109141781Snjl#define CPUFREQ_FLAG_INFO_ONLY	(1<<16)
110141236Snjl
111141236Snjl/*
112141236Snjl * When setting a level, the caller indicates the priority of this request.
113141236Snjl * Priorities determine, among other things, whether a level can be
114141236Snjl * overridden by other callers.  For example, if the user sets a level but
115141236Snjl * the system thermal driver needs to override it for emergency cooling,
116141236Snjl * the driver would use a higher priority.  Once the event has passed, the
117141236Snjl * driver would call cpufreq to resume any previous level.
118141236Snjl */
119141236Snjl#define CPUFREQ_PRIO_HIGHEST	1000000
120141236Snjl#define CPUFREQ_PRIO_KERN	1000
121141236Snjl#define CPUFREQ_PRIO_USER	100
122141236Snjl#define CPUFREQ_PRIO_LOWEST	0
123141236Snjl
124141236Snjl/*
125141236Snjl * Register and unregister a driver with the cpufreq core.  Once a driver
126141236Snjl * is registered, it must support calls to its CPUFREQ_GET, CPUFREQ_GET_LEVEL,
127141236Snjl * and CPUFREQ_SET methods.  It must also unregister before returning from
128141236Snjl * its DEVICE_DETACH method.
129141236Snjl */
130141236Snjlint	cpufreq_register(device_t dev);
131141236Snjlint	cpufreq_unregister(device_t dev);
132141236Snjl
133167905Snjl/*
134167905Snjl * Notify the cpufreq core that the number of or values for settings have
135167905Snjl * changed.
136167905Snjl */
137167905Snjlint	cpufreq_settings_changed(device_t dev);
138167905Snjl
139167905Snjl/*
140167905Snjl * Eventhandlers that are called before and after a change in frequency.
141167905Snjl * The new level and the result of the change (0 is success) is passed in.
142167905Snjl * If the driver wishes to revoke the change from cpufreq_pre_change, it
143167905Snjl * stores a non-zero error code in the result parameter and the change will
144167905Snjl * not be made.  If the post-change eventhandler gets a non-zero result,
145167905Snjl * no change was made and the previous level remains in effect.  If a change
146167905Snjl * is revoked, the post-change eventhandler is still called with the error
147167905Snjl * value supplied by the revoking driver.  This gives listeners who cached
148167905Snjl * some data in preparation for a level change a chance to clean up.
149167905Snjl */
150167905Snjltypedef void (*cpufreq_pre_notify_fn)(void *, const struct cf_level *, int *);
151167905Snjltypedef void (*cpufreq_post_notify_fn)(void *, const struct cf_level *, int);
152167905SnjlEVENTHANDLER_DECLARE(cpufreq_pre_change, cpufreq_pre_notify_fn);
153167905SnjlEVENTHANDLER_DECLARE(cpufreq_post_change, cpufreq_post_notify_fn);
154167905Snjl
155167905Snjl/*
156167905Snjl * Eventhandler called when the available list of levels changed.
157167905Snjl * The unit number of the device (i.e. "cpufreq0") whose levels changed
158167905Snjl * is provided so the listener can retrieve the new list of levels.
159167905Snjl */
160167905Snjltypedef void (*cpufreq_levels_notify_fn)(void *, int);
161167905SnjlEVENTHANDLER_DECLARE(cpufreq_levels_changed, cpufreq_levels_notify_fn);
162167905Snjl
163141236Snjl/* Allow values to be +/- a bit since sometimes we have to estimate. */
164141236Snjl#define CPUFREQ_CMP(x, y)	(abs((x) - (y)) < 25)
165141236Snjl
166141236Snjl/*
167141236Snjl * Machine-dependent functions.
168141236Snjl */
169141236Snjl
170141236Snjl/* Estimate the current clock rate for the given CPU id. */
171141236Snjlint	cpu_est_clockrate(int cpu_id, uint64_t *rate);
172141236Snjl
173141236Snjl#endif /* !_SYS_CPU_H_ */
174