xref: /illumos-gate/usr/src/uts/intel/io/vmm/io/vatpit.c (revision 38aced4f)
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 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/queue.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mutex.h>
39 #include <sys/systm.h>
40 
41 #include <machine/vmm.h>
42 
43 #include "vmm_ktr.h"
44 #include "vatpic.h"
45 #include "vioapic.h"
46 #include "vatpit.h"
47 
48 static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)");
49 
50 #define	VATPIT_LOCK(vatpit)		mutex_enter(&((vatpit)->lock))
51 #define	VATPIT_UNLOCK(vatpit)		mutex_exit(&((vatpit)->lock))
52 
53 #define	TIMER_SEL_MASK		0xc0
54 #define	TIMER_RW_MASK		0x30
55 #define	TIMER_MODE_MASK		0x0f
56 #define	TIMER_SEL_READBACK	0xc0
57 
58 #define	TIMER_STS_OUT		0x80
59 #define	TIMER_STS_NULLCNT	0x40
60 
61 #define	TIMER_RB_LCTR		0x20
62 #define	TIMER_RB_LSTATUS	0x10
63 #define	TIMER_RB_CTR_2		0x08
64 #define	TIMER_RB_CTR_1		0x04
65 #define	TIMER_RB_CTR_0		0x02
66 
67 #define	TMR2_OUT_STS		0x20
68 
69 #define	PIT_8254_FREQ		1193182
70 #define	TIMER_DIV(freq, hz)	(((freq) + (hz) / 2) / (hz))
71 
72 struct vatpit_callout_arg {
73 	struct vatpit	*vatpit;
74 	int		channel_num;
75 };
76 
77 struct channel {
78 	uint8_t		mode;
79 	uint16_t	initial;	/* initial counter value */
80 
81 	uint8_t		reg_cr[2];
82 	uint8_t		reg_ol[2];
83 	uint8_t		reg_status;
84 
85 	bool		slatched;	/* status latched */
86 	bool		olatched;	/* output latched */
87 	bool		cr_sel;		/* read MSB from control register */
88 	bool		ol_sel;		/* read MSB from output latch */
89 	bool		fr_sel;		/* read MSB from free-running timer */
90 
91 	hrtime_t	time_loaded;	/* time when counter was loaded */
92 	hrtime_t	time_target;	/* target time */
93 	uint64_t	total_target;
94 
95 	struct callout	callout;
96 	struct vatpit_callout_arg callout_arg;
97 };
98 
99 struct vatpit {
100 	struct vm	*vm;
101 	kmutex_t	lock;
102 
103 	struct channel	channel[3];
104 };
105 
106 static void pit_timer_start_cntr0(struct vatpit *vatpit);
107 
108 static uint64_t
109 vatpit_delta_ticks(struct vatpit *vatpit, struct channel *c)
110 {
111 	const hrtime_t delta = gethrtime() - c->time_loaded;
112 
113 	return (hrt_freq_count(delta, PIT_8254_FREQ));
114 }
115 
116 static int
117 vatpit_get_out(struct vatpit *vatpit, int channel)
118 {
119 	struct channel *c;
120 	uint64_t delta_ticks;
121 	int out;
122 
123 	c = &vatpit->channel[channel];
124 
125 	switch (c->mode) {
126 	case TIMER_INTTC:
127 		delta_ticks = vatpit_delta_ticks(vatpit, c);
128 		out = (delta_ticks >= c->initial);
129 		break;
130 	default:
131 		out = 0;
132 		break;
133 	}
134 
135 	return (out);
136 }
137 
138 static void
139 vatpit_callout_handler(void *a)
140 {
141 	struct vatpit_callout_arg *arg = a;
142 	struct vatpit *vatpit;
143 	struct callout *callout;
144 	struct channel *c;
145 
146 	vatpit = arg->vatpit;
147 	c = &vatpit->channel[arg->channel_num];
148 	callout = &c->callout;
149 
150 	VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num);
151 
152 	VATPIT_LOCK(vatpit);
153 
154 	if (callout_pending(callout))		/* callout was reset */
155 		goto done;
156 
157 	if (!callout_active(callout))		/* callout was stopped */
158 		goto done;
159 
160 	callout_deactivate(callout);
161 
162 	if (c->mode == TIMER_RATEGEN || c->mode == TIMER_SQWAVE) {
163 		pit_timer_start_cntr0(vatpit);
164 	}
165 
166 	(void) vatpic_pulse_irq(vatpit->vm, 0);
167 	(void) vioapic_pulse_irq(vatpit->vm, 2);
168 
169 done:
170 	VATPIT_UNLOCK(vatpit);
171 }
172 
173 static void
174 pit_timer_start_cntr0(struct vatpit *vatpit)
175 {
176 	struct channel *c = &vatpit->channel[0];
177 
178 	if (c->initial == 0) {
179 		return;
180 	}
181 
182 	c->total_target += c->initial;
183 	c->time_target = c->time_loaded +
184 	    hrt_freq_interval(PIT_8254_FREQ, c->total_target);
185 
186 	/*
187 	 * If we are more than 'c->initial' ticks behind, reset the timer base
188 	 * to fire at the next 'c->initial' interval boundary.
189 	 */
190 	hrtime_t now = gethrtime();
191 	if (c->time_target < now) {
192 		const uint64_t ticks_behind =
193 		    hrt_freq_count(c->time_target - now, PIT_8254_FREQ);
194 
195 		c->total_target += roundup(ticks_behind, c->initial);
196 		c->time_target = c->time_loaded +
197 		    hrt_freq_interval(PIT_8254_FREQ, c->total_target);
198 	}
199 
200 	callout_reset_hrtime(&c->callout, c->time_target,
201 	    vatpit_callout_handler, &c->callout_arg, C_ABSOLUTE);
202 }
203 
204 static uint16_t
205 pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)
206 {
207 	uint16_t lval;
208 	uint64_t delta_ticks;
209 
210 	/* cannot latch a new value until the old one has been consumed */
211 	if (latch && c->olatched)
212 		return (0);
213 
214 	if (c->initial == 0) {
215 		/*
216 		 * This is possibly an OS bug - reading the value of the timer
217 		 * without having set up the initial value.
218 		 *
219 		 * The original user-space version of this code set the timer to
220 		 * 100hz in this condition; do the same here.
221 		 */
222 		c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
223 		c->time_loaded = gethrtime();
224 		c->reg_status &= ~TIMER_STS_NULLCNT;
225 	}
226 
227 	delta_ticks = vatpit_delta_ticks(vatpit, c);
228 	lval = c->initial - delta_ticks % c->initial;
229 
230 	if (latch) {
231 		c->olatched = true;
232 		c->ol_sel = true;
233 		c->reg_ol[1] = lval;		/* LSB */
234 		c->reg_ol[0] = lval >> 8;	/* MSB */
235 	}
236 
237 	return (lval);
238 }
239 
240 static int
241 pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd)
242 {
243 	struct channel *c;
244 
245 	c = &vatpit->channel[channel];
246 
247 	/*
248 	 * Latch the count/status of the timer if not already latched.
249 	 * N.B. that the count/status latch-select bits are active-low.
250 	 */
251 	if ((cmd & TIMER_RB_LCTR) == 0 && !c->olatched) {
252 		(void) pit_update_counter(vatpit, c, true);
253 	}
254 
255 	if ((cmd & TIMER_RB_LSTATUS) == 0 && !c->slatched) {
256 		c->slatched = true;
257 		/*
258 		 * For mode 0, see if the elapsed time is greater
259 		 * than the initial value - this results in the
260 		 * output pin being set to 1 in the status byte.
261 		 */
262 		if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel))
263 			c->reg_status |= TIMER_STS_OUT;
264 		else
265 			c->reg_status &= ~TIMER_STS_OUT;
266 	}
267 
268 	return (0);
269 }
270 
271 static int
272 pit_readback(struct vatpit *vatpit, uint8_t cmd)
273 {
274 	int error;
275 
276 	/*
277 	 * The readback command can apply to all timers.
278 	 */
279 	error = 0;
280 	if (cmd & TIMER_RB_CTR_0)
281 		error = pit_readback1(vatpit, 0, cmd);
282 	if (!error && cmd & TIMER_RB_CTR_1)
283 		error = pit_readback1(vatpit, 1, cmd);
284 	if (!error && cmd & TIMER_RB_CTR_2)
285 		error = pit_readback1(vatpit, 2, cmd);
286 
287 	return (error);
288 }
289 
290 static int
291 vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
292 {
293 	struct channel *c;
294 	int sel, rw;
295 	uint8_t mode;
296 
297 	sel = val & TIMER_SEL_MASK;
298 	rw = val & TIMER_RW_MASK;
299 	mode = val & TIMER_MODE_MASK;
300 
301 	/* Clear don't-care bit (M2) when M1 is set */
302 	if ((mode & TIMER_RATEGEN) != 0) {
303 		mode &= ~TIMER_SWSTROBE;
304 	}
305 
306 	if (sel == TIMER_SEL_READBACK)
307 		return (pit_readback(vatpit, val));
308 
309 	if (rw != TIMER_LATCH && rw != TIMER_16BIT)
310 		return (-1);
311 
312 	if (rw != TIMER_LATCH) {
313 		/*
314 		 * Counter mode is not affected when issuing a
315 		 * latch command.
316 		 */
317 		if (mode != TIMER_INTTC &&
318 		    mode != TIMER_RATEGEN &&
319 		    mode != TIMER_SQWAVE &&
320 		    mode != TIMER_SWSTROBE)
321 			return (-1);
322 	}
323 
324 	c = &vatpit->channel[sel >> 6];
325 	if (rw == TIMER_LATCH) {
326 		(void) pit_update_counter(vatpit, c, true);
327 	} else {
328 		c->mode = mode;
329 		c->olatched = false;	/* reset latch after reprogramming */
330 		c->reg_status |= TIMER_STS_NULLCNT;
331 	}
332 
333 	return (0);
334 }
335 
336 int
337 vatpit_handler(void *arg, bool in, uint16_t port, uint8_t bytes, uint32_t *eax)
338 {
339 	struct vatpit *vatpit = arg;
340 	struct channel *c;
341 	uint8_t val;
342 	int error;
343 
344 	if (bytes != 1)
345 		return (-1);
346 
347 	val = *eax;
348 
349 	if (port == TIMER_MODE) {
350 		if (in) {
351 			VM_CTR0(vatpit->vm, "vatpit attempt to read mode");
352 			return (-1);
353 		}
354 
355 		VATPIT_LOCK(vatpit);
356 		error = vatpit_update_mode(vatpit, val);
357 		VATPIT_UNLOCK(vatpit);
358 
359 		return (error);
360 	}
361 
362 	/* counter ports */
363 	KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,
364 	    ("invalid port 0x%x", port));
365 	c = &vatpit->channel[port - TIMER_CNTR0];
366 
367 	VATPIT_LOCK(vatpit);
368 	if (in && c->slatched) {
369 		/* Return the status byte if latched */
370 		*eax = c->reg_status;
371 		c->slatched = false;
372 		c->reg_status = 0;
373 	} else if (in) {
374 		/*
375 		 * The spec says that once the output latch is completely
376 		 * read it should revert to "following" the counter. Use
377 		 * the free running counter for this case (i.e. Linux
378 		 * TSC calibration). Assuming the access mode is 16-bit,
379 		 * toggle the MSB/LSB bit on each read.
380 		 */
381 		if (!c->olatched) {
382 			uint16_t tmp;
383 
384 			tmp = pit_update_counter(vatpit, c, false);
385 			if (c->fr_sel) {
386 				tmp >>= 8;
387 			}
388 			tmp &= 0xff;
389 			*eax = tmp;
390 			c->fr_sel = !c->fr_sel;
391 		} else {
392 			if (c->ol_sel) {
393 				*eax = c->reg_ol[1];
394 				c->ol_sel = false;
395 			} else {
396 				*eax = c->reg_ol[0];
397 				c->olatched = false;
398 			}
399 		}
400 	} else {
401 		if (!c->cr_sel) {
402 			c->reg_cr[0] = *eax;
403 			c->cr_sel = true;
404 		} else {
405 			c->reg_cr[1] = *eax;
406 			c->cr_sel = false;
407 
408 			c->reg_status &= ~TIMER_STS_NULLCNT;
409 			c->fr_sel = false;
410 			c->initial = c->reg_cr[0] | (uint16_t)c->reg_cr[1] << 8;
411 			c->time_loaded = gethrtime();
412 			/* Start an interval timer for channel 0 */
413 			if (port == TIMER_CNTR0) {
414 				c->time_target = c->time_loaded;
415 				c->total_target = 0;
416 				pit_timer_start_cntr0(vatpit);
417 			}
418 			if (c->initial == 0)
419 				c->initial = 0xffff;
420 		}
421 	}
422 	VATPIT_UNLOCK(vatpit);
423 
424 	return (0);
425 }
426 
427 int
428 vatpit_nmisc_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
429     uint32_t *eax)
430 {
431 	struct vatpit *vatpit = arg;
432 
433 	if (in) {
434 			VATPIT_LOCK(vatpit);
435 			if (vatpit_get_out(vatpit, 2))
436 				*eax = TMR2_OUT_STS;
437 			else
438 				*eax = 0;
439 
440 			VATPIT_UNLOCK(vatpit);
441 	}
442 
443 	return (0);
444 }
445 
446 struct vatpit *
447 vatpit_init(struct vm *vm)
448 {
449 	struct vatpit *vatpit;
450 	struct vatpit_callout_arg *arg;
451 	int i;
452 
453 	vatpit = malloc(sizeof (struct vatpit), M_VATPIT, M_WAITOK | M_ZERO);
454 	vatpit->vm = vm;
455 
456 	mutex_init(&vatpit->lock, NULL, MUTEX_ADAPTIVE, NULL);
457 
458 	for (i = 0; i < 3; i++) {
459 		callout_init(&vatpit->channel[i].callout, 1);
460 		arg = &vatpit->channel[i].callout_arg;
461 		arg->vatpit = vatpit;
462 		arg->channel_num = i;
463 	}
464 
465 	return (vatpit);
466 }
467 
468 void
469 vatpit_cleanup(struct vatpit *vatpit)
470 {
471 	int i;
472 
473 	for (i = 0; i < 3; i++)
474 		callout_drain(&vatpit->channel[i].callout);
475 
476 	mutex_destroy(&vatpit->lock);
477 	free(vatpit, M_VATPIT);
478 }
479 
480 void
481 vatpit_localize_resources(struct vatpit *vatpit)
482 {
483 	for (uint_t i = 0; i < 3; i++) {
484 		/* Only localize channels which might be running */
485 		if (vatpit->channel[i].mode != 0) {
486 			vmm_glue_callout_localize(&vatpit->channel[i].callout);
487 		}
488 	}
489 }
490