[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <47E91589.50906@goop.org>
Date: Tue, 25 Mar 2008 08:08:57 -0700
From: Jeremy Fitzhardinge <jeremy@...p.org>
To: "Dong, Eddie" <eddie.dong@...el.com>
CC: virtualization@...ts.linux-foundation.org,
linux-kernel@...r.kernel.org,
Andrew Morton <akpm@...ux-foundation.org>,
linux-ia64@...r.kernel.org, kvm-ia64-devel@...ts.sourceforge.net,
xen-ia64-devel@...ts.xensource.com
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 <eddie.dong@...el.com>
>
> 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 <jeremy@...source.com>, 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 <jeremy@...source.com>, 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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists