2008-03-20 09:13:59

by Dong, Eddie

[permalink] [raw]
Subject: Xen common code across architecture

Jeremy & all:
Current xen kernel codes are in arch/x86/xen, but xen dynamic
irqchip (events.c) are common for other architectures such as IA64. We
are in progress with enabling pv_ops for IA64 now and want to reuse same
code, do we need to move the code to some place common? suggestions?
Thanks, eddie


2008-03-20 14:27:00

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: Xen common code across architecture

Dong, Eddie wrote:
> Current xen kernel codes are in arch/x86/xen, but xen dynamic
> irqchip (events.c) are common for other architectures such as IA64. We
> are in progress with enabling pv_ops for IA64 now and want to reuse same
> code, do we need to move the code to some place common? suggestions?

I'm fine with moving common stuff like that to drivers/xen/.

J

2008-03-25 06:17:08

by Dong, Eddie

[permalink] [raw]
Subject: RE: Xen common code across architecture

Jeremy/Andrew:

Isaku Yamahata, I and some other IA64/Xen community memebers are

working together to enable pv_ops for IA64 Linux. This patch is a
preparation to
move common arch/x86/xen/events.c to drivers/xen (contents are
identical) against
mm tree, it is based on Yamahata's IA64/pv_ops patch serie.
In case you want to have a brief view of whole pv_ops/IA64 patch
serie,
please refer to IA64 Linux mailinglist.

Thanks, Eddie


Move events.c to drivers/xen for IA64/Xen
support.


Signed-off-by: Yaozu (Eddie) Dong <[email protected]>

