hv: vlapic_timer: add vlapic one-shot/periodic timer support
Enable guest LAPIC one-shot/periodic timer support. Change-Id: I368e28beaa81d6566de2626bbe26c9f8972f0891 Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
parent
47116e8c4b
commit
46f64b55b4
|
@ -224,6 +224,15 @@ vlapic_id_write_handler(struct vlapic *vlapic)
|
|||
lapic->id = vlapic_get_id(vlapic);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
vlapic_timer_divisor_shift(uint32_t dcr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = ((dcr & 0x3) | ((dcr & 0x8) >> 1));
|
||||
return ((val + 1) & 0x7);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
vlapic_lvtt_oneshot(struct vlapic *vlapic)
|
||||
{
|
||||
|
@ -280,6 +289,32 @@ static void vlapic_reset_timer(struct vlapic *vlapic)
|
|||
timer->period_in_cycle = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_expiration(struct vlapic *vlapic)
|
||||
{
|
||||
uint64_t now = rdtsc();
|
||||
uint64_t delta;
|
||||
struct vlapic_timer *vlapic_timer;
|
||||
struct timer *timer;
|
||||
uint32_t tmicr, divisor_shift;
|
||||
|
||||
vlapic_timer = &vlapic->vlapic_timer;
|
||||
tmicr = vlapic_timer->tmicr;
|
||||
divisor_shift = vlapic_timer->divisor_shift;
|
||||
|
||||
if (!tmicr || divisor_shift > 8)
|
||||
return false;
|
||||
|
||||
delta = tmicr << divisor_shift;
|
||||
timer = &vlapic_timer->timer;
|
||||
|
||||
if (vlapic_lvtt_period(vlapic))
|
||||
timer->period_in_cycle = delta;
|
||||
timer->fire_tsc = now + delta;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vlapic_update_lvtt(struct vlapic *vlapic,
|
||||
uint32_t val)
|
||||
{
|
||||
|
@ -303,19 +338,53 @@ static void vlapic_update_lvtt(struct vlapic *vlapic,
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t vlapic_get_ccr(__unused struct vlapic *vlapic)
|
||||
static uint32_t vlapic_get_ccr(struct vlapic *vlapic)
|
||||
{
|
||||
return 0;
|
||||
uint64_t now = rdtsc();
|
||||
uint64_t remain_count = 0;
|
||||
struct vlapic_timer *vlapic_timer;
|
||||
|
||||
vlapic_timer = &vlapic->vlapic_timer;
|
||||
|
||||
if (vlapic_timer->tmicr && !vlapic_lvtt_tsc_deadline(vlapic)) {
|
||||
uint64_t fire_tsc = vlapic_timer->timer.fire_tsc;
|
||||
uint32_t divisor_shift = vlapic_timer->divisor_shift;
|
||||
|
||||
if (now < fire_tsc)
|
||||
remain_count = (fire_tsc - now) >> divisor_shift;
|
||||
}
|
||||
|
||||
return remain_count;
|
||||
}
|
||||
|
||||
static void vlapic_dcr_write_handler(__unused struct vlapic *vlapic)
|
||||
static void vlapic_dcr_write_handler(struct vlapic *vlapic)
|
||||
{
|
||||
uint32_t divisor_shift;
|
||||
struct vlapic_timer *vlapic_timer;
|
||||
struct lapic *lapic = vlapic->apic_page;
|
||||
|
||||
vlapic_timer = &vlapic->vlapic_timer;
|
||||
divisor_shift = vlapic_timer_divisor_shift(lapic->dcr_timer);
|
||||
|
||||
vlapic_timer->divisor_shift = divisor_shift;
|
||||
}
|
||||
|
||||
static void vlapic_icrtmr_write_handler(__unused struct vlapic *vlapic)
|
||||
static void vlapic_icrtmr_write_handler(struct vlapic *vlapic)
|
||||
{
|
||||
}
|
||||
struct lapic *lapic;
|
||||
struct vlapic_timer *vlapic_timer;
|
||||
|
||||
if (vlapic_lvtt_tsc_deadline(vlapic))
|
||||
return;
|
||||
|
||||
lapic = vlapic->apic_page;
|
||||
vlapic_timer = &vlapic->vlapic_timer;
|
||||
vlapic_timer->tmicr = lapic->icr_timer;
|
||||
|
||||
del_timer(&vlapic_timer->timer);
|
||||
if (set_expiration(vlapic))
|
||||
add_timer(&vlapic_timer->timer);
|
||||
}
|
||||
|
||||
static uint64_t vlapic_get_tsc_deadline_msr(struct vlapic *vlapic)
|
||||
{
|
||||
|
@ -1165,10 +1234,12 @@ vlapic_svr_write_handler(struct vlapic *vlapic)
|
|||
if ((changed & APIC_SVR_ENABLE) != 0) {
|
||||
if ((new & APIC_SVR_ENABLE) == 0) {
|
||||
/*
|
||||
* TODO: The apic is now disabled so stop the apic timer
|
||||
* The apic is now disabled so stop the apic timer
|
||||
* and mask all the LVT entries.
|
||||
*/
|
||||
dev_dbg(ACRN_DBG_LAPIC, "vlapic is software-disabled");
|
||||
del_timer(&vlapic->vlapic_timer.timer);
|
||||
|
||||
vlapic_mask_lvts(vlapic);
|
||||
/* the only one enabled LINT0-ExtINT vlapic disabled */
|
||||
if (vlapic->vm->vpic_wire_mode == VPIC_WIRE_NULL) {
|
||||
|
@ -1183,7 +1254,8 @@ vlapic_svr_write_handler(struct vlapic *vlapic)
|
|||
*/
|
||||
dev_dbg(ACRN_DBG_LAPIC, "vlapic is software-enabled");
|
||||
if (vlapic_lvtt_period(vlapic))
|
||||
vlapic_icrtmr_write_handler(vlapic);
|
||||
if (set_expiration(vlapic))
|
||||
add_timer(&vlapic->vlapic_timer.timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1302,10 +1374,9 @@ vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset,
|
|||
if (vlapic_lvtt_tsc_deadline(vlapic))
|
||||
*data = 0;
|
||||
else
|
||||
*data = vlapic_get_ccr(vlapic);
|
||||
*data = lapic->icr_timer;
|
||||
break;
|
||||
case APIC_OFFSET_TIMER_CCR:
|
||||
/* TODO */
|
||||
*data = vlapic_get_ccr(vlapic);
|
||||
break;
|
||||
case APIC_OFFSET_TIMER_DCR:
|
||||
|
|
|
@ -112,7 +112,7 @@ struct vlapic_timer {
|
|||
struct timer timer;
|
||||
uint32_t mode;
|
||||
uint32_t tmicr;
|
||||
uint32_t divisor;
|
||||
uint32_t divisor_shift;
|
||||
};
|
||||
|
||||
struct vlapic {
|
||||
|
|
Loading…
Reference in New Issue