All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.