Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9226d125d94c7e4964dd41cc5e9ca2ff84091d01
Commit:     9226d125d94c7e4964dd41cc5e9ca2ff84091d01
Parent:     c119ecce894120790903ef535dac3e105f3d6cde
Author:     Zachary Amsden <[EMAIL PROTECTED]>
AuthorDate: Tue Feb 13 13:26:21 2007 +0100
Committer:  Andi Kleen <[EMAIL PROTECTED]>
CommitDate: Tue Feb 13 13:26:21 2007 +0100

    [PATCH] i386: paravirt CPU hypercall batching mode
    
    The VMI ROM has a mode where hypercalls can be queued and batched.  This 
turns
    out to be a significant win during context switch, but must be done at a
    specific point before side effects to CPU state are visible to subsequent
    instructions.  This is similar to the MMU batching hooks already provided.
    The same hooks could be used by the Xen backend to implement a context 
switch
    multicall.
    
    To explain a bit more about lazy modes in the paravirt patches, basically, 
the
    idea is that only one of lazy CPU or MMU mode can be active at any given 
time.
     Lazy MMU mode is similar to this lazy CPU mode, and allows for batching of
    multiple PTE updates (say, inside a remap loop), but to avoid keeping some
    kind of state machine about when to flush cpu or mmu updates, we just allow
    one or the other to be active.  Although there is no real reason a more
    comprehensive scheme could not be implemented, there is also no demonstrated
    need for this extra complexity.
    
    Signed-off-by: Zachary Amsden <[EMAIL PROTECTED]>
    Signed-off-by: Andi Kleen <[EMAIL PROTECTED]>
    Cc: Andi Kleen <[EMAIL PROTECTED]>
    Cc: Jeremy Fitzhardinge <[EMAIL PROTECTED]>
    Cc: Rusty Russell <[EMAIL PROTECTED]>
    Cc: Chris Wright <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
---
 arch/i386/kernel/paravirt.c   |    1 +
 arch/i386/kernel/process.c    |   25 +++++++++++++++++--------
 include/asm-generic/pgtable.h |   13 +++++++++++++
 include/asm-i386/paravirt.h   |   15 +++++++++++++++
 kernel/sched.c                |    7 +++++++
 5 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index 7329ec9..4dfdac4 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -545,6 +545,7 @@ struct paravirt_ops paravirt_ops = {
        .apic_write_atomic = native_apic_write_atomic,
        .apic_read = native_apic_read,
 #endif
+       .set_lazy_mode = (void *)native_nop,
 
        .flush_tlb_user = native_flush_tlb,
        .flush_tlb_kernel = native_flush_tlb_global,
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 23ae198..cfae587 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -670,14 +670,6 @@ struct task_struct fastcall * __switch_to(struct 
task_struct *prev_p, struct tas
        load_TLS(next, cpu);
 
        /*
-        * Restore %gs if needed (which is common)
-        */
-       if (prev->gs | next->gs)
-               loadsegment(gs, next->gs);
-
-       write_pda(pcurrent, next_p);
-
-       /*
         * Now maybe handle debug registers and/or IO bitmaps
         */
        if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)
@@ -686,6 +678,15 @@ struct task_struct fastcall * __switch_to(struct 
task_struct *prev_p, struct tas
 
        disable_tsc(prev_p, next_p);
 
+       /*
+        * Leave lazy mode, flushing any hypercalls made here.
+        * This must be done before restoring TLS segments so
+        * the GDT and LDT are properly updated, and must be
+        * done before math_state_restore, so the TS bit is up
+        * to date.
+        */
+       arch_leave_lazy_cpu_mode();
+
        /* If the task has used fpu the last 5 timeslices, just do a full
         * restore of the math state immediately to avoid the trap; the
         * chances of needing FPU soon are obviously high now
@@ -693,6 +694,14 @@ struct task_struct fastcall * __switch_to(struct 
task_struct *prev_p, struct tas
        if (next_p->fpu_counter > 5)
                math_state_restore();
 
+       /*
+        * Restore %gs if needed (which is common)
+        */
+       if (prev->gs | next->gs)
+               loadsegment(gs, next->gs);
+
+       write_pda(pcurrent, next_p);
+
        return prev_p;
 }
 
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 9d774d0..00c2343 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -183,6 +183,19 @@ static inline void ptep_set_wrprotect(struct mm_struct 
*mm, unsigned long addres
 #endif
 
 /*
+ * A facility to provide batching of the reload of page tables with the
+ * actual context switch code for paravirtualized guests.  By convention,
+ * only one of the lazy modes (CPU, MMU) should be active at any given
+ * time, entry should never be nested, and entry and exits should always
+ * be paired.  This is for sanity of maintaining and reasoning about the
+ * kernel code.
+ */
+#ifndef __HAVE_ARCH_ENTER_LAZY_CPU_MODE
+#define arch_enter_lazy_cpu_mode()     do {} while (0)
+#define arch_leave_lazy_cpu_mode()     do {} while (0)
+#endif
+
+/*
  * When walking page tables, get the address of the next boundary,
  * or the end address of the range if that comes earlier.  Although no
  * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout.
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index 53da276..38e5164 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -146,6 +146,8 @@ struct paravirt_ops
        void (fastcall *pmd_clear)(pmd_t *pmdp);
 #endif
 
+       void (fastcall *set_lazy_mode)(int mode);
+
        /* These two are jmp to, not actually called. */
        void (fastcall *irq_enable_sysexit)(void);
        void (fastcall *iret)(void);
@@ -386,6 +388,19 @@ static inline void pmd_clear(pmd_t *pmdp)
 }
 #endif
 
+/* Lazy mode for batching updates / context switch */
+#define PARAVIRT_LAZY_NONE 0
+#define PARAVIRT_LAZY_MMU  1
+#define PARAVIRT_LAZY_CPU  2
+
+#define  __HAVE_ARCH_ENTER_LAZY_CPU_MODE
+#define arch_enter_lazy_cpu_mode() 
paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_CPU)
+#define arch_leave_lazy_cpu_mode() 
paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE)
+
+#define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+#define arch_enter_lazy_mmu_mode() 
paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_MMU)
+#define arch_leave_lazy_mmu_mode() 
paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE)
+
 /* These all sit in the .parainstructions section to tell us what to patch. */
 struct paravirt_patch {
        u8 *instr;              /* original instructions */
diff --git a/kernel/sched.c b/kernel/sched.c
index 08f8617..0dc7572 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1853,6 +1853,13 @@ context_switch(struct rq *rq, struct task_struct *prev,
        struct mm_struct *mm = next->mm;
        struct mm_struct *oldmm = prev->active_mm;
 
+       /*
+        * For paravirt, this is coupled with an exit in switch_to to
+        * combine the page table reload and the switch backend into
+        * one hypercall.
+        */
+       arch_enter_lazy_cpu_mode();
+
        if (!mm) {
                next->active_mm = oldmm;
                atomic_inc(&oldmm->mm_count);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to