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 /* 22*5cd376e8SJimmy 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 387ff178cdSJimmy Vetayases static int hpet_init_proxy(int *hpet_vect, iflag_t *hpet_flags); 397ff178cdSJimmy Vetayases static boolean_t hpet_install_proxy(void); 407ff178cdSJimmy Vetayases static boolean_t hpet_callback(int code); 417ff178cdSJimmy Vetayases static boolean_t hpet_cpr(int code); 427ff178cdSJimmy Vetayases static boolean_t hpet_resume(void); 437ff178cdSJimmy Vetayases static void hpet_cst_callback(uint32_t code); 447ff178cdSJimmy Vetayases static boolean_t hpet_deep_idle_config(int code); 457ff178cdSJimmy Vetayases static int hpet_validate_table(ACPI_TABLE_HPET *hpet_table); 467ff178cdSJimmy Vetayases static boolean_t hpet_checksum_table(unsigned char *table, unsigned int len); 477ff178cdSJimmy Vetayases static void *hpet_memory_map(ACPI_TABLE_HPET *hpet_table); 487ff178cdSJimmy Vetayases static int hpet_start_main_counter(hpet_info_t *hip); 497ff178cdSJimmy Vetayases static int hpet_stop_main_counter(hpet_info_t *hip); 507ff178cdSJimmy Vetayases static uint64_t hpet_read_main_counter_value(hpet_info_t *hip); 517ff178cdSJimmy Vetayases static uint64_t hpet_set_leg_rt_cnf(hpet_info_t *hip, uint32_t new_value); 527ff178cdSJimmy Vetayases static uint64_t hpet_read_gen_cap(hpet_info_t *hip); 537ff178cdSJimmy Vetayases static uint64_t hpet_read_gen_config(hpet_info_t *hip); 547ff178cdSJimmy Vetayases static uint64_t hpet_read_gen_intrpt_stat(hpet_info_t *hip); 557ff178cdSJimmy Vetayases static uint64_t hpet_read_timer_N_config(hpet_info_t *hip, uint_t n); 567ff178cdSJimmy Vetayases static hpet_TN_conf_cap_t hpet_convert_timer_N_config(uint64_t conf); 577ff178cdSJimmy Vetayases static void hpet_write_gen_config(hpet_info_t *hip, uint64_t l); 587ff178cdSJimmy Vetayases static void hpet_write_gen_intrpt_stat(hpet_info_t *hip, uint64_t l); 597ff178cdSJimmy Vetayases static void hpet_write_timer_N_config(hpet_info_t *hip, uint_t n, uint64_t l); 607ff178cdSJimmy Vetayases static void hpet_write_timer_N_comp(hpet_info_t *hip, uint_t n, uint64_t l); 617ff178cdSJimmy Vetayases static void hpet_disable_timer(hpet_info_t *hip, uint32_t timer_n); 627ff178cdSJimmy Vetayases static void hpet_enable_timer(hpet_info_t *hip, uint32_t timer_n); 637ff178cdSJimmy Vetayases static int hpet_get_IOAPIC_intr_capable_timer(hpet_info_t *hip); 647ff178cdSJimmy Vetayases static int hpet_timer_available(uint32_t allocated_timers, uint32_t n); 657ff178cdSJimmy Vetayases static void hpet_timer_alloc(uint32_t *allocated_timers, uint32_t n); 667ff178cdSJimmy Vetayases static void hpet_timer_set_up(hpet_info_t *hip, uint32_t timer_n, 677ff178cdSJimmy Vetayases uint32_t interrupt); 687ff178cdSJimmy Vetayases static uint_t hpet_isr(char *arg); 697ff178cdSJimmy Vetayases static uint32_t hpet_install_interrupt_handler(uint_t (*func)(char *), 707ff178cdSJimmy Vetayases int vector); 717ff178cdSJimmy Vetayases static void hpet_uninstall_interrupt_handler(void); 727ff178cdSJimmy Vetayases static void hpet_expire_all(void); 737ff178cdSJimmy Vetayases static boolean_t hpet_guaranteed_schedule(hrtime_t required_wakeup_time); 747ff178cdSJimmy Vetayases static boolean_t hpet_use_hpet_timer(hrtime_t *expire); 757ff178cdSJimmy Vetayases static void hpet_use_lapic_timer(hrtime_t expire); 767ff178cdSJimmy Vetayases static void hpet_init_proxy_data(void); 777ff178cdSJimmy 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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