diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-14 17:07:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-14 17:07:33 -0700 |
commit | 2605a103cadb29053d6bc7e81c7de802ec75ce6c (patch) | |
tree | e2a83845f59217d66252c7a9265ff99a3b69f525 /include | |
parent | 53a3f3087be361dacfc02e7a85b6d6142a41ce8a (diff) | |
parent | ebb2a97b2e7422176d52f4f33e3ee400653875b4 (diff) |
Merge git://git.linux-xtensa.org/kernel/xtensa-feed
* git://git.linux-xtensa.org/kernel/xtensa-feed:
[patch 1/2] Xtensa: enable arbitary tty speed setting ioctls
[patch 2/2] xtensa console.c: remove duplicate #include
[XTENSA] Add support for cache-aliasing
[XTENSA] Add kernel module support
[XTENSA] Add support for executable/non-executable feature in the mmu
[XTENSA] Use the generic version of get_order
[XTENSA] Initialize semaphore_wake_lock
[XTENSA] Add typecast macro for constants
[XTENSA] Fix timer instabilities.
[XTENSA] Fix fadvise64_64
[XTENSA] Remove extraneous include statement
[XTENSA] Move string-io functions to io.c from pci.c
[XTENSA] Move pre-initialized structures to init_task.c
[XTENSA] Add freestanding option to CFLAGS
[XTENSA] Add getpgrp system-call to unistd.h
[XTENSA] add missing system calls
[XTENSA] fix wrong usage of __init and __initdata in traps.c
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-xtensa/bugs.h | 6 | ||||
-rw-r--r-- | include/asm-xtensa/cache.h | 9 | ||||
-rw-r--r-- | include/asm-xtensa/cacheflush.h | 81 | ||||
-rw-r--r-- | include/asm-xtensa/elf.h | 50 | ||||
-rw-r--r-- | include/asm-xtensa/io.h | 1 | ||||
-rw-r--r-- | include/asm-xtensa/ioctls.h | 4 | ||||
-rw-r--r-- | include/asm-xtensa/page.h | 106 | ||||
-rw-r--r-- | include/asm-xtensa/pgalloc.h | 107 | ||||
-rw-r--r-- | include/asm-xtensa/pgtable.h | 235 | ||||
-rw-r--r-- | include/asm-xtensa/processor.h | 2 | ||||
-rw-r--r-- | include/asm-xtensa/syscall.h | 24 | ||||
-rw-r--r-- | include/asm-xtensa/termbits.h | 5 | ||||
-rw-r--r-- | include/asm-xtensa/termios.h | 6 | ||||
-rw-r--r-- | include/asm-xtensa/timex.h | 4 | ||||
-rw-r--r-- | include/asm-xtensa/tlb.h | 30 | ||||
-rw-r--r-- | include/asm-xtensa/types.h | 9 | ||||
-rw-r--r-- | include/asm-xtensa/unistd.h | 128 |
17 files changed, 530 insertions, 277 deletions
diff --git a/include/asm-xtensa/bugs.h b/include/asm-xtensa/bugs.h index c4228532013..69b29d19824 100644 --- a/include/asm-xtensa/bugs.h +++ b/include/asm-xtensa/bugs.h @@ -13,10 +13,6 @@ #ifndef _XTENSA_BUGS_H #define _XTENSA_BUGS_H -#include <asm/processor.h> - -static void __init check_bugs(void) -{ -} +static void check_bugs(void) { } #endif /* _XTENSA_BUGS_H */ diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h index 1c4a78f29ae..3bba2a540cf 100644 --- a/include/asm-xtensa/cache.h +++ b/include/asm-xtensa/cache.h @@ -19,6 +19,15 @@ #define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS) #define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS) +#define DCACHE_WAY_SHIFT (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH) +#define ICACHE_WAY_SHIFT (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH) + +/* Maximum cache size per way. */ +#if DCACHE_WAY_SIZE >= ICACHE_WAY_SIZE +# define CACHE_WAY_SIZE DCACHE_WAY_SIZE +#else +# define CACHE_WAY_SIZE ICACHE_WAY_SIZE +#endif #endif /* _XTENSA_CACHE_H */ diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h index 22ef901b784..b773c57e75a 100644 --- a/include/asm-xtensa/cacheflush.h +++ b/include/asm-xtensa/cacheflush.h @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * (C) 2001 - 2006 Tensilica Inc. + * (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_CACHEFLUSH_H @@ -18,10 +18,7 @@ #include <asm/page.h> /* - * flush and invalidate data cache, invalidate instruction cache: - * - * __flush_invalidate_cache_all() - * __flush_invalidate_cache_range(from,sze) + * Lo-level routines for cache flushing. * * invalidate data or instruction cache: * @@ -40,26 +37,39 @@ * __flush_invalidate_dcache_all() * __flush_invalidate_dcache_page(adr) * __flush_invalidate_dcache_range(from,size) + * + * specials for cache aliasing: + * + * __flush_invalidate_dcache_page_alias(vaddr,paddr) + * __invalidate_icache_page_alias(vaddr,paddr) */ -extern void __flush_invalidate_cache_all(void); -extern void __flush_invalidate_cache_range(unsigned long, unsigned long); -extern void __flush_invalidate_dcache_all(void); +extern void __invalidate_dcache_all(void); extern void __invalidate_icache_all(void); - extern void __invalidate_dcache_page(unsigned long); extern void __invalidate_icache_page(unsigned long); extern void __invalidate_icache_range(unsigned long, unsigned long); extern void __invalidate_dcache_range(unsigned long, unsigned long); + #if XCHAL_DCACHE_IS_WRITEBACK +extern void __flush_invalidate_dcache_all(void); extern void __flush_dcache_page(unsigned long); +extern void __flush_dcache_range(unsigned long, unsigned long); extern void __flush_invalidate_dcache_page(unsigned long); extern void __flush_invalidate_dcache_range(unsigned long, unsigned long); #else -# define __flush_dcache_page(p) do { } while(0) -# define __flush_invalidate_dcache_page(p) do { } while(0) -# define __flush_invalidate_dcache_range(p,s) do { } while(0) +# define __flush_dcache_range(p,s) do { } while(0) +# define __flush_dcache_page(p) do { } while(0) +# define __flush_invalidate_dcache_page(p) __invalidate_dcache_page(p) +# define __flush_invalidate_dcache_range(p,s) __invalidate_dcache_range(p,s) +#endif + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) +extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long); +#endif +#if (ICACHE_WAY_SIZE > PAGE_SIZE) +extern void __invalidate_icache_page_alias(unsigned long, unsigned long); #endif /* @@ -71,17 +81,21 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long); * (see also Documentation/cachetlb.txt) */ -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +#if (DCACHE_WAY_SIZE > PAGE_SIZE) -#define flush_cache_all() __flush_invalidate_cache_all(); -#define flush_cache_mm(mm) __flush_invalidate_cache_all(); -#define flush_cache_dup_mm(mm) __flush_invalidate_cache_all(); +#define flush_cache_all() \ + do { \ + __flush_invalidate_dcache_all(); \ + __invalidate_icache_all(); \ + } while (0) -#define flush_cache_vmap(start,end) __flush_invalidate_cache_all(); -#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all(); +#define flush_cache_mm(mm) flush_cache_all() +#define flush_cache_dup_mm(mm) flush_cache_mm(mm) -extern void flush_dcache_page(struct page*); +#define flush_cache_vmap(start,end) flush_cache_all() +#define flush_cache_vunmap(start,end) flush_cache_all() +extern void flush_dcache_page(struct page*); extern void flush_cache_range(struct vm_area_struct*, ulong, ulong); extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long); @@ -101,24 +115,39 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon #endif +/* Ensure consistency between data and instruction cache. */ #define flush_icache_range(start,end) \ - __invalidate_icache_range(start,(end)-(start)) + do { \ + __flush_dcache_range(start, (end) - (start)); \ + __invalidate_icache_range(start,(end) - (start)); \ + } while (0) /* This is not required, see Documentation/cachetlb.txt */ - -#define flush_icache_page(vma,page) do { } while(0) +#define flush_icache_page(vma,page) do { } while (0) #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) +#if (DCACHE_WAY_SIZE > PAGE_SIZE) -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ - memcpy(dst, src, len) +extern void copy_to_user_page(struct vm_area_struct*, struct page*, + unsigned long, void*, const void*, unsigned long); +extern void copy_from_user_page(struct vm_area_struct*, struct page*, + unsigned long, void*, const void*, unsigned long); + +#else + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ + do { \ + memcpy(dst, src, len); \ + __flush_dcache_range((unsigned long) dst, len); \ + __invalidate_icache_range((unsigned long) dst, len); \ + } while (0) #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) -#endif /* __KERNEL__ */ +#endif +#endif /* __KERNEL__ */ #endif /* _XTENSA_CACHEFLUSH_H */ - diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 1569b53cec9..7083d46766a 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -20,6 +20,56 @@ #define EM_XTENSA 94 #define EM_XTENSA_OLD 0xABC7 +/* Xtensa relocations defined by the ABIs */ + +#define R_XTENSA_NONE 0 +#define R_XTENSA_32 1 +#define R_XTENSA_RTLD 2 +#define R_XTENSA_GLOB_DAT 3 +#define R_XTENSA_JMP_SLOT 4 +#define R_XTENSA_RELATIVE 5 +#define R_XTENSA_PLT 6 +#define R_XTENSA_OP0 8 +#define R_XTENSA_OP1 9 +#define R_XTENSA_OP2 10 +#define R_XTENSA_ASM_EXPAND 11 +#define R_XTENSA_ASM_SIMPLIFY 12 +#define R_XTENSA_GNU_VTINHERIT 15 +#define R_XTENSA_GNU_VTENTRY 16 +#define R_XTENSA_DIFF8 17 +#define R_XTENSA_DIFF16 18 +#define R_XTENSA_DIFF32 19 +#define R_XTENSA_SLOT0_OP 20 +#define R_XTENSA_SLOT1_OP 21 +#define R_XTENSA_SLOT2_OP 22 +#define R_XTENSA_SLOT3_OP 23 +#define R_XTENSA_SLOT4_OP 24 +#define R_XTENSA_SLOT5_OP 25 +#define R_XTENSA_SLOT6_OP 26 +#define R_XTENSA_SLOT7_OP 27 +#define R_XTENSA_SLOT8_OP 28 +#define R_XTENSA_SLOT9_OP 29 +#define R_XTENSA_SLOT10_OP 30 +#define R_XTENSA_SLOT11_OP 31 +#define R_XTENSA_SLOT12_OP 32 +#define R_XTENSA_SLOT13_OP 33 +#define R_XTENSA_SLOT14_OP 34 +#define R_XTENSA_SLOT0_ALT 35 +#define R_XTENSA_SLOT1_ALT 36 +#define R_XTENSA_SLOT2_ALT 37 +#define R_XTENSA_SLOT3_ALT 38 +#define R_XTENSA_SLOT4_ALT 39 +#define R_XTENSA_SLOT5_ALT 40 +#define R_XTENSA_SLOT6_ALT 41 +#define R_XTENSA_SLOT7_ALT 42 +#define R_XTENSA_SLOT8_ALT 43 +#define R_XTENSA_SLOT9_ALT 44 +#define R_XTENSA_SLOT10_ALT 45 +#define R_XTENSA_SLOT11_ALT 46 +#define R_XTENSA_SLOT12_ALT 47 +#define R_XTENSA_SLOT13_ALT 48 +#define R_XTENSA_SLOT14_ALT 49 + /* ELF register definitions. This is needed for core dump support. */ /* diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h index 0faa614d969..47c3616ea9a 100644 --- a/include/asm-xtensa/io.h +++ b/include/asm-xtensa/io.h @@ -14,6 +14,7 @@ #ifdef __KERNEL__ #include <asm/byteorder.h> #include <asm/page.h> +#include <linux/kernel.h> #include <linux/types.h> diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h index 39e6f23921b..0ffa942954b 100644 --- a/include/asm-xtensa/ioctls.h +++ b/include/asm-xtensa/ioctls.h @@ -91,6 +91,10 @@ #define TIOCSBRK _IO('T', 39) /* BSD compatibility */ #define TIOCCBRK _IO('T', 40) /* BSD compatibility */ #define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/ +#define TCGETS2 _IOR('T', 42, struct termios2) +#define TCSETS2 _IOW('T', 43, struct termios2) +#define TCSETSW2 _IOW('T', 44, struct termios2) +#define TCSETSF2 _IOW('T', 45, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h index 1213cde7543..55ce2c9749a 100644 --- a/include/asm-xtensa/page.h +++ b/include/asm-xtensa/page.h @@ -1,11 +1,11 @@ /* - * linux/include/asm-xtensa/page.h + * include/asm-xtensa/page.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version2 as * published by the Free Software Foundation. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_PAGE_H @@ -14,6 +14,12 @@ #ifdef __KERNEL__ #include <asm/processor.h> +#include <asm/types.h> +#include <asm/cache.h> + +/* + * Fixed TLB translations in the processor. + */ #define XCHAL_KSEG_CACHED_VADDR 0xd0000000 #define XCHAL_KSEG_BYPASS_VADDR 0xd8000000 @@ -26,13 +32,60 @@ */ #define PAGE_SHIFT 12 -#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_SIZE (__XTENSA_UL_CONST(1) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK) #define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR -#define MAX_MEM_PFN XCHAL_KSEG_SIZE -#define PGTABLE_START 0x80000000 +#define MAX_MEM_PFN XCHAL_KSEG_SIZE +#define PGTABLE_START 0x80000000 + +/* + * Cache aliasing: + * + * If the cache size for one way is greater than the page size, we have to + * deal with cache aliasing. The cache index is wider than the page size: + * + * | |cache| cache index + * | pfn |off| virtual address + * |xxxx:X|zzz| + * | : | | + * | \ / | | + * |trans.| | + * | / \ | | + * |yyyy:Y|zzz| physical address + * + * When the page number is translated to the physical page address, the lowest + * bit(s) (X) that are part of the cache index are also translated (Y). + * If this translation changes bit(s) (X), the cache index is also afected, + * thus resulting in a different cache line than before. + * The kernel does not provide a mechanism to ensure that the page color + * (represented by this bit) remains the same when allocated or when pages + * are remapped. When user pages are mapped into kernel space, the color of + * the page might also change. + * + * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2 + * to temporarily map a patch so we can match the color. + */ + +#if DCACHE_WAY_SIZE > PAGE_SIZE +# define DCACHE_ALIAS_ORDER (DCACHE_WAY_SHIFT - PAGE_SHIFT) +# define DCACHE_ALIAS_MASK (PAGE_MASK & (DCACHE_WAY_SIZE - 1)) +# define DCACHE_ALIAS(a) (((a) & DCACHE_ALIAS_MASK) >> PAGE_SHIFT) +# define DCACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0) +#else +# define DCACHE_ALIAS_ORDER 0 +#endif + +#if ICACHE_WAY_SIZE > PAGE_SIZE +# define ICACHE_ALIAS_ORDER (ICACHE_WAY_SHIFT - PAGE_SHIFT) +# define ICACHE_ALIAS_MASK (PAGE_MASK & (ICACHE_WAY_SIZE - 1)) +# define ICACHE_ALIAS(a) (((a) & ICACHE_ALIAS_MASK) >> PAGE_SHIFT) +# define ICACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & ICACHE_ALIAS_MASK) == 0) +#else +# define ICACHE_ALIAS_ORDER 0 +#endif + #ifdef __ASSEMBLY__ @@ -58,34 +111,23 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* * Pure 2^n version of get_order + * Use 'nsau' instructions if supported by the processor or the generic version. */ -static inline int get_order(unsigned long size) +#if XCHAL_HAVE_NSA + +static inline __attribute_const__ int get_order(unsigned long size) { - int order; -#ifndef XCHAL_HAVE_NSU - unsigned long x1, x2, x4, x8, x16; - - size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - x1 = size & 0xAAAAAAAA; - x2 = size & 0xCCCCCCCC; - x4 = size & 0xF0F0F0F0; - x8 = size & 0xFF00FF00; - x16 = size & 0xFFFF0000; - order = x2 ? 2 : 0; - order += (x16 != 0) * 16; - order += (x8 != 0) * 8; - order += (x4 != 0) * 4; - order += (x1 != 0); - - return order; -#else - size = (size - 1) >> PAGE_SHIFT; - asm ("nsau %0, %1" : "=r" (order) : "r" (size)); - return 32 - order; -#endif + int lz; + asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT)); + return 32 - lz; } +#else + +# include <asm-generic/page.h> + +#endif struct page; extern void clear_page(void *page); @@ -96,11 +138,11 @@ extern void copy_page(void *to, void *from); * some extra work */ -#if (DCACHE_WAY_SIZE > PAGE_SIZE) -void clear_user_page(void *addr, unsigned long vaddr, struct page* page); -void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page); +#if DCACHE_WAY_SIZE > PAGE_SIZE +extern void clear_user_page(void*, unsigned long, struct page*); +extern void copy_user_page(void*, void*, unsigned long, struct page*); #else -# define clear_user_page(page,vaddr,pg) clear_page(page) +# define clear_user_page(page, vaddr, pg) clear_page(page) # define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #endif diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h index d56ddf2055e..3e5b5652510 100644 --- a/include/asm-xtensa/pgalloc.h +++ b/include/asm-xtensa/pgalloc.h @@ -1,11 +1,11 @@ /* - * linux/include/asm-xtensa/pgalloc.h + * include/asm-xtensa/pgalloc.h * * 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. * - * Copyright (C) 2001-2005 Tensilica Inc. + * Copyright (C) 2001-2007 Tensilica Inc. */ #ifndef _XTENSA_PGALLOC_H @@ -13,103 +13,54 @@ #ifdef __KERNEL__ -#include <linux/threads.h> #include <linux/highmem.h> -#include <asm/processor.h> -#include <asm/cacheflush.h> - - -/* Cache aliasing: - * - * If the cache size for one way is greater than the page size, we have to - * deal with cache aliasing. The cache index is wider than the page size: - * - * |cache | - * |pgnum |page| virtual address - * |xxxxxX|zzzz| - * | | | - * \ / | | - * trans.| | - * / \ | | - * |yyyyyY|zzzz| physical address - * - * When the page number is translated to the physical page address, the lowest - * bit(s) (X) that are also part of the cache index are also translated (Y). - * If this translation changes this bit (X), the cache index is also afected, - * thus resulting in a different cache line than before. - * The kernel does not provide a mechanism to ensure that the page color - * (represented by this bit) remains the same when allocated or when pages - * are remapped. When user pages are mapped into kernel space, the color of - * the page might also change. - * - * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2 - * to temporarily map a patch so we can match the color. - */ - -#if (DCACHE_WAY_SIZE > PAGE_SIZE) -# define PAGE_COLOR_MASK (PAGE_MASK & (DCACHE_WAY_SIZE-1)) -# define PAGE_COLOR(a) \ - (((unsigned long)(a)&PAGE_COLOR_MASK) >> PAGE_SHIFT) -# define PAGE_COLOR_EQ(a,b) \ - ((((unsigned long)(a) ^ (unsigned long)(b)) & PAGE_COLOR_MASK) == 0) -# define PAGE_COLOR_MAP0(v) \ - (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK)) -# define PAGE_COLOR_MAP1(v) \ - (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK) + DCACHE_WAY_SIZE) -#endif /* * Allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -#define pgd_free(pgd) free_page((unsigned long)(pgd)) - -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +#define pmd_populate_kernel(mm, pmdp, ptep) \ + (pmd_val(*(pmdp)) = ((unsigned long)ptep)) +#define pmd_populate(mm, pmdp, page) \ + (pmd_val(*(pmdp)) = ((unsigned long)page_to_virt(page))) -static inline void -pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *pte) +static inline pgd_t* +pgd_alloc(struct mm_struct *mm) { - pmd_val(*(pmdp)) = (unsigned long)(pte); - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp)); + return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER); } -static inline void -pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *page) +static inline void pgd_free(pgd_t *pgd) { - pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page); - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp)); + free_page((unsigned long)pgd); } +/* Use a slab cache for the pte pages (see also sparc64 implementation) */ +extern struct kmem_cache *pgtable_cache; -#else - -# define pmd_populate_kernel(mm, pmdp, pte) \ - (pmd_val(*(pmdp)) = (unsigned long)(pte)) -# define pmd_populate(mm, pmdp, page) \ - (pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page)) - -#endif - -static inline pgd_t* -pgd_alloc(struct mm_struct *mm) +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) { - pgd_t *pgd; - - pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGD_ORDER); - - if (likely(pgd != NULL)) - __flush_dcache_page((unsigned long)pgd); + return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT); +} - return pgd; +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long addr) +{ + return virt_to_page(pte_alloc_one_kernel(mm, addr)); } -extern pte_t* pte_alloc_one_kernel(struct mm_struct* mm, unsigned long addr); -extern struct page* pte_alloc_one(struct mm_struct* mm, unsigned long addr); +static inline void pte_free_kernel(pte_t *pte) +{ + kmem_cache_free(pgtable_cache, pte); +} -#define pte_free_kernel(pte) free_page((unsigned long)pte) -#define pte_free(pte) __free_page(pte) +static inline void pte_free(struct page *page) +{ + kmem_cache_free(pgtable_cache, page_address(page)); +} #endif /* __KERNEL__ */ #endif /* _XTENSA_PGALLOC_H */ diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h index 06850f3b26a..c0fcc1c9660 100644 --- a/include/asm-xtensa/pgtable.h +++ b/include/asm-xtensa/pgtable.h @@ -1,11 +1,11 @@ /* - * linux/include/asm-xtensa/pgtable.h + * include/asm-xtensa/pgtable.h * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version2 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_PGTABLE_H @@ -23,7 +23,7 @@ /* * The Xtensa architecture port of Linux has a two-level page table system, - * i.e. the logical three-level Linux page table layout are folded. + * i.e. the logical three-level Linux page table layout is folded. * Each task has the following memory page tables: * * PGD table (page directory), ie. 3rd-level page table: @@ -43,6 +43,7 @@ * * The individual pages are 4 kB big with special pages for the empty_zero_page. */ + #define PGDIR_SHIFT 22 #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) @@ -53,24 +54,26 @@ */ #define PTRS_PER_PTE 1024 #define PTRS_PER_PTE_SHIFT 10 -#define PTRS_PER_PMD 1 #define PTRS_PER_PGD 1024 #define PGD_ORDER 0 -#define PMD_ORDER 0 #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0 #define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT) -/* virtual memory area. We keep a distance to other memory regions to be +/* + * Virtual memory area. We keep a distance to other memory regions to be * on the safe side. We also use this area for cache aliasing. */ -// FIXME: virtual memory area must be configuration-dependent - #define VMALLOC_START 0xC0000000 -#define VMALLOC_END 0xC7FF0000 +#define VMALLOC_END 0xC6FEFFFF +#define TLBTEMP_BASE_1 0xC6FF0000 +#define TLBTEMP_BASE_2 0xC6FF8000 +#define MODULE_START 0xC7000000 +#define MODULE_END 0xC7FFFFFF -/* Xtensa Linux config PTE layout (when present): +/* + * Xtensa Linux config PTE layout (when present): * 31-12: PPN * 11-6: Software * 5-4: RING @@ -86,47 +89,55 @@ * See further below for PTE layout for swapped-out pages. */ -#define _PAGE_VALID (1<<0) /* hardware: page is accessible */ -#define _PAGE_WRENABLE (1<<1) /* hardware: page is writable */ +#define _PAGE_HW_EXEC (1<<0) /* hardware: page is executable */ +#define _PAGE_HW_WRITE (1<<1) /* hardware: page is writable */ + +#define _PAGE_FILE (1<<1) /* non-linear mapping, if !present */ +#define _PAGE_PROTNONE (3<<0) /* special case for VM_PROT_NONE */ /* None of these cache modes include MP coherency: */ -#define _PAGE_NO_CACHE (0<<2) /* bypass, non-speculative */ -#if XCHAL_DCACHE_IS_WRITEBACK -# define _PAGE_WRITEBACK (1<<2) /* write back */ -# define _PAGE_WRITETHRU (2<<2) /* write through */ -#else -# define _PAGE_WRITEBACK (1<<2) /* assume write through */ -# define _PAGE_WRITETHRU (1<<2) -#endif -#define _PAGE_NOALLOC (3<<2) /* don't allocate cache,if not cached */ -#define _CACHE_MASK (3<<2) +#define _PAGE_CA_BYPASS (0<<2) /* bypass, non-speculative */ +#define _PAGE_CA_WB (1<<2) /* write-back */ +#define _PAGE_CA_WT (2<<2) /* write-through */ +#define _PAGE_CA_MASK (3<<2) +#define _PAGE_INVALID (3<<2) #define _PAGE_USER (1<<4) /* user access (ring=1) */ -#define _PAGE_KERNEL (0<<4) /* kernel access (ring=0) */ /* Software */ -#define _PAGE_RW (1<<6) /* software: page writable */ +#define _PAGE_WRITABLE_BIT 6 +#define _PAGE_WRITABLE (1<<6) /* software: page writable */ #define _PAGE_DIRTY (1<<7) /* software: page dirty */ #define _PAGE_ACCESSED (1<<8) /* software: page accessed (read) */ -#define _PAGE_FILE (1<<9) /* nonlinear file mapping*/ -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _CACHE_MASK | _PAGE_DIRTY) -#define _PAGE_PRESENT ( _PAGE_VALID | _PAGE_WRITEBACK | _PAGE_ACCESSED) +/* On older HW revisions, we always have to set bit 0 */ +#if XCHAL_HW_VERSION_MAJOR < 2000 +# define _PAGE_VALID (1<<0) +#else +# define _PAGE_VALID 0 +#endif -#ifdef CONFIG_MMU +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_PRESENT (_PAGE_VALID | _PAGE_CA_WB | _PAGE_ACCESSED) -# define PAGE_NONE __pgprot(_PAGE_PRESENT) -# define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_RW) -# define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER) -# define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER) -# define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_KERNEL | _PAGE_WRENABLE) -# define PAGE_INVALID __pgprot(_PAGE_USER) +#ifdef CONFIG_MMU -# if (DCACHE_WAY_SIZE > PAGE_SIZE) -# define PAGE_DIRECTORY __pgprot(_PAGE_VALID | _PAGE_ACCESSED | _PAGE_KERNEL) -# else -# define PAGE_DIRECTORY __pgprot(_PAGE_PRESENT | _PAGE_KERNEL) -# endif +#define PAGE_NONE __pgprot(_PAGE_INVALID | _PAGE_USER | _PAGE_PROTNONE) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE) +#define PAGE_SHARED_EXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE | _PAGE_HW_EXEC) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_HW_WRITE) +#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC) + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) +# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED) +#else +# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB) +#endif #else /* no mmu */ @@ -145,23 +156,23 @@ * What follows is the closest we can get by reasonable means.. * See linux/mm/mmap.c for protection_map[] array that uses these definitions. */ -#define __P000 PAGE_NONE /* private --- */ -#define __P001 PAGE_READONLY /* private --r */ -#define __P010 PAGE_COPY /* private -w- */ -#define __P011 PAGE_COPY /* private -wr */ -#define __P100 PAGE_READONLY /* private x-- */ -#define __P101 PAGE_READONLY /* private x-r */ -#define __P110 PAGE_COPY /* private xw- */ -#define __P111 PAGE_COPY /* private xwr */ - -#define __S000 PAGE_NONE /* shared --- */ -#define __S001 PAGE_READONLY /* shared --r */ -#define __S010 PAGE_SHARED /* shared -w- */ -#define __S011 PAGE_SHARED /* shared -wr */ -#define __S100 PAGE_READONLY /* shared x-- */ -#define __S101 PAGE_READONLY /* shared x-r */ -#define __S110 PAGE_SHARED /* shared xw- */ -#define __S111 PAGE_SHARED /* shared xwr */ +#define __P000 PAGE_NONE /* private --- */ +#define __P001 PAGE_READONLY /* private --r */ +#define __P010 PAGE_COPY /* private -w- */ +#define __P011 PAGE_COPY /* private -wr */ +#define __P100 PAGE_READONLY_EXEC /* private x-- */ +#define __P101 PAGE_READONLY_EXEC /* private x-r */ +#define __P110 PAGE_COPY_EXEC /* private xw- */ +#define __P111 PAGE_COPY_EXEC /* private xwr */ + +#define __S000 PAGE_NONE /* shared --- */ +#define __S001 PAGE_READONLY /* shared --r */ +#define __S010 PAGE_SHARED /* shared -w- */ +#define __S011 PAGE_SHARED /* shared -wr */ +#define __S100 PAGE_READONLY_EXEC /* shared x-- */ +#define __S101 PAGE_READONLY_EXEC /* shared x-r */ +#define __S110 PAGE_SHARED_EXEC /* shared xw- */ +#define __S111 PAGE_SHARED_EXEC /* shared xwr */ #ifndef __ASSEMBLY__ @@ -183,35 +194,42 @@ extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)]; #define pmd_page(pmd) virt_to_page(pmd_val(pmd)) /* - * The following only work if pte_present() is true. + * pte status. */ -#define pte_none(pte) (!(pte_val(pte) ^ _PAGE_USER)) -#define pte_present(pte) (pte_val(pte) & _PAGE_VALID) +#define pte_none(pte) (pte_val(pte) == _PAGE_INVALID) +#define pte_present(pte) \ + (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_INVALID) \ + || ((pte_val(pte) & _PAGE_PROTNONE) == _PAGE_PROTNONE)) #define pte_clear(mm,addr,ptep) \ - do { update_pte(ptep, __pte(_PAGE_USER)); } while(0) + do { update_pte(ptep, __pte(_PAGE_INVALID)); } while(0) #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK) -#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0) #define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK) +#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0) -/* Note: We use the _PAGE_USER bit to indicate write-protect kernel memory */ - -static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } -static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW | _PAGE_WRENABLE); return pte; } -static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } -static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } -static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; } -static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; } -static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; } +static inline pte_t pte_wrprotect(pte_t pte) + { pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; } +static inline pte_t pte_mkclean(pte_t pte) + { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HW_WRITE); return pte; } +static inline pte_t pte_mkold(pte_t pte) + { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } +static inline pte_t pte_mkdirty(pte_t pte) + { pte_val(pte) |= _PAGE_DIRTY; return pte; } +static inline pte_t pte_mkyoung(pte_t pte) + { pte_val(pte) |= _PAGE_ACCESSED; return pte; } +static inline pte_t pte_mkwrite(pte_t pte) + { pte_val(pte) |= _PAGE_WRITABLE; return pte; } /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ + #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) #define pte_same(a,b) (pte_val(a) == pte_val(b)) #define pte_page(x) pfn_to_page(pte_pfn(x)) @@ -232,8 +250,9 @@ static inline void update_pte(pte_t *ptep, pte_t pteval) { *ptep = pteval; #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (ptep)); + __asm__ __volatile__ ("dhwb %0, 0" :: "a" (ptep)); #endif + } struct mm_struct; @@ -249,9 +268,6 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval) { *pmdp = pmdval; -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp)); -#endif } struct vm_area_struct; @@ -306,52 +322,34 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) /* * Encode and decode a swap entry. - * Each PTE in a process VM's page table is either: - * "present" -- valid and not swapped out, protection bits are meaningful; - * "not present" -- which further subdivides in these two cases: - * "none" -- no mapping at all; identified by pte_none() |