]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/amd64/vmm/io/vatpit.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / amd64 / vmm / io / vatpit.c
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
47 static 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
72 struct vatpit_callout_arg {
73         struct vatpit   *vatpit;
74         int             channel_num;
75 };
76
77
78 struct 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
94 struct vatpit {
95         struct vm       *vm;
96         struct mtx      mtx;
97
98         sbintime_t      freq_sbt;
99
100         struct channel  channel[3];
101 };
102
103 static void pit_timer_start_cntr0(struct vatpit *vatpit);
104
105 static int
106 vatpit_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
127 static void
128 vatpit_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
158 done:
159         VATPIT_UNLOCK(vatpit);
160         return;
161 }
162
163 static void
164 pit_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
190 static uint16_t
191 pit_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
227 static int
228 pit_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
258 static int
259 pit_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
278 static int
279 vatpit_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
318 int
319 vatpit_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
401 int
402 vatpit_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
422 struct vatpit *
423 vatpit_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
448 void
449 vatpit_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 }