summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-09-14 17:07:33 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-09-14 17:07:33 -0700
commit2605a103cadb29053d6bc7e81c7de802ec75ce6c (patch)
treee2a83845f59217d66252c7a9265ff99a3b69f525 /include
parent53a3f3087be361dacfc02e7a85b6d6142a41ce8a (diff)
parentebb2a97b2e7422176d52f4f33e3ee400653875b4 (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.h6
-rw-r--r--include/asm-xtensa/cache.h9
-rw-r--r--include/asm-xtensa/cacheflush.h81
-rw-r--r--include/asm-xtensa/elf.h50
-rw-r--r--include/asm-xtensa/io.h1
-rw-r--r--include/asm-xtensa/ioctls.h4
-rw-r--r--include/asm-xtensa/page.h106
-rw-r--r--include/asm-xtensa/pgalloc.h107
-rw-r--r--include/asm-xtensa/pgtable.h235
-rw-r--r--include/asm-xtensa/processor.h2
-rw-r--r--include/asm-xtensa/syscall.h24
-rw-r--r--include/asm-xtensa/termbits.h5
-rw-r--r--include/asm-xtensa/termios.h6
-rw-r--r--include/asm-xtensa/timex.h4
-rw-r--r--include/asm-xtensa/tlb.h30
-rw-r--r--include/asm-xtensa/types.h9
-rw-r--r--include/asm-xtensa/unistd.h128
17 files changed, 530 insertions, 277 deletions
diff --git a/include/asm-xtensa/bugs.h b/include/asm-xtensa/bugs.h
index c42285320133..69b29d198249 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 1c4a78f29ae2..3bba2a540cf0 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 22ef901b7845..b773c57e75a5 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 1569b53cec91..7083d46766a8 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 0faa614d9696..47c3616ea9ac 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 39e6f23921bb..0ffa942954b9 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 1213cde75438..55ce2c9749a3 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 d56ddf2055e1..3e5b56525102 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 06850f3b26a7..c0fcc1c9660c 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(), set by pte_clear(
- * "swapped out" -- the page is swapped out, and the SWP macros below
- * are used to store swap file info in the PTE itself.
*
- * In the Xtensa processor MMU, any PTE entries in user space (or anywhere
- * in virtual memory that can map differently across address spaces)
- * must have a correct ring value that represents the RASID