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