xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Boris Ostrovsky <boris.ostrovsky@oracle.com>
To: David Vrabel <david.vrabel@citrix.com>
Cc: Jan Beulich <jbeulich@suse.com>, xen-devel@lists.xen.org
Subject: Re: [PATCH 06/16] xen/events: move 2-level specific code into its own file
Date: Mon, 21 Oct 2013 10:34:55 -0400	[thread overview]
Message-ID: <52653B8F.3030905@oracle.com> (raw)
In-Reply-To: <1382106206-30366-7-git-send-email-david.vrabel@citrix.com>

On 10/18/2013 10:23 AM, David Vrabel wrote:
> From: David Vrabel <david.vrabel@citrix.com>
>
> In preparation for alternative event channel ABIs, move all the
> functions accessing the shared data structures into their own file.
>
> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
> ---
>   drivers/xen/events/Makefile          |    1 +
>   drivers/xen/events/events_2l.c       |  348 +++++++++++++++++++++++++++++++
>   drivers/xen/events/events_base.c     |  379 ++--------------------------------
>   drivers/xen/events/events_internal.h |   74 +++++++
>   include/xen/events.h                 |    2 +
>   5 files changed, 442 insertions(+), 362 deletions(-)
>   create mode 100644 drivers/xen/events/events_2l.c
>   create mode 100644 drivers/xen/events/events_internal.h

I am not sure I see what the point is for adding irq_from_virq() --- it 
is only used once (I didn't see it anywhere in subsequent patches but I 
may have missed it). There is also no complementary set_virq_to_irq() 
(or some such) so per_cpu(virq_to_irq) is still being used explicitly, 
if that was the idea for irq_from_virq().

Other than that

Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>

-boris

