xref: /freebsd/sys/amd64/vmm/io/vatpit.c (revision e883c9bb40062fca0f3b25229a146d72e54939c2)
1*e883c9bbSTycho Nightingale /*-
2*e883c9bbSTycho Nightingale  * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3*e883c9bbSTycho Nightingale  * Copyright (c) 2011 NetApp, Inc.
4*e883c9bbSTycho Nightingale  * All rights reserved.
5*e883c9bbSTycho Nightingale  *
6*e883c9bbSTycho Nightingale  * Redistribution and use in source and binary forms, with or without
7*e883c9bbSTycho Nightingale  * modification, are permitted provided that the following conditions
8*e883c9bbSTycho Nightingale  * are met:
9*e883c9bbSTycho Nightingale  * 1. Redistributions of source code must retain the above copyright
10*e883c9bbSTycho Nightingale  *    notice, this list of conditions and the following disclaimer.
11*e883c9bbSTycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
12*e883c9bbSTycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
13*e883c9bbSTycho Nightingale  *    documentation and/or other materials provided with the distribution.
14*e883c9bbSTycho Nightingale  *
15*e883c9bbSTycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16*e883c9bbSTycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*e883c9bbSTycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*e883c9bbSTycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19*e883c9bbSTycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*e883c9bbSTycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*e883c9bbSTycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*e883c9bbSTycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*e883c9bbSTycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*e883c9bbSTycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*e883c9bbSTycho Nightingale  * SUCH DAMAGE.
26*e883c9bbSTycho Nightingale  */
27*e883c9bbSTycho Nightingale 
28*e883c9bbSTycho Nightingale #include <sys/cdefs.h>
29*e883c9bbSTycho Nightingale __FBSDID("$FreeBSD$");
30*e883c9bbSTycho Nightingale 
31*e883c9bbSTycho Nightingale #include <sys/param.h>
32*e883c9bbSTycho Nightingale #include <sys/types.h>
33*e883c9bbSTycho Nightingale #include <sys/queue.h>
34*e883c9bbSTycho Nightingale #include <sys/cpuset.h>
35*e883c9bbSTycho Nightingale #include <sys/kernel.h>
36*e883c9bbSTycho Nightingale #include <sys/lock.h>
37*e883c9bbSTycho Nightingale #include <sys/malloc.h>
38*e883c9bbSTycho Nightingale #include <sys/mutex.h>
39*e883c9bbSTycho Nightingale #include <sys/systm.h>
40*e883c9bbSTycho Nightingale 
41*e883c9bbSTycho Nightingale #include <machine/vmm.h>
42*e883c9bbSTycho Nightingale 
43*e883c9bbSTycho Nightingale #include "vmm_ktr.h"
44*e883c9bbSTycho Nightingale #include "vatpic.h"
45*e883c9bbSTycho Nightingale #include "vioapic.h"
46*e883c9bbSTycho Nightingale #include "vatpit.h"
47*e883c9bbSTycho Nightingale 
48*e883c9bbSTycho Nightingale static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)");
49*e883c9bbSTycho Nightingale 
50*e883c9bbSTycho Nightingale #define	VATPIT_LOCK(vatpit)		mtx_lock_spin(&((vatpit)->mtx))
51*e883c9bbSTycho Nightingale #define	VATPIT_UNLOCK(vatpit)		mtx_unlock_spin(&((vatpit)->mtx))
52*e883c9bbSTycho Nightingale #define	VATPIT_LOCKED(vatpit)		mtx_owned(&((vatpit)->mtx))
53*e883c9bbSTycho Nightingale 
54*e883c9bbSTycho Nightingale #define	TIMER_SEL_MASK		0xc0
55*e883c9bbSTycho Nightingale #define	TIMER_RW_MASK		0x30
56*e883c9bbSTycho Nightingale #define	TIMER_MODE_MASK		0x0f
57*e883c9bbSTycho Nightingale #define	TIMER_SEL_READBACK	0xc0
58*e883c9bbSTycho Nightingale 
59*e883c9bbSTycho Nightingale #define	PIT_8254_FREQ		1193182
60*e883c9bbSTycho Nightingale #define	TIMER_DIV(freq, hz)	(((freq) + (hz) / 2) / (hz))
61*e883c9bbSTycho Nightingale 
62*e883c9bbSTycho Nightingale struct vatpit_callout_arg {
63*e883c9bbSTycho Nightingale 	struct vatpit	*vatpit;
64*e883c9bbSTycho Nightingale 	int		channel_num;
65*e883c9bbSTycho Nightingale };
66*e883c9bbSTycho Nightingale 
67*e883c9bbSTycho Nightingale 
68*e883c9bbSTycho Nightingale struct channel {
69*e883c9bbSTycho Nightingale 	int		mode;
70*e883c9bbSTycho Nightingale 	uint16_t	initial;	/* initial counter value */
71*e883c9bbSTycho Nightingale 	sbintime_t	now_sbt;	/* uptime when counter was loaded */
72*e883c9bbSTycho Nightingale 	uint8_t		cr[2];
73*e883c9bbSTycho Nightingale 	uint8_t		ol[2];
74*e883c9bbSTycho Nightingale 	int		crbyte;
75*e883c9bbSTycho Nightingale 	int		olbyte;
76*e883c9bbSTycho Nightingale 	int		frbyte;
77*e883c9bbSTycho Nightingale 	struct callout	callout;
78*e883c9bbSTycho Nightingale 	sbintime_t	callout_sbt;	/* target time */
79*e883c9bbSTycho Nightingale 	struct vatpit_callout_arg callout_arg;
80*e883c9bbSTycho Nightingale };
81*e883c9bbSTycho Nightingale 
82*e883c9bbSTycho Nightingale struct vatpit {
83*e883c9bbSTycho Nightingale 	struct vm	*vm;
84*e883c9bbSTycho Nightingale 	struct mtx	mtx;
85*e883c9bbSTycho Nightingale 
86*e883c9bbSTycho Nightingale 	sbintime_t	freq_sbt;
87*e883c9bbSTycho Nightingale 
88*e883c9bbSTycho Nightingale 	struct channel	channel[3];
89*e883c9bbSTycho Nightingale };
90*e883c9bbSTycho Nightingale 
91*e883c9bbSTycho Nightingale #define	VATPIT_CTR0(vatpit, fmt)					\
92*e883c9bbSTycho Nightingale 	VM_CTR0((vatpit)->vm, fmt)
93*e883c9bbSTycho Nightingale 
94*e883c9bbSTycho Nightingale #define	VATPIT_CTR1(vatpit, fmt, a1)					\
95*e883c9bbSTycho Nightingale 	VM_CTR1((vatpit)->vm, fmt, a1)
96*e883c9bbSTycho Nightingale 
97*e883c9bbSTycho Nightingale #define	VATPIT_CTR2(vatpit, fmt, a1, a2)				\
98*e883c9bbSTycho Nightingale 	VM_CTR2((vatpit)->vm, fmt, a1, a2)
99*e883c9bbSTycho Nightingale 
100*e883c9bbSTycho Nightingale #define	VATPIT_CTR3(vatpit, fmt, a1, a2, a3)				\
101*e883c9bbSTycho Nightingale 	VM_CTR3((vatpit)->vm, fmt, a1, a2, a3)
102*e883c9bbSTycho Nightingale 
103*e883c9bbSTycho Nightingale #define	VATPIT_CTR4(vatpit, fmt, a1, a2, a3, a4)			\
104*e883c9bbSTycho Nightingale 	VM_CTR4((vatpit)->vm, fmt, a1, a2, a3, a4)
105*e883c9bbSTycho Nightingale 
106*e883c9bbSTycho Nightingale static void pit_timer_start_cntr0(struct vatpit *vatpit);
107*e883c9bbSTycho Nightingale 
108*e883c9bbSTycho Nightingale static void
109*e883c9bbSTycho Nightingale vatpit_callout_handler(void *a)
110*e883c9bbSTycho Nightingale {
111*e883c9bbSTycho Nightingale 	struct vatpit_callout_arg *arg = a;
112*e883c9bbSTycho Nightingale 	struct vatpit *vatpit;
113*e883c9bbSTycho Nightingale 	struct callout *callout;
114*e883c9bbSTycho Nightingale 	struct channel *c;
115*e883c9bbSTycho Nightingale 
116*e883c9bbSTycho Nightingale 	vatpit = arg->vatpit;
117*e883c9bbSTycho Nightingale 	c = &vatpit->channel[arg->channel_num];
118*e883c9bbSTycho Nightingale 	callout = &c->callout;
119*e883c9bbSTycho Nightingale 
120*e883c9bbSTycho Nightingale 	VATPIT_CTR1(vatpit, "atpit t%d fired", arg->channel_num);
121*e883c9bbSTycho Nightingale 
122*e883c9bbSTycho Nightingale 	VATPIT_LOCK(vatpit);
123*e883c9bbSTycho Nightingale 
124*e883c9bbSTycho Nightingale 	if (callout_pending(callout))		/* callout was reset */
125*e883c9bbSTycho Nightingale 		goto done;
126*e883c9bbSTycho Nightingale 
127*e883c9bbSTycho Nightingale 	if (!callout_active(callout))		/* callout was stopped */
128*e883c9bbSTycho Nightingale 		goto done;
129*e883c9bbSTycho Nightingale 
130*e883c9bbSTycho Nightingale 	callout_deactivate(callout);
131*e883c9bbSTycho Nightingale 
132*e883c9bbSTycho Nightingale 	if (c->mode == TIMER_RATEGEN) {
133*e883c9bbSTycho Nightingale 		pit_timer_start_cntr0(vatpit);
134*e883c9bbSTycho Nightingale 	}
135*e883c9bbSTycho Nightingale 
136*e883c9bbSTycho Nightingale 	vatpic_pulse_irq(vatpit->vm, 0);
137*e883c9bbSTycho Nightingale 	vioapic_pulse_irq(vatpit->vm, 2);
138*e883c9bbSTycho Nightingale 
139*e883c9bbSTycho Nightingale done:
140*e883c9bbSTycho Nightingale 	VATPIT_UNLOCK(vatpit);
141*e883c9bbSTycho Nightingale 	return;
142*e883c9bbSTycho Nightingale }
143*e883c9bbSTycho Nightingale 
144*e883c9bbSTycho Nightingale static void
145*e883c9bbSTycho Nightingale pit_timer_start_cntr0(struct vatpit *vatpit)
146*e883c9bbSTycho Nightingale {
147*e883c9bbSTycho Nightingale 	struct channel *c;
148*e883c9bbSTycho Nightingale 	sbintime_t delta, precision;
149*e883c9bbSTycho Nightingale 
150*e883c9bbSTycho Nightingale 	c = &vatpit->channel[0];
151*e883c9bbSTycho Nightingale 	if (c->initial != 0) {
152*e883c9bbSTycho Nightingale 		delta = c->initial * vatpit->freq_sbt;
153*e883c9bbSTycho Nightingale 		precision = delta >> tc_precexp;
154*e883c9bbSTycho Nightingale 		c->callout_sbt = c->callout_sbt + delta;
155*e883c9bbSTycho Nightingale 
156*e883c9bbSTycho Nightingale 		callout_reset_sbt(&c->callout, c->callout_sbt,
157*e883c9bbSTycho Nightingale 		    precision, vatpit_callout_handler, &c->callout_arg,
158*e883c9bbSTycho Nightingale 		    C_ABSOLUTE);
159*e883c9bbSTycho Nightingale 	}
160*e883c9bbSTycho Nightingale }
161*e883c9bbSTycho Nightingale 
162*e883c9bbSTycho Nightingale static uint16_t
163*e883c9bbSTycho Nightingale pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)
164*e883c9bbSTycho Nightingale {
165*e883c9bbSTycho Nightingale 	uint16_t lval;
166*e883c9bbSTycho Nightingale 	sbintime_t delta_ticks;
167*e883c9bbSTycho Nightingale 
168*e883c9bbSTycho Nightingale 	/* cannot latch a new value until the old one has been consumed */
169*e883c9bbSTycho Nightingale 	if (latch && c->olbyte != 0)
170*e883c9bbSTycho Nightingale 		return (0);
171*e883c9bbSTycho Nightingale 
172*e883c9bbSTycho Nightingale 	if (c->initial == 0) {
173*e883c9bbSTycho Nightingale 		/*
174*e883c9bbSTycho Nightingale 		 * This is possibly an o/s bug - reading the value of
175*e883c9bbSTycho Nightingale 		 * the timer without having set up the initial value.
176*e883c9bbSTycho Nightingale 		 *
177*e883c9bbSTycho Nightingale 		 * The original user-space version of this code set
178*e883c9bbSTycho Nightingale 		 * the timer to 100hz in this condition; do the same
179*e883c9bbSTycho Nightingale 		 * here.
180*e883c9bbSTycho Nightingale 		 */
181*e883c9bbSTycho Nightingale 		c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
182*e883c9bbSTycho Nightingale 		c->now_sbt = sbinuptime();
183*e883c9bbSTycho Nightingale 	}
184*e883c9bbSTycho Nightingale 
185*e883c9bbSTycho Nightingale 	delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;
186*e883c9bbSTycho Nightingale 
187*e883c9bbSTycho Nightingale 	lval = c->initial - delta_ticks % c->initial;
188*e883c9bbSTycho Nightingale 
189*e883c9bbSTycho Nightingale 	if (latch) {
190*e883c9bbSTycho Nightingale 		c->olbyte = 2;
191*e883c9bbSTycho Nightingale 		c->ol[1] = lval;		/* LSB */
192*e883c9bbSTycho Nightingale 		c->ol[0] = lval >> 8;		/* MSB */
193*e883c9bbSTycho Nightingale 	}
194*e883c9bbSTycho Nightingale 
195*e883c9bbSTycho Nightingale 	return (lval);
196*e883c9bbSTycho Nightingale }
197*e883c9bbSTycho Nightingale 
198*e883c9bbSTycho Nightingale static int
199*e883c9bbSTycho Nightingale vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
200*e883c9bbSTycho Nightingale {
201*e883c9bbSTycho Nightingale 	struct channel *c;
202*e883c9bbSTycho Nightingale 	int sel, rw, mode;
203*e883c9bbSTycho Nightingale 
204*e883c9bbSTycho Nightingale 	sel = val & TIMER_SEL_MASK;
205*e883c9bbSTycho Nightingale 	rw = val & TIMER_RW_MASK;
206*e883c9bbSTycho Nightingale 	mode = val & TIMER_MODE_MASK;
207*e883c9bbSTycho Nightingale 
208*e883c9bbSTycho Nightingale 	if (sel == TIMER_SEL_READBACK)
209*e883c9bbSTycho Nightingale 		return (-1);
210*e883c9bbSTycho Nightingale 
211*e883c9bbSTycho Nightingale 	if (rw != TIMER_LATCH && rw != TIMER_16BIT)
212*e883c9bbSTycho Nightingale 		return (-1);
213*e883c9bbSTycho Nightingale 
214*e883c9bbSTycho Nightingale 	if (rw != TIMER_LATCH) {
215*e883c9bbSTycho Nightingale 		/*
216*e883c9bbSTycho Nightingale 		 * Counter mode is not affected when issuing a
217*e883c9bbSTycho Nightingale 		 * latch command.
218*e883c9bbSTycho Nightingale 		 */
219*e883c9bbSTycho Nightingale 		if (mode != TIMER_INTTC &&
220*e883c9bbSTycho Nightingale 		    mode != TIMER_RATEGEN &&
221*e883c9bbSTycho Nightingale 		    mode != TIMER_SQWAVE &&
222*e883c9bbSTycho Nightingale 		    mode != TIMER_SWSTROBE)
223*e883c9bbSTycho Nightingale 			return (-1);
224*e883c9bbSTycho Nightingale 	}
225*e883c9bbSTycho Nightingale 
226*e883c9bbSTycho Nightingale 	c = &vatpit->channel[sel >> 6];
227*e883c9bbSTycho Nightingale 	if (rw == TIMER_LATCH)
228*e883c9bbSTycho Nightingale 		pit_update_counter(vatpit, c, true);
229*e883c9bbSTycho Nightingale 	else {
230*e883c9bbSTycho Nightingale 		c->mode = mode;
231*e883c9bbSTycho Nightingale 		c->olbyte = 0;	/* reset latch after reprogramming */
232*e883c9bbSTycho Nightingale 	}
233*e883c9bbSTycho Nightingale 
234*e883c9bbSTycho Nightingale 	return (0);
235*e883c9bbSTycho Nightingale }
236*e883c9bbSTycho Nightingale 
237*e883c9bbSTycho Nightingale static int
238*e883c9bbSTycho Nightingale vatpit_get_out(struct vatpit *vatpit, int channel)
239*e883c9bbSTycho Nightingale {
240*e883c9bbSTycho Nightingale 	struct channel *c;
241*e883c9bbSTycho Nightingale 	sbintime_t delta_ticks;
242*e883c9bbSTycho Nightingale 	int out;
243*e883c9bbSTycho Nightingale 
244*e883c9bbSTycho Nightingale 	c = &vatpit->channel[channel];
245*e883c9bbSTycho Nightingale 
246*e883c9bbSTycho Nightingale 	switch (c->mode) {
247*e883c9bbSTycho Nightingale 	case TIMER_INTTC:
248*e883c9bbSTycho Nightingale 		delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;
249*e883c9bbSTycho Nightingale 		out = ((c->initial - delta_ticks) <= 0);
250*e883c9bbSTycho Nightingale 		break;
251*e883c9bbSTycho Nightingale 	default:
252*e883c9bbSTycho Nightingale 		out = 0;
253*e883c9bbSTycho Nightingale 		break;
254*e883c9bbSTycho Nightingale 	}
255*e883c9bbSTycho Nightingale 
256*e883c9bbSTycho Nightingale 	return (out);
257*e883c9bbSTycho Nightingale }
258*e883c9bbSTycho Nightingale 
259*e883c9bbSTycho Nightingale int
260*e883c9bbSTycho Nightingale vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
261*e883c9bbSTycho Nightingale {
262*e883c9bbSTycho Nightingale 	struct vatpit *vatpit;
263*e883c9bbSTycho Nightingale 	struct channel *c;
264*e883c9bbSTycho Nightingale 	int port;
265*e883c9bbSTycho Nightingale 	uint8_t val;
266*e883c9bbSTycho Nightingale 	int error;
267*e883c9bbSTycho Nightingale 
268*e883c9bbSTycho Nightingale 	vatpit = vm_atpit(vm);
269*e883c9bbSTycho Nightingale 
270*e883c9bbSTycho Nightingale 	if (vmexit->u.inout.bytes != 1)
271*e883c9bbSTycho Nightingale 		return (-1);
272*e883c9bbSTycho Nightingale 
273*e883c9bbSTycho Nightingale 	val = vmexit->u.inout.eax;
274*e883c9bbSTycho Nightingale 	port = vmexit->u.inout.port;
275*e883c9bbSTycho Nightingale 
276*e883c9bbSTycho Nightingale 	if (port == TIMER_MODE) {
277*e883c9bbSTycho Nightingale 		if (vmexit->u.inout.in != 0) {
278*e883c9bbSTycho Nightingale 			VATPIT_CTR0(vatpit, "vatpit attempt to read mode");
279*e883c9bbSTycho Nightingale 			return (-1);
280*e883c9bbSTycho Nightingale 		}
281*e883c9bbSTycho Nightingale 
282*e883c9bbSTycho Nightingale 		VATPIT_LOCK(vatpit);
283*e883c9bbSTycho Nightingale 		error = vatpit_update_mode(vatpit, val);
284*e883c9bbSTycho Nightingale 		VATPIT_UNLOCK(vatpit);
285*e883c9bbSTycho Nightingale 
286*e883c9bbSTycho Nightingale 		return (error);
287*e883c9bbSTycho Nightingale 	}
288*e883c9bbSTycho Nightingale 
289*e883c9bbSTycho Nightingale 	/* counter ports */
290*e883c9bbSTycho Nightingale 	KASSERT(port >= TIMER_CNTR0 && vmexit->u.inout.port <= TIMER_CNTR2,
291*e883c9bbSTycho Nightingale 	    ("invalid port 0x%x", port));
292*e883c9bbSTycho Nightingale 	c = &vatpit->channel[port - TIMER_CNTR0];
293*e883c9bbSTycho Nightingale 
294*e883c9bbSTycho Nightingale 	VATPIT_LOCK(vatpit);
295*e883c9bbSTycho Nightingale 	if (vmexit->u.inout.in) {
296*e883c9bbSTycho Nightingale 		/*
297*e883c9bbSTycho Nightingale 		 * The spec says that once the output latch is completely
298*e883c9bbSTycho Nightingale 		 * read it should revert to "following" the counter. Use
299*e883c9bbSTycho Nightingale 		 * the free running counter for this case (i.e. Linux
300*e883c9bbSTycho Nightingale 		 * TSC calibration). Assuming the access mode is 16-bit,
301*e883c9bbSTycho Nightingale 		 * toggle the MSB/LSB bit on each read.
302*e883c9bbSTycho Nightingale 		 */
303*e883c9bbSTycho Nightingale 		if (c->olbyte == 0) {
304*e883c9bbSTycho Nightingale 			uint16_t tmp;
305*e883c9bbSTycho Nightingale 
306*e883c9bbSTycho Nightingale 			tmp = pit_update_counter(vatpit, c, false);
307*e883c9bbSTycho Nightingale 			if (c->frbyte)
308*e883c9bbSTycho Nightingale 				tmp >>= 8;
309*e883c9bbSTycho Nightingale 			tmp &= 0xff;
310*e883c9bbSTycho Nightingale 			vmexit->u.inout.eax = tmp;
311*e883c9bbSTycho Nightingale 			c->frbyte ^= 1;
312*e883c9bbSTycho Nightingale 		}  else
313*e883c9bbSTycho Nightingale 			vmexit->u.inout.eax = c->ol[--c->olbyte];
314*e883c9bbSTycho Nightingale 	} else {
315*e883c9bbSTycho Nightingale 		c->cr[c->crbyte++] = vmexit->u.inout.eax;
316*e883c9bbSTycho Nightingale 		if (c->crbyte == 2) {
317*e883c9bbSTycho Nightingale 			c->frbyte = 0;
318*e883c9bbSTycho Nightingale 			c->crbyte = 0;
319*e883c9bbSTycho Nightingale 			c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8;
320*e883c9bbSTycho Nightingale 			c->now_sbt = sbinuptime();
321*e883c9bbSTycho Nightingale 			/* Start an interval timer for channel 0 */
322*e883c9bbSTycho Nightingale 			if (port == TIMER_CNTR0) {
323*e883c9bbSTycho Nightingale 				c->callout_sbt = c->now_sbt;
324*e883c9bbSTycho Nightingale 				pit_timer_start_cntr0(vatpit);
325*e883c9bbSTycho Nightingale 			}
326*e883c9bbSTycho Nightingale 			if (c->initial == 0)
327*e883c9bbSTycho Nightingale 				c->initial = 0xffff;
328*e883c9bbSTycho Nightingale 		}
329*e883c9bbSTycho Nightingale 	}
330*e883c9bbSTycho Nightingale 	VATPIT_UNLOCK(vatpit);
331*e883c9bbSTycho Nightingale 
332*e883c9bbSTycho Nightingale 	return (0);
333*e883c9bbSTycho Nightingale }
334*e883c9bbSTycho Nightingale 
335*e883c9bbSTycho Nightingale struct vatpit *
336*e883c9bbSTycho Nightingale vatpit_init(struct vm *vm)
337*e883c9bbSTycho Nightingale {
338*e883c9bbSTycho Nightingale 	struct vatpit *vatpit;
339*e883c9bbSTycho Nightingale 	struct bintime bt;
340*e883c9bbSTycho Nightingale 	struct vatpit_callout_arg *arg;
341*e883c9bbSTycho Nightingale 	int i;
342*e883c9bbSTycho Nightingale 
343*e883c9bbSTycho Nightingale 	vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO);
344*e883c9bbSTycho Nightingale 	vatpit->vm = vm;
345*e883c9bbSTycho Nightingale 
346*e883c9bbSTycho Nightingale 	mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN);
347*e883c9bbSTycho Nightingale 
348*e883c9bbSTycho Nightingale 	FREQ2BT(PIT_8254_FREQ, &bt);
349*e883c9bbSTycho Nightingale 	vatpit->freq_sbt = bttosbt(bt);
350*e883c9bbSTycho Nightingale 
351*e883c9bbSTycho Nightingale 	for (i = 0; i < 3; i++) {
352*e883c9bbSTycho Nightingale 		callout_init(&vatpit->channel[i].callout, true);
353*e883c9bbSTycho Nightingale 		arg = &vatpit->channel[i].callout_arg;
354*e883c9bbSTycho Nightingale 		arg->vatpit = vatpit;
355*e883c9bbSTycho Nightingale 		arg->channel_num = i;
356*e883c9bbSTycho Nightingale 	}
357*e883c9bbSTycho Nightingale 
358*e883c9bbSTycho Nightingale 	return (vatpit);
359*e883c9bbSTycho Nightingale }
360*e883c9bbSTycho Nightingale 
361*e883c9bbSTycho Nightingale void
362*e883c9bbSTycho Nightingale vatpit_cleanup(struct vatpit *vatpit)
363*e883c9bbSTycho Nightingale {
364*e883c9bbSTycho Nightingale 	int i;
365*e883c9bbSTycho Nightingale 
366*e883c9bbSTycho Nightingale 	for (i = 0; i < 3; i++)
367*e883c9bbSTycho Nightingale 		callout_drain(&vatpit->channel[i].callout);
368*e883c9bbSTycho Nightingale 
369*e883c9bbSTycho Nightingale 	free(vatpit, M_VATPIT);
370*e883c9bbSTycho Nightingale }
371