xref: /illumos-gate/usr/src/uts/intel/io/vmm/io/vatpit.c (revision 32640292)
17c8c0b82SPatrick Mooney /*-
27c8c0b82SPatrick Mooney  * Copyright (c) 2018 Joyent, Inc.
37c8c0b82SPatrick Mooney  * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
47c8c0b82SPatrick Mooney  * Copyright (c) 2011 NetApp, Inc.
57c8c0b82SPatrick Mooney  * All rights reserved.
67c8c0b82SPatrick Mooney  * Copyright (c) 2018 Joyent, Inc.
77c8c0b82SPatrick Mooney  *
87c8c0b82SPatrick Mooney  * Redistribution and use in source and binary forms, with or without
97c8c0b82SPatrick Mooney  * modification, are permitted provided that the following conditions
107c8c0b82SPatrick Mooney  * are met:
117c8c0b82SPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
127c8c0b82SPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
137c8c0b82SPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
147c8c0b82SPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
157c8c0b82SPatrick Mooney  *    documentation and/or other materials provided with the distribution.
167c8c0b82SPatrick Mooney  *
177c8c0b82SPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
187c8c0b82SPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197c8c0b82SPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207c8c0b82SPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
217c8c0b82SPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227c8c0b82SPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237c8c0b82SPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247c8c0b82SPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257c8c0b82SPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267c8c0b82SPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277c8c0b82SPatrick Mooney  * SUCH DAMAGE.
287c8c0b82SPatrick Mooney  */
29d515dd77SPatrick Mooney /*
30d515dd77SPatrick Mooney  * This file and its contents are supplied under the terms of the
31d515dd77SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
32d515dd77SPatrick Mooney  * You may only use this file in accordance with the terms of version
33d515dd77SPatrick Mooney  * 1.0 of the CDDL.
34d515dd77SPatrick Mooney  *
35d515dd77SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
36d515dd77SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
37d515dd77SPatrick Mooney  * http://www.illumos.org/license/CDDL.
38d515dd77SPatrick Mooney  *
39d515dd77SPatrick Mooney  * Copyright 2022 Oxide Computer Company
40d515dd77SPatrick Mooney  */
417c8c0b82SPatrick Mooney 
427c8c0b82SPatrick Mooney #include <sys/cdefs.h>
437c8c0b82SPatrick Mooney 
447c8c0b82SPatrick Mooney #include <sys/param.h>
457c8c0b82SPatrick Mooney #include <sys/types.h>
467c8c0b82SPatrick Mooney #include <sys/queue.h>
477c8c0b82SPatrick Mooney #include <sys/kernel.h>
488130f8e1SPatrick Mooney #include <sys/kmem.h>
497c8c0b82SPatrick Mooney #include <sys/mutex.h>
507c8c0b82SPatrick Mooney #include <sys/systm.h>
517c8c0b82SPatrick Mooney 
527c8c0b82SPatrick Mooney #include <machine/vmm.h>
537c8c0b82SPatrick Mooney 
547c8c0b82SPatrick Mooney #include "vatpic.h"
557c8c0b82SPatrick Mooney #include "vioapic.h"
567c8c0b82SPatrick Mooney #include "vatpit.h"
577c8c0b82SPatrick Mooney 
587c8c0b82SPatrick Mooney #define	VATPIT_LOCK(vatpit)		mutex_enter(&((vatpit)->lock))
597c8c0b82SPatrick Mooney #define	VATPIT_UNLOCK(vatpit)		mutex_exit(&((vatpit)->lock))
60*2cac0506SPatrick Mooney #define	VATPIT_LOCKED(vatpit)		MUTEX_HELD(&((vatpit)->lock))
617c8c0b82SPatrick Mooney 
627c8c0b82SPatrick Mooney #define	TIMER_SEL_MASK		0xc0
637c8c0b82SPatrick Mooney #define	TIMER_RW_MASK		0x30
647c8c0b82SPatrick Mooney #define	TIMER_MODE_MASK		0x0f
657c8c0b82SPatrick Mooney #define	TIMER_SEL_READBACK	0xc0
667c8c0b82SPatrick Mooney 
677c8c0b82SPatrick Mooney #define	TIMER_STS_OUT		0x80
687c8c0b82SPatrick Mooney #define	TIMER_STS_NULLCNT	0x40
697c8c0b82SPatrick Mooney 
70d515dd77SPatrick Mooney #define	VALID_STATUS_BITS	(TIMER_STS_OUT | TIMER_STS_NULLCNT)
71d515dd77SPatrick Mooney 
727c8c0b82SPatrick Mooney #define	TIMER_RB_LCTR		0x20
737c8c0b82SPatrick Mooney #define	TIMER_RB_LSTATUS	0x10
747c8c0b82SPatrick Mooney #define	TIMER_RB_CTR_2		0x08
757c8c0b82SPatrick Mooney #define	TIMER_RB_CTR_1		0x04
767c8c0b82SPatrick Mooney #define	TIMER_RB_CTR_0		0x02
777c8c0b82SPatrick Mooney 
787c8c0b82SPatrick Mooney #define	TMR2_OUT_STS		0x20
797c8c0b82SPatrick Mooney 
807c8c0b82SPatrick Mooney #define	PIT_8254_FREQ		1193182
817c8c0b82SPatrick Mooney #define	TIMER_DIV(freq, hz)	(((freq) + (hz) / 2) / (hz))
827c8c0b82SPatrick Mooney 
837c8c0b82SPatrick Mooney struct vatpit_callout_arg {
847c8c0b82SPatrick Mooney 	struct vatpit	*vatpit;
857c8c0b82SPatrick Mooney 	int		channel_num;
867c8c0b82SPatrick Mooney };
877c8c0b82SPatrick Mooney 
887c8c0b82SPatrick Mooney struct channel {
897c8c0b82SPatrick Mooney 	uint8_t		mode;
907c8c0b82SPatrick Mooney 	uint16_t	initial;	/* initial counter value */
917c8c0b82SPatrick Mooney 
927c8c0b82SPatrick Mooney 	uint8_t		reg_cr[2];
937c8c0b82SPatrick Mooney 	uint8_t		reg_ol[2];
947c8c0b82SPatrick Mooney 	uint8_t		reg_status;
957c8c0b82SPatrick Mooney 
967c8c0b82SPatrick Mooney 	bool		slatched;	/* status latched */
977c8c0b82SPatrick Mooney 	bool		olatched;	/* output latched */
987c8c0b82SPatrick Mooney 	bool		cr_sel;		/* read MSB from control register */
997c8c0b82SPatrick Mooney 	bool		ol_sel;		/* read MSB from output latch */
1007c8c0b82SPatrick Mooney 	bool		fr_sel;		/* read MSB from free-running timer */
1017c8c0b82SPatrick Mooney 
1027c8c0b82SPatrick Mooney 	hrtime_t	time_loaded;	/* time when counter was loaded */
1037c8c0b82SPatrick Mooney 	hrtime_t	time_target;	/* target time */
1047c8c0b82SPatrick Mooney 	uint64_t	total_target;
1057c8c0b82SPatrick Mooney 
1067c8c0b82SPatrick Mooney 	struct callout	callout;
1077c8c0b82SPatrick Mooney 	struct vatpit_callout_arg callout_arg;
1087c8c0b82SPatrick Mooney };
1097c8c0b82SPatrick Mooney 
1107c8c0b82SPatrick Mooney struct vatpit {
1117c8c0b82SPatrick Mooney 	struct vm	*vm;
1127c8c0b82SPatrick Mooney 	kmutex_t	lock;
1137c8c0b82SPatrick Mooney 
1147c8c0b82SPatrick Mooney 	struct channel	channel[3];
1157c8c0b82SPatrick Mooney };
1167c8c0b82SPatrick Mooney 
1177c8c0b82SPatrick Mooney static void pit_timer_start_cntr0(struct vatpit *vatpit);
1187c8c0b82SPatrick Mooney 
1197c8c0b82SPatrick Mooney static uint64_t
vatpit_delta_ticks(struct vatpit * vatpit,struct channel * c)1207c8c0b82SPatrick Mooney vatpit_delta_ticks(struct vatpit *vatpit, struct channel *c)
1217c8c0b82SPatrick Mooney {
1227c8c0b82SPatrick Mooney 	const hrtime_t delta = gethrtime() - c->time_loaded;
1237c8c0b82SPatrick Mooney 
1247c8c0b82SPatrick Mooney 	return (hrt_freq_count(delta, PIT_8254_FREQ));
1257c8c0b82SPatrick Mooney }
1267c8c0b82SPatrick Mooney 
1277c8c0b82SPatrick Mooney static int
vatpit_get_out(struct vatpit * vatpit,int channel)1287c8c0b82SPatrick Mooney vatpit_get_out(struct vatpit *vatpit, int channel)
1297c8c0b82SPatrick Mooney {
1307c8c0b82SPatrick Mooney 	struct channel *c;
1317c8c0b82SPatrick Mooney 	uint64_t delta_ticks;
1327c8c0b82SPatrick Mooney 	int out;
1337c8c0b82SPatrick Mooney 
1347c8c0b82SPatrick Mooney 	c = &vatpit->channel[channel];
1357c8c0b82SPatrick Mooney 
1367c8c0b82SPatrick Mooney 	switch (c->mode) {
1377c8c0b82SPatrick Mooney 	case TIMER_INTTC:
1387c8c0b82SPatrick Mooney 		delta_ticks = vatpit_delta_ticks(vatpit, c);
1397c8c0b82SPatrick Mooney 		out = (delta_ticks >= c->initial);
1407c8c0b82SPatrick Mooney 		break;
1417c8c0b82SPatrick Mooney 	default:
1427c8c0b82SPatrick Mooney 		out = 0;
1437c8c0b82SPatrick Mooney 		break;
1447c8c0b82SPatrick Mooney 	}
1457c8c0b82SPatrick Mooney 
1467c8c0b82SPatrick Mooney 	return (out);
1477c8c0b82SPatrick Mooney }
1487c8c0b82SPatrick Mooney 
1497c8c0b82SPatrick Mooney static void
vatpit_callout_handler(void * a)1507c8c0b82SPatrick Mooney vatpit_callout_handler(void *a)
1517c8c0b82SPatrick Mooney {
1527c8c0b82SPatrick Mooney 	struct vatpit_callout_arg *arg = a;
1537c8c0b82SPatrick Mooney 	struct vatpit *vatpit;
1547c8c0b82SPatrick Mooney 	struct callout *callout;
1557c8c0b82SPatrick Mooney 	struct channel *c;
1567c8c0b82SPatrick Mooney 
1577c8c0b82SPatrick Mooney 	vatpit = arg->vatpit;
1587c8c0b82SPatrick Mooney 	c = &vatpit->channel[arg->channel_num];
1597c8c0b82SPatrick Mooney 	callout = &c->callout;
1607c8c0b82SPatrick Mooney 
1617c8c0b82SPatrick Mooney 	VATPIT_LOCK(vatpit);
1627c8c0b82SPatrick Mooney 
1637c8c0b82SPatrick Mooney 	if (callout_pending(callout))		/* callout was reset */
1647c8c0b82SPatrick Mooney 		goto done;
1657c8c0b82SPatrick Mooney 
1667c8c0b82SPatrick Mooney 	if (!callout_active(callout))		/* callout was stopped */
1677c8c0b82SPatrick Mooney 		goto done;
1687c8c0b82SPatrick Mooney 
1697c8c0b82SPatrick Mooney 	callout_deactivate(callout);
1707c8c0b82SPatrick Mooney 
1717c8c0b82SPatrick Mooney 	if (c->mode == TIMER_RATEGEN || c->mode == TIMER_SQWAVE) {
1727c8c0b82SPatrick Mooney 		pit_timer_start_cntr0(vatpit);
173*2cac0506SPatrick Mooney 	} else {
174*2cac0506SPatrick Mooney 		/*
175*2cac0506SPatrick Mooney 		 * For non-periodic timers, clear the time target to distinguish
176*2cac0506SPatrick Mooney 		 * between a fired timer (thus a zero value) and a pending one
177*2cac0506SPatrick Mooney 		 * awaiting VM resumption (holding a non-zero value).
178*2cac0506SPatrick Mooney 		 */
179*2cac0506SPatrick Mooney 		c->time_target = 0;
1807c8c0b82SPatrick Mooney 	}
1817c8c0b82SPatrick Mooney 
182e0994bd2SPatrick Mooney 	(void) vatpic_pulse_irq(vatpit->vm, 0);
183e0994bd2SPatrick Mooney 	(void) vioapic_pulse_irq(vatpit->vm, 2);
1847c8c0b82SPatrick Mooney 
1857c8c0b82SPatrick Mooney done:
1867c8c0b82SPatrick Mooney 	VATPIT_UNLOCK(vatpit);
1877c8c0b82SPatrick Mooney }
1887c8c0b82SPatrick Mooney 
1897c8c0b82SPatrick Mooney static void
vatpit_callout_reset(struct vatpit * vatpit)190*2cac0506SPatrick Mooney vatpit_callout_reset(struct vatpit *vatpit)
191*2cac0506SPatrick Mooney {
192*2cac0506SPatrick Mooney 	struct channel *c = &vatpit->channel[0];
193*2cac0506SPatrick Mooney 
194*2cac0506SPatrick Mooney 	ASSERT(VATPIT_LOCKED(vatpit));
195*2cac0506SPatrick Mooney 	callout_reset_hrtime(&c->callout, c->time_target,
196*2cac0506SPatrick Mooney 	    vatpit_callout_handler, &c->callout_arg, C_ABSOLUTE);
197*2cac0506SPatrick Mooney }
198*2cac0506SPatrick Mooney 
199*2cac0506SPatrick Mooney static void
pit_timer_start_cntr0(struct vatpit * vatpit)2007c8c0b82SPatrick Mooney pit_timer_start_cntr0(struct vatpit *vatpit)
2017c8c0b82SPatrick Mooney {
2027c8c0b82SPatrick Mooney 	struct channel *c = &vatpit->channel[0];
2037c8c0b82SPatrick Mooney 
2047c8c0b82SPatrick Mooney 	if (c->initial == 0) {
2057c8c0b82SPatrick Mooney 		return;
2067c8c0b82SPatrick Mooney 	}
2077c8c0b82SPatrick Mooney 
2087c8c0b82SPatrick Mooney 	c->total_target += c->initial;
2097c8c0b82SPatrick Mooney 	c->time_target = c->time_loaded +
2107c8c0b82SPatrick Mooney 	    hrt_freq_interval(PIT_8254_FREQ, c->total_target);
2117c8c0b82SPatrick Mooney 
2127c8c0b82SPatrick Mooney 	/*
2137c8c0b82SPatrick Mooney 	 * If we are more than 'c->initial' ticks behind, reset the timer base
2147c8c0b82SPatrick Mooney 	 * to fire at the next 'c->initial' interval boundary.
2157c8c0b82SPatrick Mooney 	 */
2167c8c0b82SPatrick Mooney 	hrtime_t now = gethrtime();
2177c8c0b82SPatrick Mooney 	if (c->time_target < now) {
2187c8c0b82SPatrick Mooney 		const uint64_t ticks_behind =
219d515dd77SPatrick Mooney 		    hrt_freq_count(now - c->time_target, PIT_8254_FREQ);
2207c8c0b82SPatrick Mooney 
2217c8c0b82SPatrick Mooney 		c->total_target += roundup(ticks_behind, c->initial);
2227c8c0b82SPatrick Mooney 		c->time_target = c->time_loaded +
2237c8c0b82SPatrick Mooney 		    hrt_freq_interval(PIT_8254_FREQ, c->total_target);
2247c8c0b82SPatrick Mooney 	}
2257c8c0b82SPatrick Mooney 
226*2cac0506SPatrick Mooney 	vatpit_callout_reset(vatpit);
2277c8c0b82SPatrick Mooney }
2287c8c0b82SPatrick Mooney 
2297c8c0b82SPatrick Mooney static uint16_t
pit_update_counter(struct vatpit * vatpit,struct channel * c,bool latch)2307c8c0b82SPatrick Mooney pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)
2317c8c0b82SPatrick Mooney {
2327c8c0b82SPatrick Mooney 	uint16_t lval;
2337c8c0b82SPatrick Mooney 	uint64_t delta_ticks;
2347c8c0b82SPatrick Mooney 
2357c8c0b82SPatrick Mooney 	/* cannot latch a new value until the old one has been consumed */
2367c8c0b82SPatrick Mooney 	if (latch && c->olatched)
2377c8c0b82SPatrick Mooney 		return (0);
2387c8c0b82SPatrick Mooney 
2397c8c0b82SPatrick Mooney 	if (c->initial == 0) {
2407c8c0b82SPatrick Mooney 		/*
2417c8c0b82SPatrick Mooney 		 * This is possibly an OS bug - reading the value of the timer
2427c8c0b82SPatrick Mooney 		 * without having set up the initial value.
2437c8c0b82SPatrick Mooney 		 *
2447c8c0b82SPatrick Mooney 		 * The original user-space version of this code set the timer to
2457c8c0b82SPatrick Mooney 		 * 100hz in this condition; do the same here.
2467c8c0b82SPatrick Mooney 		 */
2477c8c0b82SPatrick Mooney 		c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
2487c8c0b82SPatrick Mooney 		c->time_loaded = gethrtime();
2497c8c0b82SPatrick Mooney 		c->reg_status &= ~TIMER_STS_NULLCNT;
2507c8c0b82SPatrick Mooney 	}
2517c8c0b82SPatrick Mooney 
2527c8c0b82SPatrick Mooney 	delta_ticks = vatpit_delta_ticks(vatpit, c);
2537c8c0b82SPatrick Mooney 	lval = c->initial - delta_ticks % c->initial;
2547c8c0b82SPatrick Mooney 
2557c8c0b82SPatrick Mooney 	if (latch) {
2567c8c0b82SPatrick Mooney 		c->olatched = true;
2577c8c0b82SPatrick Mooney 		c->ol_sel = true;
2587c8c0b82SPatrick Mooney 		c->reg_ol[1] = lval;		/* LSB */
2597c8c0b82SPatrick Mooney 		c->reg_ol[0] = lval >> 8;	/* MSB */
2607c8c0b82SPatrick Mooney 	}
2617c8c0b82SPatrick Mooney 
2627c8c0b82SPatrick Mooney 	return (lval);
2637c8c0b82SPatrick Mooney }
2647c8c0b82SPatrick Mooney 
2657c8c0b82SPatrick Mooney static int
pit_readback1(struct vatpit * vatpit,int channel,uint8_t cmd)2667c8c0b82SPatrick Mooney pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd)
2677c8c0b82SPatrick Mooney {
2687c8c0b82SPatrick Mooney 	struct channel *c;
2697c8c0b82SPatrick Mooney 
2707c8c0b82SPatrick Mooney 	c = &vatpit->channel[channel];
2717c8c0b82SPatrick Mooney 
2727c8c0b82SPatrick Mooney 	/*
2737c8c0b82SPatrick Mooney 	 * Latch the count/status of the timer if not already latched.
2747c8c0b82SPatrick Mooney 	 * N.B. that the count/status latch-select bits are active-low.
2757c8c0b82SPatrick Mooney 	 */
2767c8c0b82SPatrick Mooney 	if ((cmd & TIMER_RB_LCTR) == 0 && !c->olatched) {
2777c8c0b82SPatrick Mooney 		(void) pit_update_counter(vatpit, c, true);
2787c8c0b82SPatrick Mooney 	}
2797c8c0b82SPatrick Mooney 
2807c8c0b82SPatrick Mooney 	if ((cmd & TIMER_RB_LSTATUS) == 0 && !c->slatched) {
2817c8c0b82SPatrick Mooney 		c->slatched = true;
2827c8c0b82SPatrick Mooney 		/*
2837c8c0b82SPatrick Mooney 		 * For mode 0, see if the elapsed time is greater
2847c8c0b82SPatrick Mooney 		 * than the initial value - this results in the
2857c8c0b82SPatrick Mooney 		 * output pin being set to 1 in the status byte.
2867c8c0b82SPatrick Mooney 		 */
2877c8c0b82SPatrick Mooney 		if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel))
2887c8c0b82SPatrick Mooney 			c->reg_status |= TIMER_STS_OUT;
2897c8c0b82SPatrick Mooney 		else
2907c8c0b82SPatrick Mooney 			c->reg_status &= ~TIMER_STS_OUT;
2917c8c0b82SPatrick Mooney 	}
2927c8c0b82SPatrick Mooney 
2937c8c0b82SPatrick Mooney 	return (0);
2947c8c0b82SPatrick Mooney }
2957c8c0b82SPatrick Mooney 
2967c8c0b82SPatrick Mooney static int
pit_readback(struct vatpit * vatpit,uint8_t cmd)2977c8c0b82SPatrick Mooney pit_readback(struct vatpit *vatpit, uint8_t cmd)
2987c8c0b82SPatrick Mooney {
2997c8c0b82SPatrick Mooney 	int error;
3007c8c0b82SPatrick Mooney 
3017c8c0b82SPatrick Mooney 	/*
3027c8c0b82SPatrick Mooney 	 * The readback command can apply to all timers.
3037c8c0b82SPatrick Mooney 	 */
3047c8c0b82SPatrick Mooney 	error = 0;
3057c8c0b82SPatrick Mooney 	if (cmd & TIMER_RB_CTR_0)
3067c8c0b82SPatrick Mooney 		error = pit_readback1(vatpit, 0, cmd);
3077c8c0b82SPatrick Mooney 	if (!error && cmd & TIMER_RB_CTR_1)
3087c8c0b82SPatrick Mooney 		error = pit_readback1(vatpit, 1, cmd);
3097c8c0b82SPatrick Mooney 	if (!error && cmd & TIMER_RB_CTR_2)
3107c8c0b82SPatrick Mooney 		error = pit_readback1(vatpit, 2, cmd);
3117c8c0b82SPatrick Mooney 
3127c8c0b82SPatrick Mooney 	return (error);
3137c8c0b82SPatrick Mooney }
3147c8c0b82SPatrick Mooney 
3157c8c0b82SPatrick Mooney static int
vatpit_update_mode(struct vatpit * vatpit,uint8_t val)3167c8c0b82SPatrick Mooney vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
3177c8c0b82SPatrick Mooney {
3187c8c0b82SPatrick Mooney 	struct channel *c;
3197c8c0b82SPatrick Mooney 	int sel, rw;
3207c8c0b82SPatrick Mooney 	uint8_t mode;
3217c8c0b82SPatrick Mooney 
3227c8c0b82SPatrick Mooney 	sel = val & TIMER_SEL_MASK;
3237c8c0b82SPatrick Mooney 	rw = val & TIMER_RW_MASK;
3247c8c0b82SPatrick Mooney 	mode = val & TIMER_MODE_MASK;
3257c8c0b82SPatrick Mooney 
3267c8c0b82SPatrick Mooney 	/* Clear don't-care bit (M2) when M1 is set */
3277c8c0b82SPatrick Mooney 	if ((mode & TIMER_RATEGEN) != 0) {
3287c8c0b82SPatrick Mooney 		mode &= ~TIMER_SWSTROBE;
3297c8c0b82SPatrick Mooney 	}
3307c8c0b82SPatrick Mooney 
3317c8c0b82SPatrick Mooney 	if (sel == TIMER_SEL_READBACK)
3327c8c0b82SPatrick Mooney 		return (pit_readback(vatpit, val));
3337c8c0b82SPatrick Mooney 
3347c8c0b82SPatrick Mooney 	if (rw != TIMER_LATCH && rw != TIMER_16BIT)
3357c8c0b82SPatrick Mooney 		return (-1);
3367c8c0b82SPatrick Mooney 
3377c8c0b82SPatrick Mooney 	if (rw != TIMER_LATCH) {
3387c8c0b82SPatrick Mooney 		/*
3397c8c0b82SPatrick Mooney 		 * Counter mode is not affected when issuing a
3407c8c0b82SPatrick Mooney 		 * latch command.
3417c8c0b82SPatrick Mooney 		 */
3427c8c0b82SPatrick Mooney 		if (mode != TIMER_INTTC &&
3437c8c0b82SPatrick Mooney 		    mode != TIMER_RATEGEN &&
3447c8c0b82SPatrick Mooney 		    mode != TIMER_SQWAVE &&
3457c8c0b82SPatrick Mooney 		    mode != TIMER_SWSTROBE)
3467c8c0b82SPatrick Mooney 			return (-1);
3477c8c0b82SPatrick Mooney 	}
3487c8c0b82SPatrick Mooney 
3497c8c0b82SPatrick Mooney 	c = &vatpit->channel[sel >> 6];
3507c8c0b82SPatrick Mooney 	if (rw == TIMER_LATCH) {
351e0994bd2SPatrick Mooney 		(void) pit_update_counter(vatpit, c, true);
3527c8c0b82SPatrick Mooney 	} else {
3537c8c0b82SPatrick Mooney 		c->mode = mode;
3547c8c0b82SPatrick Mooney 		c->olatched = false;	/* reset latch after reprogramming */
3557c8c0b82SPatrick Mooney 		c->reg_status |= TIMER_STS_NULLCNT;
3567c8c0b82SPatrick Mooney 	}
3577c8c0b82SPatrick Mooney 
3587c8c0b82SPatrick Mooney 	return (0);
3597c8c0b82SPatrick Mooney }
3607c8c0b82SPatrick Mooney 
3617c8c0b82SPatrick Mooney int
vatpit_handler(void * arg,bool in,uint16_t port,uint8_t bytes,uint32_t * eax)3627c8c0b82SPatrick Mooney vatpit_handler(void *arg, bool in, uint16_t port, uint8_t bytes, uint32_t *eax)
3637c8c0b82SPatrick Mooney {
3647c8c0b82SPatrick Mooney 	struct vatpit *vatpit = arg;
3657c8c0b82SPatrick Mooney 	struct channel *c;
3667c8c0b82SPatrick Mooney 	uint8_t val;
3677c8c0b82SPatrick Mooney 	int error;
3687c8c0b82SPatrick Mooney 
3697c8c0b82SPatrick Mooney 	if (bytes != 1)
3707c8c0b82SPatrick Mooney 		return (-1);
3717c8c0b82SPatrick Mooney 
3727c8c0b82SPatrick Mooney 	val = *eax;
3737c8c0b82SPatrick Mooney 
3747c8c0b82SPatrick Mooney 	if (port == TIMER_MODE) {
3757c8c0b82SPatrick Mooney 		if (in) {
376d4f59ae5SPatrick Mooney 			/* Mode is write-only */
3777c8c0b82SPatrick Mooney 			return (-1);
3787c8c0b82SPatrick Mooney 		}
3797c8c0b82SPatrick Mooney 
3807c8c0b82SPatrick Mooney 		VATPIT_LOCK(vatpit);
3817c8c0b82SPatrick Mooney 		error = vatpit_update_mode(vatpit, val);
3827c8c0b82SPatrick Mooney 		VATPIT_UNLOCK(vatpit);
3837c8c0b82SPatrick Mooney 
3847c8c0b82SPatrick Mooney 		return (error);
3857c8c0b82SPatrick Mooney 	}
3867c8c0b82SPatrick Mooney 
3877c8c0b82SPatrick Mooney 	/* counter ports */
3887c8c0b82SPatrick Mooney 	KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,
3897c8c0b82SPatrick Mooney 	    ("invalid port 0x%x", port));
3907c8c0b82SPatrick Mooney 	c = &vatpit->channel[port - TIMER_CNTR0];
3917c8c0b82SPatrick Mooney 
3927c8c0b82SPatrick Mooney 	VATPIT_LOCK(vatpit);
3937c8c0b82SPatrick Mooney 	if (in && c->slatched) {
3947c8c0b82SPatrick Mooney 		/* Return the status byte if latched */
3957c8c0b82SPatrick Mooney 		*eax = c->reg_status;
3967c8c0b82SPatrick Mooney 		c->slatched = false;
3977c8c0b82SPatrick Mooney 		c->reg_status = 0;
3987c8c0b82SPatrick Mooney 	} else if (in) {
3997c8c0b82SPatrick Mooney 		/*
4007c8c0b82SPatrick Mooney 		 * The spec says that once the output latch is completely
4017c8c0b82SPatrick Mooney 		 * read it should revert to "following" the counter. Use
4027c8c0b82SPatrick Mooney 		 * the free running counter for this case (i.e. Linux
4037c8c0b82SPatrick Mooney 		 * TSC calibration). Assuming the access mode is 16-bit,
4047c8c0b82SPatrick Mooney 		 * toggle the MSB/LSB bit on each read.
4057c8c0b82SPatrick Mooney 		 */
4067c8c0b82SPatrick Mooney 		if (!c->olatched) {
4077c8c0b82SPatrick Mooney 			uint16_t tmp;
4087c8c0b82SPatrick Mooney 
4097c8c0b82SPatrick Mooney 			tmp = pit_update_counter(vatpit, c, false);
4107c8c0b82SPatrick Mooney 			if (c->fr_sel) {
4117c8c0b82SPatrick Mooney 				tmp >>= 8;
4127c8c0b82SPatrick Mooney 			}
4137c8c0b82SPatrick Mooney 			tmp &= 0xff;
4147c8c0b82SPatrick Mooney 			*eax = tmp;
4157c8c0b82SPatrick Mooney 			c->fr_sel = !c->fr_sel;
4167c8c0b82SPatrick Mooney 		} else {
4177c8c0b82SPatrick Mooney 			if (c->ol_sel) {
4187c8c0b82SPatrick Mooney 				*eax = c->reg_ol[1];
4197c8c0b82SPatrick Mooney 				c->ol_sel = false;
4207c8c0b82SPatrick Mooney 			} else {
4217c8c0b82SPatrick Mooney 				*eax = c->reg_ol[0];
4227c8c0b82SPatrick Mooney 				c->olatched = false;
4237c8c0b82SPatrick Mooney 			}
4247c8c0b82SPatrick Mooney 		}
4257c8c0b82SPatrick Mooney 	} else {
4267c8c0b82SPatrick Mooney 		if (!c->cr_sel) {
4277c8c0b82SPatrick Mooney 			c->reg_cr[0] = *eax;
4287c8c0b82SPatrick Mooney 			c->cr_sel = true;
4297c8c0b82SPatrick Mooney 		} else {
4307c8c0b82SPatrick Mooney 			c->reg_cr[1] = *eax;
4317c8c0b82SPatrick Mooney 			c->cr_sel = false;
4327c8c0b82SPatrick Mooney 
4337c8c0b82SPatrick Mooney 			c->reg_status &= ~TIMER_STS_NULLCNT;
4347c8c0b82SPatrick Mooney 			c->fr_sel = false;
4357c8c0b82SPatrick Mooney 			c->initial = c->reg_cr[0] | (uint16_t)c->reg_cr[1] << 8;
4367c8c0b82SPatrick Mooney 			c->time_loaded = gethrtime();
4377c8c0b82SPatrick Mooney 			/* Start an interval timer for channel 0 */
4387c8c0b82SPatrick Mooney 			if (port == TIMER_CNTR0) {
4397c8c0b82SPatrick Mooney 				c->time_target = c->time_loaded;
4407c8c0b82SPatrick Mooney 				c->total_target = 0;
4417c8c0b82SPatrick Mooney 				pit_timer_start_cntr0(vatpit);
4427c8c0b82SPatrick Mooney 			}
4437c8c0b82SPatrick Mooney 			if (c->initial == 0)
4447c8c0b82SPatrick Mooney 				c->initial = 0xffff;
4457c8c0b82SPatrick Mooney 		}
4467c8c0b82SPatrick Mooney 	}
4477c8c0b82SPatrick Mooney 	VATPIT_UNLOCK(vatpit);
4487c8c0b82SPatrick Mooney 
4497c8c0b82SPatrick Mooney 	return (0);
4507c8c0b82SPatrick Mooney }
4517c8c0b82SPatrick Mooney 
4527c8c0b82SPatrick Mooney int
vatpit_nmisc_handler(void * arg,bool in,uint16_t port,uint8_t bytes,uint32_t * eax)4537c8c0b82SPatrick Mooney vatpit_nmisc_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
4547c8c0b82SPatrick Mooney     uint32_t *eax)
4557c8c0b82SPatrick Mooney {
4567c8c0b82SPatrick Mooney 	struct vatpit *vatpit = arg;
4577c8c0b82SPatrick Mooney 
4587c8c0b82SPatrick Mooney 	if (in) {
4597c8c0b82SPatrick Mooney 			VATPIT_LOCK(vatpit);
4607c8c0b82SPatrick Mooney 			if (vatpit_get_out(vatpit, 2))
4617c8c0b82SPatrick Mooney 				*eax = TMR2_OUT_STS;
4627c8c0b82SPatrick Mooney 			else
4637c8c0b82SPatrick Mooney 				*eax = 0;
4647c8c0b82SPatrick Mooney 
4657c8c0b82SPatrick Mooney 			VATPIT_UNLOCK(vatpit);
4667c8c0b82SPatrick Mooney 	}
4677c8c0b82SPatrick Mooney 
4687c8c0b82SPatrick Mooney 	return (0);
4697c8c0b82SPatrick Mooney }
4707c8c0b82SPatrick Mooney 
4717c8c0b82SPatrick Mooney struct vatpit *
vatpit_init(struct vm * vm)4727c8c0b82SPatrick Mooney vatpit_init(struct vm *vm)
4737c8c0b82SPatrick Mooney {
4747c8c0b82SPatrick Mooney 	struct vatpit *vatpit;
4757c8c0b82SPatrick Mooney 	struct vatpit_callout_arg *arg;
4767c8c0b82SPatrick Mooney 	int i;
4777c8c0b82SPatrick Mooney 
4788130f8e1SPatrick Mooney 	vatpit = kmem_zalloc(sizeof (struct vatpit), KM_SLEEP);
4797c8c0b82SPatrick Mooney 	vatpit->vm = vm;
4807c8c0b82SPatrick Mooney 
4817c8c0b82SPatrick Mooney 	mutex_init(&vatpit->lock, NULL, MUTEX_ADAPTIVE, NULL);
4827c8c0b82SPatrick Mooney 
4837c8c0b82SPatrick Mooney 	for (i = 0; i < 3; i++) {
4847c8c0b82SPatrick Mooney 		callout_init(&vatpit->channel[i].callout, 1);
4857c8c0b82SPatrick Mooney 		arg = &vatpit->channel[i].callout_arg;
4867c8c0b82SPatrick Mooney 		arg->vatpit = vatpit;
4877c8c0b82SPatrick Mooney 		arg->channel_num = i;
4887c8c0b82SPatrick Mooney 	}
4897c8c0b82SPatrick Mooney 
4907c8c0b82SPatrick Mooney 	return (vatpit);
4917c8c0b82SPatrick Mooney }
4927c8c0b82SPatrick Mooney 
4937c8c0b82SPatrick Mooney void
vatpit_cleanup(struct vatpit * vatpit)4947c8c0b82SPatrick Mooney vatpit_cleanup(struct vatpit *vatpit)
4957c8c0b82SPatrick Mooney {
4967c8c0b82SPatrick Mooney 	int i;
4977c8c0b82SPatrick Mooney 
4987c8c0b82SPatrick Mooney 	for (i = 0; i < 3; i++)
4997c8c0b82SPatrick Mooney 		callout_drain(&vatpit->channel[i].callout);
5007c8c0b82SPatrick Mooney 
5017c8c0b82SPatrick Mooney 	mutex_destroy(&vatpit->lock);
5028130f8e1SPatrick Mooney 	kmem_free(vatpit, sizeof (*vatpit));
5037c8c0b82SPatrick Mooney }
5047c8c0b82SPatrick Mooney 
5057c8c0b82SPatrick Mooney void
vatpit_localize_resources(struct vatpit * vatpit)5067c8c0b82SPatrick Mooney vatpit_localize_resources(struct vatpit *vatpit)
5077c8c0b82SPatrick Mooney {
5087c8c0b82SPatrick Mooney 	for (uint_t i = 0; i < 3; i++) {
5097c8c0b82SPatrick Mooney 		/* Only localize channels which might be running */
5107c8c0b82SPatrick Mooney 		if (vatpit->channel[i].mode != 0) {
5117c8c0b82SPatrick Mooney 			vmm_glue_callout_localize(&vatpit->channel[i].callout);
5127c8c0b82SPatrick Mooney 		}
5137c8c0b82SPatrick Mooney 	}
5147c8c0b82SPatrick Mooney }
515d515dd77SPatrick Mooney 
516*2cac0506SPatrick Mooney void
vatpit_pause(struct vatpit * vatpit)517*2cac0506SPatrick Mooney vatpit_pause(struct vatpit *vatpit)
518*2cac0506SPatrick Mooney {
519*2cac0506SPatrick Mooney 	struct channel *c = &vatpit->channel[0];
520*2cac0506SPatrick Mooney 
521*2cac0506SPatrick Mooney 	VATPIT_LOCK(vatpit);
522*2cac0506SPatrick Mooney 	callout_stop(&c->callout);
523*2cac0506SPatrick Mooney 	VATPIT_UNLOCK(vatpit);
524*2cac0506SPatrick Mooney }
525*2cac0506SPatrick Mooney 
526*2cac0506SPatrick Mooney void
vatpit_resume(struct vatpit * vatpit)527*2cac0506SPatrick Mooney vatpit_resume(struct vatpit *vatpit)
528*2cac0506SPatrick Mooney {
529*2cac0506SPatrick Mooney 	struct channel *c = &vatpit->channel[0];
530*2cac0506SPatrick Mooney 
531*2cac0506SPatrick Mooney 	VATPIT_LOCK(vatpit);
532*2cac0506SPatrick Mooney 	ASSERT(!callout_active(&c->callout));
533*2cac0506SPatrick Mooney 	if (c->time_target != 0) {
534*2cac0506SPatrick Mooney 		vatpit_callout_reset(vatpit);
535*2cac0506SPatrick Mooney 	}
536*2cac0506SPatrick Mooney 	VATPIT_UNLOCK(vatpit);
537*2cac0506SPatrick Mooney }
538*2cac0506SPatrick Mooney 
539d515dd77SPatrick Mooney static int
vatpit_data_read(void * datap,const vmm_data_req_t * req)540d515dd77SPatrick Mooney vatpit_data_read(void *datap, const vmm_data_req_t *req)
541d515dd77SPatrick Mooney {
542d515dd77SPatrick Mooney 	VERIFY3U(req->vdr_class, ==, VDC_ATPIT);
543d515dd77SPatrick Mooney 	VERIFY3U(req->vdr_version, ==, 1);
544a77feb92SPatrick Mooney 	VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_atpit_v1));
545d515dd77SPatrick Mooney 
546d515dd77SPatrick Mooney 	struct vatpit *vatpit = datap;
547d515dd77SPatrick Mooney 	struct vdi_atpit_v1 *out = req->vdr_data;
548d515dd77SPatrick Mooney 
549d515dd77SPatrick Mooney 	VATPIT_LOCK(vatpit);
550d515dd77SPatrick Mooney 	for (uint_t i = 0; i < 3; i++) {
551d515dd77SPatrick Mooney 		const struct channel *src = &vatpit->channel[i];
552d515dd77SPatrick Mooney 		struct vdi_atpit_channel_v1 *chan = &out->va_channel[i];
553d515dd77SPatrick Mooney 
554d515dd77SPatrick Mooney 		chan->vac_initial = src->initial;
555d515dd77SPatrick Mooney 		chan->vac_reg_cr =
556d515dd77SPatrick Mooney 		    (src->reg_cr[0] | (uint16_t)src->reg_cr[1] << 8);
557d515dd77SPatrick Mooney 		chan->vac_reg_ol =
558d515dd77SPatrick Mooney 		    (src->reg_ol[0] | (uint16_t)src->reg_ol[1] << 8);
559d515dd77SPatrick Mooney 		chan->vac_reg_status = src->reg_status;
560d515dd77SPatrick Mooney 		chan->vac_mode = src->mode;
561d515dd77SPatrick Mooney 		chan->vac_status =
562d515dd77SPatrick Mooney 		    (src->slatched ? (1 << 0) : 0) |
563d515dd77SPatrick Mooney 		    (src->olatched ? (1 << 1) : 0) |
564d515dd77SPatrick Mooney 		    (src->cr_sel ? (1 << 2) : 0) |
565d515dd77SPatrick Mooney 		    (src->ol_sel ? (1 << 3) : 0) |
566d515dd77SPatrick Mooney 		    (src->fr_sel ? (1 << 4) : 0);
567d515dd77SPatrick Mooney 		/* Only channel 0 has the timer configured */
568*2cac0506SPatrick Mooney 		if (i == 0 && src->time_target != 0) {
569d515dd77SPatrick Mooney 			chan->vac_time_target =
570d515dd77SPatrick Mooney 			    vm_normalize_hrtime(vatpit->vm, src->time_target);
571d515dd77SPatrick Mooney 		} else {
572d515dd77SPatrick Mooney 			chan->vac_time_target = 0;
573d515dd77SPatrick Mooney 		}
574d515dd77SPatrick Mooney 	}
575d515dd77SPatrick Mooney 	VATPIT_UNLOCK(vatpit);
576d515dd77SPatrick Mooney 
577d515dd77SPatrick Mooney 	return (0);
578d515dd77SPatrick Mooney }
579d515dd77SPatrick Mooney 
580d515dd77SPatrick Mooney static bool
vatpit_data_validate(const struct vdi_atpit_v1 * src)581d515dd77SPatrick Mooney vatpit_data_validate(const struct vdi_atpit_v1 *src)
582d515dd77SPatrick Mooney {
583d515dd77SPatrick Mooney 	for (uint_t i = 0; i < 3; i++) {
584d515dd77SPatrick Mooney 		const struct vdi_atpit_channel_v1 *chan = &src->va_channel[i];
585d515dd77SPatrick Mooney 
586d515dd77SPatrick Mooney 		if ((chan->vac_status & ~VALID_STATUS_BITS) != 0) {
587d515dd77SPatrick Mooney 			return (false);
588d515dd77SPatrick Mooney 		}
589d515dd77SPatrick Mooney 	}
590d515dd77SPatrick Mooney 	return (true);
591d515dd77SPatrick Mooney }
592d515dd77SPatrick Mooney 
593d515dd77SPatrick Mooney static int
vatpit_data_write(void * datap,const vmm_data_req_t * req)594d515dd77SPatrick Mooney vatpit_data_write(void *datap, const vmm_data_req_t *req)
595d515dd77SPatrick Mooney {
596d515dd77SPatrick Mooney 	VERIFY3U(req->vdr_class, ==, VDC_ATPIT);
597d515dd77SPatrick Mooney 	VERIFY3U(req->vdr_version, ==, 1);
598a77feb92SPatrick Mooney 	VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_atpit_v1));
599d515dd77SPatrick Mooney 
600d515dd77SPatrick Mooney 	struct vatpit *vatpit = datap;
601d515dd77SPatrick Mooney 	const struct vdi_atpit_v1 *src = req->vdr_data;
602d515dd77SPatrick Mooney 	if (!vatpit_data_validate(src)) {
603d515dd77SPatrick Mooney 		return (EINVAL);
604d515dd77SPatrick Mooney 	}
605d515dd77SPatrick Mooney 
606d515dd77SPatrick Mooney 	VATPIT_LOCK(vatpit);
607d515dd77SPatrick Mooney 	for (uint_t i = 0; i < 3; i++) {
608d515dd77SPatrick Mooney 		const struct vdi_atpit_channel_v1 *chan = &src->va_channel[i];
609d515dd77SPatrick Mooney 		struct channel *out = &vatpit->channel[i];
610d515dd77SPatrick Mooney 
611d515dd77SPatrick Mooney 		out->initial = chan->vac_initial;
612d515dd77SPatrick Mooney 		out->reg_cr[0] = chan->vac_reg_cr;
613d515dd77SPatrick Mooney 		out->reg_cr[1] = chan->vac_reg_cr >> 8;
614d515dd77SPatrick Mooney 		out->reg_ol[0] = chan->vac_reg_ol;
615d515dd77SPatrick Mooney 		out->reg_ol[1] = chan->vac_reg_ol >> 8;
616d515dd77SPatrick Mooney 		out->reg_status = chan->vac_reg_status;
617d515dd77SPatrick Mooney 		out->mode = chan->vac_mode;
618d515dd77SPatrick Mooney 		out->slatched = (chan->vac_status & (1 << 0)) != 0;
619d515dd77SPatrick Mooney 		out->olatched = (chan->vac_status & (1 << 1)) != 0;
620d515dd77SPatrick Mooney 		out->cr_sel = (chan->vac_status & (1 << 2)) != 0;
621d515dd77SPatrick Mooney 		out->ol_sel = (chan->vac_status & (1 << 3)) != 0;
622d515dd77SPatrick Mooney 		out->fr_sel = (chan->vac_status & (1 << 4)) != 0;
623d515dd77SPatrick Mooney 
624d515dd77SPatrick Mooney 		/* Only channel 0 has the timer configured */
625d515dd77SPatrick Mooney 		if (i != 0) {
626d515dd77SPatrick Mooney 			continue;
627d515dd77SPatrick Mooney 		}
628d515dd77SPatrick Mooney 
629d515dd77SPatrick Mooney 		struct callout *callout = &out->callout;
630d515dd77SPatrick Mooney 		if (callout_active(callout)) {
631d515dd77SPatrick Mooney 			callout_deactivate(callout);
632d515dd77SPatrick Mooney 		}
633d515dd77SPatrick Mooney 
634d515dd77SPatrick Mooney 		if (chan->vac_time_target == 0) {
635d515dd77SPatrick Mooney 			out->time_loaded = 0;
636d515dd77SPatrick Mooney 			out->time_target = 0;
637d515dd77SPatrick Mooney 			continue;
638d515dd77SPatrick Mooney 		}
639d515dd77SPatrick Mooney 
640d515dd77SPatrick Mooney 		/* back-calculate time_loaded for the appropriate interval */
641d515dd77SPatrick Mooney 		const uint64_t time_target =
642d515dd77SPatrick Mooney 		    vm_denormalize_hrtime(vatpit->vm, chan->vac_time_target);
643d515dd77SPatrick Mooney 		out->total_target = out->initial;
644d515dd77SPatrick Mooney 		out->time_target = time_target;
645d515dd77SPatrick Mooney 		out->time_loaded = time_target -
646d515dd77SPatrick Mooney 		    hrt_freq_interval(PIT_8254_FREQ, out->initial);
647*2cac0506SPatrick Mooney 
648*2cac0506SPatrick Mooney 		if (!vm_is_paused(vatpit->vm)) {
649*2cac0506SPatrick Mooney 			vatpit_callout_reset(vatpit);
650*2cac0506SPatrick Mooney 		}
651d515dd77SPatrick Mooney 	}
652d515dd77SPatrick Mooney 	VATPIT_UNLOCK(vatpit);
653d515dd77SPatrick Mooney 
654d515dd77SPatrick Mooney 	return (0);
655d515dd77SPatrick Mooney }
656d515dd77SPatrick Mooney 
657d515dd77SPatrick Mooney static const vmm_data_version_entry_t atpit_v1 = {
658d515dd77SPatrick Mooney 	.vdve_class = VDC_ATPIT,
659d515dd77SPatrick Mooney 	.vdve_version = 1,
660d515dd77SPatrick Mooney 	.vdve_len_expect = sizeof (struct vdi_atpit_v1),
661d515dd77SPatrick Mooney 	.vdve_readf = vatpit_data_read,
662d515dd77SPatrick Mooney 	.vdve_writef = vatpit_data_write,
663d515dd77SPatrick Mooney };
664d515dd77SPatrick Mooney VMM_DATA_VERSION(atpit_v1);
665