1*13029SKrishnendu.Sadhukhan@Sun.COM /*
2*13029SKrishnendu.Sadhukhan@Sun.COM * CDDL HEADER START
3*13029SKrishnendu.Sadhukhan@Sun.COM *
4*13029SKrishnendu.Sadhukhan@Sun.COM * The contents of this file are subject to the terms of the
5*13029SKrishnendu.Sadhukhan@Sun.COM * Common Development and Distribution License (the "License").
6*13029SKrishnendu.Sadhukhan@Sun.COM * You may not use this file except in compliance with the License.
7*13029SKrishnendu.Sadhukhan@Sun.COM *
8*13029SKrishnendu.Sadhukhan@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*13029SKrishnendu.Sadhukhan@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*13029SKrishnendu.Sadhukhan@Sun.COM * See the License for the specific language governing permissions
11*13029SKrishnendu.Sadhukhan@Sun.COM * and limitations under the License.
12*13029SKrishnendu.Sadhukhan@Sun.COM *
13*13029SKrishnendu.Sadhukhan@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*13029SKrishnendu.Sadhukhan@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*13029SKrishnendu.Sadhukhan@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*13029SKrishnendu.Sadhukhan@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*13029SKrishnendu.Sadhukhan@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*13029SKrishnendu.Sadhukhan@Sun.COM *
19*13029SKrishnendu.Sadhukhan@Sun.COM * CDDL HEADER END
20*13029SKrishnendu.Sadhukhan@Sun.COM */
21*13029SKrishnendu.Sadhukhan@Sun.COM /*
22*13029SKrishnendu.Sadhukhan@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23*13029SKrishnendu.Sadhukhan@Sun.COM */
24*13029SKrishnendu.Sadhukhan@Sun.COM /*
25*13029SKrishnendu.Sadhukhan@Sun.COM * Copyright (c) 2010, Intel Corporation.
26*13029SKrishnendu.Sadhukhan@Sun.COM * All rights reserved.
27*13029SKrishnendu.Sadhukhan@Sun.COM */
28*13029SKrishnendu.Sadhukhan@Sun.COM
29*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/time.h>
30*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/psm.h>
31*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/psm_common.h>
32*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/apic.h>
33*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/pit.h>
34*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/x86_archext.h>
35*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/archsystm.h>
36*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/machsystm.h>
37*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/cpuvar.h>
38*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/clock.h>
39*13029SKrishnendu.Sadhukhan@Sun.COM #include <sys/apic_timer.h>
40*13029SKrishnendu.Sadhukhan@Sun.COM
41*13029SKrishnendu.Sadhukhan@Sun.COM /*
42*13029SKrishnendu.Sadhukhan@Sun.COM * preferred apic timer mode, allow tuning from the /etc/system file.
43*13029SKrishnendu.Sadhukhan@Sun.COM */
44*13029SKrishnendu.Sadhukhan@Sun.COM int apic_timer_preferred_mode = APIC_TIMER_MODE_DEADLINE;
45*13029SKrishnendu.Sadhukhan@Sun.COM
46*13029SKrishnendu.Sadhukhan@Sun.COM int apic_oneshot = 0;
47*13029SKrishnendu.Sadhukhan@Sun.COM uint_t apic_hertz_count;
48*13029SKrishnendu.Sadhukhan@Sun.COM uint_t apic_nsec_per_intr = 0;
49*13029SKrishnendu.Sadhukhan@Sun.COM uint64_t apic_ticks_per_SFnsecs; /* # of ticks in SF nsecs */
50*13029SKrishnendu.Sadhukhan@Sun.COM
51*13029SKrishnendu.Sadhukhan@Sun.COM static int apic_min_timer_ticks = 1; /* minimum timer tick */
52*13029SKrishnendu.Sadhukhan@Sun.COM static hrtime_t apic_nsec_max;
53*13029SKrishnendu.Sadhukhan@Sun.COM
54*13029SKrishnendu.Sadhukhan@Sun.COM static void periodic_timer_enable(void);
55*13029SKrishnendu.Sadhukhan@Sun.COM static void periodic_timer_disable(void);
56*13029SKrishnendu.Sadhukhan@Sun.COM static void periodic_timer_reprogram(hrtime_t);
57*13029SKrishnendu.Sadhukhan@Sun.COM static void oneshot_timer_enable(void);
58*13029SKrishnendu.Sadhukhan@Sun.COM static void oneshot_timer_disable(void);
59*13029SKrishnendu.Sadhukhan@Sun.COM static void oneshot_timer_reprogram(hrtime_t);
60*13029SKrishnendu.Sadhukhan@Sun.COM static void deadline_timer_enable(void);
61*13029SKrishnendu.Sadhukhan@Sun.COM static void deadline_timer_disable(void);
62*13029SKrishnendu.Sadhukhan@Sun.COM static void deadline_timer_reprogram(hrtime_t);
63*13029SKrishnendu.Sadhukhan@Sun.COM
64*13029SKrishnendu.Sadhukhan@Sun.COM extern int apic_clkvect;
65*13029SKrishnendu.Sadhukhan@Sun.COM extern uint32_t apic_divide_reg_init;
66*13029SKrishnendu.Sadhukhan@Sun.COM
67*13029SKrishnendu.Sadhukhan@Sun.COM /*
68*13029SKrishnendu.Sadhukhan@Sun.COM * apic timer data structure
69*13029SKrishnendu.Sadhukhan@Sun.COM */
70*13029SKrishnendu.Sadhukhan@Sun.COM typedef struct apic_timer {
71*13029SKrishnendu.Sadhukhan@Sun.COM int mode;
72*13029SKrishnendu.Sadhukhan@Sun.COM void (*apic_timer_enable_ops)(void);
73*13029SKrishnendu.Sadhukhan@Sun.COM void (*apic_timer_disable_ops)(void);
74*13029SKrishnendu.Sadhukhan@Sun.COM void (*apic_timer_reprogram_ops)(hrtime_t);
75*13029SKrishnendu.Sadhukhan@Sun.COM } apic_timer_t;
76*13029SKrishnendu.Sadhukhan@Sun.COM
77*13029SKrishnendu.Sadhukhan@Sun.COM static apic_timer_t apic_timer;
78*13029SKrishnendu.Sadhukhan@Sun.COM
79*13029SKrishnendu.Sadhukhan@Sun.COM /*
80*13029SKrishnendu.Sadhukhan@Sun.COM * apic timer initialization
81*13029SKrishnendu.Sadhukhan@Sun.COM *
82*13029SKrishnendu.Sadhukhan@Sun.COM * For the one-shot mode request case, the function returns the
83*13029SKrishnendu.Sadhukhan@Sun.COM * resolution (in nanoseconds) for the hardware timer interrupt.
84*13029SKrishnendu.Sadhukhan@Sun.COM * If one-shot mode capability is not available, the return value
85*13029SKrishnendu.Sadhukhan@Sun.COM * will be 0.
86*13029SKrishnendu.Sadhukhan@Sun.COM */
87*13029SKrishnendu.Sadhukhan@Sun.COM int
apic_timer_init(int hertz)88*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_init(int hertz)
89*13029SKrishnendu.Sadhukhan@Sun.COM {
90*13029SKrishnendu.Sadhukhan@Sun.COM uint_t apic_ticks = 0;
91*13029SKrishnendu.Sadhukhan@Sun.COM uint_t pit_ticks;
92*13029SKrishnendu.Sadhukhan@Sun.COM int ret, timer_mode;
93*13029SKrishnendu.Sadhukhan@Sun.COM uint16_t pit_ticks_adj;
94*13029SKrishnendu.Sadhukhan@Sun.COM static int firsttime = 1;
95*13029SKrishnendu.Sadhukhan@Sun.COM
96*13029SKrishnendu.Sadhukhan@Sun.COM if (firsttime) {
97*13029SKrishnendu.Sadhukhan@Sun.COM /* first time calibrate on CPU0 only */
98*13029SKrishnendu.Sadhukhan@Sun.COM
99*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_DIVIDE_REG, apic_divide_reg_init);
100*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_INIT_COUNT, APIC_MAXVAL);
101*13029SKrishnendu.Sadhukhan@Sun.COM apic_ticks = apic_calibrate(apicadr, &pit_ticks_adj);
102*13029SKrishnendu.Sadhukhan@Sun.COM
103*13029SKrishnendu.Sadhukhan@Sun.COM /* total number of PIT ticks corresponding to apic_ticks */
104*13029SKrishnendu.Sadhukhan@Sun.COM pit_ticks = APIC_TIME_COUNT + pit_ticks_adj;
105*13029SKrishnendu.Sadhukhan@Sun.COM
106*13029SKrishnendu.Sadhukhan@Sun.COM /*
107*13029SKrishnendu.Sadhukhan@Sun.COM * Determine the number of nanoseconds per APIC clock tick
108*13029SKrishnendu.Sadhukhan@Sun.COM * and then determine how many APIC ticks to interrupt at the
109*13029SKrishnendu.Sadhukhan@Sun.COM * desired frequency
110*13029SKrishnendu.Sadhukhan@Sun.COM * apic_ticks / (pitticks / PIT_HZ) = apic_ticks_per_s
111*13029SKrishnendu.Sadhukhan@Sun.COM * (apic_ticks * PIT_HZ) / pitticks = apic_ticks_per_s
112*13029SKrishnendu.Sadhukhan@Sun.COM * apic_ticks_per_ns = (apic_ticks * PIT_HZ) / (pitticks * 10^9)
113*13029SKrishnendu.Sadhukhan@Sun.COM * pic_ticks_per_SFns =
114*13029SKrishnendu.Sadhukhan@Sun.COM * (SF * apic_ticks * PIT_HZ) / (pitticks * 10^9)
115*13029SKrishnendu.Sadhukhan@Sun.COM */
116*13029SKrishnendu.Sadhukhan@Sun.COM apic_ticks_per_SFnsecs = ((SF * apic_ticks * PIT_HZ) /
117*13029SKrishnendu.Sadhukhan@Sun.COM ((uint64_t)pit_ticks * NANOSEC));
118*13029SKrishnendu.Sadhukhan@Sun.COM
119*13029SKrishnendu.Sadhukhan@Sun.COM /* the interval timer initial count is 32 bit max */
120*13029SKrishnendu.Sadhukhan@Sun.COM apic_nsec_max = APIC_TICKS_TO_NSECS(APIC_MAXVAL);
121*13029SKrishnendu.Sadhukhan@Sun.COM firsttime = 0;
122*13029SKrishnendu.Sadhukhan@Sun.COM }
123*13029SKrishnendu.Sadhukhan@Sun.COM
124*13029SKrishnendu.Sadhukhan@Sun.COM if (hertz == 0) {
125*13029SKrishnendu.Sadhukhan@Sun.COM /* requested one_shot */
126*13029SKrishnendu.Sadhukhan@Sun.COM
127*13029SKrishnendu.Sadhukhan@Sun.COM /*
128*13029SKrishnendu.Sadhukhan@Sun.COM * return 0 if TSC is not supported.
129*13029SKrishnendu.Sadhukhan@Sun.COM */
130*13029SKrishnendu.Sadhukhan@Sun.COM if (!tsc_gethrtime_enable)
131*13029SKrishnendu.Sadhukhan@Sun.COM return (0);
132*13029SKrishnendu.Sadhukhan@Sun.COM /*
133*13029SKrishnendu.Sadhukhan@Sun.COM * return 0 if one_shot is not preferred.
134*13029SKrishnendu.Sadhukhan@Sun.COM * here, APIC_TIMER_DEADLINE is also an one_shot mode.
135*13029SKrishnendu.Sadhukhan@Sun.COM */
136*13029SKrishnendu.Sadhukhan@Sun.COM if ((apic_timer_preferred_mode != APIC_TIMER_MODE_ONESHOT) &&
137*13029SKrishnendu.Sadhukhan@Sun.COM (apic_timer_preferred_mode != APIC_TIMER_MODE_DEADLINE))
138*13029SKrishnendu.Sadhukhan@Sun.COM return (0);
139*13029SKrishnendu.Sadhukhan@Sun.COM
140*13029SKrishnendu.Sadhukhan@Sun.COM apic_oneshot = 1;
141*13029SKrishnendu.Sadhukhan@Sun.COM ret = (int)APIC_TICKS_TO_NSECS(1);
142*13029SKrishnendu.Sadhukhan@Sun.COM if ((apic_timer_preferred_mode == APIC_TIMER_MODE_DEADLINE) &&
143*13029SKrishnendu.Sadhukhan@Sun.COM cpuid_deadline_tsc_supported()) {
144*13029SKrishnendu.Sadhukhan@Sun.COM timer_mode = APIC_TIMER_MODE_DEADLINE;
145*13029SKrishnendu.Sadhukhan@Sun.COM } else {
146*13029SKrishnendu.Sadhukhan@Sun.COM timer_mode = APIC_TIMER_MODE_ONESHOT;
147*13029SKrishnendu.Sadhukhan@Sun.COM }
148*13029SKrishnendu.Sadhukhan@Sun.COM } else {
149*13029SKrishnendu.Sadhukhan@Sun.COM /* periodic */
150*13029SKrishnendu.Sadhukhan@Sun.COM apic_nsec_per_intr = NANOSEC / hertz;
151*13029SKrishnendu.Sadhukhan@Sun.COM apic_hertz_count = APIC_NSECS_TO_TICKS(apic_nsec_per_intr);
152*13029SKrishnendu.Sadhukhan@Sun.COM
153*13029SKrishnendu.Sadhukhan@Sun.COM /* program the local APIC to interrupt at the given frequency */
154*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_INIT_COUNT, apic_hertz_count);
155*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
156*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT) | AV_PERIODIC);
157*13029SKrishnendu.Sadhukhan@Sun.COM apic_oneshot = 0;
158*13029SKrishnendu.Sadhukhan@Sun.COM timer_mode = APIC_TIMER_MODE_PERIODIC;
159*13029SKrishnendu.Sadhukhan@Sun.COM ret = NANOSEC / hertz;
160*13029SKrishnendu.Sadhukhan@Sun.COM }
161*13029SKrishnendu.Sadhukhan@Sun.COM
162*13029SKrishnendu.Sadhukhan@Sun.COM /*
163*13029SKrishnendu.Sadhukhan@Sun.COM * initialize apic_timer data structure, install the timer ops
164*13029SKrishnendu.Sadhukhan@Sun.COM */
165*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.mode = timer_mode;
166*13029SKrishnendu.Sadhukhan@Sun.COM switch (timer_mode) {
167*13029SKrishnendu.Sadhukhan@Sun.COM default:
168*13029SKrishnendu.Sadhukhan@Sun.COM /* FALLTHROUGH */
169*13029SKrishnendu.Sadhukhan@Sun.COM case APIC_TIMER_MODE_ONESHOT:
170*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_enable_ops = oneshot_timer_enable;
171*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_disable_ops = oneshot_timer_disable;
172*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_reprogram_ops = oneshot_timer_reprogram;
173*13029SKrishnendu.Sadhukhan@Sun.COM break;
174*13029SKrishnendu.Sadhukhan@Sun.COM
175*13029SKrishnendu.Sadhukhan@Sun.COM case APIC_TIMER_MODE_PERIODIC:
176*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_enable_ops = periodic_timer_enable;
177*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_disable_ops = periodic_timer_disable;
178*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_reprogram_ops = periodic_timer_reprogram;
179*13029SKrishnendu.Sadhukhan@Sun.COM break;
180*13029SKrishnendu.Sadhukhan@Sun.COM
181*13029SKrishnendu.Sadhukhan@Sun.COM case APIC_TIMER_MODE_DEADLINE:
182*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_enable_ops = deadline_timer_enable;
183*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_disable_ops = deadline_timer_disable;
184*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_reprogram_ops = deadline_timer_reprogram;
185*13029SKrishnendu.Sadhukhan@Sun.COM break;
186*13029SKrishnendu.Sadhukhan@Sun.COM }
187*13029SKrishnendu.Sadhukhan@Sun.COM
188*13029SKrishnendu.Sadhukhan@Sun.COM return (ret);
189*13029SKrishnendu.Sadhukhan@Sun.COM }
190*13029SKrishnendu.Sadhukhan@Sun.COM
191*13029SKrishnendu.Sadhukhan@Sun.COM /*
192*13029SKrishnendu.Sadhukhan@Sun.COM * periodic timer mode ops
193*13029SKrishnendu.Sadhukhan@Sun.COM */
194*13029SKrishnendu.Sadhukhan@Sun.COM /* periodic timer enable */
195*13029SKrishnendu.Sadhukhan@Sun.COM static void
periodic_timer_enable(void)196*13029SKrishnendu.Sadhukhan@Sun.COM periodic_timer_enable(void)
197*13029SKrishnendu.Sadhukhan@Sun.COM {
198*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
199*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT) | AV_PERIODIC);
200*13029SKrishnendu.Sadhukhan@Sun.COM }
201*13029SKrishnendu.Sadhukhan@Sun.COM
202*13029SKrishnendu.Sadhukhan@Sun.COM /* periodic timer disable */
203*13029SKrishnendu.Sadhukhan@Sun.COM static void
periodic_timer_disable(void)204*13029SKrishnendu.Sadhukhan@Sun.COM periodic_timer_disable(void)
205*13029SKrishnendu.Sadhukhan@Sun.COM {
206*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
207*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT) | AV_MASK);
208*13029SKrishnendu.Sadhukhan@Sun.COM }
209*13029SKrishnendu.Sadhukhan@Sun.COM
210*13029SKrishnendu.Sadhukhan@Sun.COM /* periodic timer reprogram */
211*13029SKrishnendu.Sadhukhan@Sun.COM static void
periodic_timer_reprogram(hrtime_t time)212*13029SKrishnendu.Sadhukhan@Sun.COM periodic_timer_reprogram(hrtime_t time)
213*13029SKrishnendu.Sadhukhan@Sun.COM {
214*13029SKrishnendu.Sadhukhan@Sun.COM uint_t ticks;
215*13029SKrishnendu.Sadhukhan@Sun.COM /* time is the interval for periodic mode */
216*13029SKrishnendu.Sadhukhan@Sun.COM ticks = APIC_NSECS_TO_TICKS(time);
217*13029SKrishnendu.Sadhukhan@Sun.COM
218*13029SKrishnendu.Sadhukhan@Sun.COM if (ticks < apic_min_timer_ticks)
219*13029SKrishnendu.Sadhukhan@Sun.COM ticks = apic_min_timer_ticks;
220*13029SKrishnendu.Sadhukhan@Sun.COM
221*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_INIT_COUNT, ticks);
222*13029SKrishnendu.Sadhukhan@Sun.COM }
223*13029SKrishnendu.Sadhukhan@Sun.COM
224*13029SKrishnendu.Sadhukhan@Sun.COM /*
225*13029SKrishnendu.Sadhukhan@Sun.COM * oneshot timer mode ops
226*13029SKrishnendu.Sadhukhan@Sun.COM */
227*13029SKrishnendu.Sadhukhan@Sun.COM /* oneshot timer enable */
228*13029SKrishnendu.Sadhukhan@Sun.COM static void
oneshot_timer_enable(void)229*13029SKrishnendu.Sadhukhan@Sun.COM oneshot_timer_enable(void)
230*13029SKrishnendu.Sadhukhan@Sun.COM {
231*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
232*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT));
233*13029SKrishnendu.Sadhukhan@Sun.COM }
234*13029SKrishnendu.Sadhukhan@Sun.COM
235*13029SKrishnendu.Sadhukhan@Sun.COM /* oneshot timer disable */
236*13029SKrishnendu.Sadhukhan@Sun.COM static void
oneshot_timer_disable(void)237*13029SKrishnendu.Sadhukhan@Sun.COM oneshot_timer_disable(void)
238*13029SKrishnendu.Sadhukhan@Sun.COM {
239*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
240*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT) | AV_MASK);
241*13029SKrishnendu.Sadhukhan@Sun.COM }
242*13029SKrishnendu.Sadhukhan@Sun.COM
243*13029SKrishnendu.Sadhukhan@Sun.COM /* oneshot timer reprogram */
244*13029SKrishnendu.Sadhukhan@Sun.COM static void
oneshot_timer_reprogram(hrtime_t time)245*13029SKrishnendu.Sadhukhan@Sun.COM oneshot_timer_reprogram(hrtime_t time)
246*13029SKrishnendu.Sadhukhan@Sun.COM {
247*13029SKrishnendu.Sadhukhan@Sun.COM hrtime_t now;
248*13029SKrishnendu.Sadhukhan@Sun.COM int64_t delta;
249*13029SKrishnendu.Sadhukhan@Sun.COM uint_t ticks;
250*13029SKrishnendu.Sadhukhan@Sun.COM
251*13029SKrishnendu.Sadhukhan@Sun.COM now = gethrtime();
252*13029SKrishnendu.Sadhukhan@Sun.COM delta = time - now;
253*13029SKrishnendu.Sadhukhan@Sun.COM
254*13029SKrishnendu.Sadhukhan@Sun.COM if (delta <= 0) {
255*13029SKrishnendu.Sadhukhan@Sun.COM /*
256*13029SKrishnendu.Sadhukhan@Sun.COM * requested to generate an interrupt in the past
257*13029SKrishnendu.Sadhukhan@Sun.COM * generate an interrupt as soon as possible
258*13029SKrishnendu.Sadhukhan@Sun.COM */
259*13029SKrishnendu.Sadhukhan@Sun.COM ticks = apic_min_timer_ticks;
260*13029SKrishnendu.Sadhukhan@Sun.COM } else if (delta > apic_nsec_max) {
261*13029SKrishnendu.Sadhukhan@Sun.COM /*
262*13029SKrishnendu.Sadhukhan@Sun.COM * requested to generate an interrupt at a time
263*13029SKrishnendu.Sadhukhan@Sun.COM * further than what we are capable of. Set to max
264*13029SKrishnendu.Sadhukhan@Sun.COM * the hardware can handle
265*13029SKrishnendu.Sadhukhan@Sun.COM */
266*13029SKrishnendu.Sadhukhan@Sun.COM ticks = APIC_MAXVAL;
267*13029SKrishnendu.Sadhukhan@Sun.COM #ifdef DEBUG
268*13029SKrishnendu.Sadhukhan@Sun.COM cmn_err(CE_CONT, "apic_timer_reprogram, request at"
269*13029SKrishnendu.Sadhukhan@Sun.COM " %lld too far in future, current time"
270*13029SKrishnendu.Sadhukhan@Sun.COM " %lld \n", time, now);
271*13029SKrishnendu.Sadhukhan@Sun.COM #endif
272*13029SKrishnendu.Sadhukhan@Sun.COM } else {
273*13029SKrishnendu.Sadhukhan@Sun.COM ticks = APIC_NSECS_TO_TICKS(delta);
274*13029SKrishnendu.Sadhukhan@Sun.COM }
275*13029SKrishnendu.Sadhukhan@Sun.COM
276*13029SKrishnendu.Sadhukhan@Sun.COM if (ticks < apic_min_timer_ticks)
277*13029SKrishnendu.Sadhukhan@Sun.COM ticks = apic_min_timer_ticks;
278*13029SKrishnendu.Sadhukhan@Sun.COM
279*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_INIT_COUNT, ticks);
280*13029SKrishnendu.Sadhukhan@Sun.COM }
281*13029SKrishnendu.Sadhukhan@Sun.COM
282*13029SKrishnendu.Sadhukhan@Sun.COM /*
283*13029SKrishnendu.Sadhukhan@Sun.COM * deadline timer mode ops
284*13029SKrishnendu.Sadhukhan@Sun.COM */
285*13029SKrishnendu.Sadhukhan@Sun.COM /* deadline timer enable */
286*13029SKrishnendu.Sadhukhan@Sun.COM static void
deadline_timer_enable(void)287*13029SKrishnendu.Sadhukhan@Sun.COM deadline_timer_enable(void)
288*13029SKrishnendu.Sadhukhan@Sun.COM {
289*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
290*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT) | AV_DEADLINE);
291*13029SKrishnendu.Sadhukhan@Sun.COM }
292*13029SKrishnendu.Sadhukhan@Sun.COM
293*13029SKrishnendu.Sadhukhan@Sun.COM /* deadline timer disable */
294*13029SKrishnendu.Sadhukhan@Sun.COM static void
deadline_timer_disable(void)295*13029SKrishnendu.Sadhukhan@Sun.COM deadline_timer_disable(void)
296*13029SKrishnendu.Sadhukhan@Sun.COM {
297*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_LOCAL_TIMER,
298*13029SKrishnendu.Sadhukhan@Sun.COM (apic_clkvect + APIC_BASE_VECT) | AV_MASK);
299*13029SKrishnendu.Sadhukhan@Sun.COM }
300*13029SKrishnendu.Sadhukhan@Sun.COM
301*13029SKrishnendu.Sadhukhan@Sun.COM /* deadline timer reprogram */
302*13029SKrishnendu.Sadhukhan@Sun.COM static void
deadline_timer_reprogram(hrtime_t time)303*13029SKrishnendu.Sadhukhan@Sun.COM deadline_timer_reprogram(hrtime_t time)
304*13029SKrishnendu.Sadhukhan@Sun.COM {
305*13029SKrishnendu.Sadhukhan@Sun.COM uint64_t ticks;
306*13029SKrishnendu.Sadhukhan@Sun.COM
307*13029SKrishnendu.Sadhukhan@Sun.COM if (time <= 0) {
308*13029SKrishnendu.Sadhukhan@Sun.COM /*
309*13029SKrishnendu.Sadhukhan@Sun.COM * generate an immediate interrupt
310*13029SKrishnendu.Sadhukhan@Sun.COM */
311*13029SKrishnendu.Sadhukhan@Sun.COM ticks = (uint64_t)tsc_read();
312*13029SKrishnendu.Sadhukhan@Sun.COM } else {
313*13029SKrishnendu.Sadhukhan@Sun.COM ticks = unscalehrtime(time);
314*13029SKrishnendu.Sadhukhan@Sun.COM }
315*13029SKrishnendu.Sadhukhan@Sun.COM
316*13029SKrishnendu.Sadhukhan@Sun.COM wrmsr(IA32_DEADLINE_TSC_MSR, ticks);
317*13029SKrishnendu.Sadhukhan@Sun.COM }
318*13029SKrishnendu.Sadhukhan@Sun.COM
319*13029SKrishnendu.Sadhukhan@Sun.COM /*
320*13029SKrishnendu.Sadhukhan@Sun.COM * This function will reprogram the timer.
321*13029SKrishnendu.Sadhukhan@Sun.COM *
322*13029SKrishnendu.Sadhukhan@Sun.COM * When in oneshot mode the argument is the absolute time in future to
323*13029SKrishnendu.Sadhukhan@Sun.COM * generate the interrupt at.
324*13029SKrishnendu.Sadhukhan@Sun.COM *
325*13029SKrishnendu.Sadhukhan@Sun.COM * When in periodic mode, the argument is the interval at which the
326*13029SKrishnendu.Sadhukhan@Sun.COM * interrupts should be generated. There is no need to support the periodic
327*13029SKrishnendu.Sadhukhan@Sun.COM * mode timer change at this time.
328*13029SKrishnendu.Sadhukhan@Sun.COM */
329*13029SKrishnendu.Sadhukhan@Sun.COM void
apic_timer_reprogram(hrtime_t time)330*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_reprogram(hrtime_t time)
331*13029SKrishnendu.Sadhukhan@Sun.COM {
332*13029SKrishnendu.Sadhukhan@Sun.COM /*
333*13029SKrishnendu.Sadhukhan@Sun.COM * we should be Called from high PIL context (CBE_HIGH_PIL),
334*13029SKrishnendu.Sadhukhan@Sun.COM * so kpreempt is disabled.
335*13029SKrishnendu.Sadhukhan@Sun.COM */
336*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_reprogram_ops(time);
337*13029SKrishnendu.Sadhukhan@Sun.COM }
338*13029SKrishnendu.Sadhukhan@Sun.COM
339*13029SKrishnendu.Sadhukhan@Sun.COM /*
340*13029SKrishnendu.Sadhukhan@Sun.COM * This function will enable timer interrupts.
341*13029SKrishnendu.Sadhukhan@Sun.COM */
342*13029SKrishnendu.Sadhukhan@Sun.COM void
apic_timer_enable(void)343*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_enable(void)
344*13029SKrishnendu.Sadhukhan@Sun.COM {
345*13029SKrishnendu.Sadhukhan@Sun.COM /*
346*13029SKrishnendu.Sadhukhan@Sun.COM * we should be Called from high PIL context (CBE_HIGH_PIL),
347*13029SKrishnendu.Sadhukhan@Sun.COM * so kpreempt is disabled.
348*13029SKrishnendu.Sadhukhan@Sun.COM */
349*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_enable_ops();
350*13029SKrishnendu.Sadhukhan@Sun.COM }
351*13029SKrishnendu.Sadhukhan@Sun.COM
352*13029SKrishnendu.Sadhukhan@Sun.COM /*
353*13029SKrishnendu.Sadhukhan@Sun.COM * This function will disable timer interrupts.
354*13029SKrishnendu.Sadhukhan@Sun.COM */
355*13029SKrishnendu.Sadhukhan@Sun.COM void
apic_timer_disable(void)356*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_disable(void)
357*13029SKrishnendu.Sadhukhan@Sun.COM {
358*13029SKrishnendu.Sadhukhan@Sun.COM /*
359*13029SKrishnendu.Sadhukhan@Sun.COM * we should be Called from high PIL context (CBE_HIGH_PIL),
360*13029SKrishnendu.Sadhukhan@Sun.COM * so kpreempt is disabled.
361*13029SKrishnendu.Sadhukhan@Sun.COM */
362*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer.apic_timer_disable_ops();
363*13029SKrishnendu.Sadhukhan@Sun.COM }
364*13029SKrishnendu.Sadhukhan@Sun.COM
365*13029SKrishnendu.Sadhukhan@Sun.COM /*
366*13029SKrishnendu.Sadhukhan@Sun.COM * Set timer far into the future and return timer
367*13029SKrishnendu.Sadhukhan@Sun.COM * current count in nanoseconds.
368*13029SKrishnendu.Sadhukhan@Sun.COM */
369*13029SKrishnendu.Sadhukhan@Sun.COM hrtime_t
apic_timer_stop_count(void)370*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_stop_count(void)
371*13029SKrishnendu.Sadhukhan@Sun.COM {
372*13029SKrishnendu.Sadhukhan@Sun.COM hrtime_t ns_val;
373*13029SKrishnendu.Sadhukhan@Sun.COM int enable_val, count_val;
374*13029SKrishnendu.Sadhukhan@Sun.COM
375*13029SKrishnendu.Sadhukhan@Sun.COM /*
376*13029SKrishnendu.Sadhukhan@Sun.COM * Should be called with interrupts disabled.
377*13029SKrishnendu.Sadhukhan@Sun.COM */
378*13029SKrishnendu.Sadhukhan@Sun.COM ASSERT(!interrupts_enabled());
379*13029SKrishnendu.Sadhukhan@Sun.COM
380*13029SKrishnendu.Sadhukhan@Sun.COM enable_val = apic_reg_ops->apic_read(APIC_LOCAL_TIMER);
381*13029SKrishnendu.Sadhukhan@Sun.COM if ((enable_val & AV_MASK) == AV_MASK)
382*13029SKrishnendu.Sadhukhan@Sun.COM return ((hrtime_t)-1); /* timer is disabled */
383*13029SKrishnendu.Sadhukhan@Sun.COM
384*13029SKrishnendu.Sadhukhan@Sun.COM count_val = apic_reg_ops->apic_read(APIC_CURR_COUNT);
385*13029SKrishnendu.Sadhukhan@Sun.COM ns_val = APIC_TICKS_TO_NSECS(count_val);
386*13029SKrishnendu.Sadhukhan@Sun.COM
387*13029SKrishnendu.Sadhukhan@Sun.COM apic_reg_ops->apic_write(APIC_INIT_COUNT, APIC_MAXVAL);
388*13029SKrishnendu.Sadhukhan@Sun.COM
389*13029SKrishnendu.Sadhukhan@Sun.COM return (ns_val);
390*13029SKrishnendu.Sadhukhan@Sun.COM }
391*13029SKrishnendu.Sadhukhan@Sun.COM
392*13029SKrishnendu.Sadhukhan@Sun.COM /*
393*13029SKrishnendu.Sadhukhan@Sun.COM * Reprogram timer after Deep C-State.
394*13029SKrishnendu.Sadhukhan@Sun.COM */
395*13029SKrishnendu.Sadhukhan@Sun.COM void
apic_timer_restart(hrtime_t time)396*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_restart(hrtime_t time)
397*13029SKrishnendu.Sadhukhan@Sun.COM {
398*13029SKrishnendu.Sadhukhan@Sun.COM apic_timer_reprogram(time);
399*13029SKrishnendu.Sadhukhan@Sun.COM }
400