IA64: implement PHYSDEVOP_pirq_eoi_gmfn and related stuff.

This patch is ia64 counter part of 18844:c820bf73a914.

Signed-off-by: Isaku Yamahata <[EMAIL PROTECTED]>

diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c
--- a/xen/arch/ia64/xen/domain.c
+++ b/xen/arch/ia64/xen/domain.c
@@ -1653,6 +1653,11 @@ int domain_relinquish_resources(struct d
                /*fallthrough*/
 
        case RELRES_mm_teardown:
+               if (d->arch.pirq_eoi_map != NULL) {
+                       put_page(virt_to_page(d->arch.pirq_eoi_map));
+                       d->arch.pirq_eoi_map = NULL;
+               }
+
                /* Tear down shadow mode stuff. */
                ret = mm_teardown(d);
                if (ret != 0)
diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c
--- a/xen/arch/ia64/xen/hypercall.c
+++ b/xen/arch/ia64/xen/hypercall.c
@@ -341,7 +341,39 @@ long do_physdev_op(int cmd, XEN_GUEST_HA
         ret = -EFAULT;
         if ( copy_from_guest(&eoi, arg, 1) != 0 )
             break;
+        ret = -EINVAL;
+        if ( eoi.irq < 0 || eoi.irq >= NR_IRQS )
+            break;
+        if ( current->domain->arch.pirq_eoi_map )
+            evtchn_unmask(current->domain->pirq_to_evtchn[eoi.irq]);
         ret = pirq_guest_eoi(current->domain, eoi.irq);
+        break;
+    }
+
+    case PHYSDEVOP_pirq_eoi_gmfn: {
+        struct physdev_pirq_eoi_gmfn info;
+        unsigned long mfn;
+
+        BUILD_BUG_ON(NR_IRQS > (PAGE_SIZE * 8));
+
+        ret = -EFAULT;
+        if ( copy_from_guest(&info, arg, 1) != 0 )
+            break;
+
+        ret = -EINVAL;
+        mfn = gmfn_to_mfn(current->domain, info.gmfn);
+        if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), current->domain) )
+            break;
+
+        if ( cmpxchg(&current->domain->arch.pirq_eoi_map_mfn, 0, mfn) != 0 )
+        {
+            put_page(mfn_to_page(mfn));
+            ret = -EBUSY;
+            break;
+        }
+
+        current->domain->arch.pirq_eoi_map = mfn_to_virt(mfn);
+        ret = 0;
         break;
     }
 
diff --git a/xen/arch/ia64/xen/irq.c b/xen/arch/ia64/xen/irq.c
--- a/xen/arch/ia64/xen/irq.c
+++ b/xen/arch/ia64/xen/irq.c
@@ -312,16 +312,41 @@ typedef struct {
     struct domain *guest[IRQ_MAX_GUESTS];
 } irq_guest_action_t;
 
+static inline void set_pirq_eoi(struct domain *d, unsigned int irq)
+{
+    if ( d->arch.pirq_eoi_map )
+        set_bit(irq, d->arch.pirq_eoi_map);
+}
+
+static inline void clear_pirq_eoi(struct domain *d, unsigned int irq)
+{
+    if ( d->arch.pirq_eoi_map )
+        clear_bit(irq, d->arch.pirq_eoi_map);
+}
+
+static void _irq_guest_eoi(irq_desc_t *desc)
+{
+    irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
+    unsigned int i, vector = desc - irq_desc;
+
+    if ( !(desc->status & IRQ_GUEST_EOI_PENDING) )
+        return;
+
+    for ( i = 0; i < action->nr_guests; ++i )
+        clear_pirq_eoi(action->guest[i], vector);
+
+    desc->status &= ~(IRQ_INPROGRESS|IRQ_GUEST_EOI_PENDING);
+    desc->handler->enable(vector);
+}
+
 static struct timer irq_guest_eoi_timer[NR_IRQS];
 static void irq_guest_eoi_timer_fn(void *data)
 {
        irq_desc_t *desc = data;
-       unsigned vector = desc - irq_desc;
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
-       desc->status &= ~IRQ_INPROGRESS;
-       desc->handler->enable(vector);
+       _irq_guest_eoi(desc);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -355,8 +380,22 @@ void __do_IRQ_guest(int irq)
 
        if ( already_pending == action->nr_guests )
        {
+               stop_timer(&irq_guest_eoi_timer[irq]);
                desc->handler->disable(irq);
-               stop_timer(&irq_guest_eoi_timer[irq]);
+        desc->status |= IRQ_GUEST_EOI_PENDING;
+        for ( i = 0; i < already_pending; ++i )
+        {
+            d = action->guest[i];
+            set_pirq_eoi(d, irq);
+            /*
+             * Could check here whether the guest unmasked the event by now
+             * (or perhaps just re-issue the send_guest_pirq()), and if it
+             * can now accept the event,
+             * - clear all the pirq_eoi bits we already set,
+             * - re-enable the vector, and
+             * - skip the timer setup below.
+             */
+        }
                init_timer(&irq_guest_eoi_timer[irq],
                                irq_guest_eoi_timer_fn, desc, 
smp_processor_id());
                set_timer(&irq_guest_eoi_timer[irq], NOW() + MILLISECS(1));
@@ -379,16 +418,25 @@ int pirq_guest_eoi(struct domain *d, int
 int pirq_guest_eoi(struct domain *d, int irq)
 {
     irq_desc_t *desc;
+    irq_guest_action_t *action;
 
     if ( (irq < 0) || (irq >= NR_IRQS) )
         return -EINVAL;
 
     desc = &irq_desc[irq];
     spin_lock_irq(&desc->lock);
-    if ( test_and_clear_bit(irq, &d->pirq_mask) &&
-         (--((irq_guest_action_t *)desc->action)->in_flight == 0) )
+    action = (irq_guest_action_t *)desc->action;
+
+    if ( action->ack_type == ACKTYPE_NONE )
     {
-        ASSERT(((irq_guest_action_t*)desc->action)->ack_type == 
ACKTYPE_UNMASK);
+        ASSERT(!test_bit(irq, d->pirq_mask));
+        stop_timer(&irq_guest_eoi_timer[irq]);
+        _irq_guest_eoi(desc);
+    }
+
+    if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight == 0) )
+    {
+        ASSERT(action->ack_type == ACKTYPE_UNMASK);
         desc->handler->end(irq);
     }
     spin_unlock_irq(&desc->lock);
@@ -488,6 +536,11 @@ int pirq_guest_bind(struct vcpu *v, int 
 
     action->guest[action->nr_guests++] = v->domain;
 
+    if ( action->ack_type != ACKTYPE_NONE )
+        set_pirq_eoi(v->domain, irq);
+    else
+        clear_pirq_eoi(v->domain, irq);
+
  out:
     spin_unlock_irqrestore(&desc->lock, flags);
     return rc;
diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h
--- a/xen/include/asm-ia64/domain.h
+++ b/xen/include/asm-ia64/domain.h
@@ -177,6 +177,10 @@ struct arch_domain {
     /* Address of SAL emulator data  */
     struct xen_sal_data *sal_data;
 
+    /* Shared page for notifying that explicit PIRQ EOI is required. */
+    unsigned long *pirq_eoi_map;
+    unsigned long pirq_eoi_map_mfn;
+
     /* Address of efi_runtime_services_t (placed in domain memory)  */
     void *efi_runtime;
     /* Address of fpswa_interface_t (placed in domain memory)  */


-- 
yamahata

_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@lists.xensource.com
http://lists.xensource.com/xen-ia64-devel

Reply via email to