1*e883c9bbSTycho Nightingale /*- 2*e883c9bbSTycho Nightingale * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3*e883c9bbSTycho Nightingale * Copyright (c) 2011 NetApp, Inc. 4*e883c9bbSTycho Nightingale * All rights reserved. 5*e883c9bbSTycho Nightingale * 6*e883c9bbSTycho Nightingale * Redistribution and use in source and binary forms, with or without 7*e883c9bbSTycho Nightingale * modification, are permitted provided that the following conditions 8*e883c9bbSTycho Nightingale * are met: 9*e883c9bbSTycho Nightingale * 1. Redistributions of source code must retain the above copyright 10*e883c9bbSTycho Nightingale * notice, this list of conditions and the following disclaimer. 11*e883c9bbSTycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 12*e883c9bbSTycho Nightingale * notice, this list of conditions and the following disclaimer in the 13*e883c9bbSTycho Nightingale * documentation and/or other materials provided with the distribution. 14*e883c9bbSTycho Nightingale * 15*e883c9bbSTycho Nightingale * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 16*e883c9bbSTycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*e883c9bbSTycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*e883c9bbSTycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 19*e883c9bbSTycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*e883c9bbSTycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*e883c9bbSTycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*e883c9bbSTycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*e883c9bbSTycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*e883c9bbSTycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*e883c9bbSTycho Nightingale * SUCH DAMAGE. 26*e883c9bbSTycho Nightingale */ 27*e883c9bbSTycho Nightingale 28*e883c9bbSTycho Nightingale #include <sys/cdefs.h> 29*e883c9bbSTycho Nightingale __FBSDID("$FreeBSD$"); 30*e883c9bbSTycho Nightingale 31*e883c9bbSTycho Nightingale #include <sys/param.h> 32*e883c9bbSTycho Nightingale #include <sys/types.h> 33*e883c9bbSTycho Nightingale #include <sys/queue.h> 34*e883c9bbSTycho Nightingale #include <sys/cpuset.h> 35*e883c9bbSTycho Nightingale #include <sys/kernel.h> 36*e883c9bbSTycho Nightingale #include <sys/lock.h> 37*e883c9bbSTycho Nightingale #include <sys/malloc.h> 38*e883c9bbSTycho Nightingale #include <sys/mutex.h> 39*e883c9bbSTycho Nightingale #include <sys/systm.h> 40*e883c9bbSTycho Nightingale 41*e883c9bbSTycho Nightingale #include <machine/vmm.h> 42*e883c9bbSTycho Nightingale 43*e883c9bbSTycho Nightingale #include "vmm_ktr.h" 44*e883c9bbSTycho Nightingale #include "vatpic.h" 45*e883c9bbSTycho Nightingale #include "vioapic.h" 46*e883c9bbSTycho Nightingale #include "vatpit.h" 47*e883c9bbSTycho Nightingale 48*e883c9bbSTycho Nightingale static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)"); 49*e883c9bbSTycho Nightingale 50*e883c9bbSTycho Nightingale #define VATPIT_LOCK(vatpit) mtx_lock_spin(&((vatpit)->mtx)) 51*e883c9bbSTycho Nightingale #define VATPIT_UNLOCK(vatpit) mtx_unlock_spin(&((vatpit)->mtx)) 52*e883c9bbSTycho Nightingale #define VATPIT_LOCKED(vatpit) mtx_owned(&((vatpit)->mtx)) 53*e883c9bbSTycho Nightingale 54*e883c9bbSTycho Nightingale #define TIMER_SEL_MASK 0xc0 55*e883c9bbSTycho Nightingale #define TIMER_RW_MASK 0x30 56*e883c9bbSTycho Nightingale #define TIMER_MODE_MASK 0x0f 57*e883c9bbSTycho Nightingale #define TIMER_SEL_READBACK 0xc0 58*e883c9bbSTycho Nightingale 59*e883c9bbSTycho Nightingale #define PIT_8254_FREQ 1193182 60*e883c9bbSTycho Nightingale #define TIMER_DIV(freq, hz) (((freq) + (hz) / 2) / (hz)) 61*e883c9bbSTycho Nightingale 62*e883c9bbSTycho Nightingale struct vatpit_callout_arg { 63*e883c9bbSTycho Nightingale struct vatpit *vatpit; 64*e883c9bbSTycho Nightingale int channel_num; 65*e883c9bbSTycho Nightingale }; 66*e883c9bbSTycho Nightingale 67*e883c9bbSTycho Nightingale 68*e883c9bbSTycho Nightingale struct channel { 69*e883c9bbSTycho Nightingale int mode; 70*e883c9bbSTycho Nightingale uint16_t initial; /* initial counter value */ 71*e883c9bbSTycho Nightingale sbintime_t now_sbt; /* uptime when counter was loaded */ 72*e883c9bbSTycho Nightingale uint8_t cr[2]; 73*e883c9bbSTycho Nightingale uint8_t ol[2]; 74*e883c9bbSTycho Nightingale int crbyte; 75*e883c9bbSTycho Nightingale int olbyte; 76*e883c9bbSTycho Nightingale int frbyte; 77*e883c9bbSTycho Nightingale struct callout callout; 78*e883c9bbSTycho Nightingale sbintime_t callout_sbt; /* target time */ 79*e883c9bbSTycho Nightingale struct vatpit_callout_arg callout_arg; 80*e883c9bbSTycho Nightingale }; 81*e883c9bbSTycho Nightingale 82*e883c9bbSTycho Nightingale struct vatpit { 83*e883c9bbSTycho Nightingale struct vm *vm; 84*e883c9bbSTycho Nightingale struct mtx mtx; 85*e883c9bbSTycho Nightingale 86*e883c9bbSTycho Nightingale sbintime_t freq_sbt; 87*e883c9bbSTycho Nightingale 88*e883c9bbSTycho Nightingale struct channel channel[3]; 89*e883c9bbSTycho Nightingale }; 90*e883c9bbSTycho Nightingale 91*e883c9bbSTycho Nightingale #define VATPIT_CTR0(vatpit, fmt) \ 92*e883c9bbSTycho Nightingale VM_CTR0((vatpit)->vm, fmt) 93*e883c9bbSTycho Nightingale 94*e883c9bbSTycho Nightingale #define VATPIT_CTR1(vatpit, fmt, a1) \ 95*e883c9bbSTycho Nightingale VM_CTR1((vatpit)->vm, fmt, a1) 96*e883c9bbSTycho Nightingale 97*e883c9bbSTycho Nightingale #define VATPIT_CTR2(vatpit, fmt, a1, a2) \ 98*e883c9bbSTycho Nightingale VM_CTR2((vatpit)->vm, fmt, a1, a2) 99*e883c9bbSTycho Nightingale 100*e883c9bbSTycho Nightingale #define VATPIT_CTR3(vatpit, fmt, a1, a2, a3) \ 101*e883c9bbSTycho Nightingale VM_CTR3((vatpit)->vm, fmt, a1, a2, a3) 102*e883c9bbSTycho Nightingale 103*e883c9bbSTycho Nightingale #define VATPIT_CTR4(vatpit, fmt, a1, a2, a3, a4) \ 104*e883c9bbSTycho Nightingale VM_CTR4((vatpit)->vm, fmt, a1, a2, a3, a4) 105*e883c9bbSTycho Nightingale 106*e883c9bbSTycho Nightingale static void pit_timer_start_cntr0(struct vatpit *vatpit); 107*e883c9bbSTycho Nightingale 108*e883c9bbSTycho Nightingale static void 109*e883c9bbSTycho Nightingale vatpit_callout_handler(void *a) 110*e883c9bbSTycho Nightingale { 111*e883c9bbSTycho Nightingale struct vatpit_callout_arg *arg = a; 112*e883c9bbSTycho Nightingale struct vatpit *vatpit; 113*e883c9bbSTycho Nightingale struct callout *callout; 114*e883c9bbSTycho Nightingale struct channel *c; 115*e883c9bbSTycho Nightingale 116*e883c9bbSTycho Nightingale vatpit = arg->vatpit; 117*e883c9bbSTycho Nightingale c = &vatpit->channel[arg->channel_num]; 118*e883c9bbSTycho Nightingale callout = &c->callout; 119*e883c9bbSTycho Nightingale 120*e883c9bbSTycho Nightingale VATPIT_CTR1(vatpit, "atpit t%d fired", arg->channel_num); 121*e883c9bbSTycho Nightingale 122*e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 123*e883c9bbSTycho Nightingale 124*e883c9bbSTycho Nightingale if (callout_pending(callout)) /* callout was reset */ 125*e883c9bbSTycho Nightingale goto done; 126*e883c9bbSTycho Nightingale 127*e883c9bbSTycho Nightingale if (!callout_active(callout)) /* callout was stopped */ 128*e883c9bbSTycho Nightingale goto done; 129*e883c9bbSTycho Nightingale 130*e883c9bbSTycho Nightingale callout_deactivate(callout); 131*e883c9bbSTycho Nightingale 132*e883c9bbSTycho Nightingale if (c->mode == TIMER_RATEGEN) { 133*e883c9bbSTycho Nightingale pit_timer_start_cntr0(vatpit); 134*e883c9bbSTycho Nightingale } 135*e883c9bbSTycho Nightingale 136*e883c9bbSTycho Nightingale vatpic_pulse_irq(vatpit->vm, 0); 137*e883c9bbSTycho Nightingale vioapic_pulse_irq(vatpit->vm, 2); 138*e883c9bbSTycho Nightingale 139*e883c9bbSTycho Nightingale done: 140*e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 141*e883c9bbSTycho Nightingale return; 142*e883c9bbSTycho Nightingale } 143*e883c9bbSTycho Nightingale 144*e883c9bbSTycho Nightingale static void 145*e883c9bbSTycho Nightingale pit_timer_start_cntr0(struct vatpit *vatpit) 146*e883c9bbSTycho Nightingale { 147*e883c9bbSTycho Nightingale struct channel *c; 148*e883c9bbSTycho Nightingale sbintime_t delta, precision; 149*e883c9bbSTycho Nightingale 150*e883c9bbSTycho Nightingale c = &vatpit->channel[0]; 151*e883c9bbSTycho Nightingale if (c->initial != 0) { 152*e883c9bbSTycho Nightingale delta = c->initial * vatpit->freq_sbt; 153*e883c9bbSTycho Nightingale precision = delta >> tc_precexp; 154*e883c9bbSTycho Nightingale c->callout_sbt = c->callout_sbt + delta; 155*e883c9bbSTycho Nightingale 156*e883c9bbSTycho Nightingale callout_reset_sbt(&c->callout, c->callout_sbt, 157*e883c9bbSTycho Nightingale precision, vatpit_callout_handler, &c->callout_arg, 158*e883c9bbSTycho Nightingale C_ABSOLUTE); 159*e883c9bbSTycho Nightingale } 160*e883c9bbSTycho Nightingale } 161*e883c9bbSTycho Nightingale 162*e883c9bbSTycho Nightingale static uint16_t 163*e883c9bbSTycho Nightingale pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch) 164*e883c9bbSTycho Nightingale { 165*e883c9bbSTycho Nightingale uint16_t lval; 166*e883c9bbSTycho Nightingale sbintime_t delta_ticks; 167*e883c9bbSTycho Nightingale 168*e883c9bbSTycho Nightingale /* cannot latch a new value until the old one has been consumed */ 169*e883c9bbSTycho Nightingale if (latch && c->olbyte != 0) 170*e883c9bbSTycho Nightingale return (0); 171*e883c9bbSTycho Nightingale 172*e883c9bbSTycho Nightingale if (c->initial == 0) { 173*e883c9bbSTycho Nightingale /* 174*e883c9bbSTycho Nightingale * This is possibly an o/s bug - reading the value of 175*e883c9bbSTycho Nightingale * the timer without having set up the initial value. 176*e883c9bbSTycho Nightingale * 177*e883c9bbSTycho Nightingale * The original user-space version of this code set 178*e883c9bbSTycho Nightingale * the timer to 100hz in this condition; do the same 179*e883c9bbSTycho Nightingale * here. 180*e883c9bbSTycho Nightingale */ 181*e883c9bbSTycho Nightingale c->initial = TIMER_DIV(PIT_8254_FREQ, 100); 182*e883c9bbSTycho Nightingale c->now_sbt = sbinuptime(); 183*e883c9bbSTycho Nightingale } 184*e883c9bbSTycho Nightingale 185*e883c9bbSTycho Nightingale delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt; 186*e883c9bbSTycho Nightingale 187*e883c9bbSTycho Nightingale lval = c->initial - delta_ticks % c->initial; 188*e883c9bbSTycho Nightingale 189*e883c9bbSTycho Nightingale if (latch) { 190*e883c9bbSTycho Nightingale c->olbyte = 2; 191*e883c9bbSTycho Nightingale c->ol[1] = lval; /* LSB */ 192*e883c9bbSTycho Nightingale c->ol[0] = lval >> 8; /* MSB */ 193*e883c9bbSTycho Nightingale } 194*e883c9bbSTycho Nightingale 195*e883c9bbSTycho Nightingale return (lval); 196*e883c9bbSTycho Nightingale } 197*e883c9bbSTycho Nightingale 198*e883c9bbSTycho Nightingale static int 199*e883c9bbSTycho Nightingale vatpit_update_mode(struct vatpit *vatpit, uint8_t val) 200*e883c9bbSTycho Nightingale { 201*e883c9bbSTycho Nightingale struct channel *c; 202*e883c9bbSTycho Nightingale int sel, rw, mode; 203*e883c9bbSTycho Nightingale 204*e883c9bbSTycho Nightingale sel = val & TIMER_SEL_MASK; 205*e883c9bbSTycho Nightingale rw = val & TIMER_RW_MASK; 206*e883c9bbSTycho Nightingale mode = val & TIMER_MODE_MASK; 207*e883c9bbSTycho Nightingale 208*e883c9bbSTycho Nightingale if (sel == TIMER_SEL_READBACK) 209*e883c9bbSTycho Nightingale return (-1); 210*e883c9bbSTycho Nightingale 211*e883c9bbSTycho Nightingale if (rw != TIMER_LATCH && rw != TIMER_16BIT) 212*e883c9bbSTycho Nightingale return (-1); 213*e883c9bbSTycho Nightingale 214*e883c9bbSTycho Nightingale if (rw != TIMER_LATCH) { 215*e883c9bbSTycho Nightingale /* 216*e883c9bbSTycho Nightingale * Counter mode is not affected when issuing a 217*e883c9bbSTycho Nightingale * latch command. 218*e883c9bbSTycho Nightingale */ 219*e883c9bbSTycho Nightingale if (mode != TIMER_INTTC && 220*e883c9bbSTycho Nightingale mode != TIMER_RATEGEN && 221*e883c9bbSTycho Nightingale mode != TIMER_SQWAVE && 222*e883c9bbSTycho Nightingale mode != TIMER_SWSTROBE) 223*e883c9bbSTycho Nightingale return (-1); 224*e883c9bbSTycho Nightingale } 225*e883c9bbSTycho Nightingale 226*e883c9bbSTycho Nightingale c = &vatpit->channel[sel >> 6]; 227*e883c9bbSTycho Nightingale if (rw == TIMER_LATCH) 228*e883c9bbSTycho Nightingale pit_update_counter(vatpit, c, true); 229*e883c9bbSTycho Nightingale else { 230*e883c9bbSTycho Nightingale c->mode = mode; 231*e883c9bbSTycho Nightingale c->olbyte = 0; /* reset latch after reprogramming */ 232*e883c9bbSTycho Nightingale } 233*e883c9bbSTycho Nightingale 234*e883c9bbSTycho Nightingale return (0); 235*e883c9bbSTycho Nightingale } 236*e883c9bbSTycho Nightingale 237*e883c9bbSTycho Nightingale static int 238*e883c9bbSTycho Nightingale vatpit_get_out(struct vatpit *vatpit, int channel) 239*e883c9bbSTycho Nightingale { 240*e883c9bbSTycho Nightingale struct channel *c; 241*e883c9bbSTycho Nightingale sbintime_t delta_ticks; 242*e883c9bbSTycho Nightingale int out; 243*e883c9bbSTycho Nightingale 244*e883c9bbSTycho Nightingale c = &vatpit->channel[channel]; 245*e883c9bbSTycho Nightingale 246*e883c9bbSTycho Nightingale switch (c->mode) { 247*e883c9bbSTycho Nightingale case TIMER_INTTC: 248*e883c9bbSTycho Nightingale delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt; 249*e883c9bbSTycho Nightingale out = ((c->initial - delta_ticks) <= 0); 250*e883c9bbSTycho Nightingale break; 251*e883c9bbSTycho Nightingale default: 252*e883c9bbSTycho Nightingale out = 0; 253*e883c9bbSTycho Nightingale break; 254*e883c9bbSTycho Nightingale } 255*e883c9bbSTycho Nightingale 256*e883c9bbSTycho Nightingale return (out); 257*e883c9bbSTycho Nightingale } 258*e883c9bbSTycho Nightingale 259*e883c9bbSTycho Nightingale int 260*e883c9bbSTycho Nightingale vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit) 261*e883c9bbSTycho Nightingale { 262*e883c9bbSTycho Nightingale struct vatpit *vatpit; 263*e883c9bbSTycho Nightingale struct channel *c; 264*e883c9bbSTycho Nightingale int port; 265*e883c9bbSTycho Nightingale uint8_t val; 266*e883c9bbSTycho Nightingale int error; 267*e883c9bbSTycho Nightingale 268*e883c9bbSTycho Nightingale vatpit = vm_atpit(vm); 269*e883c9bbSTycho Nightingale 270*e883c9bbSTycho Nightingale if (vmexit->u.inout.bytes != 1) 271*e883c9bbSTycho Nightingale return (-1); 272*e883c9bbSTycho Nightingale 273*e883c9bbSTycho Nightingale val = vmexit->u.inout.eax; 274*e883c9bbSTycho Nightingale port = vmexit->u.inout.port; 275*e883c9bbSTycho Nightingale 276*e883c9bbSTycho Nightingale if (port == TIMER_MODE) { 277*e883c9bbSTycho Nightingale if (vmexit->u.inout.in != 0) { 278*e883c9bbSTycho Nightingale VATPIT_CTR0(vatpit, "vatpit attempt to read mode"); 279*e883c9bbSTycho Nightingale return (-1); 280*e883c9bbSTycho Nightingale } 281*e883c9bbSTycho Nightingale 282*e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 283*e883c9bbSTycho Nightingale error = vatpit_update_mode(vatpit, val); 284*e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 285*e883c9bbSTycho Nightingale 286*e883c9bbSTycho Nightingale return (error); 287*e883c9bbSTycho Nightingale } 288*e883c9bbSTycho Nightingale 289*e883c9bbSTycho Nightingale /* counter ports */ 290*e883c9bbSTycho Nightingale KASSERT(port >= TIMER_CNTR0 && vmexit->u.inout.port <= TIMER_CNTR2, 291*e883c9bbSTycho Nightingale ("invalid port 0x%x", port)); 292*e883c9bbSTycho Nightingale c = &vatpit->channel[port - TIMER_CNTR0]; 293*e883c9bbSTycho Nightingale 294*e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 295*e883c9bbSTycho Nightingale if (vmexit->u.inout.in) { 296*e883c9bbSTycho Nightingale /* 297*e883c9bbSTycho Nightingale * The spec says that once the output latch is completely 298*e883c9bbSTycho Nightingale * read it should revert to "following" the counter. Use 299*e883c9bbSTycho Nightingale * the free running counter for this case (i.e. Linux 300*e883c9bbSTycho Nightingale * TSC calibration). Assuming the access mode is 16-bit, 301*e883c9bbSTycho Nightingale * toggle the MSB/LSB bit on each read. 302*e883c9bbSTycho Nightingale */ 303*e883c9bbSTycho Nightingale if (c->olbyte == 0) { 304*e883c9bbSTycho Nightingale uint16_t tmp; 305*e883c9bbSTycho Nightingale 306*e883c9bbSTycho Nightingale tmp = pit_update_counter(vatpit, c, false); 307*e883c9bbSTycho Nightingale if (c->frbyte) 308*e883c9bbSTycho Nightingale tmp >>= 8; 309*e883c9bbSTycho Nightingale tmp &= 0xff; 310*e883c9bbSTycho Nightingale vmexit->u.inout.eax = tmp; 311*e883c9bbSTycho Nightingale c->frbyte ^= 1; 312*e883c9bbSTycho Nightingale } else 313*e883c9bbSTycho Nightingale vmexit->u.inout.eax = c->ol[--c->olbyte]; 314*e883c9bbSTycho Nightingale } else { 315*e883c9bbSTycho Nightingale c->cr[c->crbyte++] = vmexit->u.inout.eax; 316*e883c9bbSTycho Nightingale if (c->crbyte == 2) { 317*e883c9bbSTycho Nightingale c->frbyte = 0; 318*e883c9bbSTycho Nightingale c->crbyte = 0; 319*e883c9bbSTycho Nightingale c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8; 320*e883c9bbSTycho Nightingale c->now_sbt = sbinuptime(); 321*e883c9bbSTycho Nightingale /* Start an interval timer for channel 0 */ 322*e883c9bbSTycho Nightingale if (port == TIMER_CNTR0) { 323*e883c9bbSTycho Nightingale c->callout_sbt = c->now_sbt; 324*e883c9bbSTycho Nightingale pit_timer_start_cntr0(vatpit); 325*e883c9bbSTycho Nightingale } 326*e883c9bbSTycho Nightingale if (c->initial == 0) 327*e883c9bbSTycho Nightingale c->initial = 0xffff; 328*e883c9bbSTycho Nightingale } 329*e883c9bbSTycho Nightingale } 330*e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 331*e883c9bbSTycho Nightingale 332*e883c9bbSTycho Nightingale return (0); 333*e883c9bbSTycho Nightingale } 334*e883c9bbSTycho Nightingale 335*e883c9bbSTycho Nightingale struct vatpit * 336*e883c9bbSTycho Nightingale vatpit_init(struct vm *vm) 337*e883c9bbSTycho Nightingale { 338*e883c9bbSTycho Nightingale struct vatpit *vatpit; 339*e883c9bbSTycho Nightingale struct bintime bt; 340*e883c9bbSTycho Nightingale struct vatpit_callout_arg *arg; 341*e883c9bbSTycho Nightingale int i; 342*e883c9bbSTycho Nightingale 343*e883c9bbSTycho Nightingale vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO); 344*e883c9bbSTycho Nightingale vatpit->vm = vm; 345*e883c9bbSTycho Nightingale 346*e883c9bbSTycho Nightingale mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN); 347*e883c9bbSTycho Nightingale 348*e883c9bbSTycho Nightingale FREQ2BT(PIT_8254_FREQ, &bt); 349*e883c9bbSTycho Nightingale vatpit->freq_sbt = bttosbt(bt); 350*e883c9bbSTycho Nightingale 351*e883c9bbSTycho Nightingale for (i = 0; i < 3; i++) { 352*e883c9bbSTycho Nightingale callout_init(&vatpit->channel[i].callout, true); 353*e883c9bbSTycho Nightingale arg = &vatpit->channel[i].callout_arg; 354*e883c9bbSTycho Nightingale arg->vatpit = vatpit; 355*e883c9bbSTycho Nightingale arg->channel_num = i; 356*e883c9bbSTycho Nightingale } 357*e883c9bbSTycho Nightingale 358*e883c9bbSTycho Nightingale return (vatpit); 359*e883c9bbSTycho Nightingale } 360*e883c9bbSTycho Nightingale 361*e883c9bbSTycho Nightingale void 362*e883c9bbSTycho Nightingale vatpit_cleanup(struct vatpit *vatpit) 363*e883c9bbSTycho Nightingale { 364*e883c9bbSTycho Nightingale int i; 365*e883c9bbSTycho Nightingale 366*e883c9bbSTycho Nightingale for (i = 0; i < 3; i++) 367*e883c9bbSTycho Nightingale callout_drain(&vatpit->channel[i].callout); 368*e883c9bbSTycho Nightingale 369*e883c9bbSTycho Nightingale free(vatpit, M_VATPIT); 370*e883c9bbSTycho Nightingale } 371