xref: /titanic_50/usr/src/uts/i86pc/io/hpet_acpi.c (revision a833a696f1726fd5d95ded0820612f465a2dad8d)
10e751525SEric Saxe /*
20e751525SEric Saxe  * CDDL HEADER START
30e751525SEric Saxe  *
40e751525SEric Saxe  * The contents of this file are subject to the terms of the
50e751525SEric Saxe  * Common Development and Distribution License (the "License").
60e751525SEric Saxe  * You may not use this file except in compliance with the License.
70e751525SEric Saxe  *
80e751525SEric Saxe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90e751525SEric Saxe  * or http://www.opensolaris.org/os/licensing.
100e751525SEric Saxe  * See the License for the specific language governing permissions
110e751525SEric Saxe  * and limitations under the License.
120e751525SEric Saxe  *
130e751525SEric Saxe  * When distributing Covered Code, include this CDDL HEADER in each
140e751525SEric Saxe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150e751525SEric Saxe  * If applicable, add the following below this CDDL HEADER, with the
160e751525SEric Saxe  * fields enclosed by brackets "[]" replaced with your own identifying
170e751525SEric Saxe  * information: Portions Copyright [yyyy] [name of copyright owner]
180e751525SEric Saxe  *
190e751525SEric Saxe  * CDDL HEADER END
200e751525SEric Saxe  */
210e751525SEric Saxe /*
225cd376e8SJimmy Vetayases  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
230e751525SEric Saxe  */
240e751525SEric Saxe 
250e751525SEric Saxe #include <sys/hpet_acpi.h>
260e751525SEric Saxe #include <sys/hpet.h>
270e751525SEric Saxe #include <sys/bitmap.h>
280e751525SEric Saxe #include <sys/inttypes.h>
290e751525SEric Saxe #include <sys/time.h>
300e751525SEric Saxe #include <sys/sunddi.h>
310e751525SEric Saxe #include <sys/ksynch.h>
320e751525SEric Saxe #include <sys/apic.h>
330e751525SEric Saxe #include <sys/callb.h>
340e751525SEric Saxe #include <sys/clock.h>
350e751525SEric Saxe #include <sys/archsystm.h>
360e751525SEric Saxe #include <sys/cpupart.h>
370e751525SEric Saxe 
38*7ff178cdSJimmy Vetayases static int hpet_init_proxy(int *hpet_vect, iflag_t *hpet_flags);
39*7ff178cdSJimmy Vetayases static boolean_t hpet_install_proxy(void);
40*7ff178cdSJimmy Vetayases static boolean_t hpet_callback(int code);
41*7ff178cdSJimmy Vetayases static boolean_t hpet_cpr(int code);
42*7ff178cdSJimmy Vetayases static boolean_t hpet_resume(void);
43*7ff178cdSJimmy Vetayases static void hpet_cst_callback(uint32_t code);
44*7ff178cdSJimmy Vetayases static boolean_t hpet_deep_idle_config(int code);
45*7ff178cdSJimmy Vetayases static int hpet_validate_table(ACPI_TABLE_HPET *hpet_table);
46*7ff178cdSJimmy Vetayases static boolean_t hpet_checksum_table(unsigned char *table, unsigned int len);
47*7ff178cdSJimmy Vetayases static void *hpet_memory_map(ACPI_TABLE_HPET *hpet_table);
48*7ff178cdSJimmy Vetayases static int hpet_start_main_counter(hpet_info_t *hip);
49*7ff178cdSJimmy Vetayases static int hpet_stop_main_counter(hpet_info_t *hip);
50*7ff178cdSJimmy Vetayases static uint64_t hpet_read_main_counter_value(hpet_info_t *hip);
51*7ff178cdSJimmy Vetayases static uint64_t hpet_set_leg_rt_cnf(hpet_info_t *hip, uint32_t new_value);
52*7ff178cdSJimmy Vetayases static uint64_t hpet_read_gen_cap(hpet_info_t *hip);
53*7ff178cdSJimmy Vetayases static uint64_t hpet_read_gen_config(hpet_info_t *hip);
54*7ff178cdSJimmy Vetayases static uint64_t hpet_read_gen_intrpt_stat(hpet_info_t *hip);
55*7ff178cdSJimmy Vetayases static uint64_t hpet_read_timer_N_config(hpet_info_t *hip, uint_t n);
56*7ff178cdSJimmy Vetayases static hpet_TN_conf_cap_t hpet_convert_timer_N_config(uint64_t conf);
57*7ff178cdSJimmy Vetayases static void hpet_write_gen_config(hpet_info_t *hip, uint64_t l);
58*7ff178cdSJimmy Vetayases static void hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l);
59*7ff178cdSJimmy Vetayases static void hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l);
60*7ff178cdSJimmy Vetayases static void hpet_write_timer_N_comp(hpet_info_t *hip, uint_t n, uint64_t l);
61*7ff178cdSJimmy Vetayases static void hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n);
62*7ff178cdSJimmy Vetayases static void hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n);
63*7ff178cdSJimmy Vetayases static int hpet_get_IOAPIC_intr_capable_timer(hpet_info_t *hip);
64*7ff178cdSJimmy Vetayases static int hpet_timer_available(uint32_t allocated_timers, uint32_t n);
65*7ff178cdSJimmy Vetayases static void hpet_timer_alloc(uint32_t *allocated_timers, uint32_t n);
66*7ff178cdSJimmy Vetayases static void hpet_timer_set_up(hpet_info_t *hip, uint32_t timer_n,
67*7ff178cdSJimmy Vetayases     uint32_t interrupt);
68*7ff178cdSJimmy Vetayases static uint_t hpet_isr(char *arg);
69*7ff178cdSJimmy Vetayases static uint32_t hpet_install_interrupt_handler(uint_t (*func)(char *),
70*7ff178cdSJimmy Vetayases     int vector);
71*7ff178cdSJimmy Vetayases static void hpet_uninstall_interrupt_handler(void);
72*7ff178cdSJimmy Vetayases static void hpet_expire_all(void);
73*7ff178cdSJimmy Vetayases static boolean_t hpet_guaranteed_schedule(hrtime_t required_wakeup_time);
74*7ff178cdSJimmy Vetayases static boolean_t hpet_use_hpet_timer(hrtime_t *expire);
75*7ff178cdSJimmy Vetayases static void hpet_use_lapic_timer(hrtime_t expire);
76*7ff178cdSJimmy Vetayases static void hpet_init_proxy_data(void);
77*7ff178cdSJimmy Vetayases 
780e751525SEric Saxe /*
790e751525SEric Saxe  * hpet_state_lock is used to synchronize disabling/enabling deep c-states
800e751525SEric Saxe  * and to synchronize suspend/resume.
810e751525SEric Saxe  */
820e751525SEric Saxe static kmutex_t		hpet_state_lock;
830e751525SEric Saxe static struct hpet_state {
840e751525SEric Saxe 	boolean_t	proxy_installed;	/* CBE proxy interrupt setup */
850e751525SEric Saxe 	boolean_t	cpr;			/* currently in CPR */
860e751525SEric Saxe 	boolean_t	cpu_deep_idle;		/* user enable/disable */
870e751525SEric Saxe 	boolean_t	uni_cstate;		/* disable if only one cstate */
880e751525SEric Saxe } hpet_state = { B_FALSE, B_FALSE, B_TRUE, B_TRUE};
890e751525SEric Saxe 
900e751525SEric Saxe uint64_t hpet_spin_check = HPET_SPIN_CHECK;
910e751525SEric Saxe uint64_t hpet_spin_timeout = HPET_SPIN_TIMEOUT;
920e751525SEric Saxe uint64_t hpet_idle_spin_timeout = HPET_SPIN_TIMEOUT;
930e751525SEric Saxe uint64_t hpet_isr_spin_timeout = HPET_SPIN_TIMEOUT;
940e751525SEric Saxe 
950e751525SEric Saxe static kmutex_t		hpet_proxy_lock;	/* lock for lAPIC proxy data */
960e751525SEric Saxe /*
970e751525SEric Saxe  * hpet_proxy_users is a per-cpu array.
980e751525SEric Saxe  */
990e751525SEric Saxe static hpet_proxy_t	*hpet_proxy_users;	/* one per CPU */
1000e751525SEric Saxe 
1010e751525SEric Saxe 
1020e751525SEric Saxe ACPI_TABLE_HPET		*hpet_table;		/* ACPI HPET table */
1030e751525SEric Saxe hpet_info_t		hpet_info;		/* Human readable Information */
1040e751525SEric Saxe 
1050e751525SEric Saxe /*
1060e751525SEric Saxe  * Provide HPET access from unix.so.
1070e751525SEric Saxe  * Set up pointers to access symbols in pcplusmp.
1080e751525SEric Saxe  */
1090e751525SEric Saxe static void
hpet_establish_hooks(void)1100e751525SEric Saxe hpet_establish_hooks(void)
1110e751525SEric Saxe {
1120e751525SEric Saxe 	hpet.install_proxy = &hpet_install_proxy;
1130e751525SEric Saxe 	hpet.callback = &hpet_callback;
1140e751525SEric Saxe 	hpet.use_hpet_timer = &hpet_use_hpet_timer;
1150e751525SEric Saxe 	hpet.use_lapic_timer = &hpet_use_lapic_timer;
1160e751525SEric Saxe }
1170e751525SEric Saxe 
1180e751525SEric Saxe /*
1190e751525SEric Saxe  * Get the ACPI "HPET" table.
1200e751525SEric Saxe  * acpi_probe() calls this function from mp_startup before drivers are loaded.
1210e751525SEric Saxe  * acpi_probe() verified the system is using ACPI before calling this.
1220e751525SEric Saxe  *
1230e751525SEric Saxe  * There may be more than one ACPI HPET table (Itanium only?).
1240e751525SEric Saxe  * Intel's HPET spec defines each timer block to have up to 32 counters and
1250e751525SEric Saxe  * be 1024 bytes long.  There can be more than one timer block of 32 counters.
1260e751525SEric Saxe  * Each timer block would have an additional ACPI HPET table.
1270e751525SEric Saxe  * Typical x86 systems today only have 1 HPET with 3 counters.
1280e751525SEric Saxe  * On x86 we only consume HPET table "1" for now.
1290e751525SEric Saxe  */
1300e751525SEric Saxe int
hpet_acpi_init(int * hpet_vect,iflag_t * hpet_flags)1310e751525SEric Saxe hpet_acpi_init(int *hpet_vect, iflag_t *hpet_flags)
1320e751525SEric Saxe {
1330e751525SEric Saxe 	extern hrtime_t tsc_read(void);
1340e751525SEric Saxe 	extern int	idle_cpu_no_deep_c;
1350e751525SEric Saxe 	extern int	cpuid_deep_cstates_supported(void);
1360e751525SEric Saxe 	void		*la;
1370e751525SEric Saxe 	uint64_t	ret;
1380e751525SEric Saxe 	uint_t		num_timers;
1390e751525SEric Saxe 	uint_t		ti;
1400e751525SEric Saxe 
1410e751525SEric Saxe 	(void) memset(&hpet_info, 0, sizeof (hpet_info));
1420e751525SEric Saxe 	hpet.supported = HPET_NO_SUPPORT;
1430e751525SEric Saxe 
1440e751525SEric Saxe 	if (idle_cpu_no_deep_c)
1450e751525SEric Saxe 		return (DDI_FAILURE);
1460e751525SEric Saxe 
1470e751525SEric Saxe 	if (!cpuid_deep_cstates_supported())
1480e751525SEric Saxe 		return (DDI_FAILURE);
1490e751525SEric Saxe 
1500e751525SEric Saxe 	hpet_establish_hooks();
1510e751525SEric Saxe 
1520e751525SEric Saxe 	/*
1530e751525SEric Saxe 	 * Get HPET ACPI table 1.
1540e751525SEric Saxe 	 */
1550e751525SEric Saxe 	if (ACPI_FAILURE(AcpiGetTable(ACPI_SIG_HPET, HPET_TABLE_1,
1560e751525SEric Saxe 	    (ACPI_TABLE_HEADER **)&hpet_table))) {
1570e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_acpi: unable to get ACPI HPET table");
1580e751525SEric Saxe 		return (DDI_FAILURE);
1590e751525SEric Saxe 	}
1600e751525SEric Saxe 
1610e751525SEric Saxe 	if (hpet_validate_table(hpet_table) != AE_OK) {
1620e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_acpi: invalid HPET table");
1630e751525SEric Saxe 		return (DDI_FAILURE);
1640e751525SEric Saxe 	}
1650e751525SEric Saxe 
1660e751525SEric Saxe 	la = hpet_memory_map(hpet_table);
1670e751525SEric Saxe 	if (la == NULL) {
1680e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_acpi: memory map HPET failed");
1690e751525SEric Saxe 		return (DDI_FAILURE);
1700e751525SEric Saxe 	}
1710e751525SEric Saxe 	hpet_info.logical_address = la;
1720e751525SEric Saxe 
1730e751525SEric Saxe 	ret = hpet_read_gen_cap(&hpet_info);
1740e751525SEric Saxe 	hpet_info.gen_cap.counter_clk_period = HPET_GCAP_CNTR_CLK_PERIOD(ret);
1750e751525SEric Saxe 	hpet_info.gen_cap.vendor_id = HPET_GCAP_VENDOR_ID(ret);
1760e751525SEric Saxe 	hpet_info.gen_cap.leg_route_cap = HPET_GCAP_LEG_ROUTE_CAP(ret);
1770e751525SEric Saxe 	hpet_info.gen_cap.count_size_cap = HPET_GCAP_CNT_SIZE_CAP(ret);
1780e751525SEric Saxe 	/*
1790e751525SEric Saxe 	 * Hardware contains the last timer's number.
1800e751525SEric Saxe 	 * Add 1 to get the number of timers.
1810e751525SEric Saxe 	 */
1820e751525SEric Saxe 	hpet_info.gen_cap.num_tim_cap = HPET_GCAP_NUM_TIM_CAP(ret) + 1;
1830e751525SEric Saxe 	hpet_info.gen_cap.rev_id = HPET_GCAP_REV_ID(ret);
1840e751525SEric Saxe 
1850e751525SEric Saxe 	if (hpet_info.gen_cap.counter_clk_period > HPET_MAX_CLK_PERIOD) {
1860e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_acpi: COUNTER_CLK_PERIOD 0x%lx > 0x%lx",
1870e751525SEric Saxe 		    (long)hpet_info.gen_cap.counter_clk_period,
1880e751525SEric Saxe 		    (long)HPET_MAX_CLK_PERIOD);
1890e751525SEric Saxe 		return (DDI_FAILURE);
1900e751525SEric Saxe 	}
1910e751525SEric Saxe 
1920e751525SEric Saxe 	num_timers = (uint_t)hpet_info.gen_cap.num_tim_cap;
1930e751525SEric Saxe 	if ((num_timers < 3) || (num_timers > 32)) {
1940e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_acpi: invalid number of HPET timers "
1950e751525SEric Saxe 		    "%lx", (long)num_timers);
1960e751525SEric Saxe 		return (DDI_FAILURE);
1970e751525SEric Saxe 	}
1980e751525SEric Saxe 	hpet_info.timer_n_config = (hpet_TN_conf_cap_t *)kmem_zalloc(
1990e751525SEric Saxe 	    num_timers * sizeof (uint64_t), KM_SLEEP);
2000e751525SEric Saxe 
2010e751525SEric Saxe 	ret = hpet_read_gen_config(&hpet_info);
2020e751525SEric Saxe 	hpet_info.gen_config.leg_rt_cnf = HPET_GCFR_LEG_RT_CNF_BITX(ret);
2030e751525SEric Saxe 	hpet_info.gen_config.enable_cnf = HPET_GCFR_ENABLE_CNF_BITX(ret);
2040e751525SEric Saxe 
2050e751525SEric Saxe 	/*
2060e751525SEric Saxe 	 * Solaris does not use the HPET Legacy Replacement Route capabilities.
2070e751525SEric Saxe 	 * This feature has been off by default on test systems.
2080e751525SEric Saxe 	 * The HPET spec does not specify if Legacy Replacement Route is
2090e751525SEric Saxe 	 * on or off by default, so we explicitely set it off here.
2100e751525SEric Saxe 	 * It should not matter which mode the HPET is in since we use
2110e751525SEric Saxe 	 * the first available non-legacy replacement timer: timer 2.
2120e751525SEric Saxe 	 */
2130e751525SEric Saxe 	(void) hpet_set_leg_rt_cnf(&hpet_info, 0);
2140e751525SEric Saxe 
2150e751525SEric Saxe 	ret = hpet_read_gen_config(&hpet_info);
2160e751525SEric Saxe 	hpet_info.gen_config.leg_rt_cnf = HPET_GCFR_LEG_RT_CNF_BITX(ret);
2170e751525SEric Saxe 	hpet_info.gen_config.enable_cnf = HPET_GCFR_ENABLE_CNF_BITX(ret);
2180e751525SEric Saxe 
2190e751525SEric Saxe 	hpet_info.gen_intrpt_stat = hpet_read_gen_intrpt_stat(&hpet_info);
2200e751525SEric Saxe 	hpet_info.main_counter_value = hpet_read_main_counter_value(&hpet_info);
2210e751525SEric Saxe 
2220e751525SEric Saxe 	for (ti = 0; ti < num_timers; ++ti) {
2230e751525SEric Saxe 		ret = hpet_read_timer_N_config(&hpet_info, ti);
2240e751525SEric Saxe 		/*
2250e751525SEric Saxe 		 * Make sure no timers are enabled (think fast reboot or
2260e751525SEric Saxe 		 * virtual hardware).
2270e751525SEric Saxe 		 */
2280e751525SEric Saxe 		if (ret & HPET_TIMER_N_INT_ENB_CNF_BIT) {
2290e751525SEric Saxe 			hpet_disable_timer(&hpet_info, ti);
2300e751525SEric Saxe 			ret &= ~HPET_TIMER_N_INT_ENB_CNF_BIT;
2310e751525SEric Saxe 		}
2320e751525SEric Saxe 
2330e751525SEric Saxe 		hpet_info.timer_n_config[ti] = hpet_convert_timer_N_config(ret);
2340e751525SEric Saxe 	}
2350e751525SEric Saxe 
2360e751525SEric Saxe 	/*
2370e751525SEric Saxe 	 * Be aware the Main Counter may need to be initialized in the future
2380e751525SEric Saxe 	 * if it is used for more than just Deep C-State support.
2390e751525SEric Saxe 	 * The HPET's Main Counter does not need to be initialize to a specific
2400e751525SEric Saxe 	 * value before starting it for use to wake up CPUs from Deep C-States.
2410e751525SEric Saxe 	 */
2420e751525SEric Saxe 	if (hpet_start_main_counter(&hpet_info) != AE_OK) {
2430e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_acpi: hpet_start_main_counter failed");
2440e751525SEric Saxe 		return (DDI_FAILURE);
2450e751525SEric Saxe 	}
2460e751525SEric Saxe 
2470e751525SEric Saxe 	hpet_info.period = hpet_info.gen_cap.counter_clk_period;
2480e751525SEric Saxe 	/*
2490e751525SEric Saxe 	 * Read main counter twice to record HPET latency for debugging.
2500e751525SEric Saxe 	 */
2510e751525SEric Saxe 	hpet_info.tsc[0] = tsc_read();
2520e751525SEric Saxe 	hpet_info.hpet_main_counter_reads[0] =
2530e751525SEric Saxe 	    hpet_read_main_counter_value(&hpet_info);
2540e751525SEric Saxe 	hpet_info.tsc[1] = tsc_read();
2550e751525SEric Saxe 	hpet_info.hpet_main_counter_reads[1] =
2560e751525SEric Saxe 	    hpet_read_main_counter_value(&hpet_info);
2570e751525SEric Saxe 	hpet_info.tsc[2] = tsc_read();
2580e751525SEric Saxe 
2590e751525SEric Saxe 	ret = hpet_read_gen_config(&hpet_info);
2600e751525SEric Saxe 	hpet_info.gen_config.leg_rt_cnf = HPET_GCFR_LEG_RT_CNF_BITX(ret);
2610e751525SEric Saxe 	hpet_info.gen_config.enable_cnf = HPET_GCFR_ENABLE_CNF_BITX(ret);
2620e751525SEric Saxe 
2630e751525SEric Saxe 	/*
2640e751525SEric Saxe 	 * HPET main counter reads are supported now.
2650e751525SEric Saxe 	 */
2660e751525SEric Saxe 	hpet.supported = HPET_TIMER_SUPPORT;
2670e751525SEric Saxe 
2680e751525SEric Saxe 	return (hpet_init_proxy(hpet_vect, hpet_flags));
2690e751525SEric Saxe }
2700e751525SEric Saxe 
2710e751525SEric Saxe void
hpet_acpi_fini(void)2720e751525SEric Saxe hpet_acpi_fini(void)
2730e751525SEric Saxe {
2740e751525SEric Saxe 	if (hpet.supported == HPET_NO_SUPPORT)
2750e751525SEric Saxe 		return;
2760e751525SEric Saxe 	if (hpet.supported >= HPET_TIMER_SUPPORT)
2779aa01d98SBill Holler 		(void) hpet_stop_main_counter(&hpet_info);
2780e751525SEric Saxe 	if (hpet.supported > HPET_TIMER_SUPPORT)
2790e751525SEric Saxe 		hpet_disable_timer(&hpet_info, hpet_info.cstate_timer.timer);
2800e751525SEric Saxe }
2810e751525SEric Saxe 
2820e751525SEric Saxe /*
2830e751525SEric Saxe  * Do initial setup to use a HPET timer as a proxy for Deep C-state stalled
2840e751525SEric Saxe  * LAPIC Timers.  Get a free HPET timer that supports I/O APIC routed interrupt.
2850e751525SEric Saxe  * Setup data to handle the timer's ISR, and add the timer's interrupt.
2860e751525SEric Saxe  *
2870e751525SEric Saxe  * The ddi cannot be use to allocate the HPET timer's interrupt.
2880e751525SEric Saxe  * ioapic_init_intr() in mp_platform_common() later sets up the I/O APIC
2890e751525SEric Saxe  * to handle the HPET timer's interrupt.
2900e751525SEric Saxe  *
2910e751525SEric Saxe  * Note: FSB (MSI) interrupts are not currently supported by Intel HPETs as of
2920e751525SEric Saxe  * ICH9.  The HPET spec allows for MSI.  In the future MSI may be prefered.
2930e751525SEric Saxe  */
2940e751525SEric Saxe static int
hpet_init_proxy(int * hpet_vect,iflag_t * hpet_flags)2950e751525SEric Saxe hpet_init_proxy(int *hpet_vect, iflag_t *hpet_flags)
2960e751525SEric Saxe {
2970e751525SEric Saxe 	if (hpet_get_IOAPIC_intr_capable_timer(&hpet_info) == -1) {
2980e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_acpi: get ioapic intr failed.");
2990e751525SEric Saxe 		return (DDI_FAILURE);
3000e751525SEric Saxe 	}
3010e751525SEric Saxe 
3020e751525SEric Saxe 	hpet_init_proxy_data();
3030e751525SEric Saxe 
3040e751525SEric Saxe 	if (hpet_install_interrupt_handler(&hpet_isr,
3050e751525SEric Saxe 	    hpet_info.cstate_timer.intr) != AE_OK) {
3060e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_acpi: install interrupt failed.");
3070e751525SEric Saxe 		return (DDI_FAILURE);
3080e751525SEric Saxe 	}
3090e751525SEric Saxe 	*hpet_vect = hpet_info.cstate_timer.intr;
3100e751525SEric Saxe 	hpet_flags->intr_el = INTR_EL_LEVEL;
3110e751525SEric Saxe 	hpet_flags->intr_po = INTR_PO_ACTIVE_HIGH;
3120e751525SEric Saxe 	hpet_flags->bustype = BUS_PCI;		/*  we *do* conform to PCI */
3130e751525SEric Saxe 
3140e751525SEric Saxe 	/*
3150e751525SEric Saxe 	 * Avoid a possibly stuck interrupt by programing the HPET's timer here
3160e751525SEric Saxe 	 * before the I/O APIC is programmed to handle this interrupt.
3170e751525SEric Saxe 	 */
3180e751525SEric Saxe 	hpet_timer_set_up(&hpet_info, hpet_info.cstate_timer.timer,
3190e751525SEric Saxe 	    hpet_info.cstate_timer.intr);
3200e751525SEric Saxe 
3210e751525SEric Saxe 	/*
3220e751525SEric Saxe 	 * All HPET functionality is supported.
3230e751525SEric Saxe 	 */
3240e751525SEric Saxe 	hpet.supported = HPET_FULL_SUPPORT;
3250e751525SEric Saxe 	return (DDI_SUCCESS);
3260e751525SEric Saxe }
3270e751525SEric Saxe 
3280e751525SEric Saxe /*
3290e751525SEric Saxe  * Called by kernel if it can support Deep C-States.
3300e751525SEric Saxe  */
3310e751525SEric Saxe static boolean_t
hpet_install_proxy(void)3320e751525SEric Saxe hpet_install_proxy(void)
3330e751525SEric Saxe {
3340e751525SEric Saxe 	if (hpet_state.proxy_installed == B_TRUE)
3350e751525SEric Saxe 		return (B_TRUE);
3360e751525SEric Saxe 
3370e751525SEric Saxe 	if (hpet.supported != HPET_FULL_SUPPORT)
3380e751525SEric Saxe 		return (B_FALSE);
3390e751525SEric Saxe 
3400e751525SEric Saxe 	hpet_enable_timer(&hpet_info, hpet_info.cstate_timer.timer);
3410e751525SEric Saxe 	hpet_state.proxy_installed = B_TRUE;
3420e751525SEric Saxe 
3430e751525SEric Saxe 	return (B_TRUE);
3440e751525SEric Saxe }
3450e751525SEric Saxe 
3460e751525SEric Saxe /*
3470e751525SEric Saxe  * Remove the interrupt that was added with add_avintr() in
3480e751525SEric Saxe  * hpet_install_interrupt_handler().
3490e751525SEric Saxe  */
3500e751525SEric Saxe static void
hpet_uninstall_interrupt_handler(void)3510e751525SEric Saxe hpet_uninstall_interrupt_handler(void)
3520e751525SEric Saxe {
3530e751525SEric Saxe 	rem_avintr(NULL, CBE_HIGH_PIL, (avfunc)&hpet_isr,
3540e751525SEric Saxe 	    hpet_info.cstate_timer.intr);
3550e751525SEric Saxe }
3560e751525SEric Saxe 
3570e751525SEric Saxe static int
hpet_validate_table(ACPI_TABLE_HPET * hpet_table)3580e751525SEric Saxe hpet_validate_table(ACPI_TABLE_HPET *hpet_table)
3590e751525SEric Saxe {
3600e751525SEric Saxe 	ACPI_TABLE_HEADER	*table_header = (ACPI_TABLE_HEADER *)hpet_table;
3610e751525SEric Saxe 
3620e751525SEric Saxe 	if (table_header->Length != sizeof (ACPI_TABLE_HPET)) {
3630e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_validate_table: Length %lx != sizeof ("
3640e751525SEric Saxe 		    "ACPI_TABLE_HPET) %lx.",
3650e751525SEric Saxe 		    (unsigned long)((ACPI_TABLE_HEADER *)hpet_table)->Length,
3660e751525SEric Saxe 		    (unsigned long)sizeof (ACPI_TABLE_HPET));
3670e751525SEric Saxe 		return (AE_ERROR);
3680e751525SEric Saxe 	}
3690e751525SEric Saxe 
3700e751525SEric Saxe 	if (!ACPI_COMPARE_NAME(table_header->Signature, ACPI_SIG_HPET)) {
3710e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_validate_table: Invalid HPET table "
3720e751525SEric Saxe 		    "signature");
3730e751525SEric Saxe 		return (AE_ERROR);
3740e751525SEric Saxe 	}
3750e751525SEric Saxe 
3760e751525SEric Saxe 	if (!hpet_checksum_table((unsigned char *)hpet_table,
3770e751525SEric Saxe 	    (unsigned int)table_header->Length)) {
3780e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_validate_table: Invalid HPET checksum");
3790e751525SEric Saxe 		return (AE_ERROR);
3800e751525SEric Saxe 	}
3810e751525SEric Saxe 
3820e751525SEric Saxe 	/*
3830e751525SEric Saxe 	 * Sequence should be table number - 1.  We are using table 1.
3840e751525SEric Saxe 	 */
3850e751525SEric Saxe 	if (hpet_table->Sequence != HPET_TABLE_1 - 1) {
3860e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_validate_table: Invalid Sequence %lx",
3870e751525SEric Saxe 		    (long)hpet_table->Sequence);
3880e751525SEric Saxe 		return (AE_ERROR);
3890e751525SEric Saxe 	}
3900e751525SEric Saxe 
3910e751525SEric Saxe 	return (AE_OK);
3920e751525SEric Saxe }
3930e751525SEric Saxe 
3940e751525SEric Saxe static boolean_t
hpet_checksum_table(unsigned char * table,unsigned int length)3950e751525SEric Saxe hpet_checksum_table(unsigned char *table, unsigned int length)
3960e751525SEric Saxe {
3970e751525SEric Saxe 	unsigned char	checksum = 0;
3980e751525SEric Saxe 	int		i;
3990e751525SEric Saxe 
4000e751525SEric Saxe 	for (i = 0; i < length; ++i, ++table)
4010e751525SEric Saxe 		checksum += *table;
4020e751525SEric Saxe 
4030e751525SEric Saxe 	return (checksum == 0);
4040e751525SEric Saxe }
4050e751525SEric Saxe 
4060e751525SEric Saxe static void *
hpet_memory_map(ACPI_TABLE_HPET * hpet_table)4070e751525SEric Saxe hpet_memory_map(ACPI_TABLE_HPET *hpet_table)
4080e751525SEric Saxe {
4090e751525SEric Saxe 	return (AcpiOsMapMemory(hpet_table->Address.Address, HPET_SIZE));
4100e751525SEric Saxe }
4110e751525SEric Saxe 
4120e751525SEric Saxe static int
hpet_start_main_counter(hpet_info_t * hip)4130e751525SEric Saxe hpet_start_main_counter(hpet_info_t *hip)
4140e751525SEric Saxe {
4150e751525SEric Saxe 	uint64_t	*gcr_ptr;
4160e751525SEric Saxe 	uint64_t	gcr;
4170e751525SEric Saxe 
4180e751525SEric Saxe 	gcr_ptr = (uint64_t *)HPET_GEN_CONFIG_ADDRESS(hip->logical_address);
4190e751525SEric Saxe 	gcr = *gcr_ptr;
4200e751525SEric Saxe 
4210e751525SEric Saxe 	gcr |= HPET_GCFR_ENABLE_CNF;
4220e751525SEric Saxe 	*gcr_ptr = gcr;
4230e751525SEric Saxe 	gcr = *gcr_ptr;
4240e751525SEric Saxe 
4250e751525SEric Saxe 	return (gcr & HPET_GCFR_ENABLE_CNF ? AE_OK : ~AE_OK);
4260e751525SEric Saxe }
4270e751525SEric Saxe 
4280e751525SEric Saxe static int
hpet_stop_main_counter(hpet_info_t * hip)4290e751525SEric Saxe hpet_stop_main_counter(hpet_info_t *hip)
4300e751525SEric Saxe {
4310e751525SEric Saxe 	uint64_t	*gcr_ptr;
4320e751525SEric Saxe 	uint64_t	gcr;
4330e751525SEric Saxe 
4340e751525SEric Saxe 	gcr_ptr = (uint64_t *)HPET_GEN_CONFIG_ADDRESS(hip->logical_address);
4350e751525SEric Saxe 	gcr = *gcr_ptr;
4360e751525SEric Saxe 
4370e751525SEric Saxe 	gcr &= ~HPET_GCFR_ENABLE_CNF;
4380e751525SEric Saxe 	*gcr_ptr = gcr;
4390e751525SEric Saxe 	gcr = *gcr_ptr;
4400e751525SEric Saxe 
4410e751525SEric Saxe 	return (gcr & HPET_GCFR_ENABLE_CNF ? ~AE_OK : AE_OK);
4420e751525SEric Saxe }
4430e751525SEric Saxe 
4440e751525SEric Saxe /*
4450e751525SEric Saxe  * Set the Legacy Replacement Route bit.
4460e751525SEric Saxe  * This should be called before setting up timers.
4470e751525SEric Saxe  * The HPET specification is silent regarding setting this after timers are
4480e751525SEric Saxe  * programmed.
4490e751525SEric Saxe  */
4500e751525SEric Saxe static uint64_t
hpet_set_leg_rt_cnf(hpet_info_t * hip,uint32_t new_value)4510e751525SEric Saxe hpet_set_leg_rt_cnf(hpet_info_t *hip, uint32_t new_value)
4520e751525SEric Saxe {
4530e751525SEric Saxe 	uint64_t gen_conf = hpet_read_gen_config(hip);
4540e751525SEric Saxe 
4550e751525SEric Saxe 	switch (new_value) {
4560e751525SEric Saxe 	case 0:
4570e751525SEric Saxe 		gen_conf &= ~HPET_GCFR_LEG_RT_CNF;
4580e751525SEric Saxe 		break;
4590e751525SEric Saxe 
4600e751525SEric Saxe 	case HPET_GCFR_LEG_RT_CNF:
4610e751525SEric Saxe 		gen_conf |= HPET_GCFR_LEG_RT_CNF;
4620e751525SEric Saxe 		break;
4630e751525SEric Saxe 
4640e751525SEric Saxe 	default:
4650e751525SEric Saxe 		ASSERT(new_value == 0 || new_value == HPET_GCFR_LEG_RT_CNF);
4660e751525SEric Saxe 		break;
4670e751525SEric Saxe 	}
4680e751525SEric Saxe 	hpet_write_gen_config(hip, gen_conf);
4690e751525SEric Saxe 	return (gen_conf);
4700e751525SEric Saxe }
4710e751525SEric Saxe 
4720e751525SEric Saxe static uint64_t
hpet_read_gen_cap(hpet_info_t * hip)4730e751525SEric Saxe hpet_read_gen_cap(hpet_info_t *hip)
4740e751525SEric Saxe {
4750e751525SEric Saxe 	return (*(uint64_t *)HPET_GEN_CAP_ADDRESS(hip->logical_address));
4760e751525SEric Saxe }
4770e751525SEric Saxe 
4780e751525SEric Saxe static uint64_t
hpet_read_gen_config(hpet_info_t * hip)4790e751525SEric Saxe hpet_read_gen_config(hpet_info_t *hip)
4800e751525SEric Saxe {
4810e751525SEric Saxe 	return (*(uint64_t *)
4820e751525SEric Saxe 	    HPET_GEN_CONFIG_ADDRESS(hip->logical_address));
4830e751525SEric Saxe }
4840e751525SEric Saxe 
4850e751525SEric Saxe static uint64_t
hpet_read_gen_intrpt_stat(hpet_info_t * hip)4860e751525SEric Saxe hpet_read_gen_intrpt_stat(hpet_info_t *hip)
4870e751525SEric Saxe {
4880e751525SEric Saxe 	hip->gen_intrpt_stat = *(uint64_t *)HPET_GEN_INTR_STAT_ADDRESS(
4890e751525SEric Saxe 	    hip->logical_address);
4900e751525SEric Saxe 	return (hip->gen_intrpt_stat);
4910e751525SEric Saxe }
4920e751525SEric Saxe 
4930e751525SEric Saxe static uint64_t
hpet_read_timer_N_config(hpet_info_t * hip,uint_t n)4940e751525SEric Saxe hpet_read_timer_N_config(hpet_info_t *hip, uint_t n)
4950e751525SEric Saxe {
4960e751525SEric Saxe 	uint64_t conf = *(uint64_t *)HPET_TIMER_N_CONF_ADDRESS(
4970e751525SEric Saxe 	    hip->logical_address, n);
4980e751525SEric Saxe 	hip->timer_n_config[n] = hpet_convert_timer_N_config(conf);
4990e751525SEric Saxe 	return (conf);
5000e751525SEric Saxe }
5010e751525SEric Saxe 
5020e751525SEric Saxe static hpet_TN_conf_cap_t
hpet_convert_timer_N_config(uint64_t conf)5030e751525SEric Saxe hpet_convert_timer_N_config(uint64_t conf)
5040e751525SEric Saxe {
5050e751525SEric Saxe 	hpet_TN_conf_cap_t cc = { 0 };
5060e751525SEric Saxe 
5070e751525SEric Saxe 	cc.int_route_cap = HPET_TIMER_N_INT_ROUTE_CAP(conf);
5080e751525SEric Saxe 	cc.fsb_int_del_cap = HPET_TIMER_N_FSB_INT_DEL_CAP(conf);
5090e751525SEric Saxe 	cc.fsb_int_en_cnf = HPET_TIMER_N_FSB_EN_CNF(conf);
5100e751525SEric Saxe 	cc.int_route_cnf = HPET_TIMER_N_INT_ROUTE_CNF(conf);
5110e751525SEric Saxe 	cc.mode32_cnf = HPET_TIMER_N_MODE32_CNF(conf);
5120e751525SEric Saxe 	cc.val_set_cnf = HPET_TIMER_N_VAL_SET_CNF(conf);
5130e751525SEric Saxe 	cc.size_cap = HPET_TIMER_N_SIZE_CAP(conf);
5140e751525SEric Saxe 	cc.per_int_cap = HPET_TIMER_N_PER_INT_CAP(conf);
5150e751525SEric Saxe 	cc.type_cnf = HPET_TIMER_N_TYPE_CNF(conf);
5160e751525SEric Saxe 	cc.int_enb_cnf = HPET_TIMER_N_INT_ENB_CNF(conf);
5170e751525SEric Saxe 	cc.int_type_cnf = HPET_TIMER_N_INT_TYPE_CNF(conf);
5180e751525SEric Saxe 
5190e751525SEric Saxe 	return (cc);
5200e751525SEric Saxe }
5210e751525SEric Saxe 
5220e751525SEric Saxe static uint64_t
hpet_read_main_counter_value(hpet_info_t * hip)5230e751525SEric Saxe hpet_read_main_counter_value(hpet_info_t *hip)
5240e751525SEric Saxe {
5250e751525SEric Saxe 	uint64_t	value;
5260e751525SEric Saxe 	uint32_t	*counter;
5270e751525SEric Saxe 	uint32_t	high1, high2, low;
5280e751525SEric Saxe 
5290e751525SEric Saxe 	counter = (uint32_t *)HPET_MAIN_COUNTER_ADDRESS(hip->logical_address);
5300e751525SEric Saxe 
5310e751525SEric Saxe 	/*
5320e751525SEric Saxe 	 * 32-bit main counters
5330e751525SEric Saxe 	 */
5340e751525SEric Saxe 	if (hip->gen_cap.count_size_cap == 0) {
5350e751525SEric Saxe 		value = (uint64_t)*counter;
5360e751525SEric Saxe 		hip->main_counter_value = value;
5370e751525SEric Saxe 		return (value);
5380e751525SEric Saxe 	}
5390e751525SEric Saxe 
5400e751525SEric Saxe 	/*
5410e751525SEric Saxe 	 * HPET spec claims a 64-bit read can be split into two 32-bit reads
5420e751525SEric Saxe 	 * by the hardware connection to the HPET.
5430e751525SEric Saxe 	 */
5440e751525SEric Saxe 	high2 = counter[1];
5450e751525SEric Saxe 	do {
5460e751525SEric Saxe 		high1 = high2;
5470e751525SEric Saxe 		low = counter[0];
5480e751525SEric Saxe 		high2 = counter[1];
5490e751525SEric Saxe 	} while (high2 != high1);
5500e751525SEric Saxe 
5510e751525SEric Saxe 	value = ((uint64_t)high1 << 32) | low;
5520e751525SEric Saxe 	hip->main_counter_value = value;
5530e751525SEric Saxe 	return (value);
5540e751525SEric Saxe }
5550e751525SEric Saxe 
5560e751525SEric Saxe static void
hpet_write_gen_config(hpet_info_t * hip,uint64_t l)5570e751525SEric Saxe hpet_write_gen_config(hpet_info_t *hip, uint64_t l)
5580e751525SEric Saxe {
5590e751525SEric Saxe 	*(uint64_t *)HPET_GEN_CONFIG_ADDRESS(hip->logical_address) = l;
5600e751525SEric Saxe }
5610e751525SEric Saxe 
5620e751525SEric Saxe static void
hpet_write_gen_intrpt_stat(hpet_info_t * hip,uint64_t l)5630e751525SEric Saxe hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l)
5640e751525SEric Saxe {
5650e751525SEric Saxe 	*(uint64_t *)HPET_GEN_INTR_STAT_ADDRESS(hip->logical_address) = l;
5660e751525SEric Saxe }
5670e751525SEric Saxe 
5680e751525SEric Saxe static void
hpet_write_timer_N_config(hpet_info_t * hip,uint_t n,uint64_t l)5690e751525SEric Saxe hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l)
5700e751525SEric Saxe {
5710e751525SEric Saxe 	if (hip->timer_n_config[n].size_cap == 1)
5720e751525SEric Saxe 		*(uint64_t *)HPET_TIMER_N_CONF_ADDRESS(
5730e751525SEric Saxe 		    hip->logical_address, n) = l;
5740e751525SEric Saxe 	else
5750e751525SEric Saxe 		*(uint32_t *)HPET_TIMER_N_CONF_ADDRESS(
5760e751525SEric Saxe 		    hip->logical_address, n) = (uint32_t)(0xFFFFFFFF & l);
5770e751525SEric Saxe }
5780e751525SEric Saxe 
5790e751525SEric Saxe static void
hpet_write_timer_N_comp(hpet_info_t * hip,uint_t n,uint64_t l)5800e751525SEric Saxe hpet_write_timer_N_comp(hpet_info_t *hip, uint_t n, uint64_t l)
5810e751525SEric Saxe {
5820e751525SEric Saxe 	*(uint64_t *)HPET_TIMER_N_COMP_ADDRESS(hip->logical_address, n) = l;
5830e751525SEric Saxe }
5840e751525SEric Saxe 
5850e751525SEric Saxe static void
hpet_disable_timer(hpet_info_t * hip,uint32_t timer_n)5860e751525SEric Saxe hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n)
5870e751525SEric Saxe {
5880e751525SEric Saxe 	uint64_t l;
5890e751525SEric Saxe 
5900e751525SEric Saxe 	l = hpet_read_timer_N_config(hip, timer_n);
5910e751525SEric Saxe 	l &= ~HPET_TIMER_N_INT_ENB_CNF_BIT;
5920e751525SEric Saxe 	hpet_write_timer_N_config(hip, timer_n, l);
5930e751525SEric Saxe }
5940e751525SEric Saxe 
5950e751525SEric Saxe static void
hpet_enable_timer(hpet_info_t * hip,uint32_t timer_n)5960e751525SEric Saxe hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n)
5970e751525SEric Saxe {
5980e751525SEric Saxe 	uint64_t l;
5990e751525SEric Saxe 
6000e751525SEric Saxe 	l = hpet_read_timer_N_config(hip, timer_n);
6010e751525SEric Saxe 	l |= HPET_TIMER_N_INT_ENB_CNF_BIT;
6020e751525SEric Saxe 	hpet_write_timer_N_config(hip, timer_n, l);
6030e751525SEric Saxe }
6040e751525SEric Saxe 
6050e751525SEric Saxe /*
6060e751525SEric Saxe  * Add the interrupt handler for I/O APIC interrupt number (interrupt line).
6070e751525SEric Saxe  *
6080e751525SEric Saxe  * The I/O APIC line (vector) is programmed in ioapic_init_intr() called
6090e751525SEric Saxe  * from apic_picinit() psm_ops apic_ops entry point after we return from
6100e751525SEric Saxe  * apic_init() psm_ops entry point.
6110e751525SEric Saxe  */
6120e751525SEric Saxe static uint32_t
hpet_install_interrupt_handler(uint_t (* func)(char *),int vector)6130e751525SEric Saxe hpet_install_interrupt_handler(uint_t (*func)(char *), int vector)
6140e751525SEric Saxe {
6150e751525SEric Saxe 	uint32_t retval;
6160e751525SEric Saxe 
6170e751525SEric Saxe 	retval = add_avintr(NULL, CBE_HIGH_PIL, (avfunc)func, "HPET Timer",
6180e751525SEric Saxe 	    vector, NULL, NULL, NULL, NULL);
6190e751525SEric Saxe 	if (retval == 0) {
6200e751525SEric Saxe 		cmn_err(CE_WARN, "!hpet_acpi: add_avintr() failed");
6210e751525SEric Saxe 		return (AE_BAD_PARAMETER);
6220e751525SEric Saxe 	}
6230e751525SEric Saxe 	return (AE_OK);
6240e751525SEric Saxe }
6250e751525SEric Saxe 
6260e751525SEric Saxe /*
6270e751525SEric Saxe  * The HPET timers specify which I/O APIC interrupts they can be routed to.
6280e751525SEric Saxe  * Find the first available non-legacy-replacement timer and its I/O APIC irq.
6290e751525SEric Saxe  * Supported I/O APIC IRQs are specified in the int_route_cap bitmap in each
6300e751525SEric Saxe  * timer's timer_n_config register.
6310e751525SEric Saxe  */
6320e751525SEric Saxe static int
hpet_get_IOAPIC_intr_capable_timer(hpet_info_t * hip)6330e751525SEric Saxe hpet_get_IOAPIC_intr_capable_timer(hpet_info_t *hip)
6340e751525SEric Saxe {
6350e751525SEric Saxe 	int	timer;
6360e751525SEric Saxe 	int	intr;
6370e751525SEric Saxe 
6380e751525SEric Saxe 	for (timer = HPET_FIRST_NON_LEGACY_TIMER;
6390e751525SEric Saxe 	    timer < hip->gen_cap.num_tim_cap; ++timer) {
6400e751525SEric Saxe 
6410e751525SEric Saxe 		if (!hpet_timer_available(hip->allocated_timers, timer))
6420e751525SEric Saxe 			continue;
6430e751525SEric Saxe 
6440e751525SEric Saxe 		intr = lowbit(hip->timer_n_config[timer].int_route_cap) - 1;
6450e751525SEric Saxe 		if (intr >= 0) {
6460e751525SEric Saxe 			hpet_timer_alloc(&hip->allocated_timers, timer);
6470e751525SEric Saxe 			hip->cstate_timer.timer = timer;
6480e751525SEric Saxe 			hip->cstate_timer.intr = intr;
6490e751525SEric Saxe 			return (timer);
6500e751525SEric Saxe 		}
6510e751525SEric Saxe 	}
6520e751525SEric Saxe 
6530e751525SEric Saxe 	return (-1);
6540e751525SEric Saxe }
6550e751525SEric Saxe 
6560e751525SEric Saxe /*
6570e751525SEric Saxe  * Mark this timer as used.
6580e751525SEric Saxe  */
6590e751525SEric Saxe static void
hpet_timer_alloc(uint32_t * allocated_timers,uint32_t n)6600e751525SEric Saxe hpet_timer_alloc(uint32_t *allocated_timers, uint32_t n)
6610e751525SEric Saxe {
6620e751525SEric Saxe 	*allocated_timers |= 1 << n;
6630e751525SEric Saxe }
6640e751525SEric Saxe 
6650e751525SEric Saxe /*
6660e751525SEric Saxe  * Check if this timer is available.
6670e751525SEric Saxe  * No mutual exclusion because only one thread uses this.
6680e751525SEric Saxe  */
6690e751525SEric Saxe static int
hpet_timer_available(uint32_t allocated_timers,uint32_t n)6700e751525SEric Saxe hpet_timer_available(uint32_t allocated_timers, uint32_t n)
6710e751525SEric Saxe {
6720e751525SEric Saxe 	return ((allocated_timers & (1 << n)) == 0);
6730e751525SEric Saxe }
6740e751525SEric Saxe 
6750e751525SEric Saxe /*
6760e751525SEric Saxe  * Setup timer N to route its interrupt to I/O APIC.
6770e751525SEric Saxe  */
6780e751525SEric Saxe static void
hpet_timer_set_up(hpet_info_t * hip,uint32_t timer_n,uint32_t interrupt)6790e751525SEric Saxe hpet_timer_set_up(hpet_info_t *hip, uint32_t timer_n, uint32_t interrupt)
6800e751525SEric Saxe {
6810e751525SEric Saxe 	uint64_t conf;
6820e751525SEric Saxe 
6830e751525SEric Saxe 	conf = hpet_read_timer_N_config(hip, timer_n);
6840e751525SEric Saxe 
6850e751525SEric Saxe 	/*
6860e751525SEric Saxe 	 * Caller is required to verify this interrupt route is supported.
6870e751525SEric Saxe 	 */
6880e751525SEric Saxe 	ASSERT(HPET_TIMER_N_INT_ROUTE_CAP(conf) & (1 << interrupt));
6890e751525SEric Saxe 
6900e751525SEric Saxe 	conf &= ~HPET_TIMER_N_FSB_EN_CNF_BIT;	/* use IOAPIC */
6910e751525SEric Saxe 	conf |= HPET_TIMER_N_INT_ROUTE_SHIFT(interrupt);
6920e751525SEric Saxe 	conf &= ~HPET_TIMER_N_TYPE_CNF_BIT;	/* non periodic */
6930e751525SEric Saxe 	conf &= ~HPET_TIMER_N_INT_ENB_CNF_BIT;	/* disabled */
6940e751525SEric Saxe 	conf |= HPET_TIMER_N_INT_TYPE_CNF_BIT;	/* Level Triggered */
6950e751525SEric Saxe 
6960e751525SEric Saxe 	hpet_write_timer_N_config(hip, timer_n, conf);
6970e751525SEric Saxe }
6980e751525SEric Saxe 
6990e751525SEric Saxe /*
7000e751525SEric Saxe  * The HPET's Main Counter is not stopped before programming an HPET timer.
7010e751525SEric Saxe  * This will allow the HPET to be used as a time source.
7020e751525SEric Saxe  * The programmed timer interrupt may occur before this function returns.
7030e751525SEric Saxe  * Callers must block interrupts before calling this function if they must
7040e751525SEric Saxe  * guarantee the interrupt is handled after this function returns.
7050e751525SEric Saxe  *
7060e751525SEric Saxe  * Return 0 if main counter is less than timer after enabling timer.
7070e751525SEric Saxe  * The interrupt was programmed, but it may fire before this returns.
7080e751525SEric Saxe  * Return !0 if main counter is greater than timer after enabling timer.
7090e751525SEric Saxe  * In other words: the timer will not fire, and we do not know if it did fire.
7100e751525SEric Saxe  *
7110e751525SEric Saxe  * delta is in HPET ticks.
7120e751525SEric Saxe  *
7130e751525SEric Saxe  * Writing a 64-bit value to a 32-bit register will "wrap around".
7140e751525SEric Saxe  * A 32-bit HPET timer will wrap around in a little over 5 minutes.
7150e751525SEric Saxe  */
7160e751525SEric Saxe int
hpet_timer_program(hpet_info_t * hip,uint32_t timer,uint64_t delta)7170e751525SEric Saxe hpet_timer_program(hpet_info_t *hip, uint32_t timer, uint64_t delta)
7180e751525SEric Saxe {
7190e751525SEric Saxe 	uint64_t time, program;
7200e751525SEric Saxe 
7210e751525SEric Saxe 	program = hpet_read_main_counter_value(hip);
7220e751525SEric Saxe 	program += delta;
7230e751525SEric Saxe 	hpet_write_timer_N_comp(hip, timer, program);
7240e751525SEric Saxe 
7250e751525SEric Saxe 	time = hpet_read_main_counter_value(hip);
7260e751525SEric Saxe 	if (time < program)
7270e751525SEric Saxe 		return (AE_OK);
7280e751525SEric Saxe 
7290e751525SEric Saxe 	return (AE_TIME);
7300e751525SEric Saxe }
7310e751525SEric Saxe 
7320e751525SEric Saxe /*
7330e751525SEric Saxe  * CPR and power policy-change callback entry point.
7340e751525SEric Saxe  */
7350e751525SEric Saxe boolean_t
hpet_callback(int code)7360e751525SEric Saxe hpet_callback(int code)
7370e751525SEric Saxe {
7380e751525SEric Saxe 	switch (code) {
7390e751525SEric Saxe 	case PM_DEFAULT_CPU_DEEP_IDLE:
7400e751525SEric Saxe 		/*FALLTHROUGH*/
7410e751525SEric Saxe 	case PM_ENABLE_CPU_DEEP_IDLE:
7420e751525SEric Saxe 		/*FALLTHROUGH*/
7430e751525SEric Saxe 	case PM_DISABLE_CPU_DEEP_IDLE:
7440e751525SEric Saxe 		return (hpet_deep_idle_config(code));
7450e751525SEric Saxe 
7460e751525SEric Saxe 	case CB_CODE_CPR_RESUME:
7470e751525SEric Saxe 		/*FALLTHROUGH*/
7480e751525SEric Saxe 	case CB_CODE_CPR_CHKPT:
7490e751525SEric Saxe 		return (hpet_cpr(code));
7500e751525SEric Saxe 
7510e751525SEric Saxe 	case CST_EVENT_MULTIPLE_CSTATES:
7520e751525SEric Saxe 		hpet_cst_callback(CST_EVENT_MULTIPLE_CSTATES);
7530e751525SEric Saxe 		return (B_TRUE);
7540e751525SEric Saxe 
7550e751525SEric Saxe 	case CST_EVENT_ONE_CSTATE:
7560e751525SEric Saxe 		hpet_cst_callback(CST_EVENT_ONE_CSTATE);
7570e751525SEric Saxe 		return (B_TRUE);
7580e751525SEric Saxe 
7590e751525SEric Saxe 	default:
7600e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_callback: invalid code %d\n", code);
7610e751525SEric Saxe 		return (B_FALSE);
7620e751525SEric Saxe 	}
7630e751525SEric Saxe }
7640e751525SEric Saxe 
7650e751525SEric Saxe /*
7660e751525SEric Saxe  * According to the HPET spec 1.0a: the Operating System must save and restore
7670e751525SEric Saxe  * HPET event timer hardware context through ACPI sleep state transitions.
7680e751525SEric Saxe  * Timer registers (including the main counter) may not be preserved through
7690e751525SEric Saxe  * ACPI S3, S4, or S5 sleep states.  This code does not not support S1 nor S2.
7700e751525SEric Saxe  *
7710e751525SEric Saxe  * Current HPET state is already in hpet.supported and
7720e751525SEric Saxe  * hpet_state.proxy_installed.  hpet_info contains the proxy interrupt HPET
7730e751525SEric Saxe  * Timer state.
7740e751525SEric Saxe  *
7750e751525SEric Saxe  * Future projects beware: the HPET Main Counter is undefined after ACPI S3 or
7760e751525SEric Saxe  * S4, and it is not saved/restored here.  Future projects cannot expect the
7770e751525SEric Saxe  * Main Counter to be monotomically (or accurately) increasing across CPR.
7780e751525SEric Saxe  *
7790e751525SEric Saxe  * Note: the CPR Checkpoint path later calls pause_cpus() which ensures all
7800e751525SEric Saxe  * CPUs are awake and in a spin loop before the system suspends.  The HPET is
7810e751525SEric Saxe  * not needed for Deep C-state wakeup when CPUs are in cpu_pause().
7820e751525SEric Saxe  * It is safe to leave the HPET running as the system suspends; we just
7830e751525SEric Saxe  * disable the timer from generating interrupts here.
7840e751525SEric Saxe  */
7850e751525SEric Saxe static boolean_t
hpet_cpr(int code)7860e751525SEric Saxe hpet_cpr(int code)
7870e751525SEric Saxe {
7880e751525SEric Saxe 	ulong_t		intr, dead_count = 0;
7890e751525SEric Saxe 	hrtime_t	dead = gethrtime() + hpet_spin_timeout;
7900e751525SEric Saxe 	boolean_t	ret = B_TRUE;
7910e751525SEric Saxe 
7920e751525SEric Saxe 	mutex_enter(&hpet_state_lock);
7930e751525SEric Saxe 	switch (code) {
7940e751525SEric Saxe 	case CB_CODE_CPR_CHKPT:
7950e751525SEric Saxe 		if (hpet_state.proxy_installed == B_FALSE)
7960e751525SEric Saxe 			break;
7970e751525SEric Saxe 
7980e751525SEric Saxe 		hpet_state.cpr = B_TRUE;
7990e751525SEric Saxe 
8000e751525SEric Saxe 		intr = intr_clear();
8010e751525SEric Saxe 		while (!mutex_tryenter(&hpet_proxy_lock)) {
8020e751525SEric Saxe 			/*
8030e751525SEric Saxe 			 * spin
8040e751525SEric Saxe 			 */
8050e751525SEric Saxe 			intr_restore(intr);
8060e751525SEric Saxe 			if (dead_count++ > hpet_spin_check) {
8070e751525SEric Saxe 				dead_count = 0;
8080e751525SEric Saxe 				if (gethrtime() > dead) {
8090e751525SEric Saxe 					hpet_state.cpr = B_FALSE;
8100e751525SEric Saxe 					mutex_exit(&hpet_state_lock);
8110e751525SEric Saxe 					cmn_err(CE_NOTE, "!hpet_cpr: deadman");
8120e751525SEric Saxe 					return (B_FALSE);
8130e751525SEric Saxe 				}
8140e751525SEric Saxe 			}
8150e751525SEric Saxe 			intr = intr_clear();
8160e751525SEric Saxe 		}
8170e751525SEric Saxe 		hpet_expire_all();
8180e751525SEric Saxe 		mutex_exit(&hpet_proxy_lock);
8190e751525SEric Saxe 		intr_restore(intr);
8200e751525SEric Saxe 
8210e751525SEric Saxe 		hpet_disable_timer(&hpet_info, hpet_info.cstate_timer.timer);
8220e751525SEric Saxe 		break;
8230e751525SEric Saxe 
8240e751525SEric Saxe 	case CB_CODE_CPR_RESUME:
8250e751525SEric Saxe 		if (hpet_resume() == B_TRUE)
8260e751525SEric Saxe 			hpet_state.cpr = B_FALSE;
8270e751525SEric Saxe 		else
8280e751525SEric Saxe 			cmn_err(CE_NOTE, "!hpet_resume failed.");
8290e751525SEric Saxe 		break;
8300e751525SEric Saxe 
8310e751525SEric Saxe 	default:
8320e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_cpr: invalid code %d\n", code);
8330e751525SEric Saxe 		ret = B_FALSE;
8340e751525SEric Saxe 		break;
8350e751525SEric Saxe 	}
8360e751525SEric Saxe 	mutex_exit(&hpet_state_lock);
8370e751525SEric Saxe 	return (ret);
8380e751525SEric Saxe }
8390e751525SEric Saxe 
8400e751525SEric Saxe /*
8410e751525SEric Saxe  * Assume the HPET stopped in Suspend state and timer state was lost.
8420e751525SEric Saxe  */
8430e751525SEric Saxe static boolean_t
hpet_resume(void)8440e751525SEric Saxe hpet_resume(void)
8450e751525SEric Saxe {
8460e751525SEric Saxe 	if (hpet.supported != HPET_TIMER_SUPPORT)
8470e751525SEric Saxe 		return (B_TRUE);
8480e751525SEric Saxe 
8490e751525SEric Saxe 	/*
8500e751525SEric Saxe 	 * The HPET spec does not specify if Legacy Replacement Route is
8510e751525SEric Saxe 	 * on or off by default, so we set it off here.
8520e751525SEric Saxe 	 */
8530e751525SEric Saxe 	(void) hpet_set_leg_rt_cnf(&hpet_info, 0);
8540e751525SEric Saxe 
8550e751525SEric Saxe 	if (hpet_start_main_counter(&hpet_info) != AE_OK) {
8560e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_resume: start main counter failed");
8570e751525SEric Saxe 		hpet.supported = HPET_NO_SUPPORT;
8580e751525SEric Saxe 		if (hpet_state.proxy_installed == B_TRUE) {
8590e751525SEric Saxe 			hpet_state.proxy_installed = B_FALSE;
8600e751525SEric Saxe 			hpet_uninstall_interrupt_handler();
8610e751525SEric Saxe 		}
8620e751525SEric Saxe 		return (B_FALSE);
8630e751525SEric Saxe 	}
8640e751525SEric Saxe 
8650e751525SEric Saxe 	if (hpet_state.proxy_installed == B_FALSE)
8660e751525SEric Saxe 		return (B_TRUE);
8670e751525SEric Saxe 
8680e751525SEric Saxe 	hpet_timer_set_up(&hpet_info, hpet_info.cstate_timer.timer,
8690e751525SEric Saxe 	    hpet_info.cstate_timer.intr);
8700e751525SEric Saxe 	if (hpet_state.cpu_deep_idle == B_TRUE)
8710e751525SEric Saxe 		hpet_enable_timer(&hpet_info, hpet_info.cstate_timer.timer);
8720e751525SEric Saxe 
8730e751525SEric Saxe 	return (B_TRUE);
8740e751525SEric Saxe }
8750e751525SEric Saxe 
8760e751525SEric Saxe /*
8770e751525SEric Saxe  * Callback to enable/disable Deep C-States based on power.conf setting.
8780e751525SEric Saxe  */
8790e751525SEric Saxe static boolean_t
hpet_deep_idle_config(int code)8800e751525SEric Saxe hpet_deep_idle_config(int code)
8810e751525SEric Saxe {
8820e751525SEric Saxe 	ulong_t		intr, dead_count = 0;
8830e751525SEric Saxe 	hrtime_t	dead = gethrtime() + hpet_spin_timeout;
8840e751525SEric Saxe 	boolean_t	ret = B_TRUE;
8850e751525SEric Saxe 
8860e751525SEric Saxe 	mutex_enter(&hpet_state_lock);
8870e751525SEric Saxe 	switch (code) {
8880e751525SEric Saxe 	case PM_DEFAULT_CPU_DEEP_IDLE:
8890e751525SEric Saxe 		/*FALLTHROUGH*/
8900e751525SEric Saxe 	case PM_ENABLE_CPU_DEEP_IDLE:
8910e751525SEric Saxe 
8920e751525SEric Saxe 		if (hpet_state.cpu_deep_idle == B_TRUE)
8930e751525SEric Saxe 			break;
8940e751525SEric Saxe 
8950e751525SEric Saxe 		if (hpet_state.proxy_installed == B_FALSE) {
8960e751525SEric Saxe 			ret = B_FALSE;  /* Deep C-States not supported */
8970e751525SEric Saxe 			break;
8980e751525SEric Saxe 		}
8990e751525SEric Saxe 
9000e751525SEric Saxe 		hpet_enable_timer(&hpet_info, hpet_info.cstate_timer.timer);
9010e751525SEric Saxe 		hpet_state.cpu_deep_idle = B_TRUE;
9020e751525SEric Saxe 		break;
9030e751525SEric Saxe 
9040e751525SEric Saxe 	case PM_DISABLE_CPU_DEEP_IDLE:
9050e751525SEric Saxe 
9060e751525SEric Saxe 		if ((hpet_state.cpu_deep_idle == B_FALSE) ||
9070e751525SEric Saxe 		    (hpet_state.proxy_installed == B_FALSE))
9080e751525SEric Saxe 			break;
9090e751525SEric Saxe 
9100e751525SEric Saxe 		/*
9110e751525SEric Saxe 		 * The order of these operations is important to avoid
9120e751525SEric Saxe 		 * lost wakeups: Set a flag to refuse all future LAPIC Timer
9130e751525SEric Saxe 		 * proxy requests, then wake up all CPUs from deep C-state,
9140e751525SEric Saxe 		 * and finally disable the HPET interrupt-generating timer.
9150e751525SEric Saxe 		 */
9160e751525SEric Saxe 		hpet_state.cpu_deep_idle = B_FALSE;
9170e751525SEric Saxe 
9180e751525SEric Saxe 		intr = intr_clear();
9190e751525SEric Saxe 		while (!mutex_tryenter(&hpet_proxy_lock)) {
9200e751525SEric Saxe 			/*
9210e751525SEric Saxe 			 * spin
9220e751525SEric Saxe 			 */
9230e751525SEric Saxe 			intr_restore(intr);
9240e751525SEric Saxe 			if (dead_count++ > hpet_spin_check) {
9250e751525SEric Saxe 				dead_count = 0;
9260e751525SEric Saxe 				if (gethrtime() > dead) {
9270e751525SEric Saxe 					hpet_state.cpu_deep_idle = B_TRUE;
9280e751525SEric Saxe 					mutex_exit(&hpet_state_lock);
9290e751525SEric Saxe 					cmn_err(CE_NOTE,
9300e751525SEric Saxe 					    "!hpet_deep_idle_config: deadman");
9310e751525SEric Saxe 					return (B_FALSE);
9320e751525SEric Saxe 				}
9330e751525SEric Saxe 			}
9340e751525SEric Saxe 			intr = intr_clear();
9350e751525SEric Saxe 		}
9360e751525SEric Saxe 		hpet_expire_all();
9370e751525SEric Saxe 		mutex_exit(&hpet_proxy_lock);
9380e751525SEric Saxe 		intr_restore(intr);
9390e751525SEric Saxe 
9400e751525SEric Saxe 		hpet_disable_timer(&hpet_info, hpet_info.cstate_timer.timer);
9410e751525SEric Saxe 		break;
9420e751525SEric Saxe 
9430e751525SEric Saxe 	default:
9440e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_deep_idle_config: invalid code %d\n",
9450e751525SEric Saxe 		    code);
9460e751525SEric Saxe 		ret = B_FALSE;
9470e751525SEric Saxe 		break;
9480e751525SEric Saxe 	}
9490e751525SEric Saxe 	mutex_exit(&hpet_state_lock);
9500e751525SEric Saxe 
9510e751525SEric Saxe 	return (ret);
9520e751525SEric Saxe }
9530e751525SEric Saxe 
9540e751525SEric Saxe /*
9550e751525SEric Saxe  * Callback for _CST c-state change notifications.
9560e751525SEric Saxe  */
9570e751525SEric Saxe static void
hpet_cst_callback(uint32_t code)9580e751525SEric Saxe hpet_cst_callback(uint32_t code)
9590e751525SEric Saxe {
9600e751525SEric Saxe 	ulong_t		intr, dead_count = 0;
9610e751525SEric Saxe 	hrtime_t	dead = gethrtime() + hpet_spin_timeout;
9620e751525SEric Saxe 
9630e751525SEric Saxe 	switch (code) {
9640e751525SEric Saxe 	case CST_EVENT_ONE_CSTATE:
9650e751525SEric Saxe 		hpet_state.uni_cstate = B_TRUE;
9660e751525SEric Saxe 		intr = intr_clear();
9670e751525SEric Saxe 		while (!mutex_tryenter(&hpet_proxy_lock)) {
9680e751525SEric Saxe 			/*
9690e751525SEric Saxe 			 * spin
9700e751525SEric Saxe 			 */
9710e751525SEric Saxe 			intr_restore(intr);
9720e751525SEric Saxe 			if (dead_count++ > hpet_spin_check) {
9730e751525SEric Saxe 				dead_count = 0;
9740e751525SEric Saxe 				if (gethrtime() > dead) {
9750e751525SEric Saxe 					hpet_expire_all();
9760e751525SEric Saxe 					cmn_err(CE_NOTE,
9770e751525SEric Saxe 					    "!hpet_cst_callback: deadman");
9780e751525SEric Saxe 					return;
9790e751525SEric Saxe 				}
9800e751525SEric Saxe 			}
9810e751525SEric Saxe 			intr = intr_clear();
9820e751525SEric Saxe 		}
9830e751525SEric Saxe 		hpet_expire_all();
9840e751525SEric Saxe 		mutex_exit(&hpet_proxy_lock);
9850e751525SEric Saxe 		intr_restore(intr);
9860e751525SEric Saxe 		break;
9870e751525SEric Saxe 
9880e751525SEric Saxe 	case CST_EVENT_MULTIPLE_CSTATES:
9890e751525SEric Saxe 		hpet_state.uni_cstate = B_FALSE;
9900e751525SEric Saxe 		break;
9910e751525SEric Saxe 
9920e751525SEric Saxe 	default:
9930e751525SEric Saxe 		cmn_err(CE_NOTE, "!hpet_cst_callback: invalid code %d\n", code);
9940e751525SEric Saxe 		break;
9950e751525SEric Saxe 	}
9960e751525SEric Saxe }
9970e751525SEric Saxe 
9980e751525SEric Saxe /*
9990e751525SEric Saxe  * Interrupt Service Routine for HPET I/O-APIC-generated interrupts.
10000e751525SEric Saxe  * Used to wakeup CPUs from Deep C-state when their Local APIC Timer stops.
10010e751525SEric Saxe  * This ISR runs on one CPU which pokes other CPUs out of Deep C-state as
10020e751525SEric Saxe  * needed.
10030e751525SEric Saxe  */
10040e751525SEric Saxe /* ARGSUSED */
10050e751525SEric Saxe static uint_t
hpet_isr(char * arg)10060e751525SEric Saxe hpet_isr(char *arg)
10070e751525SEric Saxe {
10080e751525SEric Saxe 	uint64_t	timer_status;
10090e751525SEric Saxe 	uint64_t	timer_mask;
10100e751525SEric Saxe 	ulong_t		intr, dead_count = 0;
10110e751525SEric Saxe 	hrtime_t	dead = gethrtime() + hpet_isr_spin_timeout;
10120e751525SEric Saxe 
10130e751525SEric Saxe 	timer_mask = HPET_INTR_STATUS_MASK(hpet_info.cstate_timer.timer);
10140e751525SEric Saxe 
10150e751525SEric Saxe 	/*
10160e751525SEric Saxe 	 * We are using a level-triggered interrupt.
10170e751525SEric Saxe 	 * HPET sets timer's General Interrupt Status Register bit N.
10180e751525SEric Saxe 	 * ISR checks this bit to see if it needs servicing.
10190e751525SEric Saxe 	 * ISR then clears this bit by writing 1 to that bit.
10200e751525SEric Saxe 	 */
10210e751525SEric Saxe 	timer_status = hpet_read_gen_intrpt_stat(&hpet_info);
10220e751525SEric Saxe 	if (!(timer_status & timer_mask))
10230e751525SEric Saxe 		return (DDI_INTR_UNCLAIMED);
10240e751525SEric Saxe 	hpet_write_gen_intrpt_stat(&hpet_info, timer_mask);
10250e751525SEric Saxe 
10260e751525SEric Saxe 	/*
10270e751525SEric Saxe 	 * Do not touch ISR data structures before checking the HPET's General
10280e751525SEric Saxe 	 * Interrupt Status register.  The General Interrupt Status register
10290e751525SEric Saxe 	 * will not be set by hardware until after timer interrupt generation
10300e751525SEric Saxe 	 * is enabled by software.  Software allocates necessary data
10310e751525SEric Saxe 	 * structures before enabling timer interrupts.  ASSERT the software
10320e751525SEric Saxe 	 * data structures required to handle this interrupt are initialized.
10330e751525SEric Saxe 	 */
10340e751525SEric Saxe 	ASSERT(hpet_proxy_users != NULL);
10350e751525SEric Saxe 
10360e751525SEric Saxe 	/*
10370e751525SEric Saxe 	 * CPUs in deep c-states do not enable interrupts until after
10380e751525SEric Saxe 	 * performing idle cleanup which includes descheduling themselves from
10390e751525SEric Saxe 	 * the HPET.  The CPU running this ISR will NEVER find itself in the
10400e751525SEric Saxe 	 * proxy list.  A lost wakeup may occur if this is false.
10410e751525SEric Saxe 	 */
10420e751525SEric Saxe 	ASSERT(hpet_proxy_users[CPU->cpu_id] == HPET_INFINITY);
10430e751525SEric Saxe 
10440e751525SEric Saxe 	/*
10450e751525SEric Saxe 	 * Higher level interrupts may deadlock with CPUs going idle if this
10460e751525SEric Saxe 	 * ISR is prempted while holding hpet_proxy_lock.
10470e751525SEric Saxe 	 */
10480e751525SEric Saxe 	intr = intr_clear();
10490e751525SEric Saxe 	while (!mutex_tryenter(&hpet_proxy_lock)) {
10500e751525SEric Saxe 		/*
10510e751525SEric Saxe 		 * spin
10520e751525SEric Saxe 		 */
10530e751525SEric Saxe 		intr_restore(intr);
10540e751525SEric Saxe 		if (dead_count++ > hpet_spin_check) {
10550e751525SEric Saxe 			dead_count = 0;
10560e751525SEric Saxe 			if (gethrtime() > dead) {
10570e751525SEric Saxe 				hpet_expire_all();
10580e751525SEric Saxe 				return (DDI_INTR_CLAIMED);
10590e751525SEric Saxe 			}
10600e751525SEric Saxe 		}
10610e751525SEric Saxe 		intr = intr_clear();
10620e751525SEric Saxe 	}
10630e751525SEric Saxe 	(void) hpet_guaranteed_schedule(HPET_INFINITY);
10640e751525SEric Saxe 	mutex_exit(&hpet_proxy_lock);
10650e751525SEric Saxe 	intr_restore(intr);
10660e751525SEric Saxe 
10670e751525SEric Saxe 	return (DDI_INTR_CLAIMED);
10680e751525SEric Saxe }
10690e751525SEric Saxe 
10700e751525SEric Saxe /*
10710e751525SEric Saxe  * Used when disabling the HPET Timer interrupt.  CPUs in Deep C-state must be
10720e751525SEric Saxe  * woken up because they can no longer rely on the HPET's Timer to wake them.
10730e751525SEric Saxe  * We do not need to wait for CPUs to wakeup.
10740e751525SEric Saxe  */
10750e751525SEric Saxe static void
hpet_expire_all(void)10760e751525SEric Saxe hpet_expire_all(void)
10770e751525SEric Saxe {
10780e751525SEric Saxe 	processorid_t	id;
10790e751525SEric Saxe 
108022bbd95eSaubrey.li@intel.com 	for (id = 0; id < max_ncpus; ++id) {
10810e751525SEric Saxe 		if (hpet_proxy_users[id] != HPET_INFINITY) {
10820e751525SEric Saxe 			hpet_proxy_users[id] = HPET_INFINITY;
10830e751525SEric Saxe 			if (id != CPU->cpu_id)
10840e751525SEric Saxe 				poke_cpu(id);
10850e751525SEric Saxe 		}
10860e751525SEric Saxe 	}
10870e751525SEric Saxe }
10880e751525SEric Saxe 
10890e751525SEric Saxe /*
10900e751525SEric Saxe  * To avoid missed wakeups this function must guarantee either the HPET timer
10910e751525SEric Saxe  * was successfully programmed to the next expire time or there are no waiting
10920e751525SEric Saxe  * CPUs.
10930e751525SEric Saxe  *
10940e751525SEric Saxe  * Callers cannot enter C2 or deeper if the HPET could not be programmed to
10950e751525SEric Saxe  * generate its next interrupt to happen at required_wakeup_time or sooner.
10960e751525SEric Saxe  * Returns B_TRUE if the HPET was programmed to interrupt by
10970e751525SEric Saxe  * required_wakeup_time, B_FALSE if not.
10980e751525SEric Saxe  */
10990e751525SEric Saxe static boolean_t
hpet_guaranteed_schedule(hrtime_t required_wakeup_time)11000e751525SEric Saxe hpet_guaranteed_schedule(hrtime_t required_wakeup_time)
11010e751525SEric Saxe {
11020e751525SEric Saxe 	hrtime_t	now, next_proxy_time;
11030e751525SEric Saxe 	processorid_t	id, next_proxy_id;
11040e751525SEric Saxe 	int		proxy_timer = hpet_info.cstate_timer.timer;
11050e751525SEric Saxe 	boolean_t	done = B_FALSE;
11060e751525SEric Saxe 
11070e751525SEric Saxe 	ASSERT(mutex_owned(&hpet_proxy_lock));
11080e751525SEric Saxe 
11090e751525SEric Saxe 	/*
11100e751525SEric Saxe 	 * Loop until we successfully program the HPET,
11110e751525SEric Saxe 	 * or no CPUs are scheduled to use the HPET as a proxy.
11120e751525SEric Saxe 	 */
11130e751525SEric Saxe 	do {
11140e751525SEric Saxe 		/*
11150e751525SEric Saxe 		 * Wake all CPUs that expired before now.
11160e751525SEric Saxe 		 * Find the next CPU to wake up and next HPET program time.
11170e751525SEric Saxe 		 */
11180e751525SEric Saxe 		now = gethrtime();
11190e751525SEric Saxe 		next_proxy_time = HPET_INFINITY;
11200e751525SEric Saxe 		next_proxy_id = CPU->cpu_id;
112122bbd95eSaubrey.li@intel.com 		for (id = 0; id < max_ncpus; ++id) {
11220e751525SEric Saxe 			if (hpet_proxy_users[id] < now) {
11230e751525SEric Saxe 				hpet_proxy_users[id] = HPET_INFINITY;
11240e751525SEric Saxe 				if (id != CPU->cpu_id)
11250e751525SEric Saxe 					poke_cpu(id);
11260e751525SEric Saxe 			} else if (hpet_proxy_users[id] < next_proxy_time) {
11270e751525SEric Saxe 				next_proxy_time = hpet_proxy_users[id];
11280e751525SEric Saxe 				next_proxy_id = id;
11290e751525SEric Saxe 			}
11300e751525SEric Saxe 		}
11310e751525SEric Saxe 
11320e751525SEric Saxe 		if (next_proxy_time == HPET_INFINITY) {
11330e751525SEric Saxe 			done = B_TRUE;
11340e751525SEric Saxe 			/*
11350e751525SEric Saxe 			 * There are currently no CPUs using the HPET's Timer
11360e751525SEric Saxe 			 * as a proxy for their LAPIC Timer.  The HPET's Timer
11370e751525SEric Saxe 			 * does not need to be programmed.
11380e751525SEric Saxe 			 *
11390e751525SEric Saxe 			 * Letting the HPET timer wrap around to the current
11400e751525SEric Saxe 			 * time is the longest possible timeout.
11410e751525SEric Saxe 			 * A 64-bit timer will wrap around in ~ 2^44 seconds.
11420e751525SEric Saxe 			 * A 32-bit timer will wrap around in ~ 2^12 seconds.
11430e751525SEric Saxe 			 *
11440e751525SEric Saxe 			 * Disabling the HPET's timer interrupt requires a
11450e751525SEric Saxe 			 * (relatively expensive) write to the HPET.
11460e751525SEric Saxe 			 * Instead we do nothing.
11470e751525SEric Saxe 			 *
11480e751525SEric Saxe 			 * We are gambling some CPU will attempt to enter a
11490e751525SEric Saxe 			 * deep c-state before the timer wraps around.
11500e751525SEric Saxe 			 * We assume one spurious interrupt in a little over an
11510e751525SEric Saxe 			 * hour has less performance impact than writing to the
11520e751525SEric Saxe 			 * HPET's timer disable bit every time all CPUs wakeup
11530e751525SEric Saxe 			 * from deep c-state.
11540e751525SEric Saxe 			 */
11550e751525SEric Saxe 
11560e751525SEric Saxe 		} else {
11570e751525SEric Saxe 			/*
11580e751525SEric Saxe 			 * Idle CPUs disable interrupts before programming the
11590e751525SEric Saxe 			 * HPET to prevent a lost wakeup if the HPET
11600e751525SEric Saxe 			 * interrupts the idle cpu before it can enter a
11610e751525SEric Saxe 			 * Deep C-State.
11620e751525SEric Saxe 			 */
11630e751525SEric Saxe 			if (hpet_timer_program(&hpet_info, proxy_timer,
11640e751525SEric Saxe 			    HRTIME_TO_HPET_TICKS(next_proxy_time - gethrtime()))
11650e751525SEric Saxe 			    != AE_OK) {
11660e751525SEric Saxe 				/*
11670e751525SEric Saxe 				 * We could not program the HPET to wakeup the
11680e751525SEric Saxe 				 * next CPU.  We must wake the CPU ourself to
11690e751525SEric Saxe 				 * avoid a lost wakeup.
11700e751525SEric Saxe 				 */
11710e751525SEric Saxe 				hpet_proxy_users[next_proxy_id] = HPET_INFINITY;
11720e751525SEric Saxe 				if (next_proxy_id != CPU->cpu_id)
11730e751525SEric Saxe 					poke_cpu(next_proxy_id);
11740e751525SEric Saxe 			} else {
11750e751525SEric Saxe 				done = B_TRUE;
11760e751525SEric Saxe 			}
11770e751525SEric Saxe 		}
11780e751525SEric Saxe 
11790e751525SEric Saxe 	} while (!done);
11800e751525SEric Saxe 
11810e751525SEric Saxe 	return (next_proxy_time <= required_wakeup_time);
11820e751525SEric Saxe }
11830e751525SEric Saxe 
11840e751525SEric Saxe /*
11850e751525SEric Saxe  * Use an HPET timer to act as this CPU's proxy local APIC timer.
11860e751525SEric Saxe  * Used in deep c-states C2 and above while the CPU's local APIC timer stalls.
11870e751525SEric Saxe  * Called by the idle thread with interrupts enabled.
11880e751525SEric Saxe  * Always returns with interrupts disabled.
11890e751525SEric Saxe  *
11900e751525SEric Saxe  * There are 3 possible outcomes from this function:
11910e751525SEric Saxe  * 1. The Local APIC Timer was already disabled before this function was called.
11920e751525SEric Saxe  *	LAPIC TIMER	: disabled
11930e751525SEric Saxe  *	HPET		: not scheduled to wake this CPU
11940e751525SEric Saxe  *	*lapic_expire	: (hrtime_t)HPET_INFINITY
11950e751525SEric Saxe  *	Returns		: B_TRUE
11960e751525SEric Saxe  * 2. Successfully programmed the HPET to act as a LAPIC Timer proxy.
11970e751525SEric Saxe  *	LAPIC TIMER	: disabled
11980e751525SEric Saxe  *	HPET		: scheduled to wake this CPU
11990e751525SEric Saxe  *	*lapic_expire	: hrtime_t when LAPIC timer would have expired
12000e751525SEric Saxe  *	Returns		: B_TRUE
12010e751525SEric Saxe  * 3. Failed to programmed the HPET to act as a LAPIC Timer proxy.
12020e751525SEric Saxe  *	LAPIC TIMER	: enabled
12030e751525SEric Saxe  *	HPET		: not scheduled to wake this CPU
12040e751525SEric Saxe  *	*lapic_expire	: (hrtime_t)HPET_INFINITY
12050e751525SEric Saxe  *	Returns		: B_FALSE
12060e751525SEric Saxe  *
12070e751525SEric Saxe  * The idle thread cannot enter Deep C-State in case 3.
12080e751525SEric Saxe  * The idle thread must re-enable & re-program the LAPIC_TIMER in case 2.
12090e751525SEric Saxe  */
12100e751525SEric Saxe static boolean_t
hpet_use_hpet_timer(hrtime_t * lapic_expire)12110e751525SEric Saxe hpet_use_hpet_timer(hrtime_t *lapic_expire)
12120e751525SEric Saxe {
12130e751525SEric Saxe 	extern hrtime_t	apic_timer_stop_count(void);
12140e751525SEric Saxe 	extern void	apic_timer_restart(hrtime_t);
12150e751525SEric Saxe 	hrtime_t	now, expire, dead;
12160e751525SEric Saxe 	uint64_t	lapic_count, dead_count;
12170e751525SEric Saxe 	cpupart_t	*cpu_part;
12180e751525SEric Saxe 	processorid_t	cpu_sid;
12190e751525SEric Saxe 	processorid_t	cpu_id = CPU->cpu_id;
12200e751525SEric Saxe 	processorid_t	id;
12210e751525SEric Saxe 	boolean_t	rslt;
12220e751525SEric Saxe 	boolean_t	hset_update;
12230e751525SEric Saxe 
12240e751525SEric Saxe 	cpu_part = CPU->cpu_part;
12250e751525SEric Saxe 	cpu_sid = CPU->cpu_seqid;
12260e751525SEric Saxe 
12270e751525SEric Saxe 	ASSERT(CPU->cpu_thread == CPU->cpu_idle_thread);
12280e751525SEric Saxe 
12290e751525SEric Saxe 	/*
12300e751525SEric Saxe 	 * A critical section exists between when the HPET is programmed
12310e751525SEric Saxe 	 * to interrupt the CPU and when this CPU enters an idle state.
12320e751525SEric Saxe 	 * Interrupts must be blocked during that time to prevent lost
12330e751525SEric Saxe 	 * CBE wakeup interrupts from either LAPIC or HPET.
12340e751525SEric Saxe 	 *
12350e751525SEric Saxe 	 * Must block interrupts before acquiring hpet_proxy_lock to prevent
12360e751525SEric Saxe 	 * a deadlock with the ISR if the ISR runs on this CPU after the
12370e751525SEric Saxe 	 * idle thread acquires the mutex but before it clears interrupts.
12380e751525SEric Saxe 	 */
1239cef70d2cSBill Holler 	ASSERT(!interrupts_enabled());
12400e751525SEric Saxe 	lapic_count = apic_timer_stop_count();
12410e751525SEric Saxe 	now = gethrtime();
12420e751525SEric Saxe 	dead = now + hpet_idle_spin_timeout;
12430e751525SEric Saxe 	*lapic_expire = expire = now + lapic_count;
12440e751525SEric Saxe 	if (lapic_count == (hrtime_t)-1) {
12450e751525SEric Saxe 		/*
12460e751525SEric Saxe 		 * LAPIC timer is currently disabled.
12470e751525SEric Saxe 		 * Will not use the HPET as a LAPIC Timer proxy.
12480e751525SEric Saxe 		 */
12490e751525SEric Saxe 		*lapic_expire = (hrtime_t)HPET_INFINITY;
12500e751525SEric Saxe 		return (B_TRUE);
12510e751525SEric Saxe 	}
12520e751525SEric Saxe 
12530e751525SEric Saxe 	/*
12540e751525SEric Saxe 	 * Serialize hpet_proxy data structure manipulation.
12550e751525SEric Saxe 	 */
12560e751525SEric Saxe 	dead_count = 0;
12570e751525SEric Saxe 	while (!mutex_tryenter(&hpet_proxy_lock)) {
12580e751525SEric Saxe 		/*
12590e751525SEric Saxe 		 * spin
12600e751525SEric Saxe 		 */
12610e751525SEric Saxe 		apic_timer_restart(expire);
12620e751525SEric Saxe 		sti();
12630e751525SEric Saxe 		cli();
12640e751525SEric Saxe 
12650e751525SEric Saxe 		if (dead_count++ > hpet_spin_check) {
12660e751525SEric Saxe 			dead_count = 0;
12670e751525SEric Saxe 			hset_update = (((CPU->cpu_flags & CPU_OFFLINE) == 0) &&
12680e751525SEric Saxe 			    (ncpus > 1));
12690e751525SEric Saxe 			if (hset_update &&
12700e751525SEric Saxe 			    !bitset_in_set(&cpu_part->cp_haltset, cpu_sid)) {
12710e751525SEric Saxe 				*lapic_expire = (hrtime_t)HPET_INFINITY;
12720e751525SEric Saxe 				return (B_FALSE);
12730e751525SEric Saxe 			}
12740e751525SEric Saxe 		}
12750e751525SEric Saxe 
12760e751525SEric Saxe 		lapic_count = apic_timer_stop_count();
12770e751525SEric Saxe 		now = gethrtime();
12780e751525SEric Saxe 		*lapic_expire = expire = now + lapic_count;
12790e751525SEric Saxe 		if (lapic_count == (hrtime_t)-1) {
12800e751525SEric Saxe 			/*
12810e751525SEric Saxe 			 * LAPIC timer is currently disabled.
12820e751525SEric Saxe 			 * Will not use the HPET as a LAPIC Timer proxy.
12830e751525SEric Saxe 			 */
12840e751525SEric Saxe 			*lapic_expire = (hrtime_t)HPET_INFINITY;
12850e751525SEric Saxe 			return (B_TRUE);
12860e751525SEric Saxe 		}
12870e751525SEric Saxe 		if (now > dead) {
12880e751525SEric Saxe 			apic_timer_restart(expire);
12890e751525SEric Saxe 			*lapic_expire = (hrtime_t)HPET_INFINITY;
12900e751525SEric Saxe 			return (B_FALSE);
12910e751525SEric Saxe 		}
12920e751525SEric Saxe 	}
12930e751525SEric Saxe 
12940e751525SEric Saxe 	if ((hpet_state.cpr == B_TRUE) ||
12950e751525SEric Saxe 	    (hpet_state.cpu_deep_idle == B_FALSE) ||
12960e751525SEric Saxe 	    (hpet_state.proxy_installed == B_FALSE) ||
12970e751525SEric Saxe 	    (hpet_state.uni_cstate == B_TRUE)) {
12980e751525SEric Saxe 		mutex_exit(&hpet_proxy_lock);
12990e751525SEric Saxe 		apic_timer_restart(expire);
13000e751525SEric Saxe 		*lapic_expire = (hrtime_t)HPET_INFINITY;
13010e751525SEric Saxe 		return (B_FALSE);
13020e751525SEric Saxe 	}
13030e751525SEric Saxe 
13040e751525SEric Saxe 	hpet_proxy_users[cpu_id] = expire;
13050e751525SEric Saxe 
13060e751525SEric Saxe 	/*
13070e751525SEric Saxe 	 * We are done if another cpu is scheduled on the HPET with an
13080e751525SEric Saxe 	 * expire time before us.  The next HPET interrupt has been programmed
13090e751525SEric Saxe 	 * to fire before our expire time.
13100e751525SEric Saxe 	 */
131122bbd95eSaubrey.li@intel.com 	for (id = 0; id < max_ncpus; ++id) {
13120e751525SEric Saxe 		if ((hpet_proxy_users[id] <= expire) && (id != cpu_id)) {
13130e751525SEric Saxe 			mutex_exit(&hpet_proxy_lock);
13140e751525SEric Saxe 			return (B_TRUE);
13150e751525SEric Saxe 		}
13160e751525SEric Saxe 	}
13170e751525SEric Saxe 
13180e751525SEric Saxe 	/*
13190e751525SEric Saxe 	 * We are the next lAPIC to expire.
13200e751525SEric Saxe 	 * Program the HPET with our expire time.
13210e751525SEric Saxe 	 */
13220e751525SEric Saxe 	rslt = hpet_guaranteed_schedule(expire);
13230e751525SEric Saxe 	mutex_exit(&hpet_proxy_lock);
13240e751525SEric Saxe 
13250e751525SEric Saxe 	if (rslt == B_FALSE) {
13260e751525SEric Saxe 		apic_timer_restart(expire);
13270e751525SEric Saxe 		*lapic_expire = (hrtime_t)HPET_INFINITY;
13280e751525SEric Saxe 	}
13290e751525SEric Saxe 
13300e751525SEric Saxe 	return (rslt);
13310e751525SEric Saxe }
13320e751525SEric Saxe 
13330e751525SEric Saxe /*
13340e751525SEric Saxe  * Called by the idle thread when waking up from Deep C-state before enabling
13350e751525SEric Saxe  * interrupts.  With an array data structure it is faster to always remove
13360e751525SEric Saxe  * ourself from the array without checking if the HPET ISR already removed.
13370e751525SEric Saxe  *
13380e751525SEric Saxe  * We use a lazy algorithm for removing CPUs from the HPET's schedule.
13390e751525SEric Saxe  * We do not reprogram the HPET here because this CPU has real work to do.
13400e751525SEric Saxe  * On a idle system the CPU was probably woken up by the HPET's ISR.
13410e751525SEric Saxe  * On a heavily loaded system CPUs are not going into Deep C-state.
13420e751525SEric Saxe  * On a moderately loaded system another CPU will usually enter Deep C-state
13430e751525SEric Saxe  * and reprogram the HPET before the HPET fires with our wakeup.
13440e751525SEric Saxe  */
13450e751525SEric Saxe static void
hpet_use_lapic_timer(hrtime_t expire)13460e751525SEric Saxe hpet_use_lapic_timer(hrtime_t expire)
13470e751525SEric Saxe {
13480e751525SEric Saxe 	extern void	apic_timer_restart(hrtime_t);
13490e751525SEric Saxe 	processorid_t	cpu_id = CPU->cpu_id;
13500e751525SEric Saxe 
13510e751525SEric Saxe 	ASSERT(CPU->cpu_thread == CPU->cpu_idle_thread);
13520e751525SEric Saxe 	ASSERT(!interrupts_enabled());
13530e751525SEric Saxe 
13540e751525SEric Saxe 	hpet_proxy_users[cpu_id] = HPET_INFINITY;
13550e751525SEric Saxe 
13560e751525SEric Saxe 	/*
13570e751525SEric Saxe 	 * Do not enable a LAPIC Timer that was initially disabled.
13580e751525SEric Saxe 	 */
13590e751525SEric Saxe 	if (expire != HPET_INFINITY)
13600e751525SEric Saxe 		apic_timer_restart(expire);
13610e751525SEric Saxe }
13620e751525SEric Saxe 
13630e751525SEric Saxe /*
13640e751525SEric Saxe  * Initialize data structure to keep track of CPUs using HPET as a proxy for
13650e751525SEric Saxe  * their stalled local APIC timer.  For now this is just an array.
13660e751525SEric Saxe  */
13670e751525SEric Saxe static void
hpet_init_proxy_data(void)13680e751525SEric Saxe hpet_init_proxy_data(void)
13690e751525SEric Saxe {
13700e751525SEric Saxe 	processorid_t	id;
13710e751525SEric Saxe 
13720e751525SEric Saxe 	/*
137322bbd95eSaubrey.li@intel.com 	 * Use max_ncpus for hot plug compliance.
13740e751525SEric Saxe 	 */
137522bbd95eSaubrey.li@intel.com 	hpet_proxy_users = kmem_zalloc(max_ncpus * sizeof (*hpet_proxy_users),
13760e751525SEric Saxe 	    KM_SLEEP);
13770e751525SEric Saxe 
13780e751525SEric Saxe 	/*
13790e751525SEric Saxe 	 * Unused entries always contain HPET_INFINITY.
13800e751525SEric Saxe 	 */
138122bbd95eSaubrey.li@intel.com 	for (id = 0; id < max_ncpus; ++id)
13820e751525SEric Saxe 		hpet_proxy_users[id] = HPET_INFINITY;
13830e751525SEric Saxe }
1384