xref: /illumos-gate/usr/src/uts/intel/io/vmm/io/vatpit.c (revision 32640292)
1 /*-
2  * Copyright (c) 2018 Joyent, Inc.
3  * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
4  * Copyright (c) 2011 NetApp, Inc.
5  * All rights reserved.
6  * Copyright (c) 2018 Joyent, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 /*
30  * This file and its contents are supplied under the terms of the
31  * Common Development and Distribution License ("CDDL"), version 1.0.
32  * You may only use this file in accordance with the terms of version
33  * 1.0 of the CDDL.
34  *
35  * A full copy of the text of the CDDL should have accompanied this
36  * source.  A copy of the CDDL is also available via the Internet at
37  * http://www.illumos.org/license/CDDL.
38  *
39  * Copyright 2022 Oxide Computer Company
40  */
41 
42 #include <sys/cdefs.h>
43 
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/queue.h>
47 #include <sys/kernel.h>
48 #include <sys/kmem.h>
49 #include <sys/mutex.h>
50 #include <sys/systm.h>
51 
52 #include <machine/vmm.h>
53 
54 #include "vatpic.h"
55 #include "vioapic.h"
56 #include "vatpit.h"
57 
58 #define	VATPIT_LOCK(vatpit)		mutex_enter(&((vatpit)->lock))
59 #define	VATPIT_UNLOCK(vatpit)		mutex_exit(&((vatpit)->lock))
60 #define	VATPIT_LOCKED(vatpit)		MUTEX_HELD(&((vatpit)->lock))
61 
62 #define	TIMER_SEL_MASK		0xc0
63 #define	TIMER_RW_MASK		0x30
64 #define	TIMER_MODE_MASK		0x0f
65 #define	TIMER_SEL_READBACK	0xc0
66 
67 #define	TIMER_STS_OUT		0x80
68 #define	TIMER_STS_NULLCNT	0x40
69 
70 #define	VALID_STATUS_BITS	(TIMER_STS_OUT | TIMER_STS_NULLCNT)
71 
72 #define	TIMER_RB_LCTR		0x20
73 #define	TIMER_RB_LSTATUS	0x10
74 #define	TIMER_RB_CTR_2		0x08
75 #define	TIMER_RB_CTR_1		0x04
76 #define	TIMER_RB_CTR_0		0x02
77 
78 #define	TMR2_OUT_STS		0x20
79 
80 #define	PIT_8254_FREQ		1193182
81 #define	TIMER_DIV(freq, hz)	(((freq) + (hz) / 2) / (hz))
82 
83 struct vatpit_callout_arg {
84 	struct vatpit	*vatpit;
85 	int		channel_num;
86 };
87 
88 struct channel {
89 	uint8_t		mode;
90 	uint16_t	initial;	/* initial counter value */
91 
92 	uint8_t		reg_cr[2];
93 	uint8_t		reg_ol[2];
94 	uint8_t		reg_status;
95 
96 	bool		slatched;	/* status latched */
97 	bool		olatched;	/* output latched */
98 	bool		cr_sel;		/* read MSB from control register */
99 	bool		ol_sel;		/* read MSB from output latch */
100 	bool		fr_sel;		/* read MSB from free-running timer */
101 
102 	hrtime_t	time_loaded;	/* time when counter was loaded */
103 	hrtime_t	time_target;	/* target time */
104 	uint64_t	total_target;
105 
106 	struct callout	callout;
107 	struct vatpit_callout_arg callout_arg;
108 };
109 
110 struct vatpit {
111 	struct vm	*vm;
112 	kmutex_t	lock;
113 
114 	struct channel	channel[3];
115 };
116 
117 static void pit_timer_start_cntr0(struct vatpit *vatpit);
118 
119 static uint64_t
vatpit_delta_ticks(struct vatpit * vatpit,struct channel * c)120 vatpit_delta_ticks(struct vatpit *vatpit, struct channel *c)
121 {
122 	const hrtime_t delta = gethrtime() - c->time_loaded;
123 
124 	return (hrt_freq_count(delta, PIT_8254_FREQ));
125 }
126 
127 static int
vatpit_get_out(struct vatpit * vatpit,int channel)128 vatpit_get_out(struct vatpit *vatpit, int channel)
129 {
130 	struct channel *c;
131 	uint64_t delta_ticks;
132 	int out;
133 
134 	c = &vatpit->channel[channel];
135 
136 	switch (c->mode) {
137 	case TIMER_INTTC:
138 		delta_ticks = vatpit_delta_ticks(vatpit, c);
139 		out = (delta_ticks >= c->initial);
140 		break;
141 	default:
142 		out = 0;
143 		break;
144 	}
145 
146 	return (out);
147 }
148 
149 static void
vatpit_callout_handler(void * a)150 vatpit_callout_handler(void *a)
151 {
152 	struct vatpit_callout_arg *arg = a;
153 	struct vatpit *vatpit;
154 	struct callout *callout;
155 	struct channel *c;
156 
157 	vatpit = arg->vatpit;
158 	c = &vatpit->channel[arg->channel_num];
159 	callout = &c->callout;
160 
161 	VATPIT_LOCK(vatpit);
162 
163 	if (callout_pending(callout))		/* callout was reset */
164 		goto done;
165 
166 	if (!callout_active(callout))		/* callout was stopped */
167 		goto done;
168 
169 	callout_deactivate(callout);
170 
171 	if (c->mode == TIMER_RATEGEN || c->mode == TIMER_SQWAVE) {
172 		pit_timer_start_cntr0(vatpit);
173 	} else {
174 		/*
175 		 * For non-periodic timers, clear the time target to distinguish
176 		 * between a fired timer (thus a zero value) and a pending one
177 		 * awaiting VM resumption (holding a non-zero value).
178 		 */
179 		c->time_target = 0;
180 	}
181 
182 	(void) vatpic_pulse_irq(vatpit->vm, 0);
183 	(void) vioapic_pulse_irq(vatpit->vm, 2);
184 
185 done:
186 	VATPIT_UNLOCK(vatpit);
187 }
188 
189 static void
vatpit_callout_reset(struct vatpit * vatpit)190 vatpit_callout_reset(struct vatpit *vatpit)
191 {
192 	struct channel *c = &vatpit->channel[0];
193 
194 	ASSERT(VATPIT_LOCKED(vatpit));
195 	callout_reset_hrtime(&c->callout, c->time_target,
196 	    vatpit_callout_handler, &c->callout_arg, C_ABSOLUTE);
197 }
198 
199 static void
pit_timer_start_cntr0(struct vatpit * vatpit)200 pit_timer_start_cntr0(struct vatpit *vatpit)
201 {
202 	struct channel *c = &vatpit->channel[0];
203 
204 	if (c->initial == 0) {
205 		return;
206 	}
207 
208 	c->total_target += c->initial;
209 	c->time_target = c->time_loaded +
210 	    hrt_freq_interval(PIT_8254_FREQ, c->total_target);
211 
212 	/*
213 	 * If we are more than 'c->initial' ticks behind, reset the timer base
214 	 * to fire at the next 'c->initial' interval boundary.
215 	 */
216 	hrtime_t now = gethrtime();
217 	if (c->time_target < now) {
218 		const uint64_t ticks_behind =
219 		    hrt_freq_count(now - c->time_target, PIT_8254_FREQ);
220 
221 		c->total_target += roundup(ticks_behind, c->initial);
222 		c->time_target = c->time_loaded +
223 		    hrt_freq_interval(PIT_8254_FREQ, c->total_target);
224 	}
225 
226 	vatpit_callout_reset(vatpit);
227 }
228 
229 static uint16_t
pit_update_counter(struct vatpit * vatpit,struct channel * c,bool latch)230 pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)
231 {
232 	uint16_t lval;
233 	uint64_t delta_ticks;
234 
235 	/* cannot latch a new value until the old one has been consumed */
236 	if (latch && c->olatched)
237 		return (0);
238 
239 	if (c->initial == 0) {
240 		/*
241 		 * This is possibly an OS bug - reading the value of the timer
242 		 * without having set up the initial value.
243 		 *
244 		 * The original user-space version of this code set the timer to
245 		 * 100hz in this condition; do the same here.
246 		 */
247 		c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
248 		c->time_loaded = gethrtime();
249 		c->reg_status &= ~TIMER_STS_NULLCNT;
250 	}
251 
252 	delta_ticks = vatpit_delta_ticks(vatpit, c);
253 	lval = c->initial - delta_ticks % c->initial;
254 
255 	if (latch) {
256 		c->olatched = true;
257 		c->ol_sel = true;
258 		c->reg_ol[1] = lval;		/* LSB */
259 		c->reg_ol[0] = lval >> 8;	/* MSB */
260 	}
261 
262 	return (lval);
263 }
264 
265 static int
pit_readback1(struct vatpit * vatpit,int channel,uint8_t cmd)266 pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd)
267 {
268 	struct channel *c;
269 
270 	c = &vatpit->channel[channel];
271 
272 	/*
273 	 * Latch the count/status of the timer if not already latched.
274 	 * N.B. that the count/status latch-select bits are active-low.
275 	 */
276 	if ((cmd & TIMER_RB_LCTR) == 0 && !c->olatched) {
277 		(void) pit_update_counter(vatpit, c, true);
278 	}
279 
280 	if ((cmd & TIMER_RB_LSTATUS) == 0 && !c->slatched) {
281 		c->slatched = true;
282 		/*
283 		 * For mode 0, see if the elapsed time is greater
284 		 * than the initial value - this results in the
285 		 * output pin being set to 1 in the status byte.
286 		 */
287 		if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel))
288 			c->reg_status |= TIMER_STS_OUT;
289 		else
290 			c->reg_status &= ~TIMER_STS_OUT;
291 	}
292 
293 	return (0);
294 }
295 
296 static int
pit_readback(struct vatpit * vatpit,uint8_t cmd)297 pit_readback(struct vatpit *vatpit, uint8_t cmd)
298 {
299 	int error;
300 
301 	/*
302 	 * The readback command can apply to all timers.
303 	 */
304 	error = 0;
305 	if (cmd & TIMER_RB_CTR_0)
306 		error = pit_readback1(vatpit, 0, cmd);
307 	if (!error && cmd & TIMER_RB_CTR_1)
308 		error = pit_readback1(vatpit, 1, cmd);
309 	if (!error && cmd & TIMER_RB_CTR_2)
310 		error = pit_readback1(vatpit, 2, cmd);
311 
312 	return (error);
313 }
314 
315 static int
vatpit_update_mode(struct vatpit * vatpit,uint8_t val)316 vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
317 {
318 	struct channel *c;
319 	int sel, rw;
320 	uint8_t mode;
321 
322 	sel = val & TIMER_SEL_MASK;
323 	rw = val & TIMER_RW_MASK;
324 	mode = val & TIMER_MODE_MASK;
325 
326 	/* Clear don't-care bit (M2) when M1 is set */
327 	if ((mode & TIMER_RATEGEN) != 0) {
328 		mode &= ~TIMER_SWSTROBE;
329 	}
330 
331 	if (sel == TIMER_SEL_READBACK)
332 		return (pit_readback(vatpit, val));
333 
334 	if (rw != TIMER_LATCH && rw != TIMER_16BIT)
335 		return (-1);
336 
337 	if (rw != TIMER_LATCH) {
338 		/*
339 		 * Counter mode is not affected when issuing a
340 		 * latch command.
341 		 */
342 		if (mode != TIMER_INTTC &&
343 		    mode != TIMER_RATEGEN &&
344 		    mode != TIMER_SQWAVE &&
345 		    mode != TIMER_SWSTROBE)
346 			return (-1);
347 	}
348 
349 	c = &vatpit->channel[sel >> 6];
350 	if (rw == TIMER_LATCH) {
351 		(void) pit_update_counter(vatpit, c, true);
352 	} else {
353 		c->mode = mode;
354 		c->olatched = false;	/* reset latch after reprogramming */
355 		c->reg_status |= TIMER_STS_NULLCNT;
356 	}
357 
358 	return (0);
359 }
360 
361 int
vatpit_handler(void * arg,bool in,uint16_t port,uint8_t bytes,uint32_t * eax)362 vatpit_handler(void *arg, bool in, uint16_t port, uint8_t bytes, uint32_t *eax)
363 {
364 	struct vatpit *vatpit = arg;
365 	struct channel *c;
366 	uint8_t val;
367 	int error;
368 
369 	if (bytes != 1)
370 		return (-1);
371 
372 	val = *eax;
373 
374 	if (port == TIMER_MODE) {
375 		if (in) {
376 			/* Mode is write-only */
377 			return (-1);
378 		}
379 
380 		VATPIT_LOCK(vatpit);
381 		error = vatpit_update_mode(vatpit, val);
382 		VATPIT_UNLOCK(vatpit);
383 
384 		return (error);
385 	}
386 
387 	/* counter ports */
388 	KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,
389 	    ("invalid port 0x%x", port));
390 	c = &vatpit->channel[port - TIMER_CNTR0];
391 
392 	VATPIT_LOCK(vatpit);
393 	if (in && c->slatched) {
394 		/* Return the status byte if latched */
395 		*eax = c->reg_status;
396 		c->slatched = false;
397 		c->reg_status = 0;
398 	} else if (in) {
399 		/*
400 		 * The spec says that once the output latch is completely
401 		 * read it should revert to "following" the counter. Use
402 		 * the free running counter for this case (i.e. Linux
403 		 * TSC calibration). Assuming the access mode is 16-bit,
404 		 * toggle the MSB/LSB bit on each read.
405 		 */
406 		if (!c->olatched) {
407 			uint16_t tmp;
408 
409 			tmp = pit_update_counter(vatpit, c, false);
410 			if (c->fr_sel) {
411 				tmp >>= 8;
412 			}
413 			tmp &= 0xff;
414 			*eax = tmp;
415 			c->fr_sel = !c->fr_sel;
416 		} else {
417 			if (c->ol_sel) {
418 				*eax = c->reg_ol[1];
419 				c->ol_sel = false;
420 			} else {
421 				*eax = c->reg_ol[0];
422 				c->olatched = false;
423 			}
424 		}
425 	} else {
426 		if (!c->cr_sel) {
427 			c->reg_cr[0] = *eax;
428 			c->cr_sel = true;
429 		} else {
430 			c->reg_cr[1] = *eax;
431 			c->cr_sel = false;
432 
433 			c->reg_status &= ~TIMER_STS_NULLCNT;
434 			c->fr_sel = false;
435 			c->initial = c->reg_cr[0] | (uint16_t)c->reg_cr[1] << 8;
436 			c->time_loaded = gethrtime();
437 			/* Start an interval timer for channel 0 */
438 			if (port == TIMER_CNTR0) {
439 				c->time_target = c->time_loaded;
440 				c->total_target = 0;
441 				pit_timer_start_cntr0(vatpit);
442 			}
443 			if (c->initial == 0)
444 				c->initial = 0xffff;
445 		}
446 	}
447 	VATPIT_UNLOCK(vatpit);
448 
449 	return (0);
450 }
451 
452 int
vatpit_nmisc_handler(void * arg,bool in,uint16_t port,uint8_t bytes,uint32_t * eax)453 vatpit_nmisc_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
454     uint32_t *eax)
455 {
456 	struct vatpit *vatpit = arg;
457 
458 	if (in) {
459 			VATPIT_LOCK(vatpit);
460 			if (vatpit_get_out(vatpit, 2))
461 				*eax = TMR2_OUT_STS;
462 			else
463 				*eax = 0;
464 
465 			VATPIT_UNLOCK(vatpit);
466 	}
467 
468 	return (0);
469 }
470 
471 struct vatpit *
vatpit_init(struct vm * vm)472 vatpit_init(struct vm *vm)
473 {
474 	struct vatpit *vatpit;
475 	struct vatpit_callout_arg *arg;
476 	int i;
477 
478 	vatpit = kmem_zalloc(sizeof (struct vatpit), KM_SLEEP);
479 	vatpit->vm = vm;
480 
481 	mutex_init(&vatpit->lock, NULL, MUTEX_ADAPTIVE, NULL);
482 
483 	for (i = 0; i < 3; i++) {
484 		callout_init(&vatpit->channel[i].callout, 1);
485 		arg = &vatpit->channel[i].callout_arg;
486 		arg->vatpit = vatpit;
487 		arg->channel_num = i;
488 	}
489 
490 	return (vatpit);
491 }
492 
493 void
vatpit_cleanup(struct vatpit * vatpit)494 vatpit_cleanup(struct vatpit *vatpit)
495 {
496 	int i;
497 
498 	for (i = 0; i < 3; i++)
499 		callout_drain(&vatpit->channel[i].callout);
500 
501 	mutex_destroy(&vatpit->lock);
502 	kmem_free(vatpit, sizeof (*vatpit));
503 }
504 
505 void
vatpit_localize_resources(struct vatpit * vatpit)506 vatpit_localize_resources(struct vatpit *vatpit)
507 {
508 	for (uint_t i = 0; i < 3; i++) {
509 		/* Only localize channels which might be running */
510 		if (vatpit->channel[i].mode != 0) {
511 			vmm_glue_callout_localize(&vatpit->channel[i].callout);
512 		}
513 	}
514 }
515 
516 void
vatpit_pause(struct vatpit * vatpit)517 vatpit_pause(struct vatpit *vatpit)
518 {
519 	struct channel *c = &vatpit->channel[0];
520 
521 	VATPIT_LOCK(vatpit);
522 	callout_stop(&c->callout);
523 	VATPIT_UNLOCK(vatpit);
524 }
525 
526 void
vatpit_resume(struct vatpit * vatpit)527 vatpit_resume(struct vatpit *vatpit)
528 {
529 	struct channel *c = &vatpit->channel[0];
530 
531 	VATPIT_LOCK(vatpit);
532 	ASSERT(!callout_active(&c->callout));
533 	if (c->time_target != 0) {
534 		vatpit_callout_reset(vatpit);
535 	}
536 	VATPIT_UNLOCK(vatpit);
537 }
538 
539 static int
vatpit_data_read(void * datap,const vmm_data_req_t * req)540 vatpit_data_read(void *datap, const vmm_data_req_t *req)
541 {
542 	VERIFY3U(req->vdr_class, ==, VDC_ATPIT);
543 	VERIFY3U(req->vdr_version, ==, 1);
544 	VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_atpit_v1));
545 
546 	struct vatpit *vatpit = datap;
547 	struct vdi_atpit_v1 *out = req->vdr_data;
548 
549 	VATPIT_LOCK(vatpit);
550 	for (uint_t i = 0; i < 3; i++) {
551 		const struct channel *src = &vatpit->channel[i];
552 		struct vdi_atpit_channel_v1 *chan = &out->va_channel[i];
553 
554 		chan->vac_initial = src->initial;
555 		chan->vac_reg_cr =
556 		    (src->reg_cr[0] | (uint16_t)src->reg_cr[1] << 8);
557 		chan->vac_reg_ol =
558 		    (src->reg_ol[0] | (uint16_t)src->reg_ol[1] << 8);
559 		chan->vac_reg_status = src->reg_status;
560 		chan->vac_mode = src->mode;
561 		chan->vac_status =
562 		    (src->slatched ? (1 << 0) : 0) |
563 		    (src->olatched ? (1 << 1) : 0) |
564 		    (src->cr_sel ? (1 << 2) : 0) |
565 		    (src->ol_sel ? (1 << 3) : 0) |
566 		    (src->fr_sel ? (1 << 4) : 0);
567 		/* Only channel 0 has the timer configured */
568 		if (i == 0 && src->time_target != 0) {
569 			chan->vac_time_target =
570 			    vm_normalize_hrtime(vatpit->vm, src->time_target);
571 		} else {
572 			chan->vac_time_target = 0;
573 		}
574 	}
575 	VATPIT_UNLOCK(vatpit);
576 
577 	return (0);
578 }
579 
580 static bool
vatpit_data_validate(const struct vdi_atpit_v1 * src)581 vatpit_data_validate(const struct vdi_atpit_v1 *src)
582 {
583 	for (uint_t i = 0; i < 3; i++) {
584 		const struct vdi_atpit_channel_v1 *chan = &src->va_channel[i];
585 
586 		if ((chan->vac_status & ~VALID_STATUS_BITS) != 0) {
587 			return (false);
588 		}
589 	}
590 	return (true);
591 }
592 
593 static int
vatpit_data_write(void * datap,const vmm_data_req_t * req)594 vatpit_data_write(void *datap, const vmm_data_req_t *req)
595 {
596 	VERIFY3U(req->vdr_class, ==, VDC_ATPIT);
597 	VERIFY3U(req->vdr_version, ==, 1);
598 	VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_atpit_v1));
599 
600 	struct vatpit *vatpit = datap;
601 	const struct vdi_atpit_v1 *src = req->vdr_data;
602 	if (!vatpit_data_validate(src)) {
603 		return (EINVAL);
604 	}
605 
606 	VATPIT_LOCK(vatpit);
607 	for (uint_t i = 0; i < 3; i++) {
608 		const struct vdi_atpit_channel_v1 *chan = &src->va_channel[i];
609 		struct channel *out = &vatpit->channel[i];
610 
611 		out->initial = chan->vac_initial;
612 		out->reg_cr[0] = chan->vac_reg_cr;
613 		out->reg_cr[1] = chan->vac_reg_cr >> 8;
614 		out->reg_ol[0] = chan->vac_reg_ol;
615 		out->reg_ol[1] = chan->vac_reg_ol >> 8;
616 		out->reg_status = chan->vac_reg_status;
617 		out->mode = chan->vac_mode;
618 		out->slatched = (chan->vac_status & (1 << 0)) != 0;
619 		out->olatched = (chan->vac_status & (1 << 1)) != 0;
620 		out->cr_sel = (chan->vac_status & (1 << 2)) != 0;
621 		out->ol_sel = (chan->vac_status & (1 << 3)) != 0;
622 		out->fr_sel = (chan->vac_status & (1 << 4)) != 0;
623 
624 		/* Only channel 0 has the timer configured */
625 		if (i != 0) {
626 			continue;
627 		}
628 
629 		struct callout *callout = &out->callout;
630 		if (callout_active(callout)) {
631 			callout_deactivate(callout);
632 		}
633 
634 		if (chan->vac_time_target == 0) {
635 			out->time_loaded = 0;
636 			out->time_target = 0;
637 			continue;
638 		}
639 
640 		/* back-calculate time_loaded for the appropriate interval */
641 		const uint64_t time_target =
642 		    vm_denormalize_hrtime(vatpit->vm, chan->vac_time_target);
643 		out->total_target = out->initial;
644 		out->time_target = time_target;
645 		out->time_loaded = time_target -
646 		    hrt_freq_interval(PIT_8254_FREQ, out->initial);
647 
648 		if (!vm_is_paused(vatpit->vm)) {
649 			vatpit_callout_reset(vatpit);
650 		}
651 	}
652 	VATPIT_UNLOCK(vatpit);
653 
654 	return (0);
655 }
656 
657 static const vmm_data_version_entry_t atpit_v1 = {
658 	.vdve_class = VDC_ATPIT,
659 	.vdve_version = 1,
660 	.vdve_len_expect = sizeof (struct vdi_atpit_v1),
661 	.vdve_readf = vatpit_data_read,
662 	.vdve_writef = vatpit_data_write,
663 };
664 VMM_DATA_VERSION(atpit_v1);
665