1/* 2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31 32 33#include <mach/mach_types.h> 34 35#include <architecture/i386/pio.h> 36#include <i386/machine_cpu.h> 37#include <i386/cpuid.h> 38#include <i386/cpu_threads.h> 39#include <i386/mp.h> 40#include <i386/machine_routines.h> 41#include <i386/pal_routines.h> 42#include <i386/proc_reg.h> 43#include <i386/misc_protos.h> 44#include <i386/lapic.h> 45#include <pexpert/pexpert.h> 46#include <machine/limits.h> 47#include <sys/kdebug.h> 48#include <i386/tsc.h> 49#include <i386/rtclock_protos.h> 50#include <i386/pal_routines.h> 51#include <kern/timer_queue.h> 52 53static uint64_t rtc_decrementer_min; 54static uint64_t rtc_decrementer_max; 55 56static uint64_t 57deadline_to_decrementer( 58 uint64_t deadline, 59 uint64_t now) 60{ 61 uint64_t delta; 62 63 if (deadline <= now) 64 return rtc_decrementer_min; 65 else { 66 delta = deadline - now; 67 return MIN(MAX(rtc_decrementer_min,delta),rtc_decrementer_max); 68 } 69} 70 71 72/* 73 * Regular local APIC timer case: 74 */ 75static void 76rtc_lapic_config_timer(void) 77{ 78 lapic_config_timer(TRUE, one_shot, divide_by_1); 79} 80static uint64_t 81rtc_lapic_set_timer(uint64_t deadline, uint64_t now) 82{ 83 uint64_t count; 84 uint64_t set = 0; 85 86 if (deadline > 0) { 87 /* 88 * Convert delta to bus ticks 89 * - time now is not relevant 90 */ 91 count = deadline_to_decrementer(deadline, now); 92 set = now + count; 93 lapic_set_timer_fast((uint32_t) tmrCvt(count, busFCvtn2t)); 94 } else { 95 lapic_set_timer(FALSE, one_shot, divide_by_1, 0); 96 } 97 98 KERNEL_DEBUG_CONSTANT( 99 DECR_SET_APIC_DEADLINE | DBG_FUNC_NONE, 100 now, deadline, 101 set, LAPIC_READ(TIMER_CURRENT_COUNT), 102 0); 103 104 return set; 105} 106 107/* 108 * TSC-deadline timer case: 109 */ 110static void 111rtc_lapic_config_tsc_deadline_timer(void) 112{ 113 lapic_config_tsc_deadline_timer(); 114} 115static uint64_t 116rtc_lapic_set_tsc_deadline_timer(uint64_t deadline, uint64_t now) 117{ 118 uint64_t delta; 119 uint64_t delta_tsc; 120 uint64_t tsc = rdtsc64(); 121 uint64_t set = 0; 122 123 if (deadline > 0) { 124 /* 125 * Convert to TSC 126 */ 127 delta = deadline_to_decrementer(deadline, now); 128 set = now + delta; 129 delta_tsc = tmrCvt(delta, tscFCvtn2t); 130 lapic_set_tsc_deadline_timer(tsc + delta_tsc); 131 } else { 132 lapic_set_tsc_deadline_timer(0); 133 } 134 135 KERNEL_DEBUG_CONSTANT( 136 DECR_SET_TSC_DEADLINE | DBG_FUNC_NONE, 137 now, deadline, 138 tsc, lapic_get_tsc_deadline_timer(), 139 0); 140 141 return set; 142} 143 144/* 145 * Definitions for timer operations table 146 */ 147 148rtc_timer_t rtc_timer_lapic = { 149 rtc_lapic_config_timer, 150 rtc_lapic_set_timer 151}; 152 153rtc_timer_t rtc_timer_tsc_deadline = { 154 rtc_lapic_config_tsc_deadline_timer, 155 rtc_lapic_set_tsc_deadline_timer 156}; 157 158rtc_timer_t *rtc_timer = &rtc_timer_lapic; /* defaults to LAPIC timer */ 159 160/* 161 * rtc_timer_init() is called at startup on the boot processor only. 162 */ 163void 164rtc_timer_init(void) 165{ 166 int TSC_deadline_timer = 0; 167 168 /* See whether we can use the local apic in TSC-deadline mode */ 169 if ((cpuid_features() & CPUID_FEATURE_TSCTMR)) { 170 TSC_deadline_timer = 1; 171 PE_parse_boot_argn("TSC_deadline_timer", &TSC_deadline_timer, 172 sizeof(TSC_deadline_timer)); 173 printf("TSC Deadline Timer supported %s enabled\n", 174 TSC_deadline_timer ? "and" : "but not"); 175 } 176 177 if (TSC_deadline_timer) { 178 rtc_timer = &rtc_timer_tsc_deadline; 179 rtc_decrementer_max = UINT64_MAX; /* effectively none */ 180 /* 181 * The min could be as low as 1nsec, 182 * but we're being conservative for now and making it the same 183 * as for the local apic timer. 184 */ 185 rtc_decrementer_min = 1*NSEC_PER_USEC; /* 1 usec */ 186 } else { 187 /* 188 * Compute the longest interval using LAPIC timer. 189 */ 190 rtc_decrementer_max = tmrCvt(0x7fffffffULL, busFCvtt2n); 191 kprintf("maxDec: %lld\n", rtc_decrementer_max); 192 rtc_decrementer_min = 1*NSEC_PER_USEC; /* 1 usec */ 193 } 194 195 /* Point LAPIC interrupts to hardclock() */ 196 lapic_set_timer_func((i386_intr_func_t) rtclock_intr); 197} 198