[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86: Support x2APIC mode.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1209638096 -3600 # Node ID 9fd00ff95068a613dac994a6a3d7025d7dd465d9 # Parent f13ff27fa0d1ca8eed461ba47e49f784716b874b x86: Support x2APIC mode. Signed-off-by: Dexuan Cui <dexuan.cui@xxxxxxxxx> --- xen/arch/x86/apic.c | 50 ++++++++++-- xen/arch/x86/genapic/Makefile | 1 xen/arch/x86/genapic/delivery.c | 2 xen/arch/x86/genapic/probe.c | 2 xen/arch/x86/genapic/x2apic.c | 79 ++++++++++++++++++++ xen/arch/x86/hvm/vlapic.c | 4 - xen/arch/x86/io_apic.c | 2 xen/arch/x86/mpparse.c | 11 +- xen/arch/x86/nmi.c | 5 - xen/arch/x86/setup.c | 3 xen/arch/x86/shutdown.c | 2 xen/arch/x86/smp.c | 5 + xen/arch/x86/smpboot.c | 91 +++++++++++++---------- xen/include/asm-x86/apic.h | 105 ++++++++++++++++++++++++++- xen/include/asm-x86/apicdef.h | 19 +++- xen/include/asm-x86/cpufeature.h | 2 xen/include/asm-x86/genapic.h | 14 +++ xen/include/asm-x86/hvm/vlapic.h | 2 xen/include/asm-x86/mach-generic/mach_apic.h | 2 xen/include/asm-x86/msr-index.h | 1 xen/include/asm-x86/smp.h | 4 - 21 files changed, 334 insertions(+), 72 deletions(-) diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/apic.c --- a/xen/arch/x86/apic.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/apic.c Thu May 01 11:34:56 2008 +0100 @@ -47,6 +47,8 @@ int enable_local_apic __initdata = 0; /* */ int apic_verbosity; +int x2apic_enabled __read_mostly = 0; + static void apic_pm_activate(void); @@ -306,7 +308,10 @@ int __init verify_local_APIC(void) */ reg0 = apic_read(APIC_LVR); apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0); - apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); + + /* We don't try writing LVR in x2APIC mode since that incurs #GP. */ + if ( !x2apic_enabled ) + apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); reg1 = apic_read(APIC_LVR); apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1); @@ -610,7 +615,8 @@ int lapic_suspend(void) apic_pm_state.apic_id = apic_read(APIC_ID); apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); apic_pm_state.apic_ldr = apic_read(APIC_LDR); - apic_pm_state.apic_dfr = apic_read(APIC_DFR); + if ( !x2apic_enabled ) + apic_pm_state.apic_dfr = apic_read(APIC_DFR); apic_pm_state.apic_spiv = apic_read(APIC_SPIV); apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); @@ -643,14 +649,20 @@ int lapic_resume(void) * FIXME! This will be wrong if we ever support suspend on * SMP! We'll need to do this as part of the CPU restore! */ - rdmsr(MSR_IA32_APICBASE, l, h); - l &= ~MSR_IA32_APICBASE_BASE; - l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; - wrmsr(MSR_IA32_APICBASE, l, h); + if ( !x2apic_enabled ) + { + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_BASE; + l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; + wrmsr(MSR_IA32_APICBASE, l, h); + } + else + enable_x2apic(); apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); apic_write(APIC_ID, apic_pm_state.apic_id); - apic_write(APIC_DFR, apic_pm_state.apic_dfr); + if ( !x2apic_enabled ) + apic_write(APIC_DFR, apic_pm_state.apic_dfr); apic_write(APIC_LDR, apic_pm_state.apic_ldr); apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); apic_write(APIC_SPIV, apic_pm_state.apic_spiv); @@ -809,10 +821,29 @@ no_apic: return -1; } +void enable_x2apic(void) +{ + u32 lo, hi; + + rdmsr(MSR_IA32_APICBASE, lo, hi); + if ( !(lo & MSR_IA32_APICBASE_EXTD) ) + { + lo |= MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD; + wrmsr(MSR_IA32_APICBASE, lo, 0); + printk("x2APIC mode enabled.\n"); + } + else + printk("x2APIC mode enabled by BIOS.\n"); + + x2apic_enabled = 1; +} + void __init init_apic_mappings(void) { unsigned long apic_phys; + if ( x2apic_enabled ) + goto __next; /* * If no local APIC can be found then set up a fake all * zeroes page to simulate the local APIC and another @@ -828,12 +859,13 @@ void __init init_apic_mappings(void) apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); +__next: /* * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ if (boot_cpu_physical_apicid == -1U) - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + boot_cpu_physical_apicid = get_apic_id(); #ifdef CONFIG_X86_IO_APIC { @@ -1271,7 +1303,7 @@ int __init APIC_init_uniprocessor (void) * might be zero if read from MP tables. Get it from LAPIC. */ #ifdef CONFIG_CRASH_DUMP - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + boot_cpu_physical_apicid = get_apic_id(); #endif phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/genapic/Makefile --- a/xen/arch/x86/genapic/Makefile Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/genapic/Makefile Thu May 01 11:34:56 2008 +0100 @@ -1,4 +1,5 @@ obj-y += bigsmp.o obj-y += bigsmp.o +obj-y += x2apic.o obj-y += default.o obj-y += delivery.o obj-y += probe.o diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/genapic/delivery.c --- a/xen/arch/x86/genapic/delivery.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/genapic/delivery.c Thu May 01 11:34:56 2008 +0100 @@ -17,7 +17,7 @@ void init_apic_ldr_flat(void) apic_write_around(APIC_DFR, APIC_DFR_FLAT); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; - val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); + val |= SET_xAPIC_LOGICAL_ID(1UL << smp_processor_id()); apic_write_around(APIC_LDR, val); } diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/genapic/probe.c --- a/xen/arch/x86/genapic/probe.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/genapic/probe.c Thu May 01 11:34:56 2008 +0100 @@ -14,6 +14,7 @@ #include <asm/apicdef.h> #include <asm/genapic.h> +extern struct genapic apic_x2apic; extern struct genapic apic_summit; extern struct genapic apic_bigsmp; extern struct genapic apic_default; @@ -21,6 +22,7 @@ struct genapic *genapic; struct genapic *genapic; struct genapic *apic_probe[] __initdata = { + &apic_x2apic, &apic_summit, &apic_bigsmp, &apic_default, /* must be last */ diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/genapic/x2apic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/genapic/x2apic.c Thu May 01 11:34:56 2008 +0100 @@ -0,0 +1,79 @@ +/* + * x2APIC driver. + * + * Copyright (c) 2008, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <xen/cpumask.h> +#include <asm/apicdef.h> +#include <asm/genapic.h> +#include <xen/smp.h> +#include <asm/mach-default/mach_mpparse.h> + +__init int probe_x2apic(void) +{ + return x2apic_is_available(); +} + +struct genapic apic_x2apic= { + APIC_INIT("x2apic", probe_x2apic), + GENAPIC_X2APIC +}; + +void init_apic_ldr_x2apic(void) +{ + /* We only use physical delivery mode. */ + return; +} + +void clustered_apic_check_x2apic(void) +{ + /* We only use physical delivery mode. */ + return; +} + +cpumask_t target_cpus_x2apic(void) +{ + /* Deliver interrupts only to CPU0 for now */ + return cpumask_of_cpu(0); +} + +unsigned int cpu_mask_to_apicid_x2apic(cpumask_t cpumask) +{ + return cpu_physical_id(first_cpu(cpumask)); +} + +void send_IPI_mask_x2apic(cpumask_t cpumask, int vector) +{ + unsigned int query_cpu; + u32 cfg, dest; + unsigned long flags; + + ASSERT(cpus_subset(cpumask, cpu_online_map)); + ASSERT(!cpus_empty(cpumask)); + + local_irq_save(flags); + + cfg = APIC_DM_FIXED | 0 /* no shorthand */ | APIC_DEST_PHYSICAL | vector; + for_each_cpu_mask(query_cpu, cpumask) + { + dest = cpu_physical_id(query_cpu); + apic_icr_write(cfg, dest); + } + + local_irq_restore(flags); +} + diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/hvm/vlapic.c --- a/xen/arch/x86/hvm/vlapic.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/hvm/vlapic.c Thu May 01 11:34:56 2008 +0100 @@ -171,7 +171,7 @@ int vlapic_match_logical_addr(struct vla int result = 0; uint8_t logical_id; - logical_id = GET_APIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR)); + logical_id = GET_xAPIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR)); switch ( vlapic_get_reg(vlapic, APIC_DFR) ) { @@ -484,7 +484,7 @@ static int vlapic_ipi( static int vlapic_ipi( struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high) { - unsigned int dest = GET_APIC_DEST_FIELD(icr_high); + unsigned int dest = GET_xAPIC_DEST_FIELD(icr_high); unsigned int short_hand = icr_low & APIC_SHORT_MASK; unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; unsigned int level = icr_low & APIC_INT_ASSERT; diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/io_apic.c --- a/xen/arch/x86/io_apic.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/io_apic.c Thu May 01 11:34:56 2008 +0100 @@ -1125,7 +1125,7 @@ void disable_IO_APIC(void) entry.delivery_mode = dest_ExtINT; /* ExtInt */ entry.vector = 0; entry.dest.physical.physical_dest = - GET_APIC_ID(apic_read(APIC_ID)); + get_apic_id(); /* * Add it to the IO-APIC irq-routing table: diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/mpparse.c --- a/xen/arch/x86/mpparse.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/mpparse.c Thu May 01 11:34:56 2008 +0100 @@ -814,12 +814,15 @@ void __init mp_register_lapic_address ( void __init mp_register_lapic_address ( u64 address) { - mp_lapic_addr = (unsigned long) address; - - set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); + if ( !x2apic_enabled ) + { + mp_lapic_addr = (unsigned long) address; + + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); + } if (boot_cpu_physical_apicid == -1U) - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + boot_cpu_physical_apicid = get_apic_id(); Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid); } diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/nmi.c --- a/xen/arch/x86/nmi.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/nmi.c Thu May 01 11:34:56 2008 +0100 @@ -434,14 +434,13 @@ void nmi_watchdog_tick(struct cpu_user_r */ static void do_nmi_trigger(unsigned char key) { - u32 id = GET_APIC_ID(apic_read(APIC_ID)); + u32 id = get_apic_id(); printk("Triggering NMI on APIC ID %x\n", id); local_irq_disable(); apic_wait_icr_idle(); - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(id)); - apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_PHYSICAL); + apic_icr_write(APIC_DM_NMI | APIC_DEST_PHYSICAL, id); local_irq_enable(); } diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/setup.c Thu May 01 11:34:56 2008 +0100 @@ -890,6 +890,9 @@ void __init __start_xen(unsigned long mb generic_apic_probe(); + if ( x2apic_is_available() ) + enable_x2apic(); + acpi_boot_init(); init_cpu_to_node(); diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/shutdown.c --- a/xen/arch/x86/shutdown.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/shutdown.c Thu May 01 11:34:56 2008 +0100 @@ -209,7 +209,7 @@ void machine_restart(void) local_irq_enable(); /* Ensure we are the boot CPU. */ - if ( GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid ) + if ( get_apic_id() != boot_cpu_physical_apicid ) { /* Send IPI to the boot CPU (logical cpu 0). */ on_selected_cpus(cpumask_of_cpu(0), (void *)machine_restart, diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/smp.c --- a/xen/arch/x86/smp.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/smp.c Thu May 01 11:34:56 2008 +0100 @@ -72,11 +72,14 @@ static inline int __prepare_ICR (unsigne static inline int __prepare_ICR2 (unsigned int mask) { - return SET_APIC_DEST_FIELD(mask); + return SET_xAPIC_DEST_FIELD(mask); } void apic_wait_icr_idle(void) { + if ( x2apic_enabled ) + return; + while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ) cpu_relax(); } diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/arch/x86/smpboot.c --- a/xen/arch/x86/smpboot.c Thu May 01 11:30:42 2008 +0100 +++ b/xen/arch/x86/smpboot.c Thu May 01 11:34:56 2008 +0100 @@ -325,10 +325,13 @@ void __devinit smp_callin(void) */ wait_for_init_deassert(&init_deasserted); + if ( x2apic_is_available() ) + enable_x2apic(); + /* * (This works even if the APIC is not enabled.) */ - phys_id = GET_APIC_ID(apic_read(APIC_ID)); + phys_id = get_apic_id(); cpuid = smp_processor_id(); if (cpu_isset(cpuid, cpu_callin_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", @@ -548,7 +551,7 @@ static void map_cpu_to_logical_apicid(vo static void map_cpu_to_logical_apicid(void) { int cpu = smp_processor_id(); - int apicid = hard_smp_processor_id(); + int apicid = logical_smp_processor_id(); cpu_2_logical_apicid[cpu] = apicid; } @@ -575,8 +578,7 @@ static inline void __inquire_remote_apic */ apic_wait_icr_idle(); - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); + apic_icr_write(APIC_DM_REMRD | regs[i], apicid); timeout = 0; do { @@ -597,6 +599,21 @@ static inline void __inquire_remote_apic #endif #ifdef WAKE_SECONDARY_VIA_NMI + +static int logical_apicid_to_cpu(int logical_apicid) +{ + int i; + + for ( i = 0; i < sizeof(cpu_2_logical_apicid); i++ ) + if ( cpu_2_logical_apicid[i] == logical_apicid ) + break; + + if ( i == sizeof(cpu_2_logical_apicid) ); + i = -1; /* not found */ + + return i; +} + /* * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this @@ -607,20 +624,26 @@ wakeup_secondary_cpu(int logical_apicid, { unsigned long send_status = 0, accept_status = 0; int timeout, maxlvt; - - /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid)); + int dest_cpu; + u32 dest; + + dest_cpu = logical_apicid_to_cpu(logical_apicid); + BUG_ON(dest_cpu == -1); + + dest = cpu_physical_id(dest_cpu); /* Boot on the stack */ - /* Kick the second */ - apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL); + apic_icr_write(APIC_DM_NMI | APIC_DEST_PHYSICAL, dest_cpu); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + if ( !x2apic_enabled ) + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + else + send_status = 0; /* We go out of the loop directly. */ } while (send_status && (timeout++ < 1000)); /* @@ -666,40 +689,37 @@ wakeup_secondary_cpu(int phys_apicid, un Dprintk("Asserting INIT.\n"); /* - * Turn INIT on target chip - */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); - - /* - * Send IPI - */ - apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT - | APIC_DM_INIT); + * Turn INIT on target chip via IPI + */ + apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT, + phys_apicid); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + if ( !x2apic_enabled ) + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + else + send_status = 0; /* We go out of the loop dirctly. */ } while (send_status && (timeout++ < 1000)); mdelay(10); Dprintk("Deasserting INIT.\n"); - /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); - - /* Send IPI */ - apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); + apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + if ( !x2apic_enabled ) + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + else + send_status = 0; /* We go out of the loop dirctly. */ } while (send_status && (timeout++ < 1000)); atomic_set(&init_deasserted, 1); @@ -731,15 +751,9 @@ wakeup_secondary_cpu(int phys_apicid, un /* * STARTUP IPI - */ - - /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); - - /* Boot on the stack */ - /* Kick the second */ - apic_write_around(APIC_ICR, APIC_DM_STARTUP - | (start_eip >> 12)); + * Boot on the stack + */ + apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12), phys_apicid); /* * Give the other CPU some time to accept the IPI. @@ -753,7 +767,10 @@ wakeup_secondary_cpu(int phys_apicid, un do { Dprintk("+"); udelay(100); - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + if ( !x2apic_enabled ) + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + else + send_status = 0; /* We go out of the loop dirctly. */ } while (send_status && (timeout++ < 1000)); /* @@ -988,7 +1005,7 @@ static void __init smp_boot_cpus(unsigne printk("CPU%d: ", 0); print_cpu_info(&cpu_data[0]); - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + boot_cpu_physical_apicid = get_apic_id(); x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; stack_base[0] = stack_start.esp; diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/apic.h --- a/xen/include/asm-x86/apic.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/apic.h Thu May 01 11:34:56 2008 +0100 @@ -16,6 +16,21 @@ #define APIC_DEBUG 2 extern int apic_verbosity; +extern int x2apic_enabled; + +extern void enable_x2apic(void); + +static __inline int x2apic_is_available(void) +{ + unsigned int op = 1, eax, ecx; + + asm ( "cpuid" + : "=a" (eax), "=c" (ecx) + : "0" (op) + : "bx", "dx" ); + + return (ecx & (1U << 21)); +} /* * Define the default level of output to be very little @@ -35,19 +50,103 @@ extern int apic_verbosity; * Basic functions accessing APICs. */ +static __inline void apic_mem_write(unsigned long reg, u32 v) +{ + *((volatile u32 *)(APIC_BASE+reg)) = v; +} + +static __inline void apic_mem_write_atomic(unsigned long reg, u32 v) +{ + (void)xchg((volatile u32 *)(APIC_BASE+reg), v); +} + +static __inline u32 apic_mem_read(unsigned long reg) +{ + return *((volatile u32 *)(APIC_BASE+reg)); +} + +/* NOTE: in x2APIC mode, we should use apic_icr_write()/apic_icr_read() to + * access the 64-bit ICR register. + */ + +static __inline void apic_wrmsr(unsigned long reg, u32 low, u32 high) +{ + __asm__ __volatile__("wrmsr" + : /* no outputs */ + : "c" (APIC_MSR_BASE + (reg >> 4)), "a" (low), "d" (high)); +} + +static __inline void apic_rdmsr(unsigned long reg, u32 *low, u32 *high) +{ + __asm__ __volatile__("rdmsr" + : "=a" (*low), "=d" (*high) + : "c" (APIC_MSR_BASE + (reg >> 4))); +} + static __inline void apic_write(unsigned long reg, u32 v) { - *((volatile u32 *)(APIC_BASE+reg)) = v; + + if ( x2apic_enabled ) + apic_wrmsr(reg, v, 0); + else + apic_mem_write(reg, v); } static __inline void apic_write_atomic(unsigned long reg, u32 v) { - (void)xchg((volatile u32 *)(APIC_BASE+reg), v); + if ( x2apic_enabled ) + apic_wrmsr(reg, v, 0); + else + apic_mem_write_atomic(reg, v); } static __inline u32 apic_read(unsigned long reg) { - return *((volatile u32 *)(APIC_BASE+reg)); + u32 lo, hi; + + if ( x2apic_enabled ) + apic_rdmsr(reg, &lo, &hi); + else + lo = apic_mem_read(reg); + return lo; +} + +static __inline u64 apic_icr_read(void) +{ + u32 lo, hi; + + if ( x2apic_enabled ) + apic_rdmsr(APIC_ICR, &lo, &hi); + else + { + lo = apic_mem_read(APIC_ICR); + hi = apic_mem_read(APIC_ICR2); + } + + return ((u64)lo) | (((u64)hi) << 32); +} + +static __inline void apic_icr_write(u32 low, u32 dest) +{ + if ( x2apic_enabled ) + apic_wrmsr(APIC_ICR, low, dest); + else + { + apic_mem_write(APIC_ICR2, dest << 24); + apic_mem_write(APIC_ICR, low); + } +} + +static __inline u32 get_apic_id(void) /* Get the physical APIC id */ +{ + u32 id = apic_read(APIC_ID); + return x2apic_enabled ? id : GET_xAPIC_ID(id); +} + +static __inline u32 get_logical_apic_id(void) +{ + u32 logical_id = apic_read(APIC_LDR); + return x2apic_enabled ? logical_id : GET_xAPIC_LOGICAL_ID(logical_id); } void apic_wait_icr_idle(void); diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/apicdef.h --- a/xen/include/asm-x86/apicdef.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/apicdef.h Thu May 01 11:34:56 2008 +0100 @@ -12,8 +12,8 @@ #define APIC_ID 0x20 #define APIC_ID_MASK (0xFFu<<24) -#define GET_APIC_ID(x) (((x)>>24)&0xFFu) -#define SET_APIC_ID(x) (((x)<<24)) +#define GET_xAPIC_ID(x) (((x)>>24)&0xFFu) +#define SET_xAPIC_ID(x) (((x)<<24)) #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF #define GET_APIC_VERSION(x) ((x)&0xFF) @@ -30,8 +30,8 @@ #define APIC_RRR 0xC0 #define APIC_LDR 0xD0 #define APIC_LDR_MASK (0xFF<<24) -#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF) -#define SET_APIC_LOGICAL_ID(x) (((x)<<24)) +#define GET_xAPIC_LOGICAL_ID(x) (((x)>>24)&0xFF) +#define SET_xAPIC_LOGICAL_ID(x) (((x)<<24)) #define APIC_ALL_CPUS 0xFF #define APIC_DFR 0xE0 #define APIC_DFR_CLUSTER 0x0FFFFFFFul @@ -74,8 +74,8 @@ #define APIC_DM_EXTINT 0x00700 #define APIC_VECTOR_MASK 0x000FF #define APIC_ICR2 0x310 -#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) -#define SET_APIC_DEST_FIELD(x) ((x)<<24) +#define GET_xAPIC_DEST_FIELD(x) (((x)>>24)&0xFF) +#define SET_xAPIC_DEST_FIELD(x) ((x)<<24) #define APIC_LVTT 0x320 #define APIC_LVTTHMR 0x330 #define APIC_LVTPC 0x340 @@ -103,6 +103,10 @@ #define APIC_TMICT 0x380 #define APIC_TMCCT 0x390 #define APIC_TDCR 0x3E0 + +/* Only available in x2APIC mode */ +#define APIC_SELF_IPI 0x400 + #define APIC_TDR_DIV_TMBASE (1<<2) #define APIC_TDR_DIV_1 0xB #define APIC_TDR_DIV_2 0x0 @@ -114,6 +118,9 @@ #define APIC_TDR_DIV_128 0xA #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) + +/* It's only used in x2APIC mode of an x2APIC unit. */ +#define APIC_MSR_BASE 0x800 #ifdef __i386__ #define MAX_IO_APICS 64 diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/cpufeature.h --- a/xen/include/asm-x86/cpufeature.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/cpufeature.h Thu May 01 11:34:56 2008 +0100 @@ -92,6 +92,7 @@ #define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ #define X86_FEATURE_SSE4_1 (4*32+19) /* Streaming SIMD Extensions 4.1 */ #define X86_FEATURE_SSE4_2 (4*32+20) /* Streaming SIMD Extensions 4.2 */ +#define X86_FEATURE_X2APIC (4*32+21) /* Extended xAPIC */ #define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ @@ -182,6 +183,7 @@ #define cpu_has_ffxsr ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) \ && boot_cpu_has(X86_FEATURE_FFXSR)) +#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC) #endif /* __ASM_I386_CPUFEATURE_H */ /* diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/genapic.h --- a/xen/include/asm-x86/genapic.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/genapic.h Thu May 01 11:34:56 2008 +0100 @@ -62,6 +62,20 @@ void send_IPI_mask_flat(cpumask_t mask, .cpu_mask_to_apicid = cpu_mask_to_apicid_flat, \ .send_IPI_mask = send_IPI_mask_flat +void init_apic_ldr_x2apic(void); +void clustered_apic_check_x2apic(void); +cpumask_t target_cpus_x2apic(void); +unsigned int cpu_mask_to_apicid_x2apic(cpumask_t cpumask); +void send_IPI_mask_x2apic(cpumask_t mask, int vector); +#define GENAPIC_X2APIC \ + .int_delivery_mode = dest_Fixed, \ + .int_dest_mode = 0 /* physical delivery */, \ + .init_apic_ldr = init_apic_ldr_x2apic, \ + .clustered_apic_check = clustered_apic_check_x2apic, \ + .target_cpus = target_cpus_x2apic, \ + .cpu_mask_to_apicid = cpu_mask_to_apicid_x2apic, \ + .send_IPI_mask = send_IPI_mask_x2apic + void init_apic_ldr_phys(void); void clustered_apic_check_phys(void); cpumask_t target_cpus_phys(void); diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/hvm/vlapic.h --- a/xen/include/asm-x86/hvm/vlapic.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/hvm/vlapic.h Thu May 01 11:34:56 2008 +0100 @@ -34,7 +34,7 @@ #define vlapic_domain(vpic) (vlapic_vcpu(vlapic)->domain) #define VLAPIC_ID(vlapic) \ - (GET_APIC_ID(vlapic_get_reg((vlapic), APIC_ID))) + (GET_xAPIC_ID(vlapic_get_reg((vlapic), APIC_ID))) /* * APIC can be disabled in two ways: diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/mach-generic/mach_apic.h --- a/xen/include/asm-x86/mach-generic/mach_apic.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/mach-generic/mach_apic.h Thu May 01 11:34:56 2008 +0100 @@ -62,7 +62,7 @@ extern void generic_bigsmp_probe(void); */ static inline int apic_id_registered(void) { - return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), + return physid_isset(get_apic_id(), phys_cpu_present_map); } diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/msr-index.h --- a/xen/include/asm-x86/msr-index.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/msr-index.h Thu May 01 11:34:56 2008 +0100 @@ -236,6 +236,7 @@ #define MSR_IA32_APICBASE 0x0000001b #define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_EXTD (1<<10) #define MSR_IA32_APICBASE_ENABLE (1<<11) #define MSR_IA32_APICBASE_BASE (0xfffff<<12) diff -r f13ff27fa0d1 -r 9fd00ff95068 xen/include/asm-x86/smp.h --- a/xen/include/asm-x86/smp.h Thu May 01 11:30:42 2008 +0100 +++ b/xen/include/asm-x86/smp.h Thu May 01 11:34:56 2008 +0100 @@ -90,13 +90,13 @@ static inline int hard_smp_processor_id( static inline int hard_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); + return get_apic_id(); } static __inline int logical_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_LOGICAL_ID(*(unsigned int *)(APIC_BASE+APIC_LDR)); + return get_logical_apic_id(); } #endif _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |