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