1/*-
2 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3 * Copyright (c) 2011 NetApp, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/types.h>
33#include <sys/queue.h>
34#include <sys/kernel.h>
35#include <sys/lock.h>
36#include <sys/malloc.h>
37#include <sys/mutex.h>
38#include <sys/systm.h>
39
40#include <machine/vmm.h>
41
42#include "vmm_ktr.h"
43#include "vatpic.h"
44#include "vioapic.h"
45#include "vatpit.h"
46
47static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)");
48
49#define	VATPIT_LOCK(vatpit)		mtx_lock_spin(&((vatpit)->mtx))
50#define	VATPIT_UNLOCK(vatpit)		mtx_unlock_spin(&((vatpit)->mtx))
51#define	VATPIT_LOCKED(vatpit)		mtx_owned(&((vatpit)->mtx))
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
72struct vatpit_callout_arg {
73	struct vatpit	*vatpit;
74	int		channel_num;
75};
76
77
78struct channel {
79	int		mode;
80	uint16_t	initial;	/* initial counter value */
81	sbintime_t	now_sbt;	/* uptime when counter was loaded */
82	uint8_t		cr[2];
83	uint8_t		ol[2];
84	bool		slatched;	/* status latched */
85	uint8_t		status;
86	int		crbyte;
87	int		olbyte;
88	int		frbyte;
89	struct callout	callout;
90	sbintime_t	callout_sbt;	/* target time */
91	struct vatpit_callout_arg callout_arg;
92};
93
94struct vatpit {
95	struct vm	*vm;
96	struct mtx	mtx;
97
98	sbintime_t	freq_sbt;
99
100	struct channel	channel[3];
101};
102
103static void pit_timer_start_cntr0(struct vatpit *vatpit);
104
105static int
106vatpit_get_out(struct vatpit *vatpit, int channel)
107{
108	struct channel *c;
109	sbintime_t delta_ticks;
110	int out;
111
112	c = &vatpit->channel[channel];
113
114	switch (c->mode) {
115	case TIMER_INTTC:
116		delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;
117		out = ((c->initial - delta_ticks) <= 0);
118		break;
119	default:
120		out = 0;
121		break;
122	}
123
124	return (out);
125}
126
127static void
128vatpit_callout_handler(void *a)
129{
130	struct vatpit_callout_arg *arg = a;
131	struct vatpit *vatpit;
132	struct callout *callout;
133	struct channel *c;
134
135	vatpit = arg->vatpit;
136	c = &vatpit->channel[arg->channel_num];
137	callout = &c->callout;
138
139	VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num);
140
141	VATPIT_LOCK(vatpit);
142
143	if (callout_pending(callout))		/* callout was reset */
144		goto done;
145
146	if (!callout_active(callout))		/* callout was stopped */
147		goto done;
148
149	callout_deactivate(callout);
150
151	if (c->mode == TIMER_RATEGEN) {
152		pit_timer_start_cntr0(vatpit);
153	}
154
155	vatpic_pulse_irq(vatpit->vm, 0);
156	vioapic_pulse_irq(vatpit->vm, 2);
157
158done:
159	VATPIT_UNLOCK(vatpit);
160	return;
161}
162
163static void
164pit_timer_start_cntr0(struct vatpit *vatpit)
165{
166	struct channel *c;
167	sbintime_t now, delta, precision;
168
169	c = &vatpit->channel[0];
170	if (c->initial != 0) {
171		delta = c->initial * vatpit->freq_sbt;
172		precision = delta >> tc_precexp;
173		c->callout_sbt = c->callout_sbt + delta;
174
175		/*
176		 * Reset 'callout_sbt' if the time that the callout
177		 * was supposed to fire is more than 'c->initial'
178		 * ticks in the past.
179		 */
180		now = sbinuptime();
181		if (c->callout_sbt < now)
182			c->callout_sbt = now + delta;
183
184		callout_reset_sbt(&c->callout, c->callout_sbt,
185		    precision, vatpit_callout_handler, &c->callout_arg,
186		    C_ABSOLUTE);
187	}
188}
189
190static uint16_t
191pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)
192{
193	uint16_t lval;
194	sbintime_t delta_ticks;
195
196	/* cannot latch a new value until the old one has been consumed */
197	if (latch && c->olbyte != 0)
198		return (0);
199
200	if (c->initial == 0) {
201		/*
202		 * This is possibly an o/s bug - reading the value of
203		 * the timer without having set up the initial value.
204		 *
205		 * The original user-space version of this code set
206		 * the timer to 100hz in this condition; do the same
207		 * here.
208		 */
209		c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
210		c->now_sbt = sbinuptime();
211		c->status &= ~TIMER_STS_NULLCNT;
212	}
213
214	delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;
215
216	lval = c->initial - delta_ticks % c->initial;
217
218	if (latch) {
219		c->olbyte = 2;
220		c->ol[1] = lval;		/* LSB */
221		c->ol[0] = lval >> 8;		/* MSB */
222	}
223
224	return (lval);
225}
226
227static int
228pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd)
229{
230	struct channel *c;
231
232	c = &vatpit->channel[channel];
233
234	/*
235	 * Latch the count/status of the timer if not already latched.
236	 * N.B. that the count/status latch-select bits are active-low.
237	 */
238	if (!(cmd & TIMER_RB_LCTR) && !c->olbyte) {
239		(void) pit_update_counter(vatpit, c, true);
240	}
241
242	if (!(cmd & TIMER_RB_LSTATUS) && !c->slatched) {
243		c->slatched = true;
244		/*
245		 * For mode 0, see if the elapsed time is greater
246		 * than the initial value - this results in the
247		 * output pin being set to 1 in the status byte.
248		 */
249		if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel))
250			c->status |= TIMER_STS_OUT;
251		else
252			c->status &= ~TIMER_STS_OUT;
253	}
254
255	return (0);
256}
257
258static int
259pit_readback(struct vatpit *vatpit, uint8_t cmd)
260{
261	int error;
262
263	/*
264	 * The readback command can apply to all timers.
265	 */
266	error = 0;
267	if (cmd & TIMER_RB_CTR_0)
268		error = pit_readback1(vatpit, 0, cmd);
269	if (!error && cmd & TIMER_RB_CTR_1)
270		error = pit_readback1(vatpit, 1, cmd);
271	if (!error && cmd & TIMER_RB_CTR_2)
272		error = pit_readback1(vatpit, 2, cmd);
273
274	return (error);
275}
276
277
278static int
279vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
280{
281	struct channel *c;
282	int sel, rw, mode;
283
284	sel = val & TIMER_SEL_MASK;
285	rw = val & TIMER_RW_MASK;
286	mode = val & TIMER_MODE_MASK;
287
288	if (sel == TIMER_SEL_READBACK)
289		return (pit_readback(vatpit, val));
290
291	if (rw != TIMER_LATCH && rw != TIMER_16BIT)
292		return (-1);
293
294	if (rw != TIMER_LATCH) {
295		/*
296		 * Counter mode is not affected when issuing a
297		 * latch command.
298		 */
299		if (mode != TIMER_INTTC &&
300		    mode != TIMER_RATEGEN &&
301		    mode != TIMER_SQWAVE &&
302		    mode != TIMER_SWSTROBE)
303			return (-1);
304	}
305
306	c = &vatpit->channel[sel >> 6];
307	if (rw == TIMER_LATCH)
308		pit_update_counter(vatpit, c, true);
309	else {
310		c->mode = mode;
311		c->olbyte = 0;	/* reset latch after reprogramming */
312		c->status |= TIMER_STS_NULLCNT;
313	}
314
315	return (0);
316}
317
318int
319vatpit_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
320    uint32_t *eax)
321{
322	struct vatpit *vatpit;
323	struct channel *c;
324	uint8_t val;
325	int error;
326
327	vatpit = vm_atpit(vm);
328
329	if (bytes != 1)
330		return (-1);
331
332	val = *eax;
333
334	if (port == TIMER_MODE) {
335		if (in) {
336			VM_CTR0(vatpit->vm, "vatpit attempt to read mode");
337			return (-1);
338		}
339
340		VATPIT_LOCK(vatpit);
341		error = vatpit_update_mode(vatpit, val);
342		VATPIT_UNLOCK(vatpit);
343
344		return (error);
345	}
346
347	/* counter ports */
348	KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,
349	    ("invalid port 0x%x", port));
350	c = &vatpit->channel[port - TIMER_CNTR0];
351
352	VATPIT_LOCK(vatpit);
353	if (in && c->slatched) {
354		/*
355		 * Return the status byte if latched
356		 */
357		*eax = c->status;
358		c->slatched = false;
359		c->status = 0;
360	} else if (in) {
361		/*
362		 * The spec says that once the output latch is completely
363		 * read it should revert to "following" the counter. Use
364		 * the free running counter for this case (i.e. Linux
365		 * TSC calibration). Assuming the access mode is 16-bit,
366		 * toggle the MSB/LSB bit on each read.
367		 */
368		if (c->olbyte == 0) {
369			uint16_t tmp;
370
371			tmp = pit_update_counter(vatpit, c, false);
372			if (c->frbyte)
373				tmp >>= 8;
374			tmp &= 0xff;
375			*eax = tmp;
376			c->frbyte ^= 1;
377		}  else
378			*eax = c->ol[--c->olbyte];
379	} else {
380		c->cr[c->crbyte++] = *eax;
381		if (c->crbyte == 2) {
382			c->status &= ~TIMER_STS_NULLCNT;
383			c->frbyte = 0;
384			c->crbyte = 0;
385			c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8;
386			c->now_sbt = sbinuptime();
387			/* Start an interval timer for channel 0 */
388			if (port == TIMER_CNTR0) {
389				c->callout_sbt = c->now_sbt;
390				pit_timer_start_cntr0(vatpit);
391			}
392			if (c->initial == 0)
393				c->initial = 0xffff;
394		}
395	}
396	VATPIT_UNLOCK(vatpit);
397
398	return (0);
399}
400
401int
402vatpit_nmisc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
403    uint32_t *eax)
404{
405	struct vatpit *vatpit;
406
407	vatpit = vm_atpit(vm);
408
409	if (in) {
410			VATPIT_LOCK(vatpit);
411			if (vatpit_get_out(vatpit, 2))
412				*eax = TMR2_OUT_STS;
413			else
414				*eax = 0;
415
416			VATPIT_UNLOCK(vatpit);
417	}
418
419	return (0);
420}
421
422struct vatpit *
423vatpit_init(struct vm *vm)
424{
425	struct vatpit *vatpit;
426	struct bintime bt;
427	struct vatpit_callout_arg *arg;
428	int i;
429
430	vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO);
431	vatpit->vm = vm;
432
433	mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN);
434
435	FREQ2BT(PIT_8254_FREQ, &bt);
436	vatpit->freq_sbt = bttosbt(bt);
437
438	for (i = 0; i < 3; i++) {
439		callout_init(&vatpit->channel[i].callout, true);
440		arg = &vatpit->channel[i].callout_arg;
441		arg->vatpit = vatpit;
442		arg->channel_num = i;
443	}
444
445	return (vatpit);
446}
447
448void
449vatpit_cleanup(struct vatpit *vatpit)
450{
451	int i;
452
453	for (i = 0; i < 3; i++)
454		callout_drain(&vatpit->channel[i].callout);
455
456	free(vatpit, M_VATPIT);
457}
458