x86/mm/tlb: Add freed_tables element to flush_tlb_info
[linux-2.6-microblaze.git] / arch / x86 / mm / tlb.c
index 752dbf4..92e46f4 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/export.h>
 #include <linux/cpu.h>
 #include <linux/debugfs.h>
-#include <linux/gfp.h>
 
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -186,7 +185,6 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
 {
        struct mm_struct *real_prev = this_cpu_read(cpu_tlbstate.loaded_mm);
        u16 prev_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid);
-       bool was_lazy = this_cpu_read(cpu_tlbstate.is_lazy);
        unsigned cpu = smp_processor_id();
        u64 next_tlb_gen;
        bool need_flush;
@@ -244,40 +242,17 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                           next->context.ctx_id);
 
                /*
-                * Even in lazy TLB mode, the CPU should stay set in the
-                * mm_cpumask. The TLB shootdown code can figure out from
-                * from cpu_tlbstate.is_lazy whether or not to send an IPI.
+                * We don't currently support having a real mm loaded without
+                * our cpu set in mm_cpumask().  We have all the bookkeeping
+                * in place to figure out whether we would need to flush
+                * if our cpu were cleared in mm_cpumask(), but we don't
+                * currently use it.
                 */
                if (WARN_ON_ONCE(real_prev != &init_mm &&
                                 !cpumask_test_cpu(cpu, mm_cpumask(next))))
                        cpumask_set_cpu(cpu, mm_cpumask(next));
 
-               /*
-                * If the CPU is not in lazy TLB mode, we are just switching
-                * from one thread in a process to another thread in the same
-                * process. No TLB flush required.
-                */
-               if (!was_lazy)
-                       return;
-
-               /*
-                * Read the tlb_gen to check whether a flush is needed.
-                * If the TLB is up to date, just use it.
-                * The barrier synchronizes with the tlb_gen increment in
-                * the TLB shootdown code.
-                */
-               smp_mb();
-               next_tlb_gen = atomic64_read(&next->context.tlb_gen);
-               if (this_cpu_read(cpu_tlbstate.ctxs[prev_asid].tlb_gen) ==
-                               next_tlb_gen)
-                       return;
-
-               /*
-                * TLB contents went out of date while we were in lazy
-                * mode. Fall through to the TLB switching code below.
-                */
-               new_asid = prev_asid;
-               need_flush = true;
+               return;
        } else {
                u64 last_ctx_id = this_cpu_read(cpu_tlbstate.last_ctx_id);
 
@@ -329,6 +304,10 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                next_tlb_gen = atomic64_read(&next->context.tlb_gen);
 
                choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush);
