|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 5/6] vpt: add support for level interrupts
Level trigger interrupts will be asserted regardless of whether the
interrupt is masked, and thus the callback will also be executed.
Add a new 'level' parameter to create_periodic_time in order to create
level triggered timers.
Note that none of the current users of vpt are switched to use level
triggered interrupts yet.
Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
xen/arch/x86/hvm/hpet.c | 2 +-
xen/arch/x86/hvm/i8254.c | 4 ++--
xen/arch/x86/hvm/rtc.c | 2 +-
xen/arch/x86/hvm/vlapic.c | 8 +++----
xen/arch/x86/hvm/vpt.c | 45 ++++++++++++++++++++++++++++-------
xen/include/asm-x86/hvm/vpt.h | 3 ++-
6 files changed, 47 insertions(+), 17 deletions(-)
diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c
index f7ef4f7514..72209350ba 100644
--- a/xen/arch/x86/hvm/hpet.c
+++ b/xen/arch/x86/hvm/hpet.c
@@ -302,7 +302,7 @@ static void hpet_set_timer(HPETState *h, unsigned int tn,
create_periodic_time(vhpet_vcpu(h), &h->pt[tn],
hpet_tick_to_ns(h, diff),
oneshot ? 0 : hpet_tick_to_ns(h, h->hpet.period[tn]),
- irq, NULL, NULL);
+ irq, NULL, NULL, false);
}
static inline uint64_t hpet_fixup_reg(
diff --git a/xen/arch/x86/hvm/i8254.c b/xen/arch/x86/hvm/i8254.c
index 992f08dd6c..b8ec56f8d3 100644
--- a/xen/arch/x86/hvm/i8254.c
+++ b/xen/arch/x86/hvm/i8254.c
@@ -191,14 +191,14 @@ static void pit_load_count(PITState *pit, int channel,
int val)
/* Periodic timer. */
TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, period);
create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired,
- &pit->count_load_time[channel]);
+ &pit->count_load_time[channel], false);
break;
case 1:
case 4:
/* One-shot timer. */
TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, 0);
create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
- &pit->count_load_time[channel]);
+ &pit->count_load_time[channel], false);
break;
default:
TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c
index cb75b99ed1..96921bb5b5 100644
--- a/xen/arch/x86/hvm/rtc.c
+++ b/xen/arch/x86/hvm/rtc.c
@@ -156,7 +156,7 @@ static void rtc_timer_update(RTCState *s)
{
TRACE_2D(TRC_HVM_EMUL_RTC_START_TIMER, delta, period);
create_periodic_time(v, &s->pt, delta, period,
- RTC_IRQ, rtc_pf_callback, s);
+ RTC_IRQ, rtc_pf_callback, s, false);
}
else
s->check_ticks_since = now;
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 1b9f00a0e4..d2ac4b8625 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -762,7 +762,7 @@ static void vlapic_update_timer(struct vlapic *vlapic,
uint32_t lvtt,
create_periodic_time(current, &vlapic->pt, delta,
is_periodic ? period : 0, vlapic->pt.irq,
is_periodic ? vlapic_pt_cb : NULL,
- &vlapic->timer_last_update);
+ &vlapic->timer_last_update, false);
vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
if ( !tmict_updated )
@@ -1166,7 +1166,7 @@ void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t
value)
TRC_PAR_LONG(0LL), vlapic->pt.irq);
create_periodic_time(v, &vlapic->pt, delta, 0,
vlapic->pt.irq, vlapic_tdt_pt_cb,
- &vlapic->timer_last_update);
+ &vlapic->timer_last_update, false);
vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
}
else
@@ -1180,7 +1180,7 @@ void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t
value)
TRC_PAR_LONG(0LL), vlapic->pt.irq);
create_periodic_time(v, &vlapic->pt, 0, 0,
vlapic->pt.irq, vlapic_tdt_pt_cb,
- &vlapic->timer_last_update);
+ &vlapic->timer_last_update, false);
vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
}
else
@@ -1431,7 +1431,7 @@ static void lapic_rearm(struct vlapic *s)
vlapic_lvtt_period(s) ? period : 0,
s->pt.irq,
vlapic_lvtt_period(s) ? vlapic_pt_cb : NULL,
- &s->timer_last_update);
+ &s->timer_last_update, false);
s->timer_last_update = s->pt.last_plt_gtime;
}
diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c
index 2565f7237e..e98bc41b1c 100644
--- a/xen/arch/x86/hvm/vpt.c
+++ b/xen/arch/x86/hvm/vpt.c
@@ -306,6 +306,7 @@ int pt_update_irq(struct vcpu *v)
struct periodic_time *pt, *temp, *earliest_pt;
uint64_t max_lag;
int irq, pt_vector = -1;
+ bool level;
spin_lock(&v->arch.hvm_vcpu.tm_lock);
@@ -316,7 +317,9 @@ int pt_update_irq(struct vcpu *v)
if ( pt->pending_intr_nr )
{
/* RTC code takes care of disabling the timer itself. */
- if ( (pt->irq != RTC_IRQ || !pt->priv) && pt_irq_masked(pt) )
+ if ( (pt->irq != RTC_IRQ || !pt->priv) && pt_irq_masked(pt) &&
+ /* Level interrupts should be asserted even if masked. */
+ !pt->level )
{
/* suspend timer emulation */
list_del(&pt->list);
@@ -341,6 +344,7 @@ int pt_update_irq(struct vcpu *v)
earliest_pt->irq_issued = 1;
irq = earliest_pt->irq;
+ level = earliest_pt->level;
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
@@ -374,13 +378,36 @@ int pt_update_irq(struct vcpu *v)
break;
case PTSRC_ioapic:
- /*
- * NB: At the moment IO-APIC routed interrupts generated by vpt devices
- * (HPET) are edge-triggered.
- */
- pt_vector = hvm_ioapic_assert(v->domain, irq, false);
+ pt_vector = hvm_ioapic_assert(v->domain, irq, level);
if ( pt_vector < 0 || !vlapic_test_irq(vcpu_vlapic(v), pt_vector) )
+ {
pt_vector = -1;
+ if ( level )
+ {
+ /*
+ * Level interrupts are asserted even if the interrupt is
+ * masked, so also execute the callback associated with the
+ * timer.
+ */
+ time_cb *cb = NULL;
+ void *cb_priv;
+
+ spin_lock(&v->arch.hvm_vcpu.tm_lock);
+ /* Make sure the timer is still on the list. */
+ list_for_each_entry ( pt, &v->arch.hvm_vcpu.tm_list, list )
+ if ( pt == earliest_pt )
+ {
+ pt_irq_fired(v, pt);
+ cb = pt->cb;
+ cb_priv = pt->priv;
+ break;
+ }
+ spin_unlock(&v->arch.hvm_vcpu.tm_lock);
+
+ if ( cb != NULL )
+ cb(v, cb_priv);
+ }
+ }
break;
}
@@ -447,12 +474,13 @@ void pt_migrate(struct vcpu *v)
void create_periodic_time(
struct vcpu *v, struct periodic_time *pt, uint64_t delta,
- uint64_t period, uint8_t irq, time_cb *cb, void *data)
+ uint64_t period, uint8_t irq, time_cb *cb, void *data, bool level)
{
if ( !pt->source ||
(irq >= NR_ISAIRQS && pt->source == PTSRC_isa) ||
(irq >= hvm_domain_irq(v->domain)->nr_gsis &&
- pt->source == PTSRC_ioapic) )
+ pt->source == PTSRC_ioapic) ||
+ (level && pt->source != PTSRC_ioapic) )
{
ASSERT_UNREACHABLE();
return;
@@ -480,6 +508,7 @@ void create_periodic_time(
pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
pt->irq = irq;
pt->one_shot = !period;
+ pt->level = level;
pt->scheduled = NOW() + delta;
if ( !pt->one_shot )
diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h
index f693c0bcf1..61c26ed8b2 100644
--- a/xen/include/asm-x86/hvm/vpt.h
+++ b/xen/include/asm-x86/hvm/vpt.h
@@ -42,6 +42,7 @@ struct periodic_time {
bool do_not_freeze;
bool irq_issued;
bool warned_timeout_too_short;
+ bool level;
#define PTSRC_isa 1 /* ISA time source */
#define PTSRC_lapic 2 /* LAPIC time source */
#define PTSRC_ioapic 3 /* IOAPIC time source */
@@ -169,7 +170,7 @@ void pt_may_unmask_irq(struct domain *d, struct
periodic_time *vlapic_pt);
*/
void create_periodic_time(
struct vcpu *v, struct periodic_time *pt, uint64_t delta,
- uint64_t period, uint8_t irq, time_cb *cb, void *data);
+ uint64_t period, uint8_t irq, time_cb *cb, void *data, bool level);
void destroy_periodic_time(struct periodic_time *pt);
int pv_pit_handler(int port, int data, int write);
--
2.17.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |