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