Commit 9c7fd8c7 authored by Russell King's avatar Russell King

[ARM] Optimise ARM TLB handling

Sanitise includes of asm/tlbflush.h, asm/cacheflush.h, asm/proc-fns.h
Implement ARM-specific TLB "shootdown" code.  It turns out that it
is overall more efficient to unconditionally invalidate the whole
TLB rather than entry by entry when removing areas.
parent d6494ca3
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/page.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
......
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/cacheflush.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include "fault.h" #include "fault.h"
......
...@@ -519,6 +519,10 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) ...@@ -519,6 +519,10 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
bdata->node_boot_start >> PAGE_SHIFT, zhole_size); bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
} }
#ifndef CONFIG_DISCONTIGMEM
mem_map = contig_page_data.node_mem_map;
#endif
/* /*
* finish off the bad pages once * finish off the bad pages once
* the mem_map is initialised * the mem_map is initialised
...@@ -559,7 +563,9 @@ void __init mem_init(void) ...@@ -559,7 +563,9 @@ void __init mem_init(void)
initpages = &__init_end - &__init_begin; initpages = &__init_end - &__init_begin;
high_memory = (void *)__va(meminfo.end); high_memory = (void *)__va(meminfo.end);
#ifndef CONFIG_DISCONTIGMEM
max_mapnr = virt_to_page(high_memory) - mem_map; max_mapnr = virt_to_page(high_memory) - mem_map;
#endif
/* /*
* We may have non-contiguous memory. * We may have non-contiguous memory.
......
...@@ -15,9 +15,11 @@ ...@@ -15,9 +15,11 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbflush.h>
/* /*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/highmem.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include <asm/rmap.h> #include <asm/rmap.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/tlbflush.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/cacheflush.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/tlbflush.h>
#ifndef MULTI_CPU #ifndef MULTI_CPU
EXPORT_SYMBOL(cpu_cache_clean_invalidate_all); EXPORT_SYMBOL(cpu_cache_clean_invalidate_all);
...@@ -29,11 +31,11 @@ EXPORT_SYMBOL(cpu_set_pte); ...@@ -29,11 +31,11 @@ EXPORT_SYMBOL(cpu_set_pte);
EXPORT_SYMBOL(processor); EXPORT_SYMBOL(processor);
#endif #endif
#ifndef MULTI_TLB /*
EXPORT_SYMBOL_NOVERS(__cpu_flush_kern_tlb_all); * No module should need to touch the TLB (and currently
EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_mm); * no modules do. We export this for "loadkernel" support
EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_range); * (booting a new kernel from within a running kernel.)
EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_page); */
#else #ifdef MULTI_TLB
EXPORT_SYMBOL(cpu_tlb); EXPORT_SYMBOL(cpu_tlb);
#endif #endif
...@@ -13,31 +13,10 @@ ...@@ -13,31 +13,10 @@
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/constants.h> #include <asm/constants.h>
#include <asm/tlbflush.h>
#include "proc-macros.S" #include "proc-macros.S"
.align 5 .align 5
/*
* v3_flush_user_tlb_mm(mm)
*
* Invalidate all TLB entries in a particular address space
*
* - mm - mm_struct describing address space
*/
ENTRY(v3_flush_user_tlb_mm)
act_mm r1 @ get current->active_mm
teq r0, r1 @ == mm ?
movne pc, lr @ no, we dont do anything
/*
* v3_flush_kern_tlb_all()
*
* Invalidate the entire TLB
*/
ENTRY(v3_flush_kern_tlb_all)
mov r0, #0
mcr p15, 0, r0, c5, c0, 0 @ invalidate TLB
mov pc, lr
/* /*
* v3_flush_user_tlb_range(start, end, mm) * v3_flush_user_tlb_range(start, end, mm)
* *
...@@ -62,32 +41,11 @@ ENTRY(v3_flush_kern_tlb_range) ...@@ -62,32 +41,11 @@ ENTRY(v3_flush_kern_tlb_range)
blo 1b blo 1b
mov pc, lr mov pc, lr
/*
* v3_flush_user_tlb_page(vaddr,vma)
*
* Invalidate the specified page in the specified address space.
*
* - vaddr - virtual address (may not be aligned)
* - vma - vma_struct describing address range
*/
.align 5
ENTRY(v3_flush_user_tlb_page)
vma_vm_mm r2, r1 @ get vma->vm_mm
act_mm r3 @ get current->active_mm
teq r2, r3 @ equal
movne pc, lr @ no
ENTRY(v3_flush_kern_tlb_page)
mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry
mov pc, lr
.section ".text.init", #alloc, #execinstr .section ".text.init", #alloc, #execinstr
.type v3_tlb_fns, #object .type v3_tlb_fns, #object
ENTRY(v3_tlb_fns) ENTRY(v3_tlb_fns)
.long v3_flush_kern_tlb_all
.long v3_flush_user_tlb_mm
.long v3_flush_user_tlb_range .long v3_flush_user_tlb_range
.long v3_flush_user_tlb_page
.long v3_flush_kern_tlb_range .long v3_flush_kern_tlb_range
.long v3_flush_kern_tlb_page .long v3_tlb_flags
.size v3_tlb_fns, . - v3_tlb_fns .size v3_tlb_fns, . - v3_tlb_fns
...@@ -14,31 +14,10 @@ ...@@ -14,31 +14,10 @@
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/constants.h> #include <asm/constants.h>
#include <asm/tlbflush.h>
#include "proc-macros.S" #include "proc-macros.S"
.align 5 .align 5
/*
* v4_flush_user_tlb_mm(mm)
*
* Invalidate all TLB entries in a particular address space
*
* - mm - mm_struct describing address space
*/
ENTRY(v4_flush_user_tlb_mm)
act_mm r1 @ get current->active_mm
teq r0, r1 @ == mm ?
movne pc, lr @ no, we dont do anything
/*
* v4_flush_kern_tlb_all()
*
* Invalidate the entire TLB
*/
ENTRY(v4_flush_kern_tlb_all)
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mov pc, lr
/* /*
* v4_flush_user_tlb_range(start, end, mm) * v4_flush_user_tlb_range(start, end, mm)
* *
...@@ -64,25 +43,6 @@ ENTRY(v4_flush_user_tlb_range) ...@@ -64,25 +43,6 @@ ENTRY(v4_flush_user_tlb_range)
blo 1b blo 1b
mov pc, lr mov pc, lr
/*
* v4_flush_user_tlb_page(vaddr,vma)
*
* Invalidate the specified page in the specified address space.
*
* - vaddr - virtual address (may not be aligned)
* - vma - vma_struct describing address range
*/
.align 5
ENTRY(v4_flush_user_tlb_page)
vma_vm_mm r2, r1 @ get vma->vm_mm
act_mm r3 @ get current->active_mm
teq r2, r3 @ equal
movne pc, lr @ no
vma_vm_flags r2, r1
.v4_flush_kern_tlb_page:
mcr p15, 0, r0, c8, c7, 1 @ invalidate TLB entry
mov pc, lr
/* /*
* v4_flush_kerm_tlb_range(start, end) * v4_flush_kerm_tlb_range(start, end)
* *
...@@ -95,27 +55,11 @@ ENTRY(v4_flush_user_tlb_page) ...@@ -95,27 +55,11 @@ ENTRY(v4_flush_user_tlb_page)
.globl v4_flush_kern_tlb_range .globl v4_flush_kern_tlb_range
.equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range .equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range
/*
* v4_flush_kern_tlb_page(kaddr)
*
* Invalidate the TLB entry for the specified page. The address
* will be in the kernels virtual memory space. Current uses
* only require the D-TLB to be invalidated.
*
* - kaddr - Kernel virtual memory address
*/
.globl v4_flush_kern_tlb_page
.equ v4_flush_kern_tlb_page, .v4_flush_kern_tlb_page
.section ".text.init", #alloc, #execinstr .section ".text.init", #alloc, #execinstr
.type v4_tlb_fns, #object .type v4_tlb_fns, #object
ENTRY(v4_tlb_fns) ENTRY(v4_tlb_fns)
.long v4_flush_kern_tlb_all
.long v4_flush_user_tlb_mm
.long v4_flush_user_tlb_range .long v4_flush_user_tlb_range
.long v4_flush_user_tlb_page
.long v4_flush_kern_tlb_range .long v4_flush_kern_tlb_range
.long v4_flush_kern_tlb_page .long v4_tlb_flags
.size v4_tlb_fns, . - v4_tlb_fns .size v4_tlb_fns, . - v4_tlb_fns
...@@ -14,34 +14,10 @@ ...@@ -14,34 +14,10 @@
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/constants.h> #include <asm/constants.h>
#include <asm/tlbflush.h>
#include "proc-macros.S" #include "proc-macros.S"
.align 5 .align 5
/*
* v4wb_flush_user_tlb_mm(mm)
*
* Invalidate all TLB entries in a particular address space
*
* - mm - mm_struct describing address space
*/
ENTRY(v4wb_flush_user_tlb_mm)
ENTRY(v4wbi_flush_user_tlb_mm)
act_mm r1 @ get current->active_mm
teq r0, r1 @ == mm ?
movne pc, lr @ no, we dont do anything
/*
* v4wb_flush_tlb_all()
*
* Invalidate the entire TLB
*/
ENTRY(v4wb_flush_kern_tlb_all)
ENTRY(v4wbi_flush_kern_tlb_all)
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mov pc, lr
/* /*
* v4wb_flush_user_tlb_range(start, end, mm) * v4wb_flush_user_tlb_range(start, end, mm)
* *
...@@ -69,28 +45,6 @@ ENTRY(v4wb_flush_user_tlb_range) ...@@ -69,28 +45,6 @@ ENTRY(v4wb_flush_user_tlb_range)
blo 1b blo 1b
mov pc, lr mov pc, lr
/*
* v4wb_flush_user_tlb_page(vaddr,vma)
*
* Invalidate the specified page in the specified address space.
*
* - vaddr - virtual address (may not be aligned)
* - vma - vma_struct describing address range
*/
.align 5
ENTRY(v4wb_flush_user_tlb_page)
vma_vm_mm r2, r1 @ get vma->vm_mm
act_mm r3 @ get current->active_mm
teq r2, r3 @ equal
movne pc, lr @ no
vma_vm_flags r2, r1
mov r3, #0
mcr p15, 0, r3, c7, c10, 4 @ drain WB
tst r2, #VM_EXEC
mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
mov pc, lr
/* /*
* v4_flush_kerm_tlb_range(start, end) * v4_flush_kerm_tlb_range(start, end)
* *
...@@ -112,20 +66,6 @@ ENTRY(v4wb_flush_kern_tlb_range) ...@@ -112,20 +66,6 @@ ENTRY(v4wb_flush_kern_tlb_range)
blo 1b blo 1b
mov pc, lr mov pc, lr
/*
* v4_flush_kern_tlb_page(kaddr)
*
* Invalidate the TLB entry for the specified page. The address
* will be in the kernels virtual memory space. Current uses
* only require the D-TLB to be invalidated.
*
* - kaddr - Kernel virtual memory address
*/
ENTRY(v4wb_flush_kern_tlb_page)
mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
mov pc, lr
/* /*
* These two are optimised for ARM920, ARM922, ARM926, Xscale * These two are optimised for ARM920, ARM922, ARM926, Xscale
*/ */
...@@ -158,28 +98,6 @@ ENTRY(v4wbi_flush_user_tlb_range) ...@@ -158,28 +98,6 @@ ENTRY(v4wbi_flush_user_tlb_range)
blo 1b blo 1b
mov pc, lr mov pc, lr
/*
* v4wb_flush_tlb_page(vaddr,vma)
*
* Invalidate the specified page in the specified address space.
*
* - vaddr - virtual address (may not be aligned)
* - vma - vma_struct describing address range
*/
.align 5
ENTRY(v4wbi_flush_user_tlb_page)
vma_vm_mm r2, r1 @ get vma->vm_mm
act_mm r3 @ get current->active_mm
teq r2, r3 @ equal
movne pc, lr @ no
vma_vm_flags r2, r1
mov r3, #0
mcr p15, 0, r3, c7, c10, 4 @ drain WB
tst r2, #VM_EXEC
mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
mov pc, lr
ENTRY(v4wbi_flush_kern_tlb_range) ENTRY(v4wbi_flush_kern_tlb_range)
mov r3, #0 mov r3, #0
mcr p15, 0, r3, c7, c10, 4 @ drain WB mcr p15, 0, r3, c7, c10, 4 @ drain WB
...@@ -192,29 +110,18 @@ ENTRY(v4wbi_flush_kern_tlb_range) ...@@ -192,29 +110,18 @@ ENTRY(v4wbi_flush_kern_tlb_range)
blo 1b blo 1b
mov pc, lr mov pc, lr
ENTRY(v4wbi_flush_kern_tlb_page)
mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
mov pc, lr
.section ".text.init", #alloc, #execinstr .section ".text.init", #alloc, #execinstr
.type v4wb_tlb_fns, #object .type v4wb_tlb_fns, #object
ENTRY(v4wb_tlb_fns) ENTRY(v4wb_tlb_fns)
.long v4wb_flush_kern_tlb_all
.long v4wb_flush_user_tlb_mm
.long v4wb_flush_user_tlb_range .long v4wb_flush_user_tlb_range
.long v4wb_flush_user_tlb_page
.long v4wb_flush_kern_tlb_range .long v4wb_flush_kern_tlb_range
.long v4wb_flush_kern_tlb_page .long v4wb_tlb_flags
.size v4wb_tlb_fns, . - v4wb_tlb_fns .size v4wb_tlb_fns, . - v4wb_tlb_fns
.type v4wbi_tlb_fns, #object .type v4wbi_tlb_fns, #object
ENTRY(v4wbi_tlb_fns) ENTRY(v4wbi_tlb_fns)
.long v4wbi_flush_kern_tlb_all
.long v4wbi_flush_user_tlb_mm
.long v4wbi_flush_user_tlb_range .long v4wbi_flush_user_tlb_range
.long v4wbi_flush_user_tlb_page
.long v4wbi_flush_kern_tlb_range .long v4wbi_flush_kern_tlb_range
.long v4wbi_flush_kern_tlb_page .long v4wbi_tlb_flags
.size v4wbi_tlb_fns, . - v4wbi_tlb_fns .size v4wbi_tlb_fns, . - v4wbi_tlb_fns
...@@ -26,59 +26,6 @@ ...@@ -26,59 +26,6 @@
/*
* MMU TLB Model
* =============
*
* We have the following to choose from:
* v3 - ARMv3
* v4 - ARMv4 without write buffer
* v4wb - ARMv4 with write buffer without I TLB flush entry instruction
* v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
*/
#undef _TLB
#undef MULTI_TLB
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v3
# endif
#endif
#if defined(CONFIG_CPU_ARM720T)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4
# endif
#endif
#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \
defined(CONFIG_CPU_XSCALE)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4wbi
# endif
#endif
#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4wb
# endif
#endif
#ifndef _TLB
#error Unknown TLB model
#endif
/* /*
* Data Abort Model * Data Abort Model
* ================ * ================
...@@ -156,69 +103,4 @@ ...@@ -156,69 +103,4 @@
#error Unknown data abort handler type #error Unknown data abort handler type
#endif #endif
/*
* User Space Model
* ================
*
* This section selects the correct set of functions for dealing with
* page-based copying and clearing for user space for the particular
* processor(s) we're building for.
*
* We have the following to choose from:
* v3 - ARMv3
* v4wt - ARMv4 with writethrough cache, without minicache
* v4wb - ARMv4 with writeback cache, without minicache
* v4_mc - ARMv4 with minicache
* xscale - Xscale
*/
#undef _USER
#undef MULTI_USER
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v3
# endif
#endif
#if defined(CONFIG_CPU_ARM720T)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v4wt
# endif
#endif
#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_SA110) || \
defined(CONFIG_CPU_ARM1020)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v4wb
# endif
#endif
#if defined(CONFIG_CPU_SA1100)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v4_mc
# endif
#endif
#if defined(CONFIG_CPU_XSCALE)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER xscale_mc
# endif
#endif
#ifndef _USER
#error Unknown user operations model
#endif
#endif #endif
...@@ -8,6 +8,70 @@ ...@@ -8,6 +8,70 @@
#include <asm/glue.h> #include <asm/glue.h>
/*
* User Space Model
* ================
*
* This section selects the correct set of functions for dealing with
* page-based copying and clearing for user space for the particular
* processor(s) we're building for.
*
* We have the following to choose from:
* v3 - ARMv3
* v4wt - ARMv4 with writethrough cache, without minicache
* v4wb - ARMv4 with writeback cache, without minicache
* v4_mc - ARMv4 with minicache
* xscale - Xscale
*/
#undef _USER
#undef MULTI_USER
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v3
# endif
#endif
#if defined(CONFIG_CPU_ARM720T)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v4wt
# endif
#endif
#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_SA110) || \
defined(CONFIG_CPU_ARM1020)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v4wb
# endif
#endif
#if defined(CONFIG_CPU_SA1100)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER v4_mc
# endif
#endif
#if defined(CONFIG_CPU_XSCALE)
# ifdef _USER
# define MULTI_USER 1
# else
# define _USER xscale_mc
# endif
#endif
#ifndef _USER
#error Unknown user operations model
#endif
struct cpu_user_fns { struct cpu_user_fns {
void (*cpu_clear_user_page)(void *p, unsigned long user); void (*cpu_clear_user_page)(void *p, unsigned long user);
void (*cpu_copy_user_page)(void *to, const void *from, void (*cpu_copy_user_page)(void *to, const void *from,
......
...@@ -11,9 +11,6 @@ ...@@ -11,9 +11,6 @@
#define _ASMARM_PGALLOC_H #define _ASMARM_PGALLOC_H
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/proc/pgalloc.h> #include <asm/proc/pgalloc.h>
/* /*
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/proc-fns.h>
#include <asm/arch/vmalloc.h> #include <asm/arch/vmalloc.h>
/* /*
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
#ifndef __ASM_PROC_SYSTEM_H #ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H #define __ASM_PROC_SYSTEM_H
#include <asm/proc-fns.h>
#define vectors_base() (0) #define vectors_base() (0)
static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* *
* Page table allocation/freeing primitives for 32-bit ARM processors. * Page table allocation/freeing primitives for 32-bit ARM processors.
*/ */
#include <asm/cacheflush.h>
#include "pgtable.h" #include "pgtable.h"
/* /*
......
...@@ -7,6 +7,113 @@ ...@@ -7,6 +7,113 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <asm/glue.h>
#define TLB_V3_PAGE (1 << 0)
#define TLB_V4_U_PAGE (1 << 1)
#define TLB_V4_D_PAGE (1 << 2)
#define TLB_V4_I_PAGE (1 << 3)
#define TLB_V3_FULL (1 << 8)
#define TLB_V4_U_FULL (1 << 9)
#define TLB_V4_D_FULL (1 << 10)
#define TLB_V4_I_FULL (1 << 11)
#define TLB_WB (1 << 31)
/*
* MMU TLB Model
* =============
*
* We have the following to choose from:
* v3 - ARMv3
* v4 - ARMv4 without write buffer
* v4wb - ARMv4 with write buffer without I TLB flush entry instruction
* v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
*/
#undef _TLB
#undef MULTI_TLB
#define v3_tlb_flags (TLB_V3_FULL | TLB_V3_PAGE)
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v3
# endif
#endif
#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE)
#if defined(CONFIG_CPU_ARM720T)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4
# endif
#endif
#define v4wbi_tlb_flags (TLB_WB | \
TLB_V4_I_FULL | TLB_V4_D_FULL | \
TLB_V4_I_PAGE | TLB_V4_D_PAGE)
#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \
defined(CONFIG_CPU_XSCALE)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4wbi
# endif
#endif
#define v4wb_tlb_flags (TLB_WB | \
TLB_V4_I_FULL | TLB_V4_D_FULL | \
TLB_V4_D_PAGE)
#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
# ifdef _TLB
# define MULTI_TLB 1
# else
# define _TLB v4wb
# endif
#endif
#ifndef _TLB
#error Unknown TLB model
#endif
#ifndef __ASSEMBLY__
struct cpu_tlb_fns {
void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
void (*flush_kern_range)(unsigned long, unsigned long);
unsigned long tlb_flags;
};
/*
* Select the calling method
*/
#ifdef MULTI_TLB
extern struct cpu_tlb_fns cpu_tlb;
#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range
#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
#define __cpu_tlb_flags cpu_tlb.tlb_flags
#else
#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range)
#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range)
#define __cpu_tlb_flags __glue(_TLB,_tlb_flags)
extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
#endif
/* /*
* TLB Management * TLB Management
...@@ -51,56 +158,94 @@ ...@@ -51,56 +158,94 @@
* - kaddr - Kernel virtual memory address * - kaddr - Kernel virtual memory address
*/ */
struct cpu_tlb_fns { #define tlb_flag(f) (__cpu_tlb_flags & (f))
void (*flush_kern_all)(void);
void (*flush_user_mm)(struct mm_struct *);
void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
void (*flush_user_page)(unsigned long, struct vm_area_struct *);
void (*flush_kern_range)(unsigned long, unsigned long);
void (*flush_kern_page)(unsigned long);
};
/* static inline void flush_tlb_all(void)
* Convert calls to our calling convention. {
*/ const int zero = 0;
#define flush_tlb_all() __cpu_flush_kern_tlb_all()
#define flush_tlb_mm(mm) __cpu_flush_user_tlb_mm(mm)
#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
#define flush_tlb_page(vma,vaddr) __cpu_flush_user_tlb_page(vaddr,vma)
#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
#define flush_tlb_kernel_page(kaddr) __cpu_flush_kern_tlb_page(kaddr)
/* if (tlb_flag(TLB_WB))
* Now select the calling method asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
*/
#ifdef MULTI_TLB
extern struct cpu_tlb_fns cpu_tlb; if (tlb_flag(TLB_V3_FULL))
asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
if (tlb_flag(TLB_V4_U_FULL))
asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
if (tlb_flag(TLB_V4_D_FULL))
asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
if (tlb_flag(TLB_V4_I_FULL))
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
#define __cpu_flush_kern_tlb_all cpu_tlb.flush_kern_all static inline void flush_tlb_mm(struct mm_struct *mm)
#define __cpu_flush_user_tlb_mm cpu_tlb.flush_user_mm {
#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range const int zero = 0;
#define __cpu_flush_user_tlb_page cpu_tlb.flush_user_page
#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
#define __cpu_flush_kern_tlb_page cpu_tlb.flush_kern_page
#else if (tlb_flag(TLB_WB))
asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
#define __cpu_flush_kern_tlb_all __glue(_TLB,_flush_kern_tlb_all) if (mm == current->active_mm) {
#define __cpu_flush_user_tlb_mm __glue(_TLB,_flush_user_tlb_mm) if (tlb_flag(TLB_V3_FULL))
#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range) asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
#define __cpu_flush_user_tlb_page __glue(_TLB,_flush_user_tlb_page) if (tlb_flag(TLB_V4_U_FULL))
#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range) asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
#define __cpu_flush_kern_tlb_page __glue(_TLB,_flush_kern_tlb_page) if (tlb_flag(TLB_V4_D_FULL))
asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
if (tlb_flag(TLB_V4_I_FULL))
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
}
extern void __cpu_flush_kern_tlb_all(void); static inline void
extern void __cpu_flush_user_tlb_mm(struct mm_struct *); flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *); {
extern void __cpu_flush_user_tlb_page(unsigned long, struct vm_area_struct *); const int zero = 0;
extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
extern void __cpu_flush_kern_tlb_page(unsigned long);
#endif uaddr &= PAGE_MASK;
if (tlb_flag(TLB_WB))
asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
if (vma->vm_mm == current->active_mm) {
if (tlb_flag(TLB_V3_PAGE))
asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (uaddr));
if (tlb_flag(TLB_V4_U_PAGE))
asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr));
if (tlb_flag(TLB_V4_D_PAGE))
asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr));
if (tlb_flag(TLB_V4_I_PAGE))
asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
}
static inline void flush_tlb_kernel_page(unsigned long kaddr)
{
const int zero = 0;
kaddr &= PAGE_MASK;
if (tlb_flag(TLB_WB))
asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
if (tlb_flag(TLB_V3_PAGE))
asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (kaddr));
if (tlb_flag(TLB_V4_U_PAGE))
asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr));
if (tlb_flag(TLB_V4_D_PAGE))
asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr));
if (tlb_flag(TLB_V4_I_PAGE))
asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr));
if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
/*
* Convert calls to our calling convention.
*/
#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
/* /*
* if PG_dcache_dirty is set for the page, we need to ensure that any * if PG_dcache_dirty is set for the page, we need to ensure that any
...@@ -123,3 +268,4 @@ extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte ...@@ -123,3 +268,4 @@ extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte
#define memc_update_addr(mm,pte,log) do { } while (0) #define memc_update_addr(mm,pte,log) do { } while (0)
#define memc_clear(mm,physaddr) do { } while (0) #define memc_clear(mm,physaddr) do { } while (0)
#endif
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <asm/proc-fns.h>
struct cpu_tlb_fns; struct cpu_tlb_fns;
struct cpu_user_fns; struct cpu_user_fns;
struct processor; struct processor;
......
/*
* linux/include/asm-arm/tlb.h
*
* Copyright (C) 2002 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Experimentation shows that on a StrongARM, it appears to be faster
* to use the "invalidate whole tlb" rather than "invalidate single
* tlb" for this.
*
* This appears true for both the process fork+exit case, as well as
* the munmap-large-area case.
*/
#ifndef __ASMARM_TLB_H #ifndef __ASMARM_TLB_H
#define __ASMARM_TLB_H #define __ASMARM_TLB_H
#include <asm/cacheflush.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#define tlb_flush(tlb) \ /*
flush_tlb_mm((tlb)->mm) * TLB handling. This allows us to remove pages from the page
#define tlb_start_vma(tlb,vma) \ * tables, and efficiently handle the TLB issues.
flush_cache_range(vma, vma->vm_start, vma->vm_end) */
#define tlb_end_vma(tlb,vma) \ typedef struct free_pte_ctx {
flush_tlb_range(vma, vma->vm_start, vma->vm_end) struct mm_struct *mm;
unsigned int freed;
#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) unsigned int flushes;
unsigned int avoided_flushes;
} mmu_gather_t;
#include <asm-generic/tlb.h> extern mmu_gather_t mmu_gathers[NR_CPUS];
#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
#define __pte_free_tlb(tlb, pte) pte_free(pte) {
int cpu = smp_processor_id();
mmu_gather_t *tlb = &mmu_gathers[cpu];
tlb->mm = mm;
tlb->freed = 0;
return tlb;
}
static inline void tlb_finish_mmu(mmu_gather_t *tlb, unsigned long start, unsigned long end)
{
struct mm_struct *mm = tlb->mm;
unsigned long freed = tlb->freed;
int rss = mm->rss;
if (rss < freed)
freed = rss;
mm->rss = rss - freed;
if (freed) {
flush_tlb_mm(mm);
tlb->flushes++;
} else {
tlb->avoided_flushes++;
}
/* keep the page table cache within bounds */
check_pgt_cache();
}
#define tlb_remove_tlb_entry(tlb,ptep,address) do { } while (0)
#define tlb_start_vma(tlb,vma) do { } while (0)
#define tlb_end_vma(tlb,vma) do { } while (0)
#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page)
#define pte_free_tlb(tlb,ptep) pte_free(ptep)
#define pmd_free_tlb(tlb,pmdp) pmd_free(pmdp)
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment