From mboxrd@z Thu Jan 1 00:00:00 1970 From: Boris Ostrovsky 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 Message-ID: <52653B8F.3030905@oracle.com> References: <1382106206-30366-1-git-send-email-david.vrabel@citrix.com> <1382106206-30366-7-git-send-email-david.vrabel@citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; Format="flowed" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1382106206-30366-7-git-send-email-david.vrabel@citrix.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: David Vrabel Cc: Jan Beulich , xen-devel@lists.xen.org List-Id: xen-devel@lists.xenproject.org On 10/18/2013 10:23 AM, David Vrabel wrote: > From: David Vrabel > > 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 > --- > 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 > > 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 , XenSource Inc, 2007 > + */ > + > +#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt > + > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#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 > #include > > +#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);