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
apic_timer_init(int hertz)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
periodic_timer_enable(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
periodic_timer_disable(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
periodic_timer_reprogram(hrtime_t time)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
oneshot_timer_enable(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
oneshot_timer_disable(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
oneshot_timer_reprogram(hrtime_t time)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
deadline_timer_enable(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
deadline_timer_disable(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
deadline_timer_reprogram(hrtime_t time)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
apic_timer_reprogram(hrtime_t time)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
apic_timer_enable(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
apic_timer_disable(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
apic_timer_stop_count(void)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
apic_timer_restart(hrtime_t time)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