Lines Matching +full:interrupt +full:- +full:counter

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
79 uint64_t isr; /* Interrupt Status */
80 uint32_t countbase; /* HPET counter base value */
85 uint64_t msireg; /* FSB interrupt routing */
89 sbintime_t callout_sbt; /* time when counter==compval */
94 #define VHPET_LOCK(vhp) mtx_lock(&((vhp)->mtx))
95 #define VHPET_UNLOCK(vhp) mtx_unlock(&((vhp)->mtx))
97 static void vhpet_start_timer(struct vhpet *vhpet, int n, uint32_t counter,
106 cap |= (VHPET_NUM_TIMERS - 1) << 8; /* number of timers */ in vhpet_capabilities()
108 cap &= ~HPET_CAP_COUNT_SIZE; /* 32-bit timer */ in vhpet_capabilities()
120 return ((vhpet->config & HPET_CNF_ENABLE) ? true : false); in vhpet_counter_enabled()
128 if ((vhpet->timer[n].cap_config & msi_enable) == msi_enable) in vhpet_timer_msi_enabled()
144 return ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ROUTE) >> 9); in vhpet_timer_ioapic_pin()
153 val = vhpet->countbase; in vhpet_counter()
156 delta = now - vhpet->countbase_sbt; in vhpet_counter()
158 "%#lx to %#lx", vhpet->countbase_sbt, now)); in vhpet_counter()
159 val += delta / vhpet->freq_sbt; in vhpet_counter()
165 * meaningless when the counter is disabled. Make sure in vhpet_counter()
178 if (vhpet->isr & (1 << n)) { in vhpet_timer_clear_isr()
181 vioapic_deassert_irq(vhpet->vm, pin); in vhpet_timer_clear_isr()
182 vhpet->isr &= ~(1 << n); in vhpet_timer_clear_isr()
190 return ((vhpet->timer[n].cap_config & HPET_TCNF_TYPE) != 0); in vhpet_periodic_timer()
197 return ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ENB) != 0); in vhpet_timer_interrupt_enabled()
207 if ((vhpet->timer[n].cap_config & HPET_TCNF_INT_TYPE) == 0) in vhpet_timer_edge_trig()
223 * If a level triggered interrupt is already asserted then just return. in vhpet_timer_interrupt()
225 if ((vhpet->isr & (1 << n)) != 0) { in vhpet_timer_interrupt()
226 VM_CTR1(vhpet->vm, "hpet t%d intr is already asserted", n); in vhpet_timer_interrupt()
231 lapic_intr_msi(vhpet->vm, vhpet->timer[n].msireg >> 32, in vhpet_timer_interrupt()
232 vhpet->timer[n].msireg & 0xffffffff); in vhpet_timer_interrupt()
238 VM_CTR1(vhpet->vm, "hpet t%d intr is not routed to ioapic", n); in vhpet_timer_interrupt()
243 vioapic_pulse_irq(vhpet->vm, pin); in vhpet_timer_interrupt()
245 vhpet->isr |= 1 << n; in vhpet_timer_interrupt()
246 vioapic_assert_irq(vhpet->vm, pin); in vhpet_timer_interrupt()
251 vhpet_adjust_compval(struct vhpet *vhpet, int n, uint32_t counter) in vhpet_adjust_compval() argument
255 KASSERT(vhpet->timer[n].comprate != 0, ("hpet t%d is not periodic", n)); in vhpet_adjust_compval()
257 compval = vhpet->timer[n].compval; in vhpet_adjust_compval()
258 comprate = vhpet->timer[n].comprate; in vhpet_adjust_compval()
262 * interrupt. in vhpet_adjust_compval()
265 * In this scenario the 'counter' is ahead of 'compval'. To find in vhpet_adjust_compval()
267 * number space between 'compval' and 'counter' into 'comprate' in vhpet_adjust_compval()
269 * of 'counter'. in vhpet_adjust_compval()
271 compnext = compval + ((counter - compval) / comprate + 1) * comprate; in vhpet_adjust_compval()
273 vhpet->timer[n].compval = compnext; in vhpet_adjust_compval()
280 uint32_t counter; in vhpet_handler() local
287 vhpet = arg->vhpet; in vhpet_handler()
288 n = arg->timer_num; in vhpet_handler()
289 callout = &vhpet->timer[n].callout; in vhpet_handler()
291 VM_CTR1(vhpet->vm, "hpet t%d fired", n); in vhpet_handler()
304 panic("vhpet(%p) callout with counter disabled", vhpet); in vhpet_handler()
306 counter = vhpet_counter(vhpet, &now); in vhpet_handler()
307 vhpet_start_timer(vhpet, n, counter, now); in vhpet_handler()
318 VM_CTR1(vhpet->vm, "hpet t%d stopped", n); in vhpet_stop_timer()
319 callout_stop(&vhpet->timer[n].callout); in vhpet_stop_timer()
323 * had a chance to execute yet then trigger the timer interrupt in vhpet_stop_timer()
324 * here. Failing to do so will result in a missed timer interrupt in vhpet_stop_timer()
325 * in the guest. This is especially bad in one-shot mode because in vhpet_stop_timer()
326 * the next interrupt has to wait for the counter to wrap around. in vhpet_stop_timer()
328 if (vhpet->timer[n].callout_sbt < now) { in vhpet_stop_timer()
329 VM_CTR1(vhpet->vm, "hpet t%d interrupt triggered after " in vhpet_stop_timer()
336 vhpet_start_timer(struct vhpet *vhpet, int n, uint32_t counter, sbintime_t now) in vhpet_start_timer() argument
340 if (vhpet->timer[n].comprate != 0) in vhpet_start_timer()
341 vhpet_adjust_compval(vhpet, n, counter); in vhpet_start_timer()
344 * In one-shot mode it is the guest's responsibility to make in vhpet_start_timer()
346 * hardware doesn't have any belt-and-suspenders to deal with in vhpet_start_timer()
351 delta = (vhpet->timer[n].compval - counter) * vhpet->freq_sbt; in vhpet_start_timer()
353 vhpet->timer[n].callout_sbt = now + delta; in vhpet_start_timer()
354 callout_reset_sbt(&vhpet->timer[n].callout, vhpet->timer[n].callout_sbt, in vhpet_start_timer()
355 precision, vhpet_handler, &vhpet->timer[n].arg, C_ABSOLUTE); in vhpet_start_timer()
363 vhpet->countbase_sbt = sbinuptime(); in vhpet_start_counting()
366 * Restart the timers based on the value of the main counter in vhpet_start_counting()
369 vhpet_start_timer(vhpet, i, vhpet->countbase, in vhpet_start_counting()
370 vhpet->countbase_sbt); in vhpet_start_counting()
375 vhpet_stop_counting(struct vhpet *vhpet, uint32_t counter, sbintime_t now) in vhpet_stop_counting() argument
379 vhpet->countbase = counter; in vhpet_stop_counting()
403 if (vhpet->isr & (1 << n)) in vhpet_timer_update_config()
407 oldval = vhpet->timer[n].cap_config; in vhpet_timer_update_config()
417 vhpet->timer[n].cap_config = newval; in vhpet_timer_update_config()
418 VM_CTR2(vhpet->vm, "hpet t%d cap_config set to 0x%016x", n, newval); in vhpet_timer_update_config()
421 * Validate the interrupt routing in the HPET_TCNF_INT_ROUTE field. in vhpet_timer_update_config()
425 allowed_irqs = vhpet->timer[n].cap_config >> 32; in vhpet_timer_update_config()
428 VM_CTR3(vhpet->vm, "hpet t%d configured invalid irq %d, " in vhpet_timer_update_config()
431 vhpet->timer[n].cap_config &= ~HPET_TCNF_INT_ROUTE; in vhpet_timer_update_config()
435 vhpet->timer[n].comprate = 0; in vhpet_timer_update_config()
439 * - interrupt is disabled in vhpet_timer_update_config()
440 * - interrupt type is changed from level to edge or fsb. in vhpet_timer_update_config()
441 * - interrupt routing is changed in vhpet_timer_update_config()
443 * This is to ensure that this timer's level triggered interrupt does in vhpet_timer_update_config()
446 if (vhpet->isr & (1 << n)) { in vhpet_timer_update_config()
461 VM_CTR1(vhpet->vm, "hpet t%d isr cleared due to " in vhpet_timer_update_config()
463 vioapic_deassert_irq(vhpet->vm, old_pin); in vhpet_timer_update_config()
464 vhpet->isr &= ~(1 << n); in vhpet_timer_update_config()
475 uint32_t isr_clear_mask, old_compval, old_comprate, counter; in vhpet_mmio_write() local
480 offset = gpa - VHPET_BASE; in vhpet_mmio_write()
499 VM_CTR2(vhpet->vm, "hpet invalid mmio write: " in vhpet_mmio_write()
505 if (offset & (size - 1)) { in vhpet_mmio_write()
506 VM_CTR2(vhpet->vm, "hpet invalid mmio write: " in vhpet_mmio_write()
513 * Get the most recent value of the counter before updating in vhpet_mmio_write()
519 counter = vhpet_counter(vhpet, nowptr); in vhpet_mmio_write()
520 oldval = vhpet->config; in vhpet_mmio_write()
521 update_register(&vhpet->config, data, mask); in vhpet_mmio_write()
527 vhpet->config &= ~HPET_CNF_LEG_RT; in vhpet_mmio_write()
529 if ((oldval ^ vhpet->config) & HPET_CNF_ENABLE) { in vhpet_mmio_write()
532 VM_CTR0(vhpet->vm, "hpet enabled"); in vhpet_mmio_write()
534 vhpet_stop_counting(vhpet, counter, now); in vhpet_mmio_write()
535 VM_CTR0(vhpet->vm, "hpet disabled"); in vhpet_mmio_write()
542 isr_clear_mask = vhpet->isr & data; in vhpet_mmio_write()
545 VM_CTR1(vhpet->vm, "hpet t%d isr cleared", i); in vhpet_mmio_write()
553 /* Zero-extend the counter to 64-bits before updating it */ in vhpet_mmio_write()
556 vhpet->countbase = val64; in vhpet_mmio_write()
571 old_compval = vhpet->timer[i].compval; in vhpet_mmio_write()
572 old_comprate = vhpet->timer[i].comprate; in vhpet_mmio_write()
580 val64 = vhpet->timer[i].comprate; in vhpet_mmio_write()
582 vhpet->timer[i].comprate = val64; in vhpet_mmio_write()
583 if ((vhpet->timer[i].cap_config & in vhpet_mmio_write()
585 vhpet->timer[i].compval = val64; in vhpet_mmio_write()
588 KASSERT(vhpet->timer[i].comprate == 0, in vhpet_mmio_write()
589 ("vhpet one-shot timer %d has invalid " in vhpet_mmio_write()
590 "rate %u", i, vhpet->timer[i].comprate)); in vhpet_mmio_write()
591 val64 = vhpet->timer[i].compval; in vhpet_mmio_write()
593 vhpet->timer[i].compval = val64; in vhpet_mmio_write()
595 vhpet->timer[i].cap_config &= ~HPET_TCNF_VAL_SET; in vhpet_mmio_write()
597 if (vhpet->timer[i].compval != old_compval || in vhpet_mmio_write()
598 vhpet->timer[i].comprate != old_comprate) { in vhpet_mmio_write()
600 counter = vhpet_counter(vhpet, &now); in vhpet_mmio_write()
601 vhpet_start_timer(vhpet, i, counter, in vhpet_mmio_write()
610 update_register(&vhpet->timer[i].msireg, data, mask); in vhpet_mmio_write()
628 offset = gpa - VHPET_BASE; in vhpet_mmio_read()
634 VM_CTR2(vhpet->vm, "hpet invalid mmio read: " in vhpet_mmio_read()
641 if (offset & (size - 1)) { in vhpet_mmio_read()
642 VM_CTR2(vhpet->vm, "hpet invalid mmio read: " in vhpet_mmio_read()
654 data = vhpet->config; in vhpet_mmio_read()
659 data = vhpet->isr; in vhpet_mmio_read()
671 data = vhpet->timer[i].cap_config; in vhpet_mmio_read()
677 data = vhpet->timer[i].compval; in vhpet_mmio_read()
683 data = vhpet->timer[i].msireg; in vhpet_mmio_read()
711 vhpet->vm = vm; in vhpet_init()
712 mtx_init(&vhpet->mtx, "vhpet lock", NULL, MTX_DEF); in vhpet_init()
715 vhpet->freq_sbt = bttosbt(bt); in vhpet_init()
719 allowed_irqs = 0xff000000; /* irqs 24-31 */ in vhpet_init()
721 allowed_irqs = 0xf << (pincount - 4); /* 4 upper irqs */ in vhpet_init()
729 vhpet->timer[i].cap_config = allowed_irqs << 32; in vhpet_init()
730 vhpet->timer[i].cap_config |= HPET_TCAP_PER_INT; in vhpet_init()
731 vhpet->timer[i].cap_config |= HPET_TCAP_FSB_INT_DEL; in vhpet_init()
733 vhpet->timer[i].compval = 0xffffffff; in vhpet_init()
734 callout_init(&vhpet->timer[i].callout, 1); in vhpet_init()
736 arg = &vhpet->timer[i].arg; in vhpet_init()
737 arg->vhpet = vhpet; in vhpet_init()
738 arg->timer_num = i; in vhpet_init()
750 callout_drain(&vhpet->timer[i].callout); in vhpet_cleanup()
752 mtx_destroy(&vhpet->mtx); in vhpet_cleanup()
760 cap->capabilities = vhpet_capabilities(); in vhpet_getcap()
771 SNAPSHOT_VAR_OR_LEAVE(vhpet->freq_sbt, meta, ret, done); in vhpet_snapshot()
772 SNAPSHOT_VAR_OR_LEAVE(vhpet->config, meta, ret, done); in vhpet_snapshot()
773 SNAPSHOT_VAR_OR_LEAVE(vhpet->isr, meta, ret, done); in vhpet_snapshot()
777 * vhpet->countbase, but rather computed relative to the current system in vhpet_snapshot()
780 if (meta->op == VM_SNAPSHOT_SAVE) in vhpet_snapshot()
783 if (meta->op == VM_SNAPSHOT_RESTORE) in vhpet_snapshot()
784 vhpet->countbase = countbase; in vhpet_snapshot()
786 for (i = 0; i < nitems(vhpet->timer); i++) { in vhpet_snapshot()
787 SNAPSHOT_VAR_OR_LEAVE(vhpet->timer[i].cap_config, in vhpet_snapshot()
789 SNAPSHOT_VAR_OR_LEAVE(vhpet->timer[i].msireg, meta, ret, done); in vhpet_snapshot()
790 SNAPSHOT_VAR_OR_LEAVE(vhpet->timer[i].compval, meta, ret, done); in vhpet_snapshot()
791 SNAPSHOT_VAR_OR_LEAVE(vhpet->timer[i].comprate, meta, ret, done); in vhpet_snapshot()
792 SNAPSHOT_VAR_OR_LEAVE(vhpet->timer[i].callout_sbt, in vhpet_snapshot()