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