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