diff -urN old/arch/x86/xen/events.c linux/arch/x86/xen/events.c
--- old/arch/x86/xen/events.c 2008-03-10 13:22:27.000000000 +0800
+++ linux/arch/x86/xen/events.c 1970-01-01 08:00:00.000000000 +0800
@@ -1,591 +0,0 @@
-/*
- * Xen event channels
- *
- * Xen models interrupts with abstract event channels. Because each
- * domain gets 1024 event channels, but NR_IRQ is not that large, we
- * must dynamically map irqs<->event channels. The event channels
- * interface with the rest of the kernel by defining a xen interrupt
- * chip. When an event is recieved, it is mapped to an irq and sent
- * through the normal interrupt processing path.
- *
- * There are four kinds of events which can be mapped to an event
- * channel:
- *
- * 1. Inter-domain notifications. This includes all the virtual
- * device events, since they're driven by front-ends in another
domain
- * (typically dom0).
- * 2. VIRQs, typically used for timers. These are per-cpu events.
- * 3. IPIs.
- * 4. Hardware interrupts. Not supported at present.
- *
- * Jeremy Fitzhardinge <[email protected]>, XenSource Inc, 2007
- */
-
-#include <linux/linkage.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/string.h>
-
-#include <asm/ptrace.h>
-#include <asm/irq.h>
-#include <asm/sync_bitops.h>
-#include <asm/xen/hypercall.h>
-#include <asm/xen/hypervisor.h>
-
-#include <xen/events.h>
-#include <xen/interface/xen.h>
-#include <xen/interface/event_channel.h>
-
-#include "xen-ops.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.
- */
-static DEFINE_SPINLOCK(irq_mapping_update_lock);
-
-/* IRQ <-> VIRQ mapping. */
-static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1]
= -1};
-
-/* IRQ <-> IPI mapping */
-static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ...
XEN_NR_IPIS-1] = -1};
-
-/* Packed IRQ information: binding type, sub-type index, and event
channel. */
-struct packed_irq
-{
- unsigned short evtchn;
- unsigned char index;
- unsigned char type;
-};
-
-static struct packed_irq irq_info[NR_IRQS];
-
-/* Binding types. */
-enum {
- IRQT_UNBOUND,
- IRQT_PIRQ,
- IRQT_VIRQ,
- IRQT_IPI,
- IRQT_EVTCHN
-};
-
-/* Convenient shorthand for packed representation of an unbound IRQ. */
-#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
-
-static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
- [0 ... NR_EVENT_CHANNELS-1] = -1
-};
-static unsigned long
cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
-static u8 cpu_evtchn[NR_EVENT_CHANNELS];
-
-/* Reference counts for bindings to IRQs. */
-static int irq_bindcount[NR_IRQS];
-
-/* Xen will never allocate port zero for any purpose. */
-#define VALID_EVTCHN(chn) ((chn) != 0)
-
-/*
- * Force a proper event-channel callback from Xen after clearing the
- * callback mask. We do this in a very simple manner, by making a call
- * down into Xen. The pending flag will be checked by Xen on return.
- */
-void force_evtchn_callback(void)
-{
- (void)HYPERVISOR_xen_version(0, NULL);
-}
-EXPORT_SYMBOL_GPL(force_evtchn_callback);
-
-static struct irq_chip xen_dynamic_chip;
-
-/* Constructor for packed IRQ information. */
-static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32
evtchn)
-{
- return (struct packed_irq) { evtchn, index, type };
-}
-
-/*
- * Accessors for packed IRQ information.
- */
-static inline unsigned int evtchn_from_irq(int irq)
-{
- return irq_info[irq].evtchn;
-}
-
-static inline unsigned int index_from_irq(int irq)
-{
- return irq_info[irq].index;
-}
-
-static inline unsigned int type_from_irq(int irq)
-{
- return irq_info[irq].type;
-}
-
-static inline unsigned long active_evtchns(unsigned int cpu,
- struct shared_info *sh,
- unsigned int idx)
-{
- return (sh->evtchn_pending[idx] &
- 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];
-
- BUG_ON(irq == -1);
-#ifdef CONFIG_SMP
- irq_desc[irq].affinity = cpumask_of_cpu(cpu);
-#endif
-
- __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
- __set_bit(chn, cpu_evtchn_mask[cpu]);
-
- cpu_evtchn[chn] = cpu;
-}
-
-static void init_evtchn_cpu_bindings(void)
-{
-#ifdef CONFIG_SMP
- int i;
- /* By default all event channels notify CPU#0. */
- for (i = 0; i < NR_IRQS; i++)
- irq_desc[i].affinity = cpumask_of_cpu(0);
-#endif
-
- memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
- memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
-}
-
-static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
-{
- return cpu_evtchn[evtchn];
-}
-
-static inline void clear_evtchn(int port)
-{
- struct shared_info *s = HYPERVISOR_shared_info;
- sync_clear_bit(port, &s->evtchn_pending[0]);
-}
-
-static inline void set_evtchn(int port)
-{
- struct shared_info *s = HYPERVISOR_shared_info;
- sync_set_bit(port, &s->evtchn_pending[0]);
-}
-
-
-/**
- * notify_remote_via_irq - send event to remote end of event channel
via irq
- * @irq: irq of event channel to send event to
- *
- * Unlike notify_remote_via_evtchn(), this is safe to use across
- * save/restore. Notifications on a broken connection are silently
- * dropped.
- */
-void notify_remote_via_irq(int irq)
-{
- int evtchn = evtchn_from_irq(irq);
-
- if (VALID_EVTCHN(evtchn))
- notify_remote_via_evtchn(evtchn);
-}
-EXPORT_SYMBOL_GPL(notify_remote_via_irq);
-
-static void mask_evtchn(int port)
-{
- struct shared_info *s = HYPERVISOR_shared_info;
- sync_set_bit(port, &s->evtchn_mask[0]);
-}
-
-static void unmask_evtchn(int port)
-{
- struct shared_info *s = HYPERVISOR_shared_info;
- unsigned int cpu = get_cpu();
-
- BUG_ON(!irqs_disabled());
-
- /* Slow path (hypercall) if this is a non-local port. */
- if (unlikely(cpu != cpu_from_evtchn(port))) {
- struct evtchn_unmask unmask = { .port = port };
- (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask,
&unmask);
- } else {
- struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
-
- sync_clear_bit(port, &s->evtchn_mask[0]);
-
- /*
- * 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 (sync_test_bit(port, &s->evtchn_pending[0]) &&
- !sync_test_and_set_bit(port / BITS_PER_LONG,
-
&vcpu_info->evtchn_pending_sel))
- vcpu_info->evtchn_upcall_pending = 1;
- }
-
- put_cpu();
-}
-
-static int find_unbound_irq(void)
-{
- int irq;
-
- /* Only allocate from dynirq range */
- for (irq = 0; irq < NR_IRQS; irq++)
- if (irq_bindcount[irq] == 0)
- break;
-
- if (irq == NR_IRQS)
- panic("No available IRQ to bind to: increase
NR_IRQS!\n");
-
- return irq;
-}
-
-int bind_evtchn_to_irq(unsigned int evtchn)
-{
- int irq;
-
- spin_lock(&irq_mapping_update_lock);
-
- irq = evtchn_to_irq[evtchn];
-
- if (irq == -1) {
- irq = find_unbound_irq();
-
- dynamic_irq_init(irq);
- set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
- handle_level_irq,
"event");
-
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
- }
-
- irq_bindcount[irq]++;
-
- spin_unlock(&irq_mapping_update_lock);
-
- return irq;
-}
-EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
-
-static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
-{
- struct evtchn_bind_ipi bind_ipi;
- int evtchn, irq;
-
- spin_lock(&irq_mapping_update_lock);
-
- irq = per_cpu(ipi_to_irq, cpu)[ipi];
- if (irq == -1) {
- irq = find_unbound_irq();
- if (irq < 0)
- goto out;
-
- dynamic_irq_init(irq);
- set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
- handle_level_irq, "ipi");
-
- bind_ipi.vcpu = cpu;
- if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
- &bind_ipi) != 0)
- BUG();
- evtchn = bind_ipi.port;
-
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
-
- per_cpu(ipi_to_irq, cpu)[ipi] = irq;
-
- bind_evtchn_to_cpu(evtchn, cpu);
- }
-
- irq_bindcount[irq]++;
-
- out:
- spin_unlock(&irq_mapping_update_lock);
- return irq;
-}
-
-
-static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
-{
- struct evtchn_bind_virq bind_virq;
- int evtchn, irq;
-
- spin_lock(&irq_mapping_update_lock);
-
- irq = per_cpu(virq_to_irq, cpu)[virq];
-
- if (irq == -1) {
- bind_virq.virq = virq;
- bind_virq.vcpu = cpu;
- if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
- &bind_virq) != 0)
- BUG();
- evtchn = bind_virq.port;
-
- irq = find_unbound_irq();
-
- dynamic_irq_init(irq);
- set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
- handle_level_irq, "virq");
-
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
-
- per_cpu(virq_to_irq, cpu)[virq] = irq;
-
- bind_evtchn_to_cpu(evtchn, cpu);
- }
-
- irq_bindcount[irq]++;
-
- spin_unlock(&irq_mapping_update_lock);
-
- return irq;
-}
-
-static void unbind_from_irq(unsigned int irq)
-{
- struct evtchn_close close;
- int evtchn = evtchn_from_irq(irq);
-
- spin_lock(&irq_mapping_update_lock);
-
- if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
- close.port = evtchn;
- if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)
!= 0)
- BUG();
-
- switch (type_from_irq(irq)) {
- case IRQT_VIRQ:
- per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
- [index_from_irq(irq)] = -1;
- break;
- default:
- break;
- }
-
- /* Closed ports are implicitly re-bound to VCPU0. */
- bind_evtchn_to_cpu(evtchn, 0);
-
- evtchn_to_irq[evtchn] = -1;
- irq_info[irq] = IRQ_UNBOUND;
-
- dynamic_irq_init(irq);
- }
-
- spin_unlock(&irq_mapping_update_lock);
-}
-
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
- irq_handler_t handler,
- unsigned long irqflags,
- const char *devname, void *dev_id)
-{
- unsigned int irq;
- int retval;
-
- irq = bind_evtchn_to_irq(evtchn);
- retval = request_irq(irq, handler, irqflags, devname, dev_id);
- if (retval != 0) {
- unbind_from_irq(irq);
- return retval;
- }
-
- return irq;
-}
-EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
-
-int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
- irq_handler_t handler,
- unsigned long irqflags, const char *devname,
void *dev_id)
-{
- unsigned int irq;
- int retval;
-
- irq = bind_virq_to_irq(virq, cpu);
- retval = request_irq(irq, handler, irqflags, devname, dev_id);
- if (retval != 0) {
- unbind_from_irq(irq);
- return retval;
- }
-
- return irq;
-}
-EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
-
-int bind_ipi_to_irqhandler(enum ipi_vector ipi,
- unsigned int cpu,
- irq_handler_t handler,
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- int irq, retval;
-
- irq = bind_ipi_to_irq(ipi, cpu);
- if (irq < 0)
- return irq;
-
- retval = request_irq(irq, handler, irqflags, devname, dev_id);
- if (retval != 0) {
- unbind_from_irq(irq);
- return retval;
- }
-
- return irq;
-}
-
-void unbind_from_irqhandler(unsigned int irq, void *dev_id)
-{
- free_irq(irq, dev_id);
- unbind_from_irq(irq);
-}
-EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
-
-void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
-{
- int irq = per_cpu(ipi_to_irq, cpu)[vector];
- BUG_ON(irq < 0);
- notify_remote_via_irq(irq);
-}
-
-
-/*
- * 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.
- */
-void xen_evtchn_do_upcall(struct pt_regs *regs)
-{
- int cpu = get_cpu();
- struct shared_info *s = HYPERVISOR_shared_info;
- struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
- unsigned long pending_words;
-
- vcpu_info->evtchn_upcall_pending = 0;
-
- /* NB. No need for a barrier here -- XCHG is a barrier on x86.
*/
- pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
- while (pending_words != 0) {
- unsigned long pending_bits;
- int word_idx = __ffs(pending_words);
- pending_words &= ~(1UL << word_idx);
-
- while ((pending_bits = active_evtchns(cpu, s, word_idx))
!= 0) {
- int bit_idx = __ffs(pending_bits);
- int port = (word_idx * BITS_PER_LONG) + bit_idx;
- int irq = evtchn_to_irq[port];
-
- if (irq != -1) {
- regs->orig_ax = ~irq;
- do_IRQ(regs);
- }
- }
- }
-
- put_cpu();
-}
-
-/* Rebind an evtchn so that it gets delivered to a specific cpu */
-static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
-{
- struct evtchn_bind_vcpu bind_vcpu;
- int evtchn = evtchn_from_irq(irq);
-
- if (!VALID_EVTCHN(evtchn))
- return;
-
- /* Send future instances of this interrupt to other vcpu. */
- bind_vcpu.port = evtchn;
- bind_vcpu.vcpu = tcpu;
-
- /*
- * If this fails, it usually just indicates that we're dealing
with a
- * virq or IPI channel, which don't actually need to be rebound.
Ignore
- * it, but don't do the xenlinux-level rebind in that case.
- */
- if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu)
>= 0)
- bind_evtchn_to_cpu(evtchn, tcpu);
-}
-
-
-static void set_affinity_irq(unsigned irq, cpumask_t dest)
-{
- unsigned tcpu = first_cpu(dest);
- rebind_irq_to_cpu(irq, tcpu);
-}
-
-static void enable_dynirq(unsigned int irq)
-{
- int evtchn = evtchn_from_irq(irq);
-
- if (VALID_EVTCHN(evtchn))
- unmask_evtchn(evtchn);
-}
-
-static void disable_dynirq(unsigned int irq)
-{
- int evtchn = evtchn_from_irq(irq);
-
- if (VALID_EVTCHN(evtchn))
- mask_evtchn(evtchn);
-}
-
-static void ack_dynirq(unsigned int irq)
-{
- int evtchn = evtchn_from_irq(irq);
-
- move_native_irq(irq);
-
- if (VALID_EVTCHN(evtchn))
- clear_evtchn(evtchn);
-}
-
-static int retrigger_dynirq(unsigned int irq)
-{
- int evtchn = evtchn_from_irq(irq);
- int ret = 0;
-
- if (VALID_EVTCHN(evtchn)) {
- set_evtchn(evtchn);
- ret = 1;
- }
-
- return ret;
-}
-
-static struct irq_chip xen_dynamic_chip __read_mostly = {
- .name = "xen-dyn",
- .mask = disable_dynirq,
- .unmask = enable_dynirq,
- .ack = ack_dynirq,
- .set_affinity = set_affinity_irq,
- .retrigger = retrigger_dynirq,
-};
-
-void __init xen_init_IRQ(void)
-{
- int i;
-
- init_evtchn_cpu_bindings();
-
- /* No event channels are 'live' right now. */
- for (i = 0; i < NR_EVENT_CHANNELS; i++)
- mask_evtchn(i);
-
- /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
- for (i = 0; i < NR_IRQS; i++)
- irq_bindcount[i] = 0;
-
- irq_ctx_init(smp_processor_id());
-}
diff -urN old/arch/x86/xen/Makefile linux/arch/x86/xen/Makefile
--- old/arch/x86/xen/Makefile 2008-03-10 13:22:27.000000000 +0800
+++ linux/arch/x86/xen/Makefile 2008-03-25 13:56:41.367764448 +0800
@@ -1,4 +1,4 @@
obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \
- events.o time.o manage.o xen-asm.o
+ time.o manage.o xen-asm.o

