xref: /illumos-gate/usr/src/uts/i86pc/sys/hpet_acpi.h (revision fdcca78f)
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #ifndef	_HPET_ACPI_H
26 #define	_HPET_ACPI_H
27 
28 #if defined(_KERNEL)
29 #include <sys/acpi/acpi.h>
30 #include <sys/acpi/actbl1.h>
31 #include <sys/acpica.h>
32 #endif	/* defined(_KERNEL) */
33 
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 /*
39  * illumos uses an HPET Timer to generate interrupts for CPUs in Deep C-state
40  * with stalled LAPIC Timers.  All CPUs use one HPET timer.  The timer's
41  * interrupt targets one CPU (via the I/O APIC).  The one CPU that receives
42  * the HPET's interrupt wakes up other CPUs as needed during the HPET Interrupt
43  * Service Routing.  The HPET ISR uses poke_cpus to wake up other CPUs with an
44  * Inter Processor Interrupt.
45  *
46  * Please see the Intel Programmer's guides.  Interrupts are disabled before
47  * a CPU Halts into Deep C-state.  (This allows CPU-hardware-specific cleanup
48  * before servicing interrupts.)  When a Deep C-state CPU wakes up (due to
49  * an externally generated interrupt), it resumes execution where it halted.
50  * The CPU returning from Deep C-state must enable interrupts before it will
51  * handle the pending interrupt that woke it from Deep C-state.
52  *
53  *
54  * HPET bits as defined in the Intel IA-PC HPET Specification Rev 1.0a.
55  *
56  * The physical address space layout of the memory mapped HPET looks like this:
57  *
58  * struct hpet {
59  *	uint64_t	gen_cap;
60  *	uint64_t	res1;
61  *	uint64_t	gen_config;
62  *	uint64_t	res2;
63  *	uint64_t	gen_inter_stat;
64  *	uint64_t	res3;
65  *	uint64_t	main_counter_value;
66  *	uint64_t	res4;
67  *	stuct hpet_timer {
68  *		uint64_t	config_and_capability;
69  *		uint64_t	comparator_value;
70  *		uint64_t	FSB_interrupt_route;
71  *		uint64_t	reserved;
72  *	} timers[32];
73  * }
74  *
75  * There are 32 possible timers in an HPET.  Only the first 3 timers are
76  * required.  The other 29 timers are optional.
77  *
78  * HPETs can have 64-bit or 32-bit timers.  Timers/compare registers can
79  * be 64-bit or 32-bit and can be a mixture of both.
80  * The first two timers are not used.  The HPET spec intends the first two
81  * timers to be used as "legacy replacement" for the PIT and RTC timers.
82  *
83  * illumos uses the first available non-legacy replacement timer as a proxy
84  * timer for processor Local APIC Timers that stop in deep idle C-states.
85  */
86 
87 /*
88  * We only use HPET table 1 on x86.  Typical x86 systems only have 1 HPET.
89  * ACPI allows for multiple HPET tables to describe multiple HPETs.
90  */
91 #define	HPET_TABLE_1		(1)
92 
93 /*
94  * HPET Specification 1.0a defines the HPET to occupy 1024 bytes regardless of
95  * the number of counters (3 to 32) in this implementation.
96  */
97 #define	HPET_SIZE		(1024)
98 
99 /*
100  * Offsets of HPET registers and macros to access them from HPET base address.
101  */
102 #define	HPET_GEN_CAP_OFFSET		(0)
103 #define	HPET_GEN_CONFIG_OFFSET		(0x10)
104 #define	HPET_GEN_INTR_STAT_OFFSET	(0x20)
105 #define	HPET_MAIN_COUNTER_OFFSET	(0xF0)
106 #define	HPET_TIMER_N_CONF_OFFSET(n)	(0x100 + (n * 0x20))
107 #define	HPET_TIMER_N_COMP_OFFSET(n)	(0x108 + (n * 0x20))
108 
109 #define	OFFSET_ADDR(a, o)		(((uintptr_t)(a)) + (o))
110 #define	HPET_GEN_CAP_ADDRESS(la)				\
111 		    OFFSET_ADDR(la, HPET_GEN_CAP_OFFSET)
112 #define	HPET_GEN_CONFIG_ADDRESS(la)				\
113 		    OFFSET_ADDR(la, HPET_GEN_CONFIG_OFFSET)
114 #define	HPET_GEN_INTR_STAT_ADDRESS(la)				\
115 		    OFFSET_ADDR(la, HPET_GEN_INTR_STAT_OFFSET)
116 #define	HPET_MAIN_COUNTER_ADDRESS(la)				\
117 		    OFFSET_ADDR(la, HPET_MAIN_COUNTER_OFFSET)
118 #define	HPET_TIMER_N_CONF_ADDRESS(la, n)			\
119 		    OFFSET_ADDR(la, HPET_TIMER_N_CONF_OFFSET(n))
120 #define	HPET_TIMER_N_COMP_ADDRESS(la, n)			\
121 		    OFFSET_ADDR(la, HPET_TIMER_N_COMP_OFFSET(n))
122 
123 /*
124  * HPET General Capabilities and ID Register
125  */
126 typedef struct hpet_gen_cap {
127 	uint32_t	counter_clk_period;	/* period in femtoseconds */
128 	uint32_t	vendor_id	:16;	/* vendor */
129 	uint32_t	leg_route_cap	:1;	/* 1=LegacyReplacemnt support */
130 	uint32_t	res1		:1;	/* reserved */
131 	uint32_t	count_size_cap	:1;	/* 0=32bit, 1=64bit wide */
132 	uint32_t	num_tim_cap	:5;	/* number of timers -1 */
133 	uint32_t	rev_id		:8;	/* revision number */
134 } hpet_gen_cap_t;
135 
136 /*
137  * Macros to parse fields of the hpet General Capabilities and ID Register.
138  */
139 #define	HPET_GCAP_CNTR_CLK_PERIOD(l)	(l >> 32)
140 #define	HPET_GCAP_VENDOR_ID(l)		BITX(l, 31, 16)
141 #define	HPET_GCAP_LEG_ROUTE_CAP(l)	BITX(l, 15, 15)
142 #define	HPET_GCAP_CNT_SIZE_CAP(l)	BITX(l, 13, 13)
143 #define	HPET_GCAP_NUM_TIM_CAP(l)	BITX(l, 12, 8)
144 #define	HPET_GCAP_REV_ID(l)		BITX(l, 7, 0)
145 
146 /*
147  * From HPET spec "The value in this field must be less than or equal to":
148  */
149 #define	HPET_MAX_CLK_PERIOD	(0x5F5E100)
150 
151 /*
152  * Femto seconds in a second.
153  */
154 #if defined(__i386)
155 #define	HPET_FEMTO_TO_NANO	(1000000LL)
156 #define	HRTIME_TO_HPET_TICKS(t)	(((t) * HPET_FEMTO_TO_NANO) / hpet_info.period)
157 #else
158 #define	HPET_FEMTO_TO_NANO	(1000000L)
159 #define	HRTIME_TO_HPET_TICKS(t)	(((t) * HPET_FEMTO_TO_NANO) / hpet_info.period)
160 #endif	/* (__i386) */
161 
162 /*
163  * HPET General Configuration Register
164  */
165 typedef struct hpet_gen_config_bitfield {
166 	uint32_t	leg_rt_cnf :1;		/* legacy replacement route */
167 	uint32_t	enable_cnf :1;		/* overal enable */
168 } hpet_gen_conf_t;
169 
170 /*
171  * General Configuration Register fields.
172  */
173 #define	HPET_GCFR_LEG_RT_CNF		(0x2)		/* bit field value */
174 #define	HPET_GCFR_ENABLE_CNF		(0x1)		/* bit field value */
175 #define	HPET_GCFR_LEG_RT_CNF_BITX(l)	BITX(l, 1, 1)
176 #define	HPET_GCFR_ENABLE_CNF_BITX(l)	BITX(l, 0, 0)
177 
178 /*
179  * General Interrupt Status Register.
180  */
181 #define	HPET_GIS_T2_INT_STS(l)		BITX(l, 2, 2)
182 #define	HPET_GIS_T1_INT_STS(l)		BITX(l, 1, 1)
183 #define	HPET_GIS_T0_INT_STS(l)		BITX(l, 0, 0)
184 #define	HPET_GIS_TN_INT_STS(l, n)	BITX(l, n, n)
185 
186 #define	HPET_INTR_STATUS_MASK(timer)	((uint64_t)1 << (timer))
187 
188 /*
189  * HPET Timer N Configuration and Capabilities Register
190  */
191 typedef struct hpet_TN_conf_cap {
192 	uint32_t	int_route_cap;		/* available I/O APIC intrups */
193 	uint32_t	res1		:16;	/* reserved */
194 	uint32_t	fsb_int_del_cap	:1;	/* FSB interrupt supported */
195 	uint32_t	fsb_int_en_cnf	:1;	/* Set FSB intr delivery */
196 	uint32_t	int_route_cnf	:5;	/* I/O APIC interrupt to use */
197 	uint32_t	mode32_cnf	:1;	/* Force 32-bit mode */
198 	uint32_t	res2		:1;	/* reserved */
199 	uint32_t	val_set_cnf	:1;	/* Set periodic mode accumula */
200 	uint32_t	size_cap	:1;	/* 1=64bit, 0=32bit timer */
201 	uint32_t	per_int_cap	:1;	/* 1=periodic mode supported */
202 	uint32_t	type_cnf	:1;	/* Enable periodic mode */
203 	uint32_t	int_enb_cnf	:1;	/* Enable interrupt generat */
204 	uint32_t	int_type_cnf	:1;	/* 0=edge, 1=level triggered */
205 	uint32_t	res3		:1;	/* reserved */
206 } hpet_TN_conf_cap_t;
207 
208 /*
209  * There are 3 to 32 timers on each HPET.
210  */
211 #define	HPET_TIMER_N_INT_ROUTE_CAP(l)	(l >> 32)
212 #define	HPET_TIMER_N_INT_TYPE_CNF(l)	BITX(l, 1, 1)
213 #define	HPET_TIMER_N_INT_ENB_CNF(l)	BITX(l, 2, 2)
214 #define	HPET_TIMER_N_TYPE_CNF(l)	BITX(l, 3, 3)
215 #define	HPET_TIMER_N_PER_INT_CAP(l)	BITX(l, 4, 4)
216 #define	HPET_TIMER_N_SIZE_CAP(l)	BITX(l, 5, 5)
217 #define	HPET_TIMER_N_VAL_SET_CNF(l)	BITX(l, 6, 6)
218 #define	HPET_TIMER_N_MODE32_CNF(l)	BITX(l, 8, 8)
219 #define	HPET_TIMER_N_INT_ROUTE_CNF(l)	BITX(l, 13, 9)
220 #define	HPET_TIMER_N_FSB_EN_CNF(l)	BITX(l, 14, 14)
221 #define	HPET_TIMER_N_FSB_INT_DEL_CAP(l)	BITX(l, 15, 15)
222 
223 #define	HPET_TIMER_N_INT_TYPE_CNF_BIT	(1 << 1)
224 #define	HPET_TIMER_N_INT_ENB_CNF_BIT	(1 << 2)
225 #define	HPET_TIMER_N_TYPE_CNF_BIT	(1 << 3)
226 #define	HPET_TIMER_N_FSB_EN_CNF_BIT	(1 << 14)
227 #define	HPET_TIMER_N_INT_ROUTE_SHIFT(i)	(i << 9)
228 
229 /*
230  * HPET Spec reserves timers 0 and 1 for legacy timer replacement (PIT and RTC).
231  * Available timers for other use such as LACPI proxy during Deep C-State
232  * start at timer 2.
233  */
234 #define	HPET_FIRST_NON_LEGACY_TIMER	(2)
235 
236 /*
237  * HPET timer and interrupt used as LAPIC proxy during deep C-State.
238  */
239 typedef struct cstate_timer {
240 	int	timer;
241 	int	intr;
242 } cstate_timer_t;
243 
244 /*
245  * Data structure of useful HPET device information.
246  */
247 typedef struct hpet_info {
248 	hpet_gen_cap_t	gen_cap;
249 	hpet_gen_conf_t	gen_config;
250 	uint64_t	gen_intrpt_stat;
251 	uint64_t	main_counter_value;
252 	void		*logical_address;	/* HPET VA memory map */
253 	hpet_TN_conf_cap_t *timer_n_config;	/* N Timer config and cap */
254 	uint32_t	num_timers;		/* number of timers */
255 	uint32_t	allocated_timers;	/* bitmap of timers in use */
256 	cstate_timer_t	cstate_timer;	/* HPET Timer used for LAPIC proxy */
257 	uint64_t	hpet_main_counter_reads[2];
258 	hrtime_t	tsc[3];
259 	hrtime_t	period;		/* counter_clk_period in Femto Secs */
260 } hpet_info_t;
261 
262 #if defined(_KERNEL)
263 
264 /*
265  * Spin mutexes are used in several places because idle threads cannot block.
266  * These defines provide a mechanism to break out of spin loops to prevent
267  * system hangs if a CPU can never get the lock (due to an unknown
268  * hardware/software bug).  100 microsecond was chosen after extensive stress
269  * testing.
270  */
271 #define	HPET_SPIN_CHECK		(1000)
272 #define	HPET_SPIN_TIMEOUT	(100000)
273 
274 /*
275  * There is one of these per CPU using the HPET as a proxy for its stalled
276  * local APIC while in c-state >= C2.
277  */
278 typedef hrtime_t hpet_proxy_t;
279 
280 extern ACPI_TABLE_HPET	*hpet_table;
281 extern hpet_info_t	hpet_info;
282 
283 #endif	/* defined(_KERNEL) */
284 
285 #ifdef __cplusplus
286 }
287 #endif
288 
289 #endif	/* _HPET_ACPI_H */
290