141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * CDDL HEADER START 341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 441afdfa7SKrishnendu Sadhukhan - Sun Microsystems * The contents of this file are subject to the terms of the 541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Common Development and Distribution License (the "License"). 641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * You may not use this file except in compliance with the License. 741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * or http://www.opensolaris.org/os/licensing. 1041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * See the License for the specific language governing permissions 1141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * and limitations under the License. 1241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 1341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * When distributing Covered Code, include this CDDL HEADER in each 1441afdfa7SKrishnendu Sadhukhan - Sun Microsystems * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * If applicable, add the following below this CDDL HEADER, with the 1641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * fields enclosed by brackets "[]" replaced with your own identifying 1741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * information: Portions Copyright [yyyy] [name of copyright owner] 1841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 1941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * CDDL HEADER END 2041afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 2141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 2241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2341afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 2441afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 2541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Copyright (c) 2010, Intel Corporation. 2641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * All rights reserved. 2741afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 28*223b8c65SGarrett D'Amore /* 29*223b8c65SGarrett D'Amore * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 30*223b8c65SGarrett D'Amore */ 3141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 3241afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/time.h> 3341afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/psm.h> 3441afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/psm_common.h> 3541afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/apic.h> 3641afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/pit.h> 3741afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/x86_archext.h> 3841afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/archsystm.h> 3941afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/machsystm.h> 4041afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/cpuvar.h> 4141afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/clock.h> 4241afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/apic_timer.h> 4341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 4441afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 4541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * preferred apic timer mode, allow tuning from the /etc/system file. 4641afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 4741afdfa7SKrishnendu Sadhukhan - Sun Microsystems int apic_timer_preferred_mode = APIC_TIMER_MODE_DEADLINE; 4841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 4941afdfa7SKrishnendu Sadhukhan - Sun Microsystems int apic_oneshot = 0; 5041afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t apic_hertz_count; 5141afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t apic_nsec_per_intr = 0; 5241afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint64_t apic_ticks_per_SFnsecs; /* # of ticks in SF nsecs */ 5341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 5441afdfa7SKrishnendu Sadhukhan - Sun Microsystems static int apic_min_timer_ticks = 1; /* minimum timer tick */ 5541afdfa7SKrishnendu Sadhukhan - Sun Microsystems static hrtime_t apic_nsec_max; 5641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 5741afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void periodic_timer_enable(void); 5841afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void periodic_timer_disable(void); 5941afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void periodic_timer_reprogram(hrtime_t); 6041afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void oneshot_timer_enable(void); 6141afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void oneshot_timer_disable(void); 6241afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void oneshot_timer_reprogram(hrtime_t); 6341afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void deadline_timer_enable(void); 6441afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void deadline_timer_disable(void); 6541afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void deadline_timer_reprogram(hrtime_t); 6641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 6741afdfa7SKrishnendu Sadhukhan - Sun Microsystems extern int apic_clkvect; 6841afdfa7SKrishnendu Sadhukhan - Sun Microsystems extern uint32_t apic_divide_reg_init; 6941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 7041afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 7141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * apic timer data structure 7241afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 7341afdfa7SKrishnendu Sadhukhan - Sun Microsystems typedef struct apic_timer { 7441afdfa7SKrishnendu Sadhukhan - Sun Microsystems int mode; 7541afdfa7SKrishnendu Sadhukhan - Sun Microsystems void (*apic_timer_enable_ops)(void); 7641afdfa7SKrishnendu Sadhukhan - Sun Microsystems void (*apic_timer_disable_ops)(void); 7741afdfa7SKrishnendu Sadhukhan - Sun Microsystems void (*apic_timer_reprogram_ops)(hrtime_t); 7841afdfa7SKrishnendu Sadhukhan - Sun Microsystems } apic_timer_t; 7941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 8041afdfa7SKrishnendu Sadhukhan - Sun Microsystems static apic_timer_t apic_timer; 8141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 8241afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 8341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * apic timer initialization 8441afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 8541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * For the one-shot mode request case, the function returns the 8641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * resolution (in nanoseconds) for the hardware timer interrupt. 8741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * If one-shot mode capability is not available, the return value 8841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * will be 0. 8941afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 9041afdfa7SKrishnendu Sadhukhan - Sun Microsystems int 9141afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_init(int hertz) 9241afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 9341afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t apic_ticks = 0; 9441afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t pit_ticks; 9541afdfa7SKrishnendu Sadhukhan - Sun Microsystems int ret, timer_mode; 9641afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint16_t pit_ticks_adj; 9741afdfa7SKrishnendu Sadhukhan - Sun Microsystems static int firsttime = 1; 9841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 9941afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (firsttime) { 10041afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* first time calibrate on CPU0 only */ 10141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 10241afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_DIVIDE_REG, apic_divide_reg_init); 10341afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_INIT_COUNT, APIC_MAXVAL); 10441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_ticks = apic_calibrate(apicadr, &pit_ticks_adj); 10541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 10641afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* total number of PIT ticks corresponding to apic_ticks */ 10741afdfa7SKrishnendu Sadhukhan - Sun Microsystems pit_ticks = APIC_TIME_COUNT + pit_ticks_adj; 10841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 10941afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 11041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Determine the number of nanoseconds per APIC clock tick 11141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * and then determine how many APIC ticks to interrupt at the 11241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * desired frequency 11341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * apic_ticks / (pitticks / PIT_HZ) = apic_ticks_per_s 11441afdfa7SKrishnendu Sadhukhan - Sun Microsystems * (apic_ticks * PIT_HZ) / pitticks = apic_ticks_per_s 11541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * apic_ticks_per_ns = (apic_ticks * PIT_HZ) / (pitticks * 10^9) 11641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * pic_ticks_per_SFns = 11741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * (SF * apic_ticks * PIT_HZ) / (pitticks * 10^9) 11841afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 11941afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_ticks_per_SFnsecs = ((SF * apic_ticks * PIT_HZ) / 12041afdfa7SKrishnendu Sadhukhan - Sun Microsystems ((uint64_t)pit_ticks * NANOSEC)); 12141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 12241afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* the interval timer initial count is 32 bit max */ 12341afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_nsec_max = APIC_TICKS_TO_NSECS(APIC_MAXVAL); 12441afdfa7SKrishnendu Sadhukhan - Sun Microsystems firsttime = 0; 12541afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 12641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 12741afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (hertz == 0) { 12841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* requested one_shot */ 12941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 13041afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 13141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * return 0 if TSC is not supported. 13241afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 13341afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (!tsc_gethrtime_enable) 13441afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 13541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 13641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * return 0 if one_shot is not preferred. 13741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * here, APIC_TIMER_DEADLINE is also an one_shot mode. 13841afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 13941afdfa7SKrishnendu Sadhukhan - Sun Microsystems if ((apic_timer_preferred_mode != APIC_TIMER_MODE_ONESHOT) && 14041afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_timer_preferred_mode != APIC_TIMER_MODE_DEADLINE)) 14141afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 14241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 14341afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_oneshot = 1; 14441afdfa7SKrishnendu Sadhukhan - Sun Microsystems ret = (int)APIC_TICKS_TO_NSECS(1); 14541afdfa7SKrishnendu Sadhukhan - Sun Microsystems if ((apic_timer_preferred_mode == APIC_TIMER_MODE_DEADLINE) && 14641afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported()) { 14741afdfa7SKrishnendu Sadhukhan - Sun Microsystems timer_mode = APIC_TIMER_MODE_DEADLINE; 14841afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else { 14941afdfa7SKrishnendu Sadhukhan - Sun Microsystems timer_mode = APIC_TIMER_MODE_ONESHOT; 15041afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 15141afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else { 15241afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* periodic */ 15341afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_nsec_per_intr = NANOSEC / hertz; 15441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_hertz_count = APIC_NSECS_TO_TICKS(apic_nsec_per_intr); 15541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 15641afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* program the local APIC to interrupt at the given frequency */ 15741afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_INIT_COUNT, apic_hertz_count); 15841afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 15941afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT) | AV_PERIODIC); 16041afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_oneshot = 0; 16141afdfa7SKrishnendu Sadhukhan - Sun Microsystems timer_mode = APIC_TIMER_MODE_PERIODIC; 16241afdfa7SKrishnendu Sadhukhan - Sun Microsystems ret = NANOSEC / hertz; 16341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 16441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 16541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 16641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * initialize apic_timer data structure, install the timer ops 16741afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 16841afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.mode = timer_mode; 16941afdfa7SKrishnendu Sadhukhan - Sun Microsystems switch (timer_mode) { 17041afdfa7SKrishnendu Sadhukhan - Sun Microsystems default: 17141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* FALLTHROUGH */ 17241afdfa7SKrishnendu Sadhukhan - Sun Microsystems case APIC_TIMER_MODE_ONESHOT: 17341afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_enable_ops = oneshot_timer_enable; 17441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_disable_ops = oneshot_timer_disable; 17541afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_reprogram_ops = oneshot_timer_reprogram; 17641afdfa7SKrishnendu Sadhukhan - Sun Microsystems break; 17741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 17841afdfa7SKrishnendu Sadhukhan - Sun Microsystems case APIC_TIMER_MODE_PERIODIC: 17941afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_enable_ops = periodic_timer_enable; 18041afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_disable_ops = periodic_timer_disable; 18141afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_reprogram_ops = periodic_timer_reprogram; 18241afdfa7SKrishnendu Sadhukhan - Sun Microsystems break; 18341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 18441afdfa7SKrishnendu Sadhukhan - Sun Microsystems case APIC_TIMER_MODE_DEADLINE: 18541afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_enable_ops = deadline_timer_enable; 18641afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_disable_ops = deadline_timer_disable; 18741afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_reprogram_ops = deadline_timer_reprogram; 18841afdfa7SKrishnendu Sadhukhan - Sun Microsystems break; 18941afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 19041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 19141afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (ret); 19241afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 19341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 19441afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 19541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * periodic timer mode ops 19641afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 19741afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* periodic timer enable */ 19841afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 19941afdfa7SKrishnendu Sadhukhan - Sun Microsystems periodic_timer_enable(void) 20041afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 20141afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 20241afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT) | AV_PERIODIC); 20341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 20441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 20541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* periodic timer disable */ 20641afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 20741afdfa7SKrishnendu Sadhukhan - Sun Microsystems periodic_timer_disable(void) 20841afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 20941afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 21041afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT) | AV_MASK); 21141afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 21241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 21341afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* periodic timer reprogram */ 21441afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 21541afdfa7SKrishnendu Sadhukhan - Sun Microsystems periodic_timer_reprogram(hrtime_t time) 21641afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 21741afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t ticks; 21841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* time is the interval for periodic mode */ 21941afdfa7SKrishnendu Sadhukhan - Sun Microsystems ticks = APIC_NSECS_TO_TICKS(time); 22041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 22141afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (ticks < apic_min_timer_ticks) 22241afdfa7SKrishnendu Sadhukhan - Sun Microsystems ticks = apic_min_timer_ticks; 22341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 22441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_INIT_COUNT, ticks); 22541afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 22641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 22741afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 22841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * oneshot timer mode ops 22941afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 23041afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* oneshot timer enable */ 23141afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 23241afdfa7SKrishnendu Sadhukhan - Sun Microsystems oneshot_timer_enable(void) 23341afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 23441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 23541afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT)); 23641afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 23741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 23841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* oneshot timer disable */ 23941afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 24041afdfa7SKrishnendu Sadhukhan - Sun Microsystems oneshot_timer_disable(void) 24141afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 24241afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 24341afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT) | AV_MASK); 24441afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 24541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 24641afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* oneshot timer reprogram */ 24741afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 24841afdfa7SKrishnendu Sadhukhan - Sun Microsystems oneshot_timer_reprogram(hrtime_t time) 24941afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 25041afdfa7SKrishnendu Sadhukhan - Sun Microsystems hrtime_t now; 25141afdfa7SKrishnendu Sadhukhan - Sun Microsystems int64_t delta; 25241afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t ticks; 25341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 25441afdfa7SKrishnendu Sadhukhan - Sun Microsystems now = gethrtime(); 25541afdfa7SKrishnendu Sadhukhan - Sun Microsystems delta = time - now; 25641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 25741afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (delta <= 0) { 25841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 25941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * requested to generate an interrupt in the past 26041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * generate an interrupt as soon as possible 26141afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 26241afdfa7SKrishnendu Sadhukhan - Sun Microsystems ticks = apic_min_timer_ticks; 26341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else if (delta > apic_nsec_max) { 26441afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 26541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * requested to generate an interrupt at a time 26641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * further than what we are capable of. Set to max 26741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * the hardware can handle 26841afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 26941afdfa7SKrishnendu Sadhukhan - Sun Microsystems ticks = APIC_MAXVAL; 27041afdfa7SKrishnendu Sadhukhan - Sun Microsystems #ifdef DEBUG 27141afdfa7SKrishnendu Sadhukhan - Sun Microsystems cmn_err(CE_CONT, "apic_timer_reprogram, request at" 27241afdfa7SKrishnendu Sadhukhan - Sun Microsystems " %lld too far in future, current time" 27341afdfa7SKrishnendu Sadhukhan - Sun Microsystems " %lld \n", time, now); 27441afdfa7SKrishnendu Sadhukhan - Sun Microsystems #endif 27541afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else { 27641afdfa7SKrishnendu Sadhukhan - Sun Microsystems ticks = APIC_NSECS_TO_TICKS(delta); 27741afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 27841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 27941afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (ticks < apic_min_timer_ticks) 28041afdfa7SKrishnendu Sadhukhan - Sun Microsystems ticks = apic_min_timer_ticks; 28141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 28241afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_INIT_COUNT, ticks); 28341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 28441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 28541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 28641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * deadline timer mode ops 28741afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 28841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* deadline timer enable */ 28941afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 29041afdfa7SKrishnendu Sadhukhan - Sun Microsystems deadline_timer_enable(void) 29141afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 292*223b8c65SGarrett D'Amore uint64_t ticks; 293*223b8c65SGarrett D'Amore 29441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 29541afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT) | AV_DEADLINE); 296*223b8c65SGarrett D'Amore /* 297*223b8c65SGarrett D'Amore * Now we have to serialize this per the SDM. That is to 298*223b8c65SGarrett D'Amore * say, the above enabling can race in the pipeline with 299*223b8c65SGarrett D'Amore * changes to the MSR. We need to make sure the above 300*223b8c65SGarrett D'Amore * operation is complete before we proceed to reprogram 301*223b8c65SGarrett D'Amore * the deadline value in reprogram(). The algorithm 302*223b8c65SGarrett D'Amore * recommended by the Intel SDM 3A in 10.5.1.4 is: 303*223b8c65SGarrett D'Amore * 304*223b8c65SGarrett D'Amore * a) write a big value to the deadline register 305*223b8c65SGarrett D'Amore * b) read the register back 306*223b8c65SGarrett D'Amore * c) if it reads zero, go back to a and try again 307*223b8c65SGarrett D'Amore */ 308*223b8c65SGarrett D'Amore 309*223b8c65SGarrett D'Amore do { 310*223b8c65SGarrett D'Amore /* write a really big value */ 311*223b8c65SGarrett D'Amore wrmsr(IA32_DEADLINE_TSC_MSR, 1ULL << 63); 312*223b8c65SGarrett D'Amore ticks = rdmsr(IA32_DEADLINE_TSC_MSR); 313*223b8c65SGarrett D'Amore } while (ticks == 0); 31441afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 31541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 31641afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* deadline timer disable */ 31741afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 31841afdfa7SKrishnendu Sadhukhan - Sun Microsystems deadline_timer_disable(void) 31941afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 32041afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 32141afdfa7SKrishnendu Sadhukhan - Sun Microsystems (apic_clkvect + APIC_BASE_VECT) | AV_MASK); 32241afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 32341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 32441afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* deadline timer reprogram */ 32541afdfa7SKrishnendu Sadhukhan - Sun Microsystems static void 32641afdfa7SKrishnendu Sadhukhan - Sun Microsystems deadline_timer_reprogram(hrtime_t time) 32741afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 328*223b8c65SGarrett D'Amore int64_t delta; 32941afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint64_t ticks; 33041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 33141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 332*223b8c65SGarrett D'Amore * Note that this entire routine is called with 333*223b8c65SGarrett D'Amore * CBE_HIGH_PIL, so we needn't worry about preemption. 33441afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 335*223b8c65SGarrett D'Amore delta = time - gethrtime(); 33641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 337*223b8c65SGarrett D'Amore /* The unscalehrtime wants unsigned values. */ 338*223b8c65SGarrett D'Amore delta = max(delta, 0); 339*223b8c65SGarrett D'Amore 340*223b8c65SGarrett D'Amore /* Now we shouldn't be interrupted, we can set the deadline */ 341*223b8c65SGarrett D'Amore ticks = (uint64_t)tsc_read() + unscalehrtime(delta); 34241afdfa7SKrishnendu Sadhukhan - Sun Microsystems wrmsr(IA32_DEADLINE_TSC_MSR, ticks); 34341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 34441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 34541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 34641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * This function will reprogram the timer. 34741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 34841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * When in oneshot mode the argument is the absolute time in future to 34941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * generate the interrupt at. 35041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 35141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * When in periodic mode, the argument is the interval at which the 35241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * interrupts should be generated. There is no need to support the periodic 35341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * mode timer change at this time. 35441afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 35541afdfa7SKrishnendu Sadhukhan - Sun Microsystems void 35641afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_reprogram(hrtime_t time) 35741afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 35841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 35941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * we should be Called from high PIL context (CBE_HIGH_PIL), 36041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * so kpreempt is disabled. 36141afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 36241afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_reprogram_ops(time); 36341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 36441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 36541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 36641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * This function will enable timer interrupts. 36741afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 36841afdfa7SKrishnendu Sadhukhan - Sun Microsystems void 36941afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_enable(void) 37041afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 37141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 37241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * we should be Called from high PIL context (CBE_HIGH_PIL), 37341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * so kpreempt is disabled. 37441afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 37541afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_enable_ops(); 37641afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 37741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 37841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 37941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * This function will disable timer interrupts. 38041afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 38141afdfa7SKrishnendu Sadhukhan - Sun Microsystems void 38241afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_disable(void) 38341afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 38441afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 38541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * we should be Called from high PIL context (CBE_HIGH_PIL), 38641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * so kpreempt is disabled. 38741afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 38841afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer.apic_timer_disable_ops(); 38941afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 39041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 39141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 39241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Set timer far into the future and return timer 39341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * current count in nanoseconds. 39441afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 39541afdfa7SKrishnendu Sadhukhan - Sun Microsystems hrtime_t 39641afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_stop_count(void) 39741afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 39841afdfa7SKrishnendu Sadhukhan - Sun Microsystems hrtime_t ns_val; 39941afdfa7SKrishnendu Sadhukhan - Sun Microsystems int enable_val, count_val; 40041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 40141afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 40241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Should be called with interrupts disabled. 40341afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 40441afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(!interrupts_enabled()); 40541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 40641afdfa7SKrishnendu Sadhukhan - Sun Microsystems enable_val = apic_reg_ops->apic_read(APIC_LOCAL_TIMER); 40741afdfa7SKrishnendu Sadhukhan - Sun Microsystems if ((enable_val & AV_MASK) == AV_MASK) 40841afdfa7SKrishnendu Sadhukhan - Sun Microsystems return ((hrtime_t)-1); /* timer is disabled */ 40941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 41041afdfa7SKrishnendu Sadhukhan - Sun Microsystems count_val = apic_reg_ops->apic_read(APIC_CURR_COUNT); 41141afdfa7SKrishnendu Sadhukhan - Sun Microsystems ns_val = APIC_TICKS_TO_NSECS(count_val); 41241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 41341afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_reg_ops->apic_write(APIC_INIT_COUNT, APIC_MAXVAL); 41441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 41541afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (ns_val); 41641afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 41741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 41841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 41941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Reprogram timer after Deep C-State. 42041afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 42141afdfa7SKrishnendu Sadhukhan - Sun Microsystems void 42241afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_restart(hrtime_t time) 42341afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 42441afdfa7SKrishnendu Sadhukhan - Sun Microsystems apic_timer_reprogram(time); 42541afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 426