>
> diff --git a/drivers/xen/events/Makefile b/drivers/xen/events/Makefile
> index f0bc607..08179fe 100644
> --- a/drivers/xen/events/Makefile
> +++ b/drivers/xen/events/Makefile
> @@ -1,3 +1,4 @@
>   obj-y += events.o
>   
>   events-y += events_base.o
> +events-y += events_2l.o
> diff --git a/drivers/xen/events/events_2l.c b/drivers/xen/events/events_2l.c
> new file mode 100644
> index 0000000..a77e98d
> --- /dev/null
> +++ b/drivers/xen/events/events_2l.c
> @@ -0,0 +1,348 @@
> +/*
> + * Xen event channels (2-level ABI)
> + *
> + * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
> + */
> +
> +#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
> +
> +#include <linux/linkage.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +
> +#include <asm/sync_bitops.h>
> +#include <asm/xen/hypercall.h>
> +#include <asm/xen/hypervisor.h>
> +
> +#include <xen/xen.h>
> +#include <xen/xen-ops.h>
> +#include <xen/events.h>
> +#include <xen/interface/xen.h>
> +#include <xen/interface/event_channel.h>
> +
> +#include "events_internal.h"
> +
> +/*
> + * Note sizeof(xen_ulong_t) can be more than sizeof(unsigned long). Be
> + * careful to only use bitops which allow for this (e.g
> + * test_bit/find_first_bit and friends but not __ffs) and to pass
> + * BITS_PER_EVTCHN_WORD as the bitmask length.
> + */
> +#define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8)
> +/*
> + * Make a bitmask (i.e. unsigned long *) of a xen_ulong_t
> + * array. Primarily to avoid long lines (hence the terse name).
> + */
> +#define BM(x) (unsigned long *)(x)
> +/* Find the first set bit in a evtchn mask */
> +#define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD)
> +
> +static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD],
> +		      cpu_evtchn_mask);
> +
> +void xen_evtchn_port_bind_to_cpu(struct irq_info *info, int cpu)
> +{
> +	clear_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, info->cpu)));
> +	set_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
> +}
> +
> +void clear_evtchn(int port)
> +{
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	sync_clear_bit(port, BM(&s->evtchn_pending[0]));
> +}
> +
> +void set_evtchn(int port)
> +{
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	sync_set_bit(port, BM(&s->evtchn_pending[0]));
> +}
> +
> +int test_evtchn(int port)
> +{
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	return sync_test_bit(port, BM(&s->evtchn_pending[0]));
> +}
> +
> +int test_and_set_mask(int port)
> +{
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
> +}
> +
> +void mask_evtchn(int port)
> +{
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	sync_set_bit(port, BM(&s->evtchn_mask[0]));
> +}
> +
> +void unmask_evtchn(int port)
> +{
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	unsigned int cpu = get_cpu();
> +	int do_hypercall = 0, evtchn_pending = 0;
> +
> +	BUG_ON(!irqs_disabled());
> +
> +	if (unlikely((cpu != cpu_from_evtchn(port))))
> +		do_hypercall = 1;
> +	else {
> +		/*
> +		 * Need to clear the mask before checking pending to
> +		 * avoid a race with an event becoming pending.
> +		 *
> +		 * EVTCHNOP_unmask will only trigger an upcall if the
> +		 * mask bit was set, so if a hypercall is needed
> +		 * remask the event.
> +		 */
> +		sync_clear_bit(port, BM(&s->evtchn_mask[0]));
> +		evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
> +
> +		if (unlikely(evtchn_pending && xen_hvm_domain())) {
> +			sync_set_bit(port, BM(&s->evtchn_mask[0]));
> +			do_hypercall = 1;
> +		}
> +	}
> +
> +	/* Slow path (hypercall) if this is a non-local port or if this is
> +	 * an hvm domain and an event is pending (hvm domains don't have
> +	 * their own implementation of irq_enable). */
> +	if (do_hypercall) {
> +		struct evtchn_unmask unmask = { .port = port };
> +		(void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
> +	} else {
> +		struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
> +
> +		/*
> +		 * The following is basically the equivalent of
> +		 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
> +		 * the interrupt edge' if the channel is masked.
> +		 */
> +		if (evtchn_pending &&
> +		    !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD,
> +					   BM(&vcpu_info->evtchn_pending_sel)))
> +			vcpu_info->evtchn_upcall_pending = 1;
> +	}
> +
> +	put_cpu();
> +}
> +
> +static DEFINE_PER_CPU(unsigned int, current_word_idx);
> +static DEFINE_PER_CPU(unsigned int, current_bit_idx);
> +
> +/*
> + * Mask out the i least significant bits of w
> + */
> +#define MASK_LSBS(w, i) (w & ((~((xen_ulong_t)0UL)) << i))
> +
> +static inline xen_ulong_t active_evtchns(unsigned int cpu,
> +					 struct shared_info *sh,
> +					 unsigned int idx)
> +{
> +	return sh->evtchn_pending[idx] &
> +		per_cpu(cpu_evtchn_mask, cpu)[idx] &
> +		~sh->evtchn_mask[idx];
> +}
> +
> +/*
> + * Search the CPU's pending events bitmasks.  For each one found, map
> + * the event number to an irq, and feed it into do_IRQ() for handling.
> + *
> + * Xen uses a two-level bitmap to speed searching.  The first level is
> + * a bitset of words which contain pending event bits.  The second
> + * level is a bitset of pending events themselves.
> + */
> +void xen_evtchn_handle_events(int cpu)
> +{
> +	int irq;
> +	xen_ulong_t pending_words;
> +	xen_ulong_t pending_bits;
> +	int start_word_idx, start_bit_idx;
> +	int word_idx, bit_idx;
> +	int i;
> +	struct irq_desc *desc;
> +	struct shared_info *s = HYPERVISOR_shared_info;
> +	struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
> +
> +	/* Timer interrupt has highest priority. */
> +	irq = irq_from_virq(cpu, VIRQ_TIMER);
> +	if (irq != -1) {
> +		unsigned int evtchn = evtchn_from_irq(irq);
> +		word_idx = evtchn / BITS_PER_LONG;
> +		bit_idx = evtchn % BITS_PER_LONG;
> +		if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx)) {
> +			desc = irq_to_desc(irq);
> +			if (desc)
> +				generic_handle_irq_desc(irq, desc);
> +		}
> +	}
> +
> +	/*
> +	 * Master flag must be cleared /before/ clearing
> +	 * selector flag. xchg_xen_ulong must contain an
> +	 * appropriate barrier.
> +	 */
> +	pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0);
> +
> +	start_word_idx = __this_cpu_read(current_word_idx);
> +	start_bit_idx = __this_cpu_read(current_bit_idx);
> +
> +	word_idx = start_word_idx;
> +
> +	for (i = 0; pending_words != 0; i++) {
> +		xen_ulong_t words;
> +
> +		words = MASK_LSBS(pending_words, word_idx);
> +
> +		/*
> +		 * If we masked out all events, wrap to beginning.
> +		 */
> +		if (words == 0) {
> +			word_idx = 0;
> +			bit_idx = 0;
> +			continue;
> +		}
> +		word_idx = EVTCHN_FIRST_BIT(words);
> +
> +		pending_bits = active_evtchns(cpu, s, word_idx);
> +		bit_idx = 0; /* usually scan entire word from start */
> +		/*
> +		 * We scan the starting word in two parts.
> +		 *
> +		 * 1st time: start in the middle, scanning the
> +		 * upper bits.
> +		 *
> +		 * 2nd time: scan the whole word (not just the
> +		 * parts skipped in the first pass) -- if an
> +		 * event in the previously scanned bits is
> +		 * pending again it would just be scanned on
> +		 * the next loop anyway.
> +		 */
> +		if (word_idx == start_word_idx) {
> +			if (i == 0)
> +				bit_idx = start_bit_idx;
> +		}
> +
> +		do {
> +			xen_ulong_t bits;
> +			int port;
> +
> +			bits = MASK_LSBS(pending_bits, bit_idx);
> +
> +			/* If we masked out all events, move on. */
> +			if (bits == 0)
> +				break;
> +
> +			bit_idx = EVTCHN_FIRST_BIT(bits);
> +
> +			/* Process port. */
> +			port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
> +			irq = evtchn_to_irq[port];
> +
> +			if (irq != -1) {
> +				desc = irq_to_desc(irq);
> +				if (desc)
> +					generic_handle_irq_desc(irq, desc);
> +			}
> +
> +			bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD;
> +
> +			/* Next caller starts at last processed + 1 */
> +			__this_cpu_write(current_word_idx,
> +					 bit_idx ? word_idx :
> +					 (word_idx+1) % BITS_PER_EVTCHN_WORD);
> +			__this_cpu_write(current_bit_idx, bit_idx);
> +		} while (bit_idx != 0);
> +
> +		/* Scan start_l1i twice; all others once. */
> +		if ((word_idx != start_word_idx) || (i != 0))
> +			pending_words &= ~(1UL << word_idx);
> +
> +		word_idx = (word_idx + 1) % BITS_PER_EVTCHN_WORD;
> +	}
> +}
> +
> +irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
> +{
> +	struct shared_info *sh = HYPERVISOR_shared_info;
> +	int cpu = smp_processor_id();
> +	xen_ulong_t *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu);
> +	int i;
> +	unsigned long flags;
> +	static DEFINE_SPINLOCK(debug_lock);
> +	struct vcpu_info *v;
> +
> +	spin_lock_irqsave(&debug_lock, flags);
> +
> +	printk("\nvcpu %d\n  ", cpu);
> +
> +	for_each_online_cpu(i) {
> +		int pending;
> +		v = per_cpu(xen_vcpu, i);
> +		pending = (get_irq_regs() && i == cpu)
> +			? xen_irqs_disabled(get_irq_regs())
> +			: v->evtchn_upcall_mask;
> +		printk("%d: masked=%d pending=%d event_sel %0*"PRI_xen_ulong"\n  ", i,
> +		       pending, v->evtchn_upcall_pending,
> +		       (int)(sizeof(v->evtchn_pending_sel)*2),
> +		       v->evtchn_pending_sel);
> +	}
> +	v = per_cpu(xen_vcpu, cpu);
> +
> +	printk("\npending:\n   ");
> +	for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
> +		printk("%0*"PRI_xen_ulong"%s",
> +		       (int)sizeof(sh->evtchn_pending[0])*2,
> +		       sh->evtchn_pending[i],
> +		       i % 8 == 0 ? "\n   " : " ");
> +	printk("\nglobal mask:\n   ");
> +	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
> +		printk("%0*"PRI_xen_ulong"%s",
> +		       (int)(sizeof(sh->evtchn_mask[0])*2),
> +		       sh->evtchn_mask[i],
> +		       i % 8 == 0 ? "\n   " : " ");
> +
> +	printk("\nglobally unmasked:\n   ");
> +	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
> +		printk("%0*"PRI_xen_ulong"%s",
> +		       (int)(sizeof(sh->evtchn_mask[0])*2),
> +		       sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
> +		       i % 8 == 0 ? "\n   " : " ");
> +
> +	printk("\nlocal cpu%d mask:\n   ", cpu);
> +	for (i = (NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD)-1; i >= 0; i--)
> +		printk("%0*"PRI_xen_ulong"%s", (int)(sizeof(cpu_evtchn[0])*2),
> +		       cpu_evtchn[i],
> +		       i % 8 == 0 ? "\n   " : " ");
> +
> +	printk("\nlocally unmasked:\n   ");
> +	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
> +		xen_ulong_t pending = sh->evtchn_pending[i]
> +			& ~sh->evtchn_mask[i]
> +			& cpu_evtchn[i];
> +		printk("%0*"PRI_xen_ulong"%s",
> +		       (int)(sizeof(sh->evtchn_mask[0])*2),
> +		       pending, i % 8 == 0 ? "\n   " : " ");
> +	}
> +
> +	printk("\npending list:\n");
> +	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
> +		if (sync_test_bit(i, BM(sh->evtchn_pending))) {
> +			int word_idx = i / BITS_PER_EVTCHN_WORD;
> +			printk("  %d: event %d -> irq %d%s%s%s\n",
> +			       cpu_from_evtchn(i), i,
> +			       evtchn_to_irq[i],
> +			       sync_test_bit(word_idx, BM(&v->evtchn_pending_sel))
> +			       ? "" : " l2-clear",
> +			       !sync_test_bit(i, BM(sh->evtchn_mask))
> +			       ? "" : " globally-masked",
> +			       sync_test_bit(i, BM(cpu_evtchn))
> +			       ? "" : " locally-masked");
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&debug_lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
> index fec5da4..8771b74 100644
> --- a/drivers/xen/events/events_base.c
> +++ b/drivers/xen/events/events_base.c
> @@ -59,6 +59,8 @@
>   #include <xen/interface/vcpu.h>
>   #include <asm/hw_irq.h>
>   
> +#include "events_internal.h"
> +
>   /*
>    * This lock protects updates to the following mapping and reference-count
>    * arrays. The lock does not need to be acquired to read the mapping tables.
> @@ -73,72 +75,12 @@ static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1};
>   /* IRQ <-> IPI mapping */
>   static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1};
>   
> -/* Interrupt types. */
> -enum xen_irq_type {
> -	IRQT_UNBOUND = 0,
> -	IRQT_PIRQ,
> -	IRQT_VIRQ,
> -	IRQT_IPI,
> -	IRQT_EVTCHN
> -};
> -
> -/*
> - * Packed IRQ information:
> - * type - enum xen_irq_type
> - * event channel - irq->event channel mapping
> - * cpu - cpu this event channel is bound to
> - * index - type-specific information:
> - *    PIRQ - physical IRQ, GSI, flags, and owner domain
> - *    VIRQ - virq number
> - *    IPI - IPI vector
> - *    EVTCHN -
> - */
> -struct irq_info {
> -	struct list_head list;
> -	int refcnt;
> -	enum xen_irq_type type;	/* type */
> -	unsigned irq;
> -	unsigned short evtchn;	/* event channel */
> -	unsigned short cpu;	/* cpu bound */
> -
> -	union {
> -		unsigned short virq;
> -		enum ipi_vector ipi;
> -		struct {
> -			unsigned short pirq;
> -			unsigned short gsi;
> -			unsigned char flags;
> -			uint16_t domid;
> -		} pirq;
> -	} u;
> -};
> -#define PIRQ_NEEDS_EOI	(1 << 0)
> -#define PIRQ_SHAREABLE	(1 << 1)
> -
> -static int *evtchn_to_irq;
> +int *evtchn_to_irq;
>   #ifdef CONFIG_X86
>   static unsigned long *pirq_eoi_map;
>   #endif
>   static bool (*pirq_needs_eoi)(unsigned irq);
>   
> -/*
> - * Note sizeof(xen_ulong_t) can be more than sizeof(unsigned long). Be
> - * careful to only use bitops which allow for this (e.g
> - * test_bit/find_first_bit and friends but not __ffs) and to pass
> - * BITS_PER_EVTCHN_WORD as the bitmask length.
> - */
> -#define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8)
> -/*
> - * Make a bitmask (i.e. unsigned long *) of a xen_ulong_t
> - * array. Primarily to avoid long lines (hence the terse name).
> - */
> -#define BM(x) (unsigned long *)(x)
> -/* Find the first set bit in a evtchn mask */
> -#define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD)
> -
> -static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD],
> -		      cpu_evtchn_mask);
> -
>   /* Xen will never allocate port zero for any purpose. */
>   #define VALID_EVTCHN(chn)	((chn) != 0)
>   
> @@ -149,7 +91,7 @@ static void enable_dynirq(struct irq_data *data);
>   static void disable_dynirq(struct irq_data *data);
>   
>   /* Get info for IRQ */
> -static struct irq_info *info_for_irq(unsigned irq)
> +struct irq_info *info_for_irq(unsigned irq)
>   {
>   	return irq_get_handler_data(irq);
>   }
> @@ -230,7 +172,7 @@ static void xen_irq_info_pirq_init(unsigned irq,
>   /*
>    * Accessors for packed IRQ information.
>    */
> -static unsigned int evtchn_from_irq(unsigned irq)
> +unsigned int evtchn_from_irq(unsigned irq)
>   {
>   	if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq)))
>   		return 0;
> @@ -244,6 +186,11 @@ unsigned irq_from_evtchn(unsigned int evtchn)
>   }
>   EXPORT_SYMBOL_GPL(irq_from_evtchn);
>   
> +int irq_from_virq(unsigned int cpu, unsigned int virq)
> +{
> +	return per_cpu(virq_to_irq, cpu)[virq];
> +}
> +
>   static enum ipi_vector ipi_from_irq(unsigned irq)
>   {
>   	struct irq_info *info = info_for_irq(irq);
> @@ -279,12 +226,12 @@ static enum xen_irq_type type_from_irq(unsigned irq)
>   	return info_for_irq(irq)->type;
>   }
>   
> -static unsigned cpu_from_irq(unsigned irq)
> +unsigned cpu_from_irq(unsigned irq)
>   {
>   	return info_for_irq(irq)->cpu;
>   }
>   
> -static unsigned int cpu_from_evtchn(unsigned int evtchn)
> +unsigned int cpu_from_evtchn(unsigned int evtchn)
>   {
>   	int irq = evtchn_to_irq[evtchn];
>   	unsigned ret = 0;
> @@ -310,55 +257,21 @@ static bool pirq_needs_eoi_flag(unsigned irq)
>   	return info->u.pirq.flags & PIRQ_NEEDS_EOI;
>   }
>   
> -static inline xen_ulong_t active_evtchns(unsigned int cpu,
> -					 struct shared_info *sh,
> -					 unsigned int idx)
> -{
> -	return sh->evtchn_pending[idx] &
> -		per_cpu(cpu_evtchn_mask, cpu)[idx] &
> -		~sh->evtchn_mask[idx];
> -}
> -
>   static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
>   {
>   	int irq = evtchn_to_irq[chn];
> +	struct irq_info *info = info_for_irq(irq);
>   
>   	BUG_ON(irq == -1);
>   #ifdef CONFIG_SMP
>   	cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
>   #endif
>   
> -	clear_bit(chn, BM(per_cpu(cpu_evtchn_mask, cpu_from_irq(irq))));
> -	set_bit(chn, BM(per_cpu(cpu_evtchn_mask, cpu)));
> +	xen_evtchn_port_bind_to_cpu(info, cpu);
>   
> -	info_for_irq(irq)->cpu = cpu;
> -}
> -
> -static inline void clear_evtchn(int port)
> -{
> -	struct shared_info *s = HYPERVISOR_shared_info;
> -	sync_clear_bit(port, BM(&s->evtchn_pending[0]));
> -}
> -
> -static inline void set_evtchn(int port)
> -{
> -	struct shared_info *s = HYPERVISOR_shared_info;
> -	sync_set_bit(port, BM(&s->evtchn_pending[0]));
> -}
> -
> -static inline int test_evtchn(int port)
> -{
> -	struct shared_info *s = HYPERVISOR_shared_info;
> -	return sync_test_bit(port, BM(&s->evtchn_pending[0]));
> -}
> -
> -static inline int test_and_set_mask(int port)
> -{
> -	struct shared_info *s = HYPERVISOR_shared_info;
> -	return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
> +	info->cpu = cpu;
>   }
>   
> -
>   /**
>    * notify_remote_via_irq - send event to remote end of event channel via irq
>    * @irq: irq of event channel to send event to
> @@ -376,63 +289,6 @@ void notify_remote_via_irq(int irq)
>   }
>   EXPORT_SYMBOL_GPL(notify_remote_via_irq);
>   
> -static void mask_evtchn(int port)
> -{
> -	struct shared_info *s = HYPERVISOR_shared_info;
> -	sync_set_bit(port, BM(&s->evtchn_mask[0]));
> -}
> -
> -static void unmask_evtchn(int port)
> -{
> -	struct shared_info *s = HYPERVISOR_shared_info;
> -	unsigned int cpu = get_cpu();
> -	int do_hypercall = 0, evtchn_pending = 0;
> -
> -	BUG_ON(!irqs_disabled());
> -
> -	if (unlikely((cpu != cpu_from_evtchn(port))))
> -		do_hypercall = 1;
> -	else {
> -		/*
> -		 * Need to clear the mask before checking pending to
> -		 * avoid a race with an event becoming pending.
> -		 *
> -		 * EVTCHNOP_unmask will only trigger an upcall if the
> -		 * mask bit was set, so if a hypercall is needed
> -		 * remask the event.
> -		 */
> -		sync_clear_bit(port, BM(&s->evtchn_mask[0]));
> -		evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
> -
> -		if (unlikely(evtchn_pending && xen_hvm_domain())) {
> -			sync_set_bit(port, BM(&s->evtchn_mask[0]));
> -			do_hypercall = 1;
> -		}
> -	}
> -
> -	/* Slow path (hypercall) if this is a non-local port or if this is
> -	 * an hvm domain and an event is pending (hvm domains don't have
> -	 * their own implementation of irq_enable). */
> -	if (do_hypercall) {
> -		struct evtchn_unmask unmask = { .port = port };
> -		(void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
> -	} else {
> -		struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
> -
> -		/*
> -		 * The following is basically the equivalent of
> -		 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
> -		 * the interrupt edge' if the channel is masked.
> -		 */
> -		if (evtchn_pending &&
> -		    !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD,
> -					   BM(&vcpu_info->evtchn_pending_sel)))
> -			vcpu_info->evtchn_upcall_pending = 1;
> -	}
> -
> -	put_cpu();
> -}
> -
>   static void xen_irq_init(unsigned irq)
>   {
>   	struct irq_info *info;
> @@ -1216,222 +1072,21 @@ void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
>   	notify_remote_via_irq(irq);
>   }
>   
> -irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
> -{
> -	struct shared_info *sh = HYPERVISOR_shared_info;
> -	int cpu = smp_processor_id();
> -	xen_ulong_t *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu);
> -	int i;
> -	unsigned long flags;
> -	static DEFINE_SPINLOCK(debug_lock);
> -	struct vcpu_info *v;
> -
> -	spin_lock_irqsave(&debug_lock, flags);
> -
> -	printk("\nvcpu %d\n  ", cpu);
> -
> -	for_each_online_cpu(i) {
> -		int pending;
> -		v = per_cpu(xen_vcpu, i);
> -		pending = (get_irq_regs() && i == cpu)
> -			? xen_irqs_disabled(get_irq_regs())
> -			: v->evtchn_upcall_mask;
> -		printk("%d: masked=%d pending=%d event_sel %0*"PRI_xen_ulong"\n  ", i,
> -		       pending, v->evtchn_upcall_pending,
> -		       (int)(sizeof(v->evtchn_pending_sel)*2),
> -		       v->evtchn_pending_sel);
> -	}
> -	v = per_cpu(xen_vcpu, cpu);
> -
> -	printk("\npending:\n   ");
> -	for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
> -		printk("%0*"PRI_xen_ulong"%s",
> -		       (int)sizeof(sh->evtchn_pending[0])*2,
> -		       sh->evtchn_pending[i],
> -		       i % 8 == 0 ? "\n   " : " ");
> -	printk("\nglobal mask:\n   ");
> -	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
> -		printk("%0*"PRI_xen_ulong"%s",
> -		       (int)(sizeof(sh->evtchn_mask[0])*2),
> -		       sh->evtchn_mask[i],
> -		       i % 8 == 0 ? "\n   " : " ");
> -
> -	printk("\nglobally unmasked:\n   ");
> -	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
> -		printk("%0*"PRI_xen_ulong"%s",
> -		       (int)(sizeof(sh->evtchn_mask[0])*2),
> -		       sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
> -		       i % 8 == 0 ? "\n   " : " ");
> -
> -	printk("\nlocal cpu%d mask:\n   ", cpu);
> -	for (i = (NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD)-1; i >= 0; i--)
> -		printk("%0*"PRI_xen_ulong"%s", (int)(sizeof(cpu_evtchn[0])*2),
> -		       cpu_evtchn[i],
> -		       i % 8 == 0 ? "\n   " : " ");
> -
> -	printk("\nlocally unmasked:\n   ");
> -	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
> -		xen_ulong_t pending = sh->evtchn_pending[i]
> -			& ~sh->evtchn_mask[i]
> -			& cpu_evtchn[i];
> -		printk("%0*"PRI_xen_ulong"%s",
> -		       (int)(sizeof(sh->evtchn_mask[0])*2),
> -		       pending, i % 8 == 0 ? "\n   " : " ");
> -	}
> -
> -	printk("\npending list:\n");
> -	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
> -		if (sync_test_bit(i, BM(sh->evtchn_pending))) {
> -			int word_idx = i / BITS_PER_EVTCHN_WORD;
> -			printk("  %d: event %d -> irq %d%s%s%s\n",
> -			       cpu_from_evtchn(i), i,
> -			       evtchn_to_irq[i],
> -			       sync_test_bit(word_idx, BM(&v->evtchn_pending_sel))
> -					     ? "" : " l2-clear",
> -			       !sync_test_bit(i, BM(sh->evtchn_mask))
> -					     ? "" : " globally-masked",
> -			       sync_test_bit(i, BM(cpu_evtchn))
> -					     ? "" : " locally-masked");
> -		}
> -	}
> -
> -	spin_unlock_irqrestore(&debug_lock, flags);
> -
> -	return IRQ_HANDLED;
> -}
> -
>   static DEFINE_PER_CPU(unsigned, xed_nesting_count);
> -static DEFINE_PER_CPU(unsigned int, current_word_idx);
> -static DEFINE_PER_CPU(unsigned int, current_bit_idx);
>   
> -/*
> - * Mask out the i least significant bits of w
> - */
> -#define MASK_LSBS(w, i) (w & ((~((xen_ulong_t)0UL)) << i))
> -
> -/*
> - * Search the CPUs pending events bitmasks.  For each one found, map
> - * the event number to an irq, and feed it into do_IRQ() for
> - * handling.
> - *
> - * Xen uses a two-level bitmap to speed searching.  The first level is
> - * a bitset of words which contain pending event bits.  The second
> - * level is a bitset of pending events themselves.
> - */
>   static void __xen_evtchn_do_upcall(void)
>   {
> -	int start_word_idx, start_bit_idx;
> -	int word_idx, bit_idx;
> -	int i, irq;
> -	int cpu = get_cpu();
> -	struct shared_info *s = HYPERVISOR_shared_info;
>   	struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
> +	int cpu = get_cpu();
>   	unsigned count;
>   
>   	do {
> -		xen_ulong_t pending_words;
> -		xen_ulong_t pending_bits;
> -		struct irq_desc *desc;
> -
>   		vcpu_info->evtchn_upcall_pending = 0;
>   
>   		if (__this_cpu_inc_return(xed_nesting_count) - 1)
>   			goto out;
>   
> -		/*
> -		 * Master flag must be cleared /before/ clearing
> -		 * selector flag. xchg_xen_ulong must contain an
> -		 * appropriate barrier.
> -		 */
> -		if ((irq = per_cpu(virq_to_irq, cpu)[VIRQ_TIMER]) != -1) {
> -			int evtchn = evtchn_from_irq(irq);
> -			word_idx = evtchn / BITS_PER_LONG;
> -			pending_bits = evtchn % BITS_PER_LONG;
> -			if (active_evtchns(cpu, s, word_idx) & (1ULL << pending_bits)) {
> -				desc = irq_to_desc(irq);
> -				if (desc)
> -					generic_handle_irq_desc(irq, desc);
> -			}
> -		}
> -
> -		pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0);
> -
> -		start_word_idx = __this_cpu_read(current_word_idx);
> -		start_bit_idx = __this_cpu_read(current_bit_idx);
> -
> -		word_idx = start_word_idx;
> -
> -		for (i = 0; pending_words != 0; i++) {
> -			xen_ulong_t words;
> -
> -			words = MASK_LSBS(pending_words, word_idx);
> -
> -			/*
> -			 * If we masked out all events, wrap to beginning.
> -			 */
> -			if (words == 0) {
> -				word_idx = 0;
> -				bit_idx = 0;
> -				continue;
> -			}
> -			word_idx = EVTCHN_FIRST_BIT(words);
> -
> -			pending_bits = active_evtchns(cpu, s, word_idx);
> -			bit_idx = 0; /* usually scan entire word from start */
> -			/*
> -			 * We scan the starting word in two parts.
> -			 *
> -			 * 1st time: start in the middle, scanning the
> -			 * upper bits.
> -			 *
> -			 * 2nd time: scan the whole word (not just the
> -			 * parts skipped in the first pass) -- if an
> -			 * event in the previously scanned bits is
> -			 * pending again it would just be scanned on
> -			 * the next loop anyway.
> -			 */
> -			if (word_idx == start_word_idx) {
> -				if (i == 0)
> -					bit_idx = start_bit_idx;
> -			}
> -
> -			do {
> -				xen_ulong_t bits;
> -				int port;
> -
> -				bits = MASK_LSBS(pending_bits, bit_idx);
> -
> -				/* If we masked out all events, move on. */
> -				if (bits == 0)
> -					break;
> -
> -				bit_idx = EVTCHN_FIRST_BIT(bits);
> -
> -				/* Process port. */
> -				port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
> -				irq = evtchn_to_irq[port];
> -
> -				if (irq != -1) {
> -					desc = irq_to_desc(irq);
> -					if (desc)
> -						generic_handle_irq_desc(irq, desc);
> -				}
> -
> -				bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD;
> -
> -				/* Next caller starts at last processed + 1 */
> -				__this_cpu_write(current_word_idx,
> -						 bit_idx ? word_idx :
> -						 (word_idx+1) % BITS_PER_EVTCHN_WORD);
> -				__this_cpu_write(current_bit_idx, bit_idx);
> -			} while (bit_idx != 0);
> -
> -			/* Scan start_l1i twice; all others once. */
> -			if ((word_idx != start_word_idx) || (i != 0))
> -				pending_words &= ~(1UL << word_idx);
> -
> -			word_idx = (word_idx + 1) % BITS_PER_EVTCHN_WORD;
> -		}
> +		xen_evtchn_handle_events(cpu);
>   
>   		BUG_ON(!irqs_disabled());
>   
> diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h
> new file mode 100644
> index 0000000..79ac70b
> --- /dev/null
> +++ b/drivers/xen/events/events_internal.h
> @@ -0,0 +1,74 @@
> +/*
> + * Xen Event Channels (internal header)
> + *
> + * Copyright (C) 2013 Citrix Systems R&D Ltd.
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2 or later.  See the file COPYING for more details.
> + */
> +#ifndef __EVENTS_INTERNAL_H__
> +#define __EVENTS_INTERNAL_H__
> +
> +/* Interrupt types. */
> +enum xen_irq_type {
> +	IRQT_UNBOUND = 0,
> +	IRQT_PIRQ,
> +	IRQT_VIRQ,
> +	IRQT_IPI,
> +	IRQT_EVTCHN
> +};
> +
> +/*
> + * Packed IRQ information:
> + * type - enum xen_irq_type
> + * event channel - irq->event channel mapping
> + * cpu - cpu this event channel is bound to
> + * index - type-specific information:
> + *    PIRQ - vector, with MSB being "needs EIO", or physical IRQ of the HVM
> + *           guest, or GSI (real passthrough IRQ) of the device.
> + *    VIRQ - virq number
> + *    IPI - IPI vector
> + *    EVTCHN -
> + */
> +struct irq_info {
> +	struct list_head list;
> +	int refcnt;
> +	enum xen_irq_type type;	/* type */
> +	unsigned irq;
> +	unsigned short evtchn;	/* event channel */
> +	unsigned short cpu;	/* cpu bound */
> +
> +	union {
> +		unsigned short virq;
> +		enum ipi_vector ipi;
> +		struct {
> +			unsigned short pirq;
> +			unsigned short gsi;
> +			unsigned char vector;
> +			unsigned char flags;
> +			uint16_t domid;
> +		} pirq;
> +	} u;
> +};
> +
> +#define PIRQ_NEEDS_EOI	(1 << 0)
> +#define PIRQ_SHAREABLE	(1 << 1)
> +
> +extern int *evtchn_to_irq;
> +
> +struct irq_info *info_for_irq(unsigned irq);
> +unsigned cpu_from_irq(unsigned irq);
> +unsigned cpu_from_evtchn(unsigned int evtchn);
> +
> +void xen_evtchn_port_bind_to_cpu(struct irq_info *info, int cpu);
> +
> +void clear_evtchn(int port);
> +void set_evtchn(int port);
> +int test_evtchn(int port);
> +int test_and_set_mask(int port);
> +void mask_evtchn(int port);
> +void unmask_evtchn(int port);
> +
> +void xen_evtchn_handle_events(int cpu);
> +
> +#endif /* #ifndef __EVENTS_INTERNAL_H__ */
> diff --git a/include/xen/events.h b/include/xen/events.h
> index c9ea10e..32ae0f2 100644
> --- a/include/xen/events.h
> +++ b/include/xen/events.h
> @@ -73,6 +73,8 @@ void xen_poll_irq_timeout(int irq, u64 timeout);
>   
>   /* Determine the IRQ which is bound to an event channel */
>   unsigned irq_from_evtchn(unsigned int evtchn);
> +int irq_from_virq(unsigned int cpu, unsigned int virq);
> +unsigned int evtchn_from_irq(unsigned irq);
>   
>   /* Xen HVM evtchn vector callback */
>   void xen_hvm_callback_vector(void);

  reply	other threads:[~2013-10-21 14:34 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-10-18 14:23 [PATCHv7 00/16] Linux: FIFO-based event channel ABI David Vrabel
2013-10-18 14:23 ` [PATCH 01/16] xen/events: refactor retrigger_dynirq() and resend_irq_on_evtchn() David Vrabel
2013-10-18 14:23 ` [PATCH 02/16] xen/events: remove unnecessary init_evtchn_cpu_bindings() David Vrabel
2013-10-18 14:23 ` [PATCH 03/16] xen/events: introduce test_and_set_mask() David Vrabel
2013-10-18 14:23 ` [PATCH 04/16] xen/events: replace raw bit ops with functions David Vrabel
2013-10-18 14:23 ` [PATCH 05/16] xen/events: move drivers/xen/events.c into drivers/xen/events/ David Vrabel
2013-10-18 14:23 ` [PATCH 06/16] xen/events: move 2-level specific code into its own file David Vrabel
2013-10-21 14:34   ` Boris Ostrovsky [this message]
2013-10-18 14:23 ` [PATCH 07/16] xen/events: add struct evtchn_ops for the low-level port operations David Vrabel
2013-10-18 14:23 ` [PATCH 08/16] xen/events: allow setup of irq_info to fail David Vrabel
2013-10-18 14:23 ` [PATCH 09/16] xen/events: add a evtchn_op for port setup David Vrabel
2013-10-18 14:23 ` [PATCH 10/16] xen/events: Refactor evtchn_to_irq array to be dynamically allocated David Vrabel
2013-10-18 14:23 ` [PATCH 11/16] xen/events: add xen_evtchn_mask_all() David Vrabel
2013-10-18 14:23 ` [PATCH 12/16] xen/evtchn: support more than 4096 ports David Vrabel
2013-10-18 14:23 ` [PATCH 13/16] xen/events: Add the hypervisor interface for the FIFO-based event channels David Vrabel
2013-10-18 14:23 ` [PATCH 14/16] xen/events: allow event channel priority to be set David Vrabel
2013-10-18 14:23 ` [PATCH 15/16] xen/x86: set VIRQ_TIMER priority to maximum David Vrabel
2013-10-18 14:23 ` [PATCH 16/16] xen/events: use the FIFO-based ABI if available David Vrabel
2013-10-21 18:23 ` [PATCHv7 00/16] Linux: FIFO-based event channel ABI Boris Ostrovsky
2013-10-25 13:06 ` Konrad Rzeszutek Wilk
2013-10-25 23:02   ` David Vrabel
2013-10-28 15:42     ` Konrad Rzeszutek Wilk
  -- strict thread matches above, loose matches on Subject: below --
2013-11-11 16:12 [PATCHv9 " David Vrabel
2013-11-11 16:12 ` [PATCH 06/16] xen/events: move 2-level specific code into its own file David Vrabel
2013-10-31 15:09 [PATCHv8 00/16] Linux: FIFO-based event channel ABI David Vrabel
2013-10-31 15:09 ` [PATCH 06/16] xen/events: move 2-level specific code into its own file David Vrabel
2013-10-08 12:48 [PATCHv6 00/16] Linux: FIFO-based event channel ABI David Vrabel
2013-10-08 12:49 ` [PATCH 06/16] xen/events: move 2-level specific code into its own file David Vrabel
2013-10-14 16:50   ` Boris Ostrovsky
2013-10-14 16:53     ` David Vrabel
2013-10-02 17:14 [PATCHv5 00/16] Linux: FIFO-based event channel ABI David Vrabel
2013-10-02 17:14 ` [PATCH 06/16] xen/events: move 2-level specific code into its own file David Vrabel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=52653B8F.3030905@oracle.com \
    --to=boris.ostrovsky@oracle.com \
    --cc=david.vrabel@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).