From b7348c664b725564f88323ed77a870b6b831d5cd Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2008 11:40:38 -0200 Subject: [PATCH] Pull xen genapic implementation from upstream Xen Signed-off-by: Eduardo Habkost --- arch/x86/xen/Makefile | 2 +- arch/x86/xen/genapic.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 1 deletions(-) create mode 100644 arch/x86/xen/genapic.c diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index e2dc9c1..147dde2 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile @@ -4,7 +4,7 @@ obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \ ifeq ($(CONFIG_X86_32),y) obj-y += init_32.o else -obj-y += init_64.o +obj-y += init_64.o genapic.o endif obj-$(CONFIG_SMP) += smp.o diff --git a/arch/x86/xen/genapic.c b/arch/x86/xen/genapic.c new file mode 100644 index 0000000..0b9e74e --- /dev/null +++ b/arch/x86/xen/genapic.c @@ -0,0 +1,190 @@ +/* + * Copyright 2004 James Cleverdon, IBM. + * Subject to the GNU Public License, v.2 + * + * Xen APIC subarch code. Maximum 8 CPUs, logical delivery. + * + * Hacked for x86-64 by James Cleverdon from i386 architecture code by + * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and + * James Cleverdon. + * + * Hacked to pieces for Xen by Chris Wright. + */ +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_XEN_PRIVILEGED_GUEST +#include +#include +#else +#include +#include +#endif +#include +#include + +DECLARE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]); + +static inline void __send_IPI_one(unsigned int cpu, int vector) +{ + int irq = per_cpu(ipi_to_irq, cpu)[vector]; + BUG_ON(irq < 0); + notify_remote_via_irq(irq); +} + +void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest) +{ + int cpu; + + switch (shortcut) { + case APIC_DEST_SELF: + __send_IPI_one(smp_processor_id(), vector); + break; + case APIC_DEST_ALLBUT: + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (cpu == smp_processor_id()) + continue; + if (cpu_isset(cpu, cpu_online_map)) { + __send_IPI_one(cpu, vector); + } + } + break; + case APIC_DEST_ALLINC: + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (cpu_isset(cpu, cpu_online_map)) { + __send_IPI_one(cpu, vector); + } + } + break; + default: + printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut, + vector); + break; + } +} + +static cpumask_t xen_target_cpus(void) +{ + return cpu_online_map; +} + +static cpumask_t xen_vector_allocation_domain(int cpu) +{ + /* Careful. Some cpus do not strictly honor the set of cpus + * specified in the interrupt destination when using lowest + * priority interrupt delivery mode. + * + * In particular there was a hyperthreading cpu observed to + * deliver interrupts to the wrong hyperthread when only one + * hyperthread was specified in the interrupt desitination. + */ + cpumask_t domain = { { [0] = APIC_ALL_CPUS, } }; + return domain; +} + +/* + * Set up the logical destination ID. + * Do nothing, not called now. + */ +static void xen_init_apic_ldr(void) +{ + Dprintk("%s\n", __FUNCTION__); + return; +} + +static void xen_send_IPI_mask(cpumask_t cpumask, int vector) +{ + unsigned long mask = cpus_addr(cpumask)[0]; + unsigned int cpu; + unsigned long flags; + + Dprintk("%s\n", __FUNCTION__); + local_irq_save(flags); + WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); + + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (cpu_isset(cpu, cpumask)) { + __send_IPI_one(cpu, vector); + } + } + local_irq_restore(flags); +} + +static void xen_send_IPI_allbutself(int vector) +{ +#ifdef CONFIG_HOTPLUG_CPU + int hotplug = 1; +#else + int hotplug = 0; +#endif + /* + * if there are no other CPUs in the system then + * we get an APIC send error if we try to broadcast. + * thus we have to avoid sending IPIs in this case. + */ + Dprintk("%s\n", __FUNCTION__); + if (hotplug || vector == NMI_VECTOR) { + cpumask_t allbutme = cpu_online_map; + + cpu_clear(smp_processor_id(), allbutme); + + if (!cpus_empty(allbutme)) + xen_send_IPI_mask(allbutme, vector); + } else if (num_online_cpus() > 1) { + xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL); + } +} + +static void xen_send_IPI_all(int vector) +{ + Dprintk("%s\n", __FUNCTION__); + if (vector == NMI_VECTOR) + xen_send_IPI_mask(cpu_online_map, vector); + else + xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); +} + +#ifdef CONFIG_XEN_PRIVILEGED_GUEST +static int xen_apic_id_registered(void) +{ + /* better be set */ + Dprintk("%s\n", __FUNCTION__); + return physid_isset(smp_processor_id(), phys_cpu_present_map); +} +#endif + +static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask) +{ + Dprintk("%s\n", __FUNCTION__); + return cpus_addr(cpumask)[0] & APIC_ALL_CPUS; +} + +static unsigned int phys_pkg_id(int index_msb) +{ + int ebx; + Dprintk("%s\n", __FUNCTION__); + ebx = cpuid_ebx(1); + return ((ebx >> 24) & 0xFF) >> index_msb; +} + +struct genapic apic_xen = { + .name = "xen", +#ifdef CONFIG_XEN_PRIVILEGED_GUEST + .int_delivery_mode = dest_LowestPrio, +#endif + .int_dest_mode = (APIC_DEST_LOGICAL != 0), + .target_cpus = xen_target_cpus, + .vector_allocation_domain = xen_vector_allocation_domain, +#ifdef CONFIG_XEN_PRIVILEGED_GUEST + .apic_id_registered = xen_apic_id_registered, +#endif + .init_apic_ldr = xen_init_apic_ldr, + .send_IPI_all = xen_send_IPI_all, + .send_IPI_allbutself = xen_send_IPI_allbutself, + .send_IPI_mask = xen_send_IPI_mask, + .cpu_mask_to_apicid = xen_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +}; -- 1.5.4.1