+
+               /* Let nmi_uaccess_okay() know that we're changing CR3. */
+               this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
+               barrier();
        }
 
        if (need_flush) {
@@ -361,6 +340,9 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
        if (next != &init_mm)
                this_cpu_write(cpu_tlbstate.last_ctx_id, next->context.ctx_id);
 
+       /* Make sure we write CR3 before loaded_mm. */
+       barrier();
+
        this_cpu_write(cpu_tlbstate.loaded_mm, next);
        this_cpu_write(cpu_tlbstate.loaded_mm_asid, new_asid);
 
@@ -473,9 +455,6 @@ static void flush_tlb_func_common(const struct flush_tlb_info *f,
                 * paging-structure cache to avoid speculatively reading
                 * garbage into our TLB.  Since switching to init_mm is barely
                 * slower than a minimal flush, just switch to init_mm.
-                *
-                * This should be rare, with native_flush_tlb_others skipping
-                * IPIs to lazy TLB mode CPUs.
                 */
                switch_mm_irqs_off(NULL, &init_mm, NULL);
                return;
@@ -536,17 +515,16 @@ static void flush_tlb_func_common(const struct flush_tlb_info *f,
            f->new_tlb_gen == local_tlb_gen + 1 &&
            f->new_tlb_gen == mm_tlb_gen) {
                /* Partial flush */
-               unsigned long addr;
-               unsigned long nr_pages = (f->end - f->start) >> PAGE_SHIFT;
+               unsigned long nr_invalidate = (f->end - f->start) >> f->stride_shift;
+               unsigned long addr = f->start;
 
-               addr = f->start;
                while (addr < f->end) {
                        __flush_tlb_one_user(addr);
-                       addr += PAGE_SIZE;
+                       addr += 1UL << f->stride_shift;
                }
                if (local)
-                       count_vm_tlb_events(NR_TLB_LOCAL_FLUSH_ONE, nr_pages);
-               trace_tlb_flush(reason, nr_pages);
+                       count_vm_tlb_events(NR_TLB_LOCAL_FLUSH_ONE, nr_invalidate);
+               trace_tlb_flush(reason, nr_invalidate);
        } else {
                /* Full flush. */
                local_flush_tlb();
@@ -582,9 +560,6 @@ static void flush_tlb_func_remote(void *info)
 void native_flush_tlb_others(const struct cpumask *cpumask,
                             const struct flush_tlb_info *info)
 {
-       cpumask_var_t lazymask;
-       unsigned int cpu;
-
        count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
        if (info->end == TLB_FLUSH_ALL)
                trace_tlb_flush(TLB_REMOTE_SEND_IPI, TLB_FLUSH_ALL);
@@ -608,6 +583,8 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
                 * that UV should be updated so that smp_call_function_many(),
                 * etc, are optimal on UV.
                 */
+               unsigned int cpu;
+
                cpu = smp_processor_id();
                cpumask = uv_flush_tlb_others(cpumask, info);
                if (cpumask)
@@ -615,29 +592,8 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
                                               (void *)info, 1);
                return;
        }
-
-       /*
-        * A temporary cpumask is used in order to skip sending IPIs
-        * to CPUs in lazy TLB state, while keeping them in mm_cpumask(mm).
-        * If the allocation fails, simply IPI every CPU in mm_cpumask.
-        */
-       if (!alloc_cpumask_var(&lazymask, GFP_ATOMIC)) {
-               smp_call_function_many(cpumask, flush_tlb_func_remote,
+       smp_call_function_many(cpumask, flush_tlb_func_remote,
                               (void *)info, 1);
-               return;
-       }
-
-       cpumask_copy(lazymask, cpumask);
-
-       for_each_cpu(cpu, lazymask) {
-               if (per_cpu(cpu_tlbstate.is_lazy, cpu))
-                       cpumask_clear_cpu(cpu, lazymask);
-       }
-
-       smp_call_function_many(lazymask, flush_tlb_func_remote,
-                              (void *)info, 1);
-
-       free_cpumask_var(lazymask);
 }
 
 /*
@@ -653,12 +609,15 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
 static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
 
 void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
-                               unsigned long end, unsigned long vmflag)
+                               unsigned long end, unsigned int stride_shift,
+                               bool freed_tables)
 {
        int cpu;
 
        struct flush_tlb_info info __aligned(SMP_CACHE_BYTES) = {
                .mm = mm,
+               .stride_shift = stride_shift,
+               .freed_tables = freed_tables,
        };
 
        cpu = get_cpu();
@@ -668,8 +627,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
 
        /* Should we flush just the requested range? */
        if ((end != TLB_FLUSH_ALL) &&
-           !(vmflag & VM_HUGETLB) &&
-           ((end - start) >> PAGE_SHIFT) <= tlb_single_page_flush_ceiling) {
+           ((end - start) >> stride_shift) <= tlb_single_page_flush_ceiling) {
                info.start = start;
                info.end = end;
        } else {
@@ -690,68 +648,6 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
        put_cpu();
 }
 
-void tlb_flush_remove_tables_local(void *arg)
-{
-       struct mm_struct *mm = arg;
-
-       if (this_cpu_read(cpu_tlbstate.loaded_mm) == mm &&
-                       this_cpu_read(cpu_tlbstate.is_lazy)) {
-               /*
-                * We're in lazy mode.  We need to at least flush our
-                * paging-structure cache to avoid speculatively reading
-                * garbage into our TLB.  Since switching to init_mm is barely
-                * slower than a minimal flush, just switch to init_mm.
-                */
-               switch_mm_irqs_off(NULL, &init_mm, NULL);
-       }
-}
-
-static void mm_fill_lazy_tlb_cpu_mask(struct mm_struct *mm,
-                                     struct cpumask *lazy_cpus)
-{
-       int cpu;
-
-       for_each_cpu(cpu, mm_cpumask(mm)) {
-               if (!per_cpu(cpu_tlbstate.is_lazy, cpu))
-                       cpumask_set_cpu(cpu, lazy_cpus);
-       }
-}
-
-void tlb_flush_remove_tables(struct mm_struct *mm)
-{
-       int cpu = get_cpu();
-       cpumask_var_t lazy_cpus;
-
-       if (cpumask_any_but(mm_cpumask(mm), cpu) >= nr_cpu_ids) {
-               put_cpu();
-               return;
-       }
-
-       if (!zalloc_cpumask_var(&lazy_cpus, GFP_ATOMIC)) {
-               /*
-                * If the cpumask allocation fails, do a brute force flush
-                * on all the CPUs that have this mm loaded.
-                */
-               smp_call_function_many(mm_cpumask(mm),
-                               tlb_flush_remove_tables_local, (void *)mm, 1);
-               put_cpu();
-               return;
-       }
-
-       /*
-        * CPUs with !is_lazy either received a TLB flush IPI while the user
-        * pages in this address range were unmapped, or have context switched
-        * and reloaded %CR3 since then.
-        *
-        * Shootdown IPIs at page table freeing time only need to be sent to
-        * CPUs that may have out of date TLB contents.
-        */
-       mm_fill_lazy_tlb_cpu_mask(mm, lazy_cpus);
-       smp_call_function_many(lazy_cpus,
-                               tlb_flush_remove_tables_local, (void *)mm, 1);
-       free_cpumask_var(lazy_cpus);
-       put_cpu();
-}
 
 static void do_flush_tlb_all(void *info)
 {