]> xenbits.xensource.com Git - people/vhanquez/xen.git/commitdiff
x86: re-inject emulated level pirqs in PV on HVM guests if still asserted
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>
Wed, 16 Nov 2011 16:33:58 +0000 (16:33 +0000)
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>
Wed, 16 Nov 2011 16:33:58 +0000 (16:33 +0000)
PV on HVM guests can loose level interrupts coming from emulated
devices if they have been remapped onto event channels.  The reason is
that we are missing the code to inject a pirq again in the guest when
the guest EOIs it, if it corresponds to an emulated level interrupt
and the interrupt is still asserted.

Fix this issue and also return error when the guest tries to get the
irq_status of a non-existing pirq.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Committed-by: Keir Fraser <keir@xen.org>
xen-unstable changeset:   24007:0526644ad2a6
xen-unstable date:        Thu Oct 27 16:07:18 2011 +0100

xen/arch/x86/physdev.c

index fff3544b688710c6263a6907aaf365bed134bc57..92a8e15abc9c11c918d9a1547b6bb787132c77fb 100644 (file)
@@ -261,6 +261,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
         ret = -EINVAL;
         if ( eoi.irq >= v->domain->nr_pirqs )
             break;
+        spin_lock(&v->domain->event_lock);
         if ( v->domain->arch.pirq_eoi_map )
             evtchn_unmask(v->domain->pirq_to_evtchn[eoi.irq]);
         if ( !is_hvm_domain(v->domain) ||
@@ -268,6 +269,19 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
             ret = pirq_guest_eoi(v->domain, eoi.irq);
         else
             ret = 0;
+        if ( is_hvm_domain(v->domain) &&
+                domain_pirq_to_emuirq(v->domain, eoi.irq) > 0 )
+        {
+            struct hvm_irq *hvm_irq = &v->domain->arch.hvm_domain.irq;
+            int gsi = domain_pirq_to_emuirq(v->domain, eoi.irq);
+
+            /* if this is a level irq and count > 0, send another
+             * notification */ 
+            if ( gsi >= NR_ISAIRQS /* ISA irqs are edge triggered */
+                    && hvm_irq->gsi_assert_count[gsi] )
+                send_guest_pirq(v->domain, eoi.irq);
+        }
+        spin_unlock(&v->domain->event_lock);
         break;
     }
 
@@ -323,9 +337,10 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
             break;
         irq_status_query.flags = 0;
         if ( is_hvm_domain(v->domain) &&
-             domain_pirq_to_irq(v->domain, irq) <= 0 )
+                domain_pirq_to_irq(v->domain, irq) <= 0 &&
+                domain_pirq_to_emuirq(v->domain, irq) == IRQ_UNBOUND )
         {
-            ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
+            ret = -EINVAL;
             break;
         }