summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm/io
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/vmm/io')
-rw-r--r--sys/amd64/vmm/io/vlapic.c113
-rw-r--r--sys/amd64/vmm/io/vlapic.h2
2 files changed, 62 insertions, 53 deletions
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index 1e8a4e8..911ed64 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -121,6 +121,31 @@ struct vlapic {
enum boot_state boot_state;
};
+#define VLAPIC_BUS_FREQ tsc_freq
+
+static int
+vlapic_timer_divisor(uint32_t dcr)
+{
+ switch (dcr & 0xB) {
+ case APIC_TDCR_2:
+ return (2);
+ case APIC_TDCR_4:
+ return (4);
+ case APIC_TDCR_8:
+ return (8);
+ case APIC_TDCR_16:
+ return (16);
+ case APIC_TDCR_32:
+ return (32);
+ case APIC_TDCR_64:
+ return (64);
+ case APIC_TDCR_128:
+ return (128);
+ default:
+ panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr);
+ }
+}
+
static void
vlapic_mask_lvts(uint32_t *lvts, int num_lvt)
{
@@ -175,6 +200,7 @@ vlapic_op_reset(void* dev)
memset(lapic, 0, sizeof(*lapic));
lapic->apr = vlapic->vcpuid;
vlapic_init_ipi(vlapic);
+ vlapic->divisor = vlapic_timer_divisor(lapic->dcr_timer);
if (vlapic->vcpuid == 0)
vlapic->boot_state = BS_RUNNING; /* BSP */
@@ -218,32 +244,6 @@ vlapic_set_intr_ready(struct vlapic *vlapic, int vector)
VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready");
}
-#define VLAPIC_BUS_FREQ tsc_freq
-#define VLAPIC_DCR(x) ((x->dcr_timer & 0x8) >> 1)|(x->dcr_timer & 0x3)
-
-static int
-vlapic_timer_divisor(uint32_t dcr)
-{
- switch (dcr & 0xB) {
- case APIC_TDCR_2:
- return (2);
- case APIC_TDCR_4:
- return (4);
- case APIC_TDCR_8:
- return (8);
- case APIC_TDCR_16:
- return (16);
- case APIC_TDCR_32:
- return (32);
- case APIC_TDCR_64:
- return (64);
- case APIC_TDCR_128:
- return (128);
- default:
- panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr);
- }
-}
-
static void
vlapic_start_timer(struct vlapic *vlapic, uint32_t elapsed)
{
@@ -755,59 +755,68 @@ vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data)
return (retval);
}
-void
+int
vlapic_timer_tick(struct vlapic *vlapic)
{
- int curticks, delta, periodic;
+ int curticks, delta, periodic, fired;
uint32_t ccr;
- uint32_t decrement, remainder;
+ uint32_t decrement, leftover;
+restart:
curticks = ticks;
-
- /* Common case */
delta = curticks - vlapic->ccr_ticks;
- if (delta == 0)
- return;
/* Local APIC timer is disabled */
if (vlapic->apic.icr_timer == 0)
- return;
+ return (-1);
/* One-shot mode and timer has already counted down to zero */
periodic = vlapic_periodic_timer(vlapic);
if (!periodic && vlapic->apic.ccr_timer == 0)
- return;
+ return (-1);
/*
* The 'curticks' and 'ccr_ticks' are out of sync by more than
* 2^31 ticks. We deal with this by restarting the timer.
*/
if (delta < 0) {
vlapic_start_timer(vlapic, 0);
- return;
+ goto restart;
}
- ccr = vlapic->apic.ccr_timer;
+ fired = 0;
decrement = (VLAPIC_BUS_FREQ / vlapic->divisor) / hz;
+
+ vlapic->ccr_ticks = curticks;
+ ccr = vlapic->apic.ccr_timer;
+
while (delta-- > 0) {
- if (ccr <= decrement) {
- remainder = decrement - ccr;
- vlapic_fire_timer(vlapic);
- if (periodic) {
- vlapic_start_timer(vlapic, remainder);
- ccr = vlapic->apic.ccr_timer;
- } else {
- /*
- * One-shot timer has counted down to zero.
- */
- ccr = 0;
- break;
- }
- } else
+ if (ccr > decrement) {
ccr -= decrement;
+ continue;
+ }
+
+ /* Trigger the local apic timer interrupt */
+ vlapic_fire_timer(vlapic);
+ if (periodic) {
+ leftover = decrement - ccr;
+ vlapic_start_timer(vlapic, leftover);
+ ccr = vlapic->apic.ccr_timer;
+ } else {
+ /*
+ * One-shot timer has counted down to zero.
+ */
+ ccr = 0;
+ }
+ fired = 1;
+ break;
}
- vlapic->ccr_ticks = curticks;
vlapic->apic.ccr_timer = ccr;
+
+ if (!fired)
+ return ((ccr / decrement) + 1);
+ else
+ return (0);
}
struct vdev_ops vlapic_dev_ops = {
diff --git a/sys/amd64/vmm/io/vlapic.h b/sys/amd64/vmm/io/vlapic.h
index f43289d..00de019 100644
--- a/sys/amd64/vmm/io/vlapic.h
+++ b/sys/amd64/vmm/io/vlapic.h
@@ -102,7 +102,7 @@ int vlapic_op_mem_read(void* dev, uint64_t gpa,
int vlapic_pending_intr(struct vlapic *vlapic);
void vlapic_intr_accepted(struct vlapic *vlapic, int vector);
void vlapic_set_intr_ready(struct vlapic *vlapic, int vector);
-void vlapic_timer_tick(struct vlapic *vlapic);
+int vlapic_timer_tick(struct vlapic *vlapic);
uint64_t vlapic_get_apicbase(struct vlapic *vlapic);
void vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val);
OpenPOWER on IntegriCloud