[xen master] x86/vpt: add support for level interrupts

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen master] x86/vpt: add support for level interrupts

patchbot
commit 0bcbc971feaa7d9ef6d92b5b39a37819d449a821
Author:     Roger Pau Monné <[hidden email]>
AuthorDate: Tue Jul 24 15:52:47 2018 +0200
Commit:     Jan Beulich <[hidden email]>
CommitDate: Tue Jul 24 15:52:47 2018 +0200

    x86/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. None of the current users of vpt are switched
    to use level triggered interrupts yet.
   
    Note that periodic level triggered interrupts are not supported. This
    is because level triggered interrupts always require a deassert of the
    IO-APIC pin, which should be done by the caller of vpt at which point
    the caller should also reset the timer if required.
   
    Signed-off-by: Roger Pau Monné <[hidden email]>
    Reviewed-by: Jan Beulich <[hidden email]>
---
 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        | 48 +++++++++++++++++++++++++++++++++++--------
 xen/include/asm-x86/hvm/vpt.h |  3 ++-
 6 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c
index 171afe9ac2..b7dcfa8af9 100644
--- a/xen/arch/x86/hvm/hpet.c
+++ b/xen/arch/x86/hvm/hpet.c
@@ -292,7 +292,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 e79ff84f0c..fa43d8f133 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
@@ -1423,7 +1423,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 f655457e03..6ac4c913bb 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,37 @@ 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 always asserted because the pin assert
+                 * count is incremented regardless of whether the pin is masked
+                 * or the vector latched in IRR, 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 +475,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) )
+         (level && period) ||
+         (pt->source == PTSRC_ioapic ? irq >= hvm_domain_irq(v->domain)->nr_gsis
+                                     : level) )
     {
         ASSERT_UNREACHABLE();
         return;
@@ -480,6 +509,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);
--
generated by git-patchbot for /home/xen/git/xen.git#master


_______________________________________________
Xen-changelog mailing list
[hidden email]
https://lists.xenproject.org/xen-changelog