x86_64: add workaround for no %gs-based percpu
authorJeremy Fitzhardinge <jeremy@goop.org>
Tue, 8 Jul 2008 22:06:42 +0000 (15:06 -0700)
committerIngo Molnar <mingo@elte.hu>
Wed, 16 Jul 2008 08:58:13 +0000 (10:58 +0200)
As a stopgap until Mike Travis's x86-64 gs-based percpu patches are
ready, provide workaround functions for x86_read/write_percpu for
Xen's use.

Specifically, this means that we can't really make use of vcpu
placement, because we can't use a single gs-based memory access to get
to vcpu fields.  So disable all that for now.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Stephen Tweedie <sct@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/head64.c
arch/x86/xen/enlighten.c
include/asm-x86/percpu.h
include/asm-x86/setup.h

index c9781982914693cbb6ba98bf7cea94b1a291c8a5..1b318e903bf63f14bd4f514ad8fd5916289bb979 100644 (file)
@@ -39,6 +39,13 @@ static struct x8664_pda *__cpu_pda[NR_CPUS] __initdata;
 static struct x8664_pda *__cpu_pda[NR_CPUS] __read_mostly;
 #endif
 
+void __init x86_64_init_pda(void)
+{
+       _cpu_pda = __cpu_pda;
+       cpu_pda(0) = &_boot_cpu_pda;
+       pda_init(0);
+}
+
 static void __init zap_identity_mappings(void)
 {
        pgd_t *pgd = pgd_offset_k(0UL);
@@ -102,9 +109,7 @@ void __init x86_64_start_kernel(char * real_mode_data)
 
        early_printk("Kernel alive\n");
 
-       _cpu_pda = __cpu_pda;
-       cpu_pda(0) = &_boot_cpu_pda;
-       pda_init(0);
+       x86_64_init_pda();
 
        early_printk("Kernel really alive\n");
 
index a85f447b8d00adb2b5a9bddfea318b8d102d9943..f3f11acf7856b6825060b46fa59fba3318691c86 100644 (file)
@@ -971,6 +971,7 @@ void xen_setup_vcpu_info_placement(void)
 
        /* xen_vcpu_setup managed to place the vcpu_info within the
           percpu area for all cpus, so make use of it */
+#ifdef CONFIG_X86_32
        if (have_vcpu_info_placement) {
                printk(KERN_INFO "Xen: using vcpu_info placement\n");
 
@@ -980,6 +981,7 @@ void xen_setup_vcpu_info_placement(void)
                pv_irq_ops.irq_enable = xen_irq_enable_direct;
                pv_mmu_ops.read_cr2 = xen_read_cr2_direct;
        }
+#endif
 }
 
 static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
@@ -1000,10 +1002,12 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
        goto patch_site
 
        switch (type) {
+#ifdef CONFIG_X86_32
                SITE(pv_irq_ops, irq_enable);
                SITE(pv_irq_ops, irq_disable);
                SITE(pv_irq_ops, save_fl);
                SITE(pv_irq_ops, restore_fl);
+#endif /* CONFIG_X86_32 */
 #undef SITE
 
        patch_site:
@@ -1323,6 +1327,7 @@ asmlinkage void __init xen_start_kernel(void)
 #ifdef CONFIG_X86_64
        /* Disable until direct per-cpu data access. */
        have_vcpu_info_placement = 0;
+       x86_64_init_pda();
 #endif
 
        xen_smp_init();
index 912a3a17b9db85958abee1464d58e64d798f5f31..4e91ee1e37aa170140e92814a08232fef4e6dfd4 100644 (file)
 
 DECLARE_PER_CPU(struct x8664_pda, pda);
 
+/*
+ * These are supposed to be implemented as a single instruction which
+ * operates on the per-cpu data base segment.  x86-64 doesn't have
+ * that yet, so this is a fairly inefficient workaround for the
+ * meantime.  The single instruction is atomic with respect to
+ * preemption and interrupts, so we need to explicitly disable
+ * interrupts here to achieve the same effect.  However, because it
+ * can be used from within interrupt-disable/enable, we can't actually
+ * disable interrupts; disabling preemption is enough.
+ */
+#define x86_read_percpu(var)                                           \
+       ({                                                              \
+               typeof(per_cpu_var(var)) __tmp;                         \
+               preempt_disable();                                      \
+               __tmp = __get_cpu_var(var);                             \
+               preempt_enable();                                       \
+               __tmp;                                                  \
+       })
+
+#define x86_write_percpu(var, val)                                     \
+       do {                                                            \
+               preempt_disable();                                      \
+               __get_cpu_var(var) = (val);                             \
+               preempt_enable();                                       \
+       } while(0)
+
 #else /* CONFIG_X86_64 */
 
 #ifdef __ASSEMBLY__
index 90ab2225e71bbefe9fb06c9d85127c555e8a8445..659492624e747f26a647bfd8640efd60332b4659 100644 (file)
@@ -76,6 +76,7 @@ extern unsigned long init_pg_tables_start;
 extern unsigned long init_pg_tables_end;
 
 #else
+void __init x86_64_init_pda(void);
 void __init x86_64_start_kernel(char *real_mode);
 void __init x86_64_start_reservations(char *real_mode_data);