[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN][POWERPC] SMP/IPI/MB combined
# HG changeset patch # User Jimi Xenidis <jimix@xxxxxxxxxxxxxx> # Node ID f911e945d9593aba1caa37845414ffd1596c64d0 # Parent 5909f57c8c399daf7d93fdef957c772f32a1a751 [XEN][POWERPC] SMP/IPI/MB combined This patch rolls up and rebases the following patches for submission against current tip of tree: * Memory barrier after SP store * IPI support * SMP support The only changes from the previous submission other than trivial fast-forward merges are to remove the ERAT flush, since it was comitted seperately, and to make the status messages about waiting for remote function completion ACKs only kick in after a full second has passed. Note that this path REQUIRES that some form of the dom0 Linux patch titled "Make Linux bail out of IPI vector reset" be applied. Signed-off-by: Amos Waterland <apw@xxxxxxxxxx> Signed-off-by: Jimi Xenidis <jimix@xxxxxxxxxxxxxx> Signed-off-by: Hollis Blanchard <hollisb@xxxxxxxxxx> --- xen/arch/powerpc/external.c | 32 ++++ xen/arch/powerpc/mpic.c | 9 - xen/arch/powerpc/mpic_init.c | 48 +++++++ xen/arch/powerpc/setup.c | 50 ++++--- xen/arch/powerpc/smp.c | 135 ++++++++++++++++++++- xen/include/asm-powerpc/mach-default/irq_vectors.h | 22 --- xen/include/asm-powerpc/smp.h | 17 ++ 7 files changed, 257 insertions(+), 56 deletions(-) diff -r 5909f57c8c39 -r f911e945d959 xen/arch/powerpc/external.c --- a/xen/arch/powerpc/external.c Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/arch/powerpc/external.c Wed Nov 22 14:53:13 2006 -0500 @@ -82,7 +82,16 @@ void do_external(struct cpu_user_regs *r vec = xen_mpic_get_irq(regs); - if (vec != -1) { + if (vector_is_ipi(vec)) { + /* do_IRQ is fundamentally broken for reliable IPI delivery. */ + irq_desc_t *desc = &irq_desc[vec]; + regs->entry_vector = vec; + spin_lock(&desc->lock); + desc->handler->ack(vec); + desc->action->handler(vector_to_irq(vec), desc->action->dev_id, regs); + desc->handler->end(vec); + spin_unlock(&desc->lock); + } else if (vec != -1) { DBG("EE:0x%lx isrc: %d\n", regs->msr, vec); regs->entry_vector = vec; do_IRQ(regs); @@ -253,3 +262,24 @@ int ioapic_guest_write(unsigned long phy BUG_ON(val != val); return 0; } + +void send_IPI_mask(cpumask_t mask, int vector) +{ + unsigned int cpus; + int const bits = 8 * sizeof(cpus); + + switch(vector) { + case CALL_FUNCTION_VECTOR: + case EVENT_CHECK_VECTOR: + break; + default: + BUG(); + return; + } + + BUG_ON(NR_CPUS > bits); + BUG_ON(fls(mask.bits[0]) > bits); + + cpus = mask.bits[0]; + mpic_send_ipi(vector, cpus); +} diff -r 5909f57c8c39 -r f911e945d959 xen/arch/powerpc/mpic.c --- a/xen/arch/powerpc/mpic.c Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/arch/powerpc/mpic.c Wed Nov 22 14:53:13 2006 -0500 @@ -27,10 +27,6 @@ #define alloc_bootmem(x) xmalloc_bytes(x) -#define request_irq(irq, handler, f, devname, dev_id) \ - panic("IPI requested: %d: %p: %s: %p\n", irq, handler, devname, dev_id) - -typedef int irqreturn_t; #define IRQ_NONE (0) #define IRQ_HANDLED (1) @@ -96,11 +92,6 @@ typedef int irqreturn_t; #endif #include <asm/mpic.h> #include <asm/smp.h> - -static inline void smp_message_recv(int msg, struct pt_regs *regs) -{ - return; -} #ifdef DEBUG #define DBG(fmt...) printk(fmt) diff -r 5909f57c8c39 -r f911e945d959 xen/arch/powerpc/mpic_init.c --- a/xen/arch/powerpc/mpic_init.c Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/arch/powerpc/mpic_init.c Wed Nov 22 14:53:13 2006 -0500 @@ -22,6 +22,7 @@ #include <xen/init.h> #include <xen/lib.h> #include <asm/mpic.h> +#include <errno.h> #include "mpic_init.h" #include "oftree.h" #include "of-devtree.h" @@ -358,6 +359,42 @@ static struct hw_interrupt_type *share_m #endif +static unsigned int mpic_startup_ipi(unsigned int irq) +{ + mpic->hc_ipi.enable(irq); + return 0; +} + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct cpu_user_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + int retval; + struct irqaction *action; + void (*func)(int, void *, struct cpu_user_regs *); + + action = xmalloc(struct irqaction); + if (!action) { + BUG(); + return -ENOMEM; + } + + /* Xen's handler prototype is slightly different than Linux's. */ + func = (void (*)(int, void *, struct cpu_user_regs *))handler; + + action->handler = func; + action->name = devname; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) { + BUG(); + xfree(action); + } + + return retval; +} + struct hw_interrupt_type *xen_mpic_init(struct hw_interrupt_type *xen_irq) { unsigned int isu_size; @@ -397,6 +434,11 @@ struct hw_interrupt_type *xen_mpic_init( hit = share_mpic(&mpic->hc_irq, xen_irq); printk("%s: success\n", __func__); + + mpic->hc_ipi.ack = xen_irq->ack; + mpic->hc_ipi.startup = mpic_startup_ipi; + mpic_request_ipis(); + return hit; } @@ -406,3 +448,9 @@ int xen_mpic_get_irq(struct cpu_user_reg return mpic_get_one_irq(mpic, regs); } + +int vector_is_ipi(int vector) +{ + BUG_ON(!mpic); + return (mpic->ipi_offset <= vector) && (vector < mpic->ipi_offset + 4); +} diff -r 5909f57c8c39 -r f911e945d959 xen/arch/powerpc/setup.c --- a/xen/arch/powerpc/setup.c Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/arch/powerpc/setup.c Wed Nov 22 14:53:13 2006 -0500 @@ -37,6 +37,7 @@ #include <xen/keyhandler.h> #include <acm/acm_hooks.h> #include <public/version.h> +#include <asm/mpic.h> #include <asm/processor.h> #include <asm/desc.h> #include <asm/cache.h> @@ -88,6 +89,8 @@ struct ns16550_defaults ns16550; extern char __per_cpu_start[], __per_cpu_data_end[], __per_cpu_end[]; +static struct domain *idle_domain; + volatile struct processor_area * volatile global_cpu_table[NR_CPUS]; int is_kernel_text(unsigned long addr) @@ -159,8 +162,6 @@ static void percpu_free_unused_areas(voi static void __init start_of_day(void) { - struct domain *idle_domain; - init_IRQ(); scheduler_init(); @@ -175,23 +176,6 @@ static void __init start_of_day(void) /* for some reason we need to set our own bit in the thread map */ cpu_set(0, cpu_sibling_map[0]); - percpu_free_unused_areas(); - - { - /* FIXME: Xen assumes that an online CPU is a schedualable - * CPU, but we just are not there yet. Remove this fragment when - * scheduling processors actually works. */ - int cpuid; - - printk("WARNING!: Taking all secondary CPUs offline\n"); - - for_each_online_cpu(cpuid) { - if (cpuid == 0) - continue; - cpu_clear(cpuid, cpu_online_map); - } - } - initialize_keytable(); /* Register another key that will allow for the the Harware Probe * to be contacted, this works with RiscWatch probes and should @@ -201,7 +185,6 @@ static void __init start_of_day(void) timer_init(); serial_init_postirq(); do_initcalls(); - schedulers_start(); } void startup_cpu_idle_loop(void) @@ -234,6 +217,7 @@ static void init_parea(int cpuid) pa->whoami = cpuid; pa->hard_id = cpu_hard_id[cpuid]; pa->hyp_stack_base = (void *)((ulong)stack + STACK_SIZE); + mb(); /* This store has the effect of invoking secondary_cpu_init. */ global_cpu_table[cpuid] = pa; @@ -263,9 +247,22 @@ static int kick_secondary_cpus(int maxcp /* This is the first C code that secondary processors invoke. */ int secondary_cpu_init(int cpuid, unsigned long r4) { + struct vcpu *vcpu; + cpu_initialize(cpuid); smp_generic_take_timebase(); + + /* If we are online, we must be able to ACK IPIs. */ + mpic_setup_this_cpu(); cpu_set(cpuid, cpu_online_map); + + vcpu = alloc_vcpu(idle_domain, cpuid, cpuid); + BUG_ON(vcpu == NULL); + + set_current(idle_domain->vcpu[cpuid]); + idle_vcpu[cpuid] = current; + startup_cpu_idle_loop(); + while(1); } @@ -336,6 +333,10 @@ static void __init __start_xen(multiboot debugger_trap_immediate(); #endif + start_of_day(); + + mpic_setup_this_cpu(); + /* Deal with secondary processors. */ if (opt_nosmp || ofd_boot_cpu == -1) { printk("nosmp: leaving secondary processors spinning forever\n"); @@ -344,7 +345,11 @@ static void __init __start_xen(multiboot kick_secondary_cpus(max_cpus); } - start_of_day(); + /* Secondary processors must be online before we call this. */ + schedulers_start(); + + /* This cannot be called before secondary cpus are marked online. */ + percpu_free_unused_areas(); /* Create initial domain 0. */ dom0 = domain_create(0, 0); @@ -403,6 +408,9 @@ static void __init __start_xen(multiboot console_end_sync(); domain_unpause_by_systemcontroller(dom0); +#ifdef DEBUG_IPI + ipi_torture_test(); +#endif startup_cpu_idle_loop(); } diff -r 5909f57c8c39 -r f911e945d959 xen/arch/powerpc/smp.c --- a/xen/arch/powerpc/smp.c Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/arch/powerpc/smp.c Wed Nov 22 14:53:13 2006 -0500 @@ -22,6 +22,8 @@ #include <xen/smp.h> #include <asm/flushtlb.h> #include <asm/debugger.h> +#include <asm/mpic.h> +#include <asm/mach-default/irq_vectors.h> int smp_num_siblings = 1; int smp_num_cpus = 1; @@ -50,7 +52,7 @@ void smp_send_event_check_mask(cpumask_t { cpu_clear(smp_processor_id(), mask); if (!cpus_empty(mask)) - unimplemented(); + send_IPI_mask(mask, EVENT_CHECK_VECTOR); } @@ -65,8 +67,20 @@ int smp_call_function(void (*func) (void void smp_send_stop(void) { - unimplemented(); -} + BUG(); +} + +struct call_data_struct { + void (*func) (void *info); + void *info; + int wait; + atomic_t started; + atomic_t finished; + cpumask_t selected; +}; + +static DEFINE_SPINLOCK(call_lock); +static struct call_data_struct call_data; int on_selected_cpus( cpumask_t selected, @@ -75,6 +89,115 @@ int on_selected_cpus( int retry, int wait) { - unimplemented(); - return 0; -} + int t, retval = 0, nr_cpus = cpus_weight(selected); + + spin_lock(&call_lock); + + call_data.func = func; + call_data.info = info; + call_data.wait = wait; + call_data.wait = 1; /* Until we get RCU around call_data. */ + atomic_set(&call_data.started, 0); + atomic_set(&call_data.finished, 0); + mb(); + + send_IPI_mask(selected, CALL_FUNCTION_VECTOR); + + /* We always wait for an initiation ACK from remote CPU. */ + for (t = 0; atomic_read(&call_data.started) != nr_cpus; t++) { + if (t && t % timebase_freq == 0) { + printk("IPI start stall: %d ACKS to %d SYNS\n", + atomic_read(&call_data.started), nr_cpus); + } + } + + /* If told to, we wait for a completion ACK from remote CPU. */ + if (wait) { + for (t = 0; atomic_read(&call_data.finished) != nr_cpus; t++) { + if (t > timebase_freq && t % timebase_freq == 0) { + printk("IPI finish stall: %d ACKS to %d SYNS\n", + atomic_read(&call_data.finished), nr_cpus); + } + } + } + + spin_unlock(&call_lock); + + return retval; +} + +void smp_call_function_interrupt(struct cpu_user_regs *regs) +{ + + void (*func)(void *info) = call_data.func; + void *info = call_data.info; + int wait = call_data.wait; + + atomic_inc(&call_data.started); + mb(); + (*func)(info); + mb(); + + if (wait) + atomic_inc(&call_data.finished); + + return; +} + +void smp_event_check_interrupt(void) +{ + /* We are knocked out of NAP state at least. */ + return; +} + +void smp_message_recv(int msg, struct cpu_user_regs *regs) +{ + switch(msg) { + case CALL_FUNCTION_VECTOR: + smp_call_function_interrupt(regs); + break; + case EVENT_CHECK_VECTOR: + smp_event_check_interrupt(); + break; + default: + BUG(); + break; + } +} + +#ifdef DEBUG_IPI +static void debug_ipi_ack(void *info) +{ + return; +} + +void ipi_torture_test(void) +{ + int cpu; + unsigned long before, after, delta; + unsigned long min = ~0, max = 0, mean = 0, sum = 0, tick = 0; + cpumask_t mask; + + cpus_clear(mask); + + while (tick < 1000000) { + for_each_online_cpu(cpu) { + cpu_set(cpu, mask); + before = mftb(); + on_selected_cpus(mask, debug_ipi_ack, NULL, 1, 1); + after = mftb(); + cpus_clear(mask); + + delta = after - before; + if (delta > max) max = delta; + if (delta < min) min = delta; + sum += delta; + tick++; + } + } + + mean = sum / tick; + + printk("IPI tb ticks: min = %ld max = %ld mean = %ld\n", min, max, mean); +} +#endif diff -r 5909f57c8c39 -r f911e945d959 xen/include/asm-powerpc/mach-default/irq_vectors.h --- a/xen/include/asm-powerpc/mach-default/irq_vectors.h Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/include/asm-powerpc/mach-default/irq_vectors.h Wed Nov 22 14:53:13 2006 -0500 @@ -37,26 +37,10 @@ #define FAST_TRAP -1 /* 0x80 */ #define FIRST_SYSTEM_VECTOR -1 +#define CALL_FUNCTION_VECTOR 0x0 +#define EVENT_CHECK_VECTOR 0x1 + #if 0 - -/* - * Vectors 0-16 in some cases are used for ISA interrupts. - */ - -/* - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - * - * some of the following vectors are 'rare', they are merged - * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. - * TLB, reschedule and local APIC vectors are performance-critical. - * - * Vectors 0xf0-0xfa are free (reserved for future Linux use). - */ -#define SPURIOUS_APIC_VECTOR 0xff -#define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define EVENT_CHECK_VECTOR 0xfc -#define CALL_FUNCTION_VECTOR 0xfb #define THERMAL_APIC_VECTOR 0xf0 /* diff -r 5909f57c8c39 -r f911e945d959 xen/include/asm-powerpc/smp.h --- a/xen/include/asm-powerpc/smp.h Wed Nov 22 14:35:09 2006 -0500 +++ b/xen/include/asm-powerpc/smp.h Wed Nov 22 14:53:13 2006 -0500 @@ -35,4 +35,21 @@ extern cpumask_t cpu_core_map[]; extern cpumask_t cpu_core_map[]; extern void __devinit smp_generic_take_timebase(void); extern void __devinit smp_generic_give_timebase(void); + +#define SA_INTERRUPT 0x20000000u +typedef int irqreturn_t; +extern int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct cpu_user_regs *), + unsigned long irqflags, const char * devname, void *dev_id); +void smp_message_recv(int msg, struct cpu_user_regs *regs); +void smp_call_function_interrupt(struct cpu_user_regs *regs); +void smp_event_check_interrupt(void); +void send_IPI_mask(cpumask_t mask, int vector); +int vector_is_ipi(int vector); + +#undef DEBUG_IPI +#ifdef DEBUG_IPI +void ipi_torture_test(void); #endif + +#endif _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |