ia64/xen-unstable

changeset 18862:f0a9a58608a0

IA64: implement PHYSDEVOP_pirq_eoi_gmfn and related stuff.

This patch is ia64 counter part of 18844:c820bf73a914.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Isaku Yamahata <yamahata@valinux.co.jp>
date Fri Dec 05 15:43:08 2008 +0900 (2008-12-05)
parents c15577ad46f2
children 09160c3bd179
files xen/arch/ia64/xen/domain.c xen/arch/ia64/xen/hypercall.c xen/arch/ia64/xen/irq.c xen/include/asm-ia64/domain.h
line diff
     1.1 --- a/xen/arch/ia64/xen/domain.c	Fri Dec 05 15:43:06 2008 +0900
     1.2 +++ b/xen/arch/ia64/xen/domain.c	Fri Dec 05 15:43:08 2008 +0900
     1.3 @@ -1653,6 +1653,11 @@ int domain_relinquish_resources(struct d
     1.4  		/*fallthrough*/
     1.5  
     1.6  	case RELRES_mm_teardown:
     1.7 +		if (d->arch.pirq_eoi_map != NULL) {
     1.8 +			put_page(virt_to_page(d->arch.pirq_eoi_map));
     1.9 +			d->arch.pirq_eoi_map = NULL;
    1.10 +		}
    1.11 +
    1.12  		/* Tear down shadow mode stuff. */
    1.13  		ret = mm_teardown(d);
    1.14  		if (ret != 0)
     2.1 --- a/xen/arch/ia64/xen/hypercall.c	Fri Dec 05 15:43:06 2008 +0900
     2.2 +++ b/xen/arch/ia64/xen/hypercall.c	Fri Dec 05 15:43:08 2008 +0900
     2.3 @@ -341,10 +341,42 @@ long do_physdev_op(int cmd, XEN_GUEST_HA
     2.4          ret = -EFAULT;
     2.5          if ( copy_from_guest(&eoi, arg, 1) != 0 )
     2.6              break;
     2.7 +        ret = -EINVAL;
     2.8 +        if ( eoi.irq < 0 || eoi.irq >= NR_IRQS )
     2.9 +            break;
    2.10 +        if ( current->domain->arch.pirq_eoi_map )
    2.11 +            evtchn_unmask(current->domain->pirq_to_evtchn[eoi.irq]);
    2.12          ret = pirq_guest_eoi(current->domain, eoi.irq);
    2.13          break;
    2.14      }
    2.15  
    2.16 +    case PHYSDEVOP_pirq_eoi_gmfn: {
    2.17 +        struct physdev_pirq_eoi_gmfn info;
    2.18 +        unsigned long mfn;
    2.19 +
    2.20 +        BUILD_BUG_ON(NR_IRQS > (PAGE_SIZE * 8));
    2.21 +
    2.22 +        ret = -EFAULT;
    2.23 +        if ( copy_from_guest(&info, arg, 1) != 0 )
    2.24 +            break;
    2.25 +
    2.26 +        ret = -EINVAL;
    2.27 +        mfn = gmfn_to_mfn(current->domain, info.gmfn);
    2.28 +        if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), current->domain) )
    2.29 +            break;
    2.30 +
    2.31 +        if ( cmpxchg(&current->domain->arch.pirq_eoi_map_mfn, 0, mfn) != 0 )
    2.32 +        {
    2.33 +            put_page(mfn_to_page(mfn));
    2.34 +            ret = -EBUSY;
    2.35 +            break;
    2.36 +        }
    2.37 +
    2.38 +        current->domain->arch.pirq_eoi_map = mfn_to_virt(mfn);
    2.39 +        ret = 0;
    2.40 +        break;
    2.41 +    }
    2.42 +
    2.43      /* Legacy since 0x00030202. */
    2.44      case PHYSDEVOP_IRQ_UNMASK_NOTIFY: {
    2.45          ret = pirq_guest_unmask(current->domain);
     3.1 --- a/xen/arch/ia64/xen/irq.c	Fri Dec 05 15:43:06 2008 +0900
     3.2 +++ b/xen/arch/ia64/xen/irq.c	Fri Dec 05 15:43:08 2008 +0900
     3.3 @@ -312,16 +312,41 @@ typedef struct {
     3.4      struct domain *guest[IRQ_MAX_GUESTS];
     3.5  } irq_guest_action_t;
     3.6  
     3.7 +static inline void set_pirq_eoi(struct domain *d, unsigned int irq)
     3.8 +{
     3.9 +    if ( d->arch.pirq_eoi_map )
    3.10 +        set_bit(irq, d->arch.pirq_eoi_map);
    3.11 +}
    3.12 +
    3.13 +static inline void clear_pirq_eoi(struct domain *d, unsigned int irq)
    3.14 +{
    3.15 +    if ( d->arch.pirq_eoi_map )
    3.16 +        clear_bit(irq, d->arch.pirq_eoi_map);
    3.17 +}
    3.18 +
    3.19 +static void _irq_guest_eoi(irq_desc_t *desc)
    3.20 +{
    3.21 +    irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
    3.22 +    unsigned int i, vector = desc - irq_desc;
    3.23 +
    3.24 +    if ( !(desc->status & IRQ_GUEST_EOI_PENDING) )
    3.25 +        return;
    3.26 +
    3.27 +    for ( i = 0; i < action->nr_guests; ++i )
    3.28 +        clear_pirq_eoi(action->guest[i], vector);
    3.29 +
    3.30 +    desc->status &= ~(IRQ_INPROGRESS|IRQ_GUEST_EOI_PENDING);
    3.31 +    desc->handler->enable(vector);
    3.32 +}
    3.33 +
    3.34  static struct timer irq_guest_eoi_timer[NR_IRQS];
    3.35  static void irq_guest_eoi_timer_fn(void *data)
    3.36  {
    3.37  	irq_desc_t *desc = data;
    3.38 -	unsigned vector = desc - irq_desc;
    3.39  	unsigned long flags;
    3.40  
    3.41  	spin_lock_irqsave(&desc->lock, flags);
    3.42 -	desc->status &= ~IRQ_INPROGRESS;
    3.43 -	desc->handler->enable(vector);
    3.44 +	_irq_guest_eoi(desc);
    3.45  	spin_unlock_irqrestore(&desc->lock, flags);
    3.46  }
    3.47  
    3.48 @@ -355,8 +380,22 @@ void __do_IRQ_guest(int irq)
    3.49  
    3.50  	if ( already_pending == action->nr_guests )
    3.51  	{
    3.52 +		stop_timer(&irq_guest_eoi_timer[irq]);
    3.53  		desc->handler->disable(irq);
    3.54 -		stop_timer(&irq_guest_eoi_timer[irq]);
    3.55 +        desc->status |= IRQ_GUEST_EOI_PENDING;
    3.56 +        for ( i = 0; i < already_pending; ++i )
    3.57 +        {
    3.58 +            d = action->guest[i];
    3.59 +            set_pirq_eoi(d, irq);
    3.60 +            /*
    3.61 +             * Could check here whether the guest unmasked the event by now
    3.62 +             * (or perhaps just re-issue the send_guest_pirq()), and if it
    3.63 +             * can now accept the event,
    3.64 +             * - clear all the pirq_eoi bits we already set,
    3.65 +             * - re-enable the vector, and
    3.66 +             * - skip the timer setup below.
    3.67 +             */
    3.68 +        }
    3.69  		init_timer(&irq_guest_eoi_timer[irq],
    3.70  				irq_guest_eoi_timer_fn, desc, smp_processor_id());
    3.71  		set_timer(&irq_guest_eoi_timer[irq], NOW() + MILLISECS(1));
    3.72 @@ -379,16 +418,25 @@ int pirq_acktype(int irq)
    3.73  int pirq_guest_eoi(struct domain *d, int irq)
    3.74  {
    3.75      irq_desc_t *desc;
    3.76 +    irq_guest_action_t *action;
    3.77  
    3.78      if ( (irq < 0) || (irq >= NR_IRQS) )
    3.79          return -EINVAL;
    3.80  
    3.81      desc = &irq_desc[irq];
    3.82      spin_lock_irq(&desc->lock);
    3.83 -    if ( test_and_clear_bit(irq, &d->pirq_mask) &&
    3.84 -         (--((irq_guest_action_t *)desc->action)->in_flight == 0) )
    3.85 +    action = (irq_guest_action_t *)desc->action;
    3.86 +
    3.87 +    if ( action->ack_type == ACKTYPE_NONE )
    3.88      {
    3.89 -        ASSERT(((irq_guest_action_t*)desc->action)->ack_type == ACKTYPE_UNMASK);
    3.90 +        ASSERT(!test_bit(irq, d->pirq_mask));
    3.91 +        stop_timer(&irq_guest_eoi_timer[irq]);
    3.92 +        _irq_guest_eoi(desc);
    3.93 +    }
    3.94 +
    3.95 +    if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight == 0) )
    3.96 +    {
    3.97 +        ASSERT(action->ack_type == ACKTYPE_UNMASK);
    3.98          desc->handler->end(irq);
    3.99      }
   3.100      spin_unlock_irq(&desc->lock);
   3.101 @@ -488,6 +536,11 @@ int pirq_guest_bind(struct vcpu *v, int 
   3.102  
   3.103      action->guest[action->nr_guests++] = v->domain;
   3.104  
   3.105 +    if ( action->ack_type != ACKTYPE_NONE )
   3.106 +        set_pirq_eoi(v->domain, irq);
   3.107 +    else
   3.108 +        clear_pirq_eoi(v->domain, irq);
   3.109 +
   3.110   out:
   3.111      spin_unlock_irqrestore(&desc->lock, flags);
   3.112      return rc;
     4.1 --- a/xen/include/asm-ia64/domain.h	Fri Dec 05 15:43:06 2008 +0900
     4.2 +++ b/xen/include/asm-ia64/domain.h	Fri Dec 05 15:43:08 2008 +0900
     4.3 @@ -177,6 +177,10 @@ struct arch_domain {
     4.4      /* Address of SAL emulator data  */
     4.5      struct xen_sal_data *sal_data;
     4.6  
     4.7 +    /* Shared page for notifying that explicit PIRQ EOI is required. */
     4.8 +    unsigned long *pirq_eoi_map;
     4.9 +    unsigned long pirq_eoi_map_mfn;
    4.10 +
    4.11      /* Address of efi_runtime_services_t (placed in domain memory)  */
    4.12      void *efi_runtime;
    4.13      /* Address of fpswa_interface_t (placed in domain memory)  */