ia64/linux-2.6.18-xen.hg

changeset 747:d545a95fca73

linux/x86: use shared page indicating the need for an EOI notification

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Nov 28 13:30:27 2008 +0000 (2008-11-28)
parents 2268be46c75e
children 39a8680e7a70
files drivers/xen/core/evtchn.c include/xen/interface/physdev.h
line diff
     1.1 --- a/drivers/xen/core/evtchn.c	Fri Nov 28 13:07:36 2008 +0000
     1.2 +++ b/drivers/xen/core/evtchn.c	Fri Nov 28 13:30:27 2008 +0000
     1.3 @@ -123,9 +123,6 @@ DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS])
     1.4  /* Reference counts for bindings to IRQs. */
     1.5  static int irq_bindcount[NR_IRQS];
     1.6  
     1.7 -/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
     1.8 -static DECLARE_BITMAP(pirq_needs_eoi, NR_PIRQS);
     1.9 -
    1.10  #ifdef CONFIG_SMP
    1.11  
    1.12  static u8 cpu_evtchn[NR_EVENT_CHANNELS];
    1.13 @@ -756,16 +753,48 @@ static struct hw_interrupt_type dynirq_t
    1.14  	.retrigger = resend_irq_on_evtchn,
    1.15  };
    1.16  
    1.17 -static inline void pirq_unmask_notify(int irq)
    1.18 +/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
    1.19 +static bool pirq_eoi_does_unmask;
    1.20 +static DECLARE_BITMAP(pirq_needs_eoi, ALIGN(NR_PIRQS, PAGE_SIZE * 8))
    1.21 +	__attribute__ ((__section__(".bss.page_aligned"), __aligned__(PAGE_SIZE)));
    1.22 +
    1.23 +static void pirq_unmask_and_notify(unsigned int evtchn, unsigned int irq)
    1.24  {
    1.25  	struct physdev_eoi eoi = { .irq = evtchn_get_xen_pirq(irq) };
    1.26 -	if (unlikely(test_bit(irq - PIRQ_BASE, pirq_needs_eoi)))
    1.27 -		VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi));
    1.28 +
    1.29 +	if (pirq_eoi_does_unmask) {
    1.30 +		if (test_bit(eoi.irq, pirq_needs_eoi))
    1.31 +			VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi));
    1.32 +		else
    1.33 +			unmask_evtchn(evtchn);
    1.34 +	} else if (test_bit(irq - PIRQ_BASE, pirq_needs_eoi)) {
    1.35 +		if (smp_processor_id() != cpu_from_evtchn(evtchn)) {
    1.36 +			struct evtchn_unmask unmask = { .port = evtchn };
    1.37 +			struct multicall_entry mcl[2];
    1.38 +
    1.39 +			mcl[0].op = __HYPERVISOR_event_channel_op;
    1.40 +			mcl[0].args[0] = EVTCHNOP_unmask;
    1.41 +			mcl[0].args[1] = (unsigned long)&unmask;
    1.42 +			mcl[1].op = __HYPERVISOR_physdev_op;
    1.43 +			mcl[1].args[0] = PHYSDEVOP_eoi;
    1.44 +			mcl[1].args[1] = (unsigned long)&eoi;
    1.45 +
    1.46 +			if (HYPERVISOR_multicall(mcl, 2))
    1.47 +				BUG();
    1.48 +		} else {
    1.49 +			unmask_evtchn(evtchn);
    1.50 +			VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi));
    1.51 +		}
    1.52 +	} else
    1.53 +		unmask_evtchn(evtchn);
    1.54  }
    1.55  
    1.56  static inline void pirq_query_unmask(int irq)
    1.57  {
    1.58  	struct physdev_irq_status_query irq_status;
    1.59 +
    1.60 +	if (pirq_eoi_does_unmask)
    1.61 +		return;
    1.62  	irq_status.irq = evtchn_get_xen_pirq(irq);
    1.63  	if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
    1.64  		irq_status.flags = 0;
    1.65 @@ -806,8 +835,7 @@ static unsigned int startup_pirq(unsigne
    1.66  	irq_info[irq] = mk_irq_info(IRQT_PIRQ, bind_pirq.pirq, evtchn);
    1.67  
    1.68   out:
    1.69 -	unmask_evtchn(evtchn);
    1.70 -	pirq_unmask_notify(irq);
    1.71 +	pirq_unmask_and_notify(evtchn, irq);
    1.72  
    1.73  	return 0;
    1.74  }
    1.75 @@ -859,10 +887,8 @@ static void end_pirq(unsigned int irq)
    1.76  	if ((irq_desc[irq].status & (IRQ_DISABLED|IRQ_PENDING)) ==
    1.77  	    (IRQ_DISABLED|IRQ_PENDING)) {
    1.78  		shutdown_pirq(irq);
    1.79 -	} else if (VALID_EVTCHN(evtchn)) {
    1.80 -		unmask_evtchn(evtchn);
    1.81 -		pirq_unmask_notify(irq);
    1.82 -	}
    1.83 +	} else if (VALID_EVTCHN(evtchn))
    1.84 +		pirq_unmask_and_notify(evtchn, irq);
    1.85  }
    1.86  
    1.87  static struct hw_interrupt_type pirq_type = {
    1.88 @@ -1012,6 +1038,14 @@ void irq_resume(void)
    1.89  
    1.90  	init_evtchn_cpu_bindings();
    1.91  
    1.92 +	if (pirq_eoi_does_unmask) {
    1.93 +		struct physdev_pirq_eoi_mfn eoi_mfn;
    1.94 +
    1.95 +		eoi_mfn.mfn = virt_to_bus(pirq_needs_eoi) >> PAGE_SHIFT;
    1.96 +		if (HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_mfn, &eoi_mfn))
    1.97 +			BUG();
    1.98 +	}
    1.99 +
   1.100  	/* New event-channel space is not 'live' yet. */
   1.101  	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
   1.102  		mask_evtchn(evtchn);
   1.103 @@ -1098,9 +1132,15 @@ int evtchn_get_xen_pirq(int irq)
   1.104  void __init xen_init_IRQ(void)
   1.105  {
   1.106  	unsigned int i;
   1.107 +	struct physdev_pirq_eoi_mfn eoi_mfn;
   1.108  
   1.109  	init_evtchn_cpu_bindings();
   1.110  
   1.111 +	BUG_ON(!bitmap_empty(pirq_needs_eoi, PAGE_SIZE * 8));
   1.112 +	eoi_mfn.mfn = virt_to_bus(pirq_needs_eoi) >> PAGE_SHIFT;
   1.113 +	if (HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_mfn, &eoi_mfn) == 0)
   1.114 +		pirq_eoi_does_unmask = true;
   1.115 +
   1.116  	/* No event channels are 'live' right now. */
   1.117  	for (i = 0; i < NR_EVENT_CHANNELS; i++)
   1.118  		mask_evtchn(i);
     2.1 --- a/include/xen/interface/physdev.h	Fri Nov 28 13:07:36 2008 +0000
     2.2 +++ b/include/xen/interface/physdev.h	Fri Nov 28 13:30:27 2008 +0000
     2.3 @@ -41,6 +41,21 @@ typedef struct physdev_eoi physdev_eoi_t
     2.4  DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t);
     2.5  
     2.6  /*
     2.7 + * Register a shared page for the hypervisor to indicate whether the guest
     2.8 + * must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly
     2.9 + * once the guest used this function in that the associated event channel
    2.10 + * will automatically get unmasked. The page registered is used as a bit
    2.11 + * array indexed by Xen's PIRQ value.
    2.12 + */
    2.13 +#define PHYSDEVOP_pirq_eoi_mfn          17
    2.14 +struct physdev_pirq_eoi_mfn {
    2.15 +    /* IN */
    2.16 +    xen_pfn_t mfn;
    2.17 +};
    2.18 +typedef struct physdev_pirq_eoi_mfn physdev_pirq_eoi_mfn_t;
    2.19 +DEFINE_XEN_GUEST_HANDLE(physdev_pirq_eoi_mfn_t);
    2.20 +
    2.21 +/*
    2.22   * Query the status of an IRQ line.
    2.23   * @arg == pointer to physdev_irq_status_query structure.
    2.24   */