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