obj-$(CONFIG_SMP) += smp.o
diff -urN old/arch/x86/xen/xen-ops.h linux/arch/x86/xen/xen-ops.h
--- old/arch/x86/xen/xen-ops.h 2008-03-25 13:21:09.996527604 +0800
+++ linux/arch/x86/xen/xen-ops.h 2008-03-25 13:59:16.349809137
+0800
@@ -2,6 +2,7 @@
#define XEN_OPS_H

#include <linux/init.h>
+#include <xen/xen-ops.h>

/* These are code, but not functions. Defined in entry.S */
extern const char xen_hypervisor_callback[];
@@ -9,7 +10,6 @@

void xen_copy_trap_info(struct trap_info *traps);

-DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
DECLARE_PER_CPU(unsigned long, xen_cr3);
DECLARE_PER_CPU(unsigned long, xen_current_cr3);

diff -urN old/drivers/xen/events.c linux/drivers/xen/events.c
--- old/drivers/xen/events.c 1970-01-01 08:00:00.000000000 +0800
+++ linux/drivers/xen/events.c 2008-03-25 13:56:41.368764287 +0800
@@ -0,0 +1,591 @@
+/*
+ * Xen event channels
+ *
+ * Xen models interrupts with abstract event channels. Because each
+ * domain gets 1024 event channels, but NR_IRQ is not that large, we
+ * must dynamically map irqs<->event channels. The event channels
+ * interface with the rest of the kernel by defining a xen interrupt
+ * chip. When an event is recieved, it is mapped to an irq and sent
+ * through the normal interrupt processing path.
+ *
+ * There are four kinds of events which can be mapped to an event
+ * channel:
+ *
+ * 1. Inter-domain notifications. This includes all the virtual
+ * device events, since they're driven by front-ends in another
domain
+ * (typically dom0).
+ * 2. VIRQs, typically used for timers. These are per-cpu events.
+ * 3. IPIs.
+ * 4. Hardware interrupts. Not supported at present.
+ *
+ * Jeremy Fitzhardinge <[email protected]>, XenSource Inc, 2007
+ */
+
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/sync_bitops.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+
+#include "xen-ops.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.
+ */
+static DEFINE_SPINLOCK(irq_mapping_update_lock);
+
+/* IRQ <-> VIRQ mapping. */
+static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1]
= -1};
+
+/* IRQ <-> IPI mapping */
+static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ...
XEN_NR_IPIS-1] = -1};
+
+/* Packed IRQ information: binding type, sub-type index, and event
channel. */
+struct packed_irq
+{
+ unsigned short evtchn;
+ unsigned char index;
+ unsigned char type;
+};
+
+static struct packed_irq irq_info[NR_IRQS];
+
+/* Binding types. */
+enum {
+ IRQT_UNBOUND,
+ IRQT_PIRQ,
+ IRQT_VIRQ,
+ IRQT_IPI,
+ IRQT_EVTCHN
+};
+
+/* Convenient shorthand for packed representation of an unbound IRQ. */
+#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
+
+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
+ [0 ... NR_EVENT_CHANNELS-1] = -1
+};
+static unsigned long
cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+/* Xen will never allocate port zero for any purpose. */
+#define VALID_EVTCHN(chn) ((chn) != 0)
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void force_evtchn_callback(void)
+{
+ (void)HYPERVISOR_xen_version(0, NULL);
+}
+EXPORT_SYMBOL_GPL(force_evtchn_callback);
+
+static struct irq_chip xen_dynamic_chip;
+
+/* Constructor for packed IRQ information. */
+static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32
evtchn)
+{
+ return (struct packed_irq) { evtchn, index, type };
+}
+
+/*
+ * Accessors for packed IRQ information.
+ */
+static inline unsigned int evtchn_from_irq(int irq)
+{
+ return irq_info[irq].evtchn;
+}
+
+static inline unsigned int index_from_irq(int irq)
+{
+ return irq_info[irq].index;
+}
+
+static inline unsigned int type_from_irq(int irq)
+{
+ return irq_info[irq].type;
+}
+
+static inline unsigned long active_evtchns(unsigned int cpu,
+ struct shared_info *sh,
+ unsigned int idx)
+{
+ return (sh->evtchn_pending[idx] &
+ 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];
+
+ BUG_ON(irq == -1);
+#ifdef CONFIG_SMP
+ irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+#endif
+
+ __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
+ __set_bit(chn, cpu_evtchn_mask[cpu]);
+
+ cpu_evtchn[chn] = cpu;
+}
+
+static void init_evtchn_cpu_bindings(void)
+{
+#ifdef CONFIG_SMP
+ int i;
+ /* By default all event channels notify CPU#0. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_desc[i].affinity = cpumask_of_cpu(0);
+#endif
+
+ memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
+ memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
+}
+
+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
+{
+ return cpu_evtchn[evtchn];
+}
+
+static inline void clear_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_clear_bit(port, &s->evtchn_pending[0]);
+}
+
+static inline void set_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_set_bit(port, &s->evtchn_pending[0]);
+}
+
+
+/**
+ * notify_remote_via_irq - send event to remote end of event channel
via irq
+ * @irq: irq of event channel to send event to
+ *
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently
+ * dropped.
+ */
+void notify_remote_via_irq(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ notify_remote_via_evtchn(evtchn);
+}
+EXPORT_SYMBOL_GPL(notify_remote_via_irq);
+
+static void mask_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_set_bit(port, &s->evtchn_mask[0]);
+}
+
+static void unmask_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ unsigned int cpu = get_cpu();
+
+ BUG_ON(!irqs_disabled());
+
+ /* Slow path (hypercall) if this is a non-local port. */
+ if (unlikely(cpu != cpu_from_evtchn(port))) {
+ struct evtchn_unmask unmask = { .port = port };
+ (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask,
&unmask);
+ } else {
+ struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+
+ sync_clear_bit(port, &s->evtchn_mask[0]);
+
+ /*
+ * 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 (sync_test_bit(port, &s->evtchn_pending[0]) &&
+ !sync_test_and_set_bit(port / BITS_PER_LONG,
+
&vcpu_info->evtchn_pending_sel))
+ vcpu_info->evtchn_upcall_pending = 1;
+ }
+
+ put_cpu();
+}
+
+static int find_unbound_irq(void)
+{
+ int irq;
+
+ /* Only allocate from dynirq range */
+ for (irq = 0; irq < NR_IRQS; irq++)
+ if (irq_bindcount[irq] == 0)
+ break;
+
+ if (irq == NR_IRQS)
+ panic("No available IRQ to bind to: increase
NR_IRQS!\n");
+
+ return irq;
+}
+
+int bind_evtchn_to_irq(unsigned int evtchn)
+{
+ int irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = evtchn_to_irq[evtchn];
+
+ if (irq == -1) {
+ irq = find_unbound_irq();
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq,
"event");
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
+ }
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
+
+static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+{
+ struct evtchn_bind_ipi bind_ipi;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = per_cpu(ipi_to_irq, cpu)[ipi];
+ if (irq == -1) {
+ irq = find_unbound_irq();
+ if (irq < 0)
+ goto out;
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "ipi");
+
+ bind_ipi.vcpu = cpu;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+ &bind_ipi) != 0)
+ BUG();
+ evtchn = bind_ipi.port;
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
+
+ per_cpu(ipi_to_irq, cpu)[ipi] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+
+ irq_bindcount[irq]++;
+
+ out:
+ spin_unlock(&irq_mapping_update_lock);
+ return irq;
+}
+
+
+static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+{
+ struct evtchn_bind_virq bind_virq;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = per_cpu(virq_to_irq, cpu)[virq];
+
+ if (irq == -1) {
+ bind_virq.virq = virq;
+ bind_virq.vcpu = cpu;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+ &bind_virq) != 0)
+ BUG();
+ evtchn = bind_virq.port;
+
+ irq = find_unbound_irq();
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "virq");
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
+
+ per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+
+static void unbind_from_irq(unsigned int irq)
+{
+ struct evtchn_close close;
+ int evtchn = evtchn_from_irq(irq);
+
+ spin_lock(&irq_mapping_update_lock);
+
+ if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
+ close.port = evtchn;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)
!= 0)
+ BUG();
+
+ switch (type_from_irq(irq)) {
+ case IRQT_VIRQ:
+ per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
+ [index_from_irq(irq)] = -1;
+ break;
+ default:
+ break;
+ }
+
+ /* Closed ports are implicitly re-bound to VCPU0. */
+ bind_evtchn_to_cpu(evtchn, 0);
+
+ evtchn_to_irq[evtchn] = -1;
+ irq_info[irq] = IRQ_UNBOUND;
+
+ dynamic_irq_init(irq);
+ }
+
+ spin_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+ irq_handler_t handler,
+ unsigned long irqflags,
+ const char *devname, void *dev_id)
+{
+ unsigned int irq;
+ int retval;
+
+ irq = bind_evtchn_to_irq(evtchn);
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
+
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
void *dev_id)
+{
+ unsigned int irq;
+ int retval;
+
+ irq = bind_virq_to_irq(virq, cpu);
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
+
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id)
+{
+ int irq, retval;
+
+ irq = bind_ipi_to_irq(ipi, cpu);
+ if (irq < 0)
+ return irq;
+
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+
+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
+{
+ free_irq(irq, dev_id);
+ unbind_from_irq(irq);
+}
+EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
+{
+ int irq = per_cpu(ipi_to_irq, cpu)[vector];
+ BUG_ON(irq < 0);
+ notify_remote_via_irq(irq);
+}
+
+
+/*
+ * 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.
+ */
+void xen_evtchn_do_upcall(struct pt_regs *regs)
+{
+ int cpu = get_cpu();
+ struct shared_info *s = HYPERVISOR_shared_info;
+ struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+ unsigned long pending_words;
+
+ vcpu_info->evtchn_upcall_pending = 0;
+
+ /* NB. No need for a barrier here -- XCHG is a barrier on x86.
*/
+ pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
+ while (pending_words != 0) {
+ unsigned long pending_bits;
+ int word_idx = __ffs(pending_words);
+ pending_words &= ~(1UL << word_idx);
+
+ while ((pending_bits = active_evtchns(cpu, s, word_idx))
!= 0) {
+ int bit_idx = __ffs(pending_bits);
+ int port = (word_idx * BITS_PER_LONG) + bit_idx;
+ int irq = evtchn_to_irq[port];
+
+ if (irq != -1) {
+ regs->orig_ax = ~irq;
+ do_IRQ(regs);
+ }
+ }
+ }
+
+ put_cpu();
+}
+
+/* Rebind an evtchn so that it gets delivered to a specific cpu */
+static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+{
+ struct evtchn_bind_vcpu bind_vcpu;
+ int evtchn = evtchn_from_irq(irq);
+
+ if (!VALID_EVTCHN(evtchn))
+ return;
+
+ /* Send future instances of this interrupt to other vcpu. */
+ bind_vcpu.port = evtchn;
+ bind_vcpu.vcpu = tcpu;
+
+ /*
+ * If this fails, it usually just indicates that we're dealing
with a
+ * virq or IPI channel, which don't actually need to be rebound.
Ignore
+ * it, but don't do the xenlinux-level rebind in that case.
+ */
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu)
>= 0)
+ bind_evtchn_to_cpu(evtchn, tcpu);
+}
+
+
+static void set_affinity_irq(unsigned irq, cpumask_t dest)
+{
+ unsigned tcpu = first_cpu(dest);
+ rebind_irq_to_cpu(irq, tcpu);
+}
+
+static void enable_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ unmask_evtchn(evtchn);
+}
+
+static void disable_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ mask_evtchn(evtchn);
+}
+
+static void ack_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ move_native_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ clear_evtchn(evtchn);
+}
+
+static int retrigger_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+ int ret = 0;
+
+ if (VALID_EVTCHN(evtchn)) {
+ set_evtchn(evtchn);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static struct irq_chip xen_dynamic_chip __read_mostly = {
+ .name = "xen-dyn",
+ .mask = disable_dynirq,
+ .unmask = enable_dynirq,
+ .ack = ack_dynirq,
+ .set_affinity = set_affinity_irq,
+ .retrigger = retrigger_dynirq,
+};
+
+void __init xen_init_IRQ(void)
+{
+ int i;
+
+ init_evtchn_cpu_bindings();
+
+ /* No event channels are 'live' right now. */
+ for (i = 0; i < NR_EVENT_CHANNELS; i++)
+ mask_evtchn(i);
+
+ /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_bindcount[i] = 0;
+
+ irq_ctx_init(smp_processor_id());
+}
diff -urN old/drivers/xen/Makefile linux/drivers/xen/Makefile
--- old/drivers/xen/Makefile 2008-03-10 13:22:27.000000000 +0800
+++ linux/drivers/xen/Makefile 2008-03-25 13:56:41.368764287 +0800
@@ -1,2 +1,2 @@
-obj-y += grant-table.o
+obj-y += grant-table.o events.o
obj-y += xenbus/
diff -urN old/include/xen/xen-ops.h linux/include/xen/xen-ops.h
--- old/include/xen/xen-ops.h 1970-01-01 08:00:00.000000000 +0800
+++ linux/include/xen/xen-ops.h 2008-03-25 14:00:09.041321546 +0800
@@ -0,0 +1,6 @@
+#ifndef INCLUDE_XEN_OPS_H
+#define INCLUDE_XEN_OPS_H
+
+DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
+
+#endif /* INCLUDE_XEN_OPS_H */


Attachments:
move_xenirq3.patch (30.14 kB)
move_xenirq3.patch

2008-03-25 06:40:12

by Dong, Eddie

[permalink] [raw]
Subject: RE: Xen common code across architecture

Dong, Eddie wrote:
> Jeremy/Andrew:
>
> Isaku Yamahata, I and some other IA64/Xen community memebers are
>
> working together to enable pv_ops for IA64 Linux. This patch is a
> preparation to
> move common arch/x86/xen/events.c to drivers/xen (contents are
> identical) against
> mm tree, it is based on Yamahata's IA64/pv_ops patch serie.
> In case you want to have a brief view of whole pv_ops/IA64 patch
> serie,
> please refer to IA64 Linux mailinglist.
>
> Thanks, Eddie
>
>
Fix a typo. Merged one is attached too.


Signed-off-by: Yaozu (Eddie) Dong <[email protected]>

--- drivers/xen/events_old.c 2008-03-25 14:31:40.503525471 +0800
+++ drivers/xen/events.c 2008-03-25 14:19:39.841851430 +0800
@@ -37,7 +37,7 @@
#include <xen/interface/xen.h>
#include <xen/interface/event_channel.h>

-#include "xen-ops.h"
+#include <xen/xen-ops.h>

/*
* This lock protects updates to the following mapping and
reference-count


Attachments:
typo (350.00 B)
typo
move_xenirq3.patch (30.14 kB)
move_xenirq3.patch
Download all attachments

2008-03-25 15:13:48

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: Xen common code across architecture

Dong, Eddie wrote:
> Jeremy/Andrew:
>
> Isaku Yamahata, I and some other IA64/Xen community memebers are
>
> working together to enable pv_ops for IA64 Linux. This patch is a
> preparation to
> move common arch/x86/xen/events.c to drivers/xen (contents are
> identical) against
> mm tree, it is based on Yamahata's IA64/pv_ops patch serie.
> In case you want to have a brief view of whole pv_ops/IA64 patch
> serie,
> please refer to IA64 Linux mailinglist.
>

How do you want to manage this work? I'm currently basing off
Ingo+tglx's x86.git tree. Would you like me to track these kinds of
common-code changes in my tree, while you maintain a separate
ia64-specific tree?

> Thanks, Eddie
>
>
> Move events.c to drivers/xen for IA64/Xen
> support.
>

Looks reasonable. One comment below.

> Signed-off-by: Yaozu (Eddie) Dong <[email protected]>
>
> diff -urN old/arch/x86/xen/events.c linux/arch/x86/xen/events.c
> --- old/arch/x86/xen/events.c 2008-03-10 13:22:27.000000000 +0800
> +++ linux/arch/x86/xen/events.c 1970-01-01 08:00:00.000000000 +0800
> @@ -1,591 +0,0 @@
> -/*
> - * Xen event channels
> - *
> - * Xen models interrupts with abstract event channels. Because each
> - * domain gets 1024 event channels, but NR_IRQ is not that large, we
> - * must dynamically map irqs<->event channels. The event channels
> - * interface with the rest of the kernel by defining a xen interrupt
> - * chip. When an event is recieved, it is mapped to an irq and sent
> - * through the normal interrupt processing path.
> - *
> - * There are four kinds of events which can be mapped to an event
> - * channel:
> - *
> - * 1. Inter-domain notifications. This includes all the virtual
> - * device events, since they're driven by front-ends in another
> domain
> - * (typically dom0).
> - * 2. VIRQs, typically used for timers. These are per-cpu events.
> - * 3. IPIs.
> - * 4. Hardware interrupts. Not supported at present.
> - *
> - * Jeremy Fitzhardinge <[email protected]>, XenSource Inc, 2007
> - */
> -
> -#include <linux/linkage.h>
> -#include <linux/interrupt.h>
> -#include <linux/irq.h>
> -#include <linux/module.h>
> -#include <linux/string.h>
> -
> -#include <asm/ptrace.h>
> -#include <asm/irq.h>
> -#include <asm/sync_bitops.h>
> -#include <asm/xen/hypercall.h>
> -#include <asm/xen/hypervisor.h>
> -
> -#include <xen/events.h>
> -#include <xen/interface/xen.h>
> -#include <xen/interface/event_channel.h>
> -
> -#include "xen-ops.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.
> - */
> -static DEFINE_SPINLOCK(irq_mapping_update_lock);
> -
> -/* IRQ <-> VIRQ mapping. */
> -static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1]
> = -1};
> -
> -/* IRQ <-> IPI mapping */
> -static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ...
> XEN_NR_IPIS-1] = -1};
> -
> -/* Packed IRQ information: binding type, sub-type index, and event
> channel. */
> -struct packed_irq
> -{
> - unsigned short evtchn;
> - unsigned char index;
> - unsigned char type;
> -};
> -
> -static struct packed_irq irq_info[NR_IRQS];
> -
> -/* Binding types. */
> -enum {
> - IRQT_UNBOUND,
> - IRQT_PIRQ,
> - IRQT_VIRQ,
> - IRQT_IPI,
> - IRQT_EVTCHN
> -};
> -
> -/* Convenient shorthand for packed representation of an unbound IRQ. */
> -#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
> -
> -static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
> - [0 ... NR_EVENT_CHANNELS-1] = -1
> -};
> -static unsigned long
> cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
> -static u8 cpu_evtchn[NR_EVENT_CHANNELS];
> -
> -/* Reference counts for bindings to IRQs. */
> -static int irq_bindcount[NR_IRQS];
> -
> -/* Xen will never allocate port zero for any purpose. */
> -#define VALID_EVTCHN(chn) ((chn) != 0)
> -
> -/*
> - * Force a proper event-channel callback from Xen after clearing the
> - * callback mask. We do this in a very simple manner, by making a call
> - * down into Xen. The pending flag will be checked by Xen on return.
> - */
> -void force_evtchn_callback(void)
> -{
> - (void)HYPERVISOR_xen_version(0, NULL);
> -}
> -EXPORT_SYMBOL_GPL(force_evtchn_callback);
> -
> -static struct irq_chip xen_dynamic_chip;
> -
> -/* Constructor for packed IRQ information. */
> -static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32
> evtchn)
> -{
> - return (struct packed_irq) { evtchn, index, type };
> -}
> -
> -/*
> - * Accessors for packed IRQ information.
> - */
> -static inline unsigned int evtchn_from_irq(int irq)
> -{
> - return irq_info[irq].evtchn;
> -}
> -
> -static inline unsigned int index_from_irq(int irq)
> -{
> - return irq_info[irq].index;
> -}
> -
> -static inline unsigned int type_from_irq(int irq)
> -{
> - return irq_info[irq].type;
> -}
> -
> -static inline unsigned long active_evtchns(unsigned int cpu,
> - struct shared_info *sh,
> - unsigned int idx)
> -{
> - return (sh->evtchn_pending[idx] &
> - 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];
> -
> - BUG_ON(irq == -1);
> -#ifdef CONFIG_SMP
> - irq_desc[irq].affinity = cpumask_of_cpu(cpu);
> -#endif
> -
> - __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
> - __set_bit(chn, cpu_evtchn_mask[cpu]);
> -
> - cpu_evtchn[chn] = cpu;
> -}
> -
> -static void init_evtchn_cpu_bindings(void)
> -{
> -#ifdef CONFIG_SMP
> - int i;
> - /* By default all event channels notify CPU#0. */
> - for (i = 0; i < NR_IRQS; i++)
> - irq_desc[i].affinity = cpumask_of_cpu(0);
> -#endif
> -
> - memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
> - memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
> -}
> -
> -static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
> -{
> - return cpu_evtchn[evtchn];
> -}
> -
> -static inline void clear_evtchn(int port)
> -{
> - struct shared_info *s = HYPERVISOR_shared_info;
> - sync_clear_bit(port, &s->evtchn_pending[0]);
> -}
> -
> -static inline void set_evtchn(int port)
> -{
> - struct shared_info *s = HYPERVISOR_shared_info;
> - sync_set_bit(port, &s->evtchn_pending[0]);
> -}
> -
> -
> -/**
> - * notify_remote_via_irq - send event to remote end of event channel
> via irq
> - * @irq: irq of event channel to send event to
> - *
> - * Unlike notify_remote_via_evtchn(), this is safe to use across
> - * save/restore. Notifications on a broken connection are silently
> - * dropped.
> - */
> -void notify_remote_via_irq(int irq)
> -{
> - int evtchn = evtchn_from_irq(irq);
> -
> - if (VALID_EVTCHN(evtchn))
> - notify_remote_via_evtchn(evtchn);
> -}
> -EXPORT_SYMBOL_GPL(notify_remote_via_irq);
> -
> -static void mask_evtchn(int port)
> -{
> - struct shared_info *s = HYPERVISOR_shared_info;
> - sync_set_bit(port, &s->evtchn_mask[0]);
> -}
> -
> -static void unmask_evtchn(int port)
> -{
> - struct shared_info *s = HYPERVISOR_shared_info;
> - unsigned int cpu = get_cpu();
> -
> - BUG_ON(!irqs_disabled());
> -
> - /* Slow path (hypercall) if this is a non-local port. */
> - if (unlikely(cpu != cpu_from_evtchn(port))) {
> - struct evtchn_unmask unmask = { .port = port };
> - (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask,
> &unmask);
> - } else {
> - struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
> -
> - sync_clear_bit(port, &s->evtchn_mask[0]);
> -
> - /*
> - * 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 (sync_test_bit(port, &s->evtchn_pending[0]) &&
> - !sync_test_and_set_bit(port / BITS_PER_LONG,
> -
> &vcpu_info->evtchn_pending_sel))
> - vcpu_info->evtchn_upcall_pending = 1;
> - }
> -
> - put_cpu();
> -}
> -
> -static int find_unbound_irq(void)
> -{
> - int irq;
> -
> - /* Only allocate from dynirq range */
> - for (irq = 0; irq < NR_IRQS; irq++)
> - if (irq_bindcount[irq] == 0)
> - break;
> -
> - if (irq == NR_IRQS)
> - panic("No available IRQ to bind to: increase
> NR_IRQS!\n");
> -
> - return irq;
> -}
> -
> -int bind_evtchn_to_irq(unsigned int evtchn)
> -{
> - int irq;
> -
> - spin_lock(&irq_mapping_update_lock);
> -
> - irq = evtchn_to_irq[evtchn];
> -
> - if (irq == -1) {
> - irq = find_unbound_irq();
> -
> - dynamic_irq_init(irq);
> - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
> - handle_level_irq,
> "event");
> -
> - evtchn_to_irq[evtchn] = irq;
> - irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
> - }
> -
> - irq_bindcount[irq]++;
> -
> - spin_unlock(&irq_mapping_update_lock);
> -
> - return irq;
> -}
> -EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
> -
> -static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
> -{
> - struct evtchn_bind_ipi bind_ipi;
> - int evtchn, irq;
> -
> - spin_lock(&irq_mapping_update_lock);
> -
> - irq = per_cpu(ipi_to_irq, cpu)[ipi];
> - if (irq == -1) {
> - irq = find_unbound_irq();
> - if (irq < 0)
> - goto out;
> -
> - dynamic_irq_init(irq);
> - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
> - handle_level_irq, "ipi");
> -
> - bind_ipi.vcpu = cpu;
> - if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
> - &bind_ipi) != 0)
> - BUG();
> - evtchn = bind_ipi.port;
> -
> - evtchn_to_irq[evtchn] = irq;
> - irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
> -
> - per_cpu(ipi_to_irq, cpu)[ipi] = irq;
> -
> - bind_evtchn_to_cpu(evtchn, cpu);
> - }
> -
> - irq_bindcount[irq]++;
> -
> - out:
> - spin_unlock(&irq_mapping_update_lock);
> - return irq;
> -}
> -
> -
> -static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
> -{
> - struct evtchn_bind_virq bind_virq;
> - int evtchn, irq;
> -
> - spin_lock(&irq_mapping_update_lock);
> -
> - irq = per_cpu(virq_to_irq, cpu)[virq];
> -
> - if (irq == -1) {
> - bind_virq.virq = virq;
> - bind_virq.vcpu = cpu;
> - if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
> - &bind_virq) != 0)
> - BUG();
> - evtchn = bind_virq.port;
> -
> - irq = find_unbound_irq();
> -
> - dynamic_irq_init(irq);
> - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
> - handle_level_irq, "virq");
> -
> - evtchn_to_irq[evtchn] = irq;
> - irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
> -
> - per_cpu(virq_to_irq, cpu)[virq] = irq;
> -
> - bind_evtchn_to_cpu(evtchn, cpu);
> - }
> -
> - irq_bindcount[irq]++;
> -
> - spin_unlock(&irq_mapping_update_lock);
> -
> - return irq;
> -}
> -
> -static void unbind_from_irq(unsigned int irq)
> -{
> - struct evtchn_close close;
> - int evtchn = evtchn_from_irq(irq);
> -
> - spin_lock(&irq_mapping_update_lock);
> -
> - if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
> - close.port = evtchn;
> - if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)
> != 0)
> - BUG();
> -
> - switch (type_from_irq(irq)) {
> - case IRQT_VIRQ:
> - per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
> - [index_from_irq(irq)] = -1;
> - break;
> - default:
> - break;
> - }
> -
> - /* Closed ports are implicitly re-bound to VCPU0. */
> - bind_evtchn_to_cpu(evtchn, 0);
> -
> - evtchn_to_irq[evtchn] = -1;
> - irq_info[irq] = IRQ_UNBOUND;
> -
> - dynamic_irq_init(irq);
> - }
> -
> - spin_unlock(&irq_mapping_update_lock);
> -}
> -
> -int bind_evtchn_to_irqhandler(unsigned int evtchn,
> - irq_handler_t handler,
> - unsigned long irqflags,
> - const char *devname, void *dev_id)
> -{
> - unsigned int irq;
> - int retval;
> -
> - irq = bind_evtchn_to_irq(evtchn);
> - retval = request_irq(irq, handler, irqflags, devname, dev_id);
> - if (retval != 0) {
> - unbind_from_irq(irq);
> - return retval;
> - }
> -
> - return irq;
> -}
> -EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
> -
> -int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
> - irq_handler_t handler,
> - unsigned long irqflags, const char *devname,
> void *dev_id)
> -{
> - unsigned int irq;
> - int retval;
> -
> - irq = bind_virq_to_irq(virq, cpu);
> - retval = request_irq(irq, handler, irqflags, devname, dev_id);
> - if (retval != 0) {
> - unbind_from_irq(irq);
> - return retval;
> - }
> -
> - return irq;
> -}
> -EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
> -
> -int bind_ipi_to_irqhandler(enum ipi_vector ipi,
> - unsigned int cpu,
> - irq_handler_t handler,
> - unsigned long irqflags,
> - const char *devname,
> - void *dev_id)
> -{
> - int irq, retval;
> -
> - irq = bind_ipi_to_irq(ipi, cpu);
> - if (irq < 0)
> - return irq;
> -
> - retval = request_irq(irq, handler, irqflags, devname, dev_id);
> - if (retval != 0) {
> - unbind_from_irq(irq);
> - return retval;
> - }
> -
> - return irq;
> -}
> -
> -void unbind_from_irqhandler(unsigned int irq, void *dev_id)
> -{
> - free_irq(irq, dev_id);
> - unbind_from_irq(irq);
> -}
> -EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
> -
> -void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
> -{
> - int irq = per_cpu(ipi_to_irq, cpu)[vector];
> - BUG_ON(irq < 0);
> - notify_remote_via_irq(irq);
> -}
> -
> -
> -/*
> - * 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.
> - */
> -void xen_evtchn_do_upcall(struct pt_regs *regs)
> -{
> - int cpu = get_cpu();
> - struct shared_info *s = HYPERVISOR_shared_info;
> - struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
> - unsigned long pending_words;
> -
> - vcpu_info->evtchn_upcall_pending = 0;
> -
> - /* NB. No need for a barrier here -- XCHG is a barrier on x86.
> */
> - pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
> - while (pending_words != 0) {
> - unsigned long pending_bits;
> - int word_idx = __ffs(pending_words);
> - pending_words &= ~(1UL << word_idx);
> -
> - while ((pending_bits = active_evtchns(cpu, s, word_idx))
> != 0) {
> - int bit_idx = __ffs(pending_bits);
> - int port = (word_idx * BITS_PER_LONG) + bit_idx;
> - int irq = evtchn_to_irq[port];
> -
> - if (irq != -1) {
> - regs->orig_ax = ~irq;
> - do_IRQ(regs);
> - }
> - }
> - }
> -
> - put_cpu();
> -}
> -
> -/* Rebind an evtchn so that it gets delivered to a specific cpu */
> -static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
> -{
> - struct evtchn_bind_vcpu bind_vcpu;
> - int evtchn = evtchn_from_irq(irq);
> -
> - if (!VALID_EVTCHN(evtchn))
> - return;
> -
> - /* Send future instances of this interrupt to other vcpu. */
> - bind_vcpu.port = evtchn;
> - bind_vcpu.vcpu = tcpu;
> -
> - /*
> - * If this fails, it usually just indicates that we're dealing
> with a
> - * virq or IPI channel, which don't actually need to be rebound.
> Ignore
> - * it, but don't do the xenlinux-level rebind in that case.
> - */
> - if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu)
>
>> = 0)
>>
> - bind_evtchn_to_cpu(evtchn, tcpu);
> -}
> -
> -
> -static void set_affinity_irq(unsigned irq, cpumask_t dest)
> -{
> - unsigned tcpu = first_cpu(dest);
> - rebind_irq_to_cpu(irq, tcpu);
> -}
> -
> -static void enable_dynirq(unsigned int irq)
> -{
> - int evtchn = evtchn_from_irq(irq);
> -
> - if (VALID_EVTCHN(evtchn))
> - unmask_evtchn(evtchn);
> -}
> -
> -static void disable_dynirq(unsigned int irq)
> -{
> - int evtchn = evtchn_from_irq(irq);
> -
> - if (VALID_EVTCHN(evtchn))
> - mask_evtchn(evtchn);
> -}
> -
> -static void ack_dynirq(unsigned int irq)
> -{
> - int evtchn = evtchn_from_irq(irq);
> -
> - move_native_irq(irq);
> -
> - if (VALID_EVTCHN(evtchn))
> - clear_evtchn(evtchn);
> -}
> -
> -static int retrigger_dynirq(unsigned int irq)
> -{
> - int evtchn = evtchn_from_irq(irq);
> - int ret = 0;
> -
> - if (VALID_EVTCHN(evtchn)) {
> - set_evtchn(evtchn);
> - ret = 1;
> - }
> -
> - return ret;
> -}
> -
> -static struct irq_chip xen_dynamic_chip __read_mostly = {
> - .name = "xen-dyn",
> - .mask = disable_dynirq,
> - .unmask = enable_dynirq,
> - .ack = ack_dynirq,
> - .set_affinity = set_affinity_irq,
> - .retrigger = retrigger_dynirq,
> -};
> -
> -void __init xen_init_IRQ(void)
> -{
> - int i;
> -
> - init_evtchn_cpu_bindings();
> -
> - /* No event channels are 'live' right now. */
> - for (i = 0; i < NR_EVENT_CHANNELS; i++)
> - mask_evtchn(i);
> -
> - /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
> - for (i = 0; i < NR_IRQS; i++)
> - irq_bindcount[i] = 0;
> -
> - irq_ctx_init(smp_processor_id());
> -}
> diff -urN old/arch/x86/xen/Makefile linux/arch/x86/xen/Makefile
> --- old/arch/x86/xen/Makefile 2008-03-10 13:22:27.000000000 +0800
> +++ linux/arch/x86/xen/Makefile 2008-03-25 13:56:41.367764448 +0800
> @@ -1,4 +1,4 @@
> obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \
> - events.o time.o manage.o xen-asm.o
> + time.o manage.o xen-asm.o
>
> obj-$(CONFIG_SMP) += smp.o
> diff -urN old/arch/x86/xen/xen-ops.h linux/arch/x86/xen/xen-ops.h
> --- old/arch/x86/xen/xen-ops.h 2008-03-25 13:21:09.996527604 +0800
> +++ linux/arch/x86/xen/xen-ops.h 2008-03-25 13:59:16.349809137
> +0800
> @@ -2,6 +2,7 @@
> #define XEN_OPS_H
>
> #include <linux/init.h>
> +#include <xen/xen-ops.h>
>
> /* These are code, but not functions. Defined in entry.S */
> extern const char xen_hypervisor_callback[];
> @@ -9,7 +10,6 @@
>
> void xen_copy_trap_info(struct trap_info *traps);
>
> -DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
> DECLARE_PER_CPU(unsigned long, xen_cr3);
> DECLARE_PER_CPU(unsigned long, xen_current_cr3);
>
> diff -urN old/drivers/xen/events.c linux/drivers/xen/events.c
> --- old/drivers/xen/events.c 1970-01-01 08:00:00.000000000 +0800
> +++ linux/drivers/xen/events.c 2008-03-25 13:56:41.368764287 +0800
> @@ -0,0 +1,591 @@
> +/*
> + * Xen event channels
> + *
> + * Xen models interrupts with abstract event channels. Because each
> + * domain gets 1024 event channels, but NR_IRQ is not that large, we
> + * must dynamically map irqs<->event channels. The event channels
> + * interface with the rest of the kernel by defining a xen interrupt
> + * chip. When an event is recieved, it is mapped to an irq and sent
> + * through the normal interrupt processing path.
> + *
> + * There are four kinds of events which can be mapped to an event
> + * channel:
> + *
> + * 1. Inter-domain notifications. This includes all the virtual
> + * device events, since they're driven by front-ends in another
> domain
> + * (typically dom0).
> + * 2. VIRQs, typically used for timers. These are per-cpu events.
> + * 3. IPIs.
> + * 4. Hardware interrupts. Not supported at present.
> + *
> + * Jeremy Fitzhardinge <[email protected]>, XenSource Inc, 2007
> + */
> +
> +#include <linux/linkage.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/string.h>
> +
> +#include <asm/ptrace.h>
> +#include <asm/irq.h>
> +#include <asm/sync_bitops.h>
> +#include <asm/xen/hypercall.h>
> +#include <asm/xen/hypervisor.h>
> +
> +#include <xen/events.h>
> +#include <xen/interface/xen.h>
> +#include <xen/interface/event_channel.h>
> +
> +#include "xen-ops.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.
> + */
> +static DEFINE_SPINLOCK(irq_mapping_update_lock);
> +
> +/* IRQ <-> VIRQ mapping. */
> +static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1]
> = -1};
> +
> +/* IRQ <-> IPI mapping */
> +static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ...
> XEN_NR_IPIS-1] = -1};
> +
> +/* Packed IRQ information: binding type, sub-type index, and event
> channel. */
> +struct packed_irq
> +{
> + unsigned short evtchn;
> + unsigned char index;
> + unsigned char type;
> +};
> +
> +static struct packed_irq irq_info[NR_IRQS];
> +
> +/* Binding types. */
> +enum {
> + IRQT_UNBOUND,
> + IRQT_PIRQ,
> + IRQT_VIRQ,
> + IRQT_IPI,
> + IRQT_EVTCHN
> +};
> +
> +/* Convenient shorthand for packed representation of an unbound IRQ. */
> +#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
> +
> +static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
> + [0 ... NR_EVENT_CHANNELS-1] = -1
> +};
> +static unsigned long
> cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
> +static u8 cpu_evtchn[NR_EVENT_CHANNELS];
> +
> +/* Reference counts for bindings to IRQs. */
> +static int irq_bindcount[NR_IRQS];
> +
> +/* Xen will never allocate port zero for any purpose. */
> +#define VALID_EVTCHN(chn) ((chn) != 0)
> +
> +/*
> + * Force a proper event-channel callback from Xen after clearing the
> + * callback mask. We do this in a very simple manner, by making a call
> + * down into Xen. The pending flag will be checked by Xen on return.
> + */
> +void force_evtchn_callback(void)
> +{
> + (void)HYPERVISOR_xen_version(0, NULL);
> +}
> +EXPORT_SYMBOL_GPL(force_evtchn_callback);
> +
> +static struct irq_chip xen_dynamic_chip;
> +
> +/* Constructor for packed IRQ information. */
> +static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32
> evtchn)
> +{
> + return (struct packed_irq) { evtchn, index, type };
> +}
> +
> +/*
> + * Accessors for packed IRQ information.
> + */
> +static inline unsigned int evtchn_from_irq(int irq)
> +{
> + return irq_info[irq].evtchn;
> +}
> +
> +static inline unsigned int index_from_irq(int irq)
> +{
> + return irq_info[irq].index;
> +}
> +
> +static inline unsigned int type_from_irq(int irq)
> +{
> + return irq_info[irq].type;
> +}
> +
> +static inline unsigned long active_evtchns(unsigned int cpu,
> + struct shared_info *sh,
> + unsigned int idx)
> +{
> + return (sh->evtchn_pending[idx] &
> + 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];
> +
> + BUG_ON(irq == -1);
> +#ifdef CONFIG_SMP
> + irq_desc[irq].affinity = cpumask_of_cpu(cpu);
> +#endif
> +
> + __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
> + __set_bit(chn, cpu_evtchn_mask[cpu]);
> +
> + cpu_evtchn[chn] = cpu;
> +}
> +
> +static void init_evtchn_cpu_bindings(void)
> +{
> +#ifdef CONFIG_SMP
> + int i;
> + /* By default all event channels notify CPU#0. */
> + for (i = 0; i < NR_IRQS; i++)
> + irq_desc[i].affinity = cpumask_of_cpu(0);
> +#endif
> +
> + memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
> + memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
> +}
> +
> +static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
> +{
> + return cpu_evtchn[evtchn];
> +}
> +
> +static inline void clear_evtchn(int port)
> +{
> + struct shared_info *s = HYPERVISOR_shared_info;
> + sync_clear_bit(port, &s->evtchn_pending[0]);
> +}
> +
> +static inline void set_evtchn(int port)
> +{
> + struct shared_info *s = HYPERVISOR_shared_info;
> + sync_set_bit(port, &s->evtchn_pending[0]);
> +}
> +
> +
> +/**
> + * notify_remote_via_irq - send event to remote end of event channel
> via irq
> + * @irq: irq of event channel to send event to
> + *
> + * Unlike notify_remote_via_evtchn(), this is safe to use across
> + * save/restore. Notifications on a broken connection are silently
> + * dropped.
> + */
> +void notify_remote_via_irq(int irq)
> +{
> + int evtchn = evtchn_from_irq(irq);
> +
> + if (VALID_EVTCHN(evtchn))
> + notify_remote_via_evtchn(evtchn);
> +}
> +EXPORT_SYMBOL_GPL(notify_remote_via_irq);
> +
> +static void mask_evtchn(int port)
> +{
> + struct shared_info *s = HYPERVISOR_shared_info;
> + sync_set_bit(port, &s->evtchn_mask[0]);
> +}
> +
> +static void unmask_evtchn(int port)
> +{
> + struct shared_info *s = HYPERVISOR_shared_info;
> + unsigned int cpu = get_cpu();
> +
> + BUG_ON(!irqs_disabled());
> +
> + /* Slow path (hypercall) if this is a non-local port. */
> + if (unlikely(cpu != cpu_from_evtchn(port))) {
> + struct evtchn_unmask unmask = { .port = port };
> + (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask,
> &unmask);
> + } else {
> + struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
> +
> + sync_clear_bit(port, &s->evtchn_mask[0]);
> +
> + /*
> + * 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 (sync_test_bit(port, &s->evtchn_pending[0]) &&
> + !sync_test_and_set_bit(port / BITS_PER_LONG,
> +
> &vcpu_info->evtchn_pending_sel))
> + vcpu_info->evtchn_upcall_pending = 1;
> + }
> +
> + put_cpu();
> +}
> +
> +static int find_unbound_irq(void)
> +{
> + int irq;
> +
> + /* Only allocate from dynirq range */
> + for (irq = 0; irq < NR_IRQS; irq++)
> + if (irq_bindcount[irq] == 0)
> + break;
> +
> + if (irq == NR_IRQS)
> + panic("No available IRQ to bind to: increase
> NR_IRQS!\n");
> +
> + return irq;
> +}
> +
> +int bind_evtchn_to_irq(unsigned int evtchn)
> +{
> + int irq;
> +
> + spin_lock(&irq_mapping_update_lock);
> +
> + irq = evtchn_to_irq[evtchn];
> +
> + if (irq == -1) {
> + irq = find_unbound_irq();
> +
> + dynamic_irq_init(irq);
> + set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
> + handle_level_irq,
> "event");
> +
> + evtchn_to_irq[evtchn] = irq;
> + irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
> + }
> +
> + irq_bindcount[irq]++;
> +
> + spin_unlock(&irq_mapping_update_lock);
> +
> + return irq;
> +}
> +EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
> +
> +static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
> +{
> + struct evtchn_bind_ipi bind_ipi;
> + int evtchn, irq;
> +
> + spin_lock(&irq_mapping_update_lock);
> +
> + irq = per_cpu(ipi_to_irq, cpu)[ipi];
> + if (irq == -1) {
> + irq = find_unbound_irq();
> + if (irq < 0)
> + goto out;
> +
> + dynamic_irq_init(irq);
> + set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
> + handle_level_irq, "ipi");
> +
> + bind_ipi.vcpu = cpu;
> + if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
> + &bind_ipi) != 0)
> + BUG();
> + evtchn = bind_ipi.port;
> +
> + evtchn_to_irq[evtchn] = irq;
> + irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
> +
> + per_cpu(ipi_to_irq, cpu)[ipi] = irq;
> +
> + bind_evtchn_to_cpu(evtchn, cpu);
> + }
> +
> + irq_bindcount[irq]++;
> +
> + out:
> + spin_unlock(&irq_mapping_update_lock);
> + return irq;
> +}
> +
> +
> +static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
> +{
> + struct evtchn_bind_virq bind_virq;
> + int evtchn, irq;
> +
> + spin_lock(&irq_mapping_update_lock);
> +
> + irq = per_cpu(virq_to_irq, cpu)[virq];
> +
> + if (irq == -1) {
> + bind_virq.virq = virq;
> + bind_virq.vcpu = cpu;
> + if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
> + &bind_virq) != 0)
> + BUG();
> + evtchn = bind_virq.port;
> +
> + irq = find_unbound_irq();
> +
> + dynamic_irq_init(irq);
> + set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
> + handle_level_irq, "virq");
> +
> + evtchn_to_irq[evtchn] = irq;
> + irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
> +
> + per_cpu(virq_to_irq, cpu)[virq] = irq;
> +
> + bind_evtchn_to_cpu(evtchn, cpu);
> + }
> +
> + irq_bindcount[irq]++;
> +
> + spin_unlock(&irq_mapping_update_lock);
> +
> + return irq;
> +}
> +
> +static void unbind_from_irq(unsigned int irq)
> +{
> + struct evtchn_close close;
> + int evtchn = evtchn_from_irq(irq);
> +
> + spin_lock(&irq_mapping_update_lock);
> +
> + if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
> + close.port = evtchn;
> + if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)
> != 0)
> + BUG();
> +
> + switch (type_from_irq(irq)) {
> + case IRQT_VIRQ:
> + per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
> + [index_from_irq(irq)] = -1;
> + break;
> + default:
> + break;
> + }
> +
> + /* Closed ports are implicitly re-bound to VCPU0. */
> + bind_evtchn_to_cpu(evtchn, 0);
> +
> + evtchn_to_irq[evtchn] = -1;
> + irq_info[irq] = IRQ_UNBOUND;
> +
> + dynamic_irq_init(irq);
> + }
> +
> + spin_unlock(&irq_mapping_update_lock);
> +}
> +
> +int bind_evtchn_to_irqhandler(unsigned int evtchn,
> + irq_handler_t handler,
> + unsigned long irqflags,
> + const char *devname, void *dev_id)
> +{
> + unsigned int irq;
> + int retval;
> +
> + irq = bind_evtchn_to_irq(evtchn);
> + retval = request_irq(irq, handler, irqflags, devname, dev_id);
> + if (retval != 0) {
> + unbind_from_irq(irq);
> + return retval;
> + }
> +
> + return irq;
> +}
> +EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
> +
> +int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
> + irq_handler_t handler,
> + unsigned long irqflags, const char *devname,
> void *dev_id)
> +{
> + unsigned int irq;
> + int retval;
> +
> + irq = bind_virq_to_irq(virq, cpu);
> + retval = request_irq(irq, handler, irqflags, devname, dev_id);
> + if (retval != 0) {
> + unbind_from_irq(irq);
> + return retval;
> + }
> +
> + return irq;
> +}
> +EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
> +
> +int bind_ipi_to_irqhandler(enum ipi_vector ipi,
> + unsigned int cpu,
> + irq_handler_t handler,
> + unsigned long irqflags,
> + const char *devname,
> + void *dev_id)
> +{
> + int irq, retval;
> +
> + irq = bind_ipi_to_irq(ipi, cpu);
> + if (irq < 0)
> + return irq;
> +
> + retval = request_irq(irq, handler, irqflags, devname, dev_id);
> + if (retval != 0) {
> + unbind_from_irq(irq);
> + return retval;
> + }
> +
> + return irq;
> +}
> +
> +void unbind_from_irqhandler(unsigned int irq, void *dev_id)
> +{
> + free_irq(irq, dev_id);
> + unbind_from_irq(irq);
> +}
> +EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
> +
> +void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
> +{
> + int irq = per_cpu(ipi_to_irq, cpu)[vector];
> + BUG_ON(irq < 0);
> + notify_remote_via_irq(irq);
> +}
> +
> +
> +/*
> + * 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.
> + */
> +void xen_evtchn_do_upcall(struct pt_regs *regs)
> +{
> + int cpu = get_cpu();
> + struct shared_info *s = HYPERVISOR_shared_info;
> + struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
> + unsigned long pending_words;
> +
> + vcpu_info->evtchn_upcall_pending = 0;
> +
> + /* NB. No need for a barrier here -- XCHG is a barrier on x86.
> */
> + pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
> + while (pending_words != 0) {
> + unsigned long pending_bits;
> + int word_idx = __ffs(pending_words);
> + pending_words &= ~(1UL << word_idx);
> +
> + while ((pending_bits = active_evtchns(cpu, s, word_idx))
> != 0) {
> + int bit_idx = __ffs(pending_bits);
> + int port = (word_idx * BITS_PER_LONG) + bit_idx;
> + int irq = evtchn_to_irq[port];
> +
> + if (irq != -1) {
> + regs->orig_ax = ~irq;
> + do_IRQ(regs);
> + }
> + }
> + }
> +
> + put_cpu();
> +}
> +
> +/* Rebind an evtchn so that it gets delivered to a specific cpu */
> +static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
> +{
> + struct evtchn_bind_vcpu bind_vcpu;
> + int evtchn = evtchn_from_irq(irq);
> +
> + if (!VALID_EVTCHN(evtchn))
> + return;
> +
> + /* Send future instances of this interrupt to other vcpu. */
> + bind_vcpu.port = evtchn;
> + bind_vcpu.vcpu = tcpu;
> +
> + /*
> + * If this fails, it usually just indicates that we're dealing
> with a
> + * virq or IPI channel, which don't actually need to be rebound.
> Ignore
> + * it, but don't do the xenlinux-level rebind in that case.
> + */
> + if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu)
>
>> = 0)
>>
> + bind_evtchn_to_cpu(evtchn, tcpu);
> +}
> +
> +
> +static void set_affinity_irq(unsigned irq, cpumask_t dest)
> +{
> + unsigned tcpu = first_cpu(dest);
> + rebind_irq_to_cpu(irq, tcpu);
> +}
> +
> +static void enable_dynirq(unsigned int irq)
> +{
> + int evtchn = evtchn_from_irq(irq);
> +
> + if (VALID_EVTCHN(evtchn))
> + unmask_evtchn(evtchn);
> +}
> +
> +static void disable_dynirq(unsigned int irq)
> +{
> + int evtchn = evtchn_from_irq(irq);
> +
> + if (VALID_EVTCHN(evtchn))
> + mask_evtchn(evtchn);
> +}
> +
> +static void ack_dynirq(unsigned int irq)
> +{
> + int evtchn = evtchn_from_irq(irq);
> +
> + move_native_irq(irq);
> +
> + if (VALID_EVTCHN(evtchn))
> + clear_evtchn(evtchn);
> +}
> +
> +static int retrigger_dynirq(unsigned int irq)
> +{
> + int evtchn = evtchn_from_irq(irq);
> + int ret = 0;
> +
> + if (VALID_EVTCHN(evtchn)) {
> + set_evtchn(evtchn);
> + ret = 1;
> + }
> +
> + return ret;
> +}
> +
> +static struct irq_chip xen_dynamic_chip __read_mostly = {
> + .name = "xen-dyn",
> + .mask = disable_dynirq,
> + .unmask = enable_dynirq,
> + .ack = ack_dynirq,
> + .set_affinity = set_affinity_irq,
> + .retrigger = retrigger_dynirq,
> +};
> +
> +void __init xen_init_IRQ(void)
> +{
> + int i;
> +
> + init_evtchn_cpu_bindings();
> +
> + /* No event channels are 'live' right now. */
> + for (i = 0; i < NR_EVENT_CHANNELS; i++)
> + mask_evtchn(i);
> +
> + /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
> + for (i = 0; i < NR_IRQS; i++)
> + irq_bindcount[i] = 0;
> +
> + irq_ctx_init(smp_processor_id());
> +}
> diff -urN old/drivers/xen/Makefile linux/drivers/xen/Makefile
> --- old/drivers/xen/Makefile 2008-03-10 13:22:27.000000000 +0800
> +++ linux/drivers/xen/Makefile 2008-03-25 13:56:41.368764287 +0800
> @@ -1,2 +1,2 @@
> -obj-y += grant-table.o
> +obj-y += grant-table.o events.o
> obj-y += xenbus/
> diff -urN old/include/xen/xen-ops.h linux/include/xen/xen-ops.h
> --- old/include/xen/xen-ops.h 1970-01-01 08:00:00.000000000 +0800
> +++ linux/include/xen/xen-ops.h 2008-03-25 14:00:09.041321546 +0800
> @@ -0,0 +1,6 @@
> +#ifndef INCLUDE_XEN_OPS_H
> +#define INCLUDE_XEN_OPS_H
> +
> +DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
>

This should include <linux/percpu.h> rather than assuming it has already
been included.

J