aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/xtensa/kernel/asm-offsets.c13
-rw-r--r--arch/xtensa/kernel/entry.S75
-rw-r--r--arch/xtensa/mm/Makefile6
-rw-r--r--arch/xtensa/mm/cache.c256
-rw-r--r--arch/xtensa/mm/fault.c6
-rw-r--r--arch/xtensa/mm/init.c252
-rw-r--r--arch/xtensa/mm/misc.S306
-rw-r--r--include/asm-xtensa/cache.h9
-rw-r--r--include/asm-xtensa/cacheflush.h81
-rw-r--r--include/asm-xtensa/io.h1
-rw-r--r--include/asm-xtensa/page.h56
-rw-r--r--include/asm-xtensa/pgalloc.h107
-rw-r--r--include/asm-xtensa/pgtable.h32
-rw-r--r--include/asm-xtensa/tlb.h30
14 files changed, 816 insertions, 414 deletions
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index d0323cd6a2ea..d5ffe7b6443e 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -18,12 +18,13 @@
18#include <linux/stddef.h> 18#include <linux/stddef.h>
19#include <linux/thread_info.h> 19#include <linux/thread_info.h>
20#include <linux/ptrace.h> 20#include <linux/ptrace.h>
21#include <linux/mm.h>
22
21#include <asm/ptrace.h> 23#include <asm/ptrace.h>
22#include <asm/processor.h> 24#include <asm/processor.h>
23#include <asm/uaccess.h> 25#include <asm/uaccess.h>
24 26
25#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val)) 27#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
26#define BLANK() asm volatile("\n->" : : )
27 28
28int main(void) 29int main(void)
29{ 30{
@@ -63,7 +64,6 @@ int main(void)
63 DEFINE(PT_SIZE, sizeof(struct pt_regs)); 64 DEFINE(PT_SIZE, sizeof(struct pt_regs));
64 DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS])); 65 DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
65 DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS])); 66 DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
66 BLANK();
67 67
68 /* struct task_struct */ 68 /* struct task_struct */
69 DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace)); 69 DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
@@ -73,27 +73,26 @@ int main(void)
73 DEFINE(TASK_THREAD, offsetof (struct task_struct, thread)); 73 DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
74 DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack)); 74 DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
75 DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct)); 75 DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
76 BLANK();
77 76
78 /* struct thread_info (offset from start_struct) */ 77 /* struct thread_info (offset from start_struct) */
79 DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra)); 78 DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
80 DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); 79 DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
81 DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save)); 80 DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
82 DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds)); 81 DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
83 BLANK();
84 82
85 /* struct mm_struct */ 83 /* struct mm_struct */
86 DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users)); 84 DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
87 DEFINE(MM_PGD, offsetof (struct mm_struct, pgd)); 85 DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
88 DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context)); 86 DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
89 BLANK(); 87
90 DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT); 88 /* struct page */
89 DEFINE(PAGE_FLAGS, offsetof(struct page, flags));
91 90
92 /* constants */ 91 /* constants */
93 DEFINE(_CLONE_VM, CLONE_VM); 92 DEFINE(_CLONE_VM, CLONE_VM);
94 DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED); 93 DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
94 DEFINE(PG_ARCH_1, PG_arch_1);
95 95
96 return 0; 96 return 0;
97} 97}
98 98
99
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 65741e3368e7..91a689eca43d 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -7,7 +7,7 @@
7 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details. 8 * for more details.
9 * 9 *
10 * Copyright (C) 2004-2005 by Tensilica Inc. 10 * Copyright (C) 2004-2007 by Tensilica Inc.
11 * 11 *
12 * Chris Zankel <chris@zankel.net> 12 * Chris Zankel <chris@zankel.net>
13 * 13 *
@@ -169,7 +169,7 @@ _user_exception:
169 * We have to save all registers up to the first '1' from 169 * We have to save all registers up to the first '1' from
170 * the right, except the current frame (bit 0). 170 * the right, except the current frame (bit 0).
171 * Assume a2 is: 001001000110001 171 * Assume a2 is: 001001000110001
172 * All regiser frames starting from the top fiel to the marked '1' 172 * All register frames starting from the top field to the marked '1'
173 * must be saved. 173 * must be saved.
174 */ 174 */
175 175
@@ -1590,7 +1590,7 @@ ENTRY(fast_second_level_miss)
1590 * The messy computation for 'pteval' above really simplifies 1590 * The messy computation for 'pteval' above really simplifies
1591 * into the following: 1591 * into the following:
1592 * 1592 *
1593 * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL 1593 * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY
1594 */ 1594 */
1595 1595
1596 movi a1, -PAGE_OFFSET 1596 movi a1, -PAGE_OFFSET
@@ -1602,7 +1602,7 @@ ENTRY(fast_second_level_miss)
1602 or a0, a0, a1 # ... | PAGE_DIRECTORY 1602 or a0, a0, a1 # ... | PAGE_DIRECTORY
1603 1603
1604 /* 1604 /*
1605 * We utilize all three wired-ways (7-9( to hold pmd translations. 1605 * We utilize all three wired-ways (7-9) to hold pmd translations.
1606 * Memory regions are mapped to the DTLBs according to bits 28 and 29. 1606 * Memory regions are mapped to the DTLBs according to bits 28 and 29.
1607 * This allows to map the three most common regions to three different 1607 * This allows to map the three most common regions to three different
1608 * DTLBs: 1608 * DTLBs:
@@ -1652,6 +1652,73 @@ ENTRY(fast_second_level_miss)
16529: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 16529: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0
1653 j 8b 1653 j 8b
1654 1654
1655#if (DCACHE_WAY_SIZE > PAGE_SIZE)
1656
16572: /* Special case for cache aliasing.
1658 * We (should) only get here if a clear_user_page, copy_user_page
1659 * or the aliased cache flush functions got preemptively interrupted
1660 * by another task. Re-establish temporary mapping to the
1661 * TLBTEMP_BASE areas.
1662 */
1663
1664 /* We shouldn't be in a double exception */
1665
1666 l32i a0, a2, PT_DEPC
1667 bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f
1668
1669 /* Make sure the exception originated in the special functions */
1670
1671 movi a0, __tlbtemp_mapping_start
1672 rsr a3, EPC_1
1673 bltu a3, a0, 2f
1674 movi a0, __tlbtemp_mapping_end
1675 bgeu a3, a0, 2f
1676
1677 /* Check if excvaddr was in one of the TLBTEMP_BASE areas. */
1678
1679 movi a3, TLBTEMP_BASE_1
1680 rsr a0, EXCVADDR
1681 bltu a0, a3, 2f
1682
1683 addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))
1684 bgeu a1, a3, 2f
1685
1686 /* Check if we have to restore an ITLB mapping. */
1687
1688 movi a1, __tlbtemp_mapping_itlb
1689 rsr a3, EPC_1
1690 sub a3, a3, a1
1691
1692 /* Calculate VPN */
1693
1694 movi a1, PAGE_MASK
1695 and a1, a1, a0
1696
1697 /* Jump for ITLB entry */
1698
1699 bgez a3, 1f
1700
1701 /* We can use up to two TLBTEMP areas, one for src and one for dst. */
1702
1703 extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 1
1704 add a1, a3, a1
1705
1706 /* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */
1707
1708 mov a0, a6
1709 movnez a0, a7, a3
1710 j 3b
1711
1712 /* ITLB entry. We only use dst in a6. */
1713
17141: witlb a6, a1
1715 isync
1716 j 4b
1717
1718
1719#endif // DCACHE_WAY_SIZE > PAGE_SIZE
1720
1721
16552: /* Invalid PGD, default exception handling */ 17222: /* Invalid PGD, default exception handling */
1656 1723
1657 movi a3, exc_table 1724 movi a3, exc_table
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile
index a5aed5932d7b..10aec22a8f98 100644
--- a/arch/xtensa/mm/Makefile
+++ b/arch/xtensa/mm/Makefile
@@ -5,9 +5,5 @@
5# removes any old dependencies. DON'T put your own dependencies here 5# removes any old dependencies. DON'T put your own dependencies here
6# unless it's something special (ie not a .c file). 6# unless it's something special (ie not a .c file).
7# 7#
8# Note 2! The CFLAGS definition is now in the main makefile...
9 8
10obj-y := init.o fault.o tlb.o misc.o 9obj-y := init.o fault.o tlb.o misc.o cache.o
11obj-m :=
12obj-n :=
13obj- :=
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c
new file mode 100644
index 000000000000..9a1fa9478ae7
--- /dev/null
+++ b/arch/xtensa/mm/cache.c
@@ -0,0 +1,256 @@
1/*
2 * arch/xtensa/mm/cache.c
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 2001-2006 Tensilica Inc.
9 *
10 * Chris Zankel <chris@zankel.net>
11 * Joe Taylor
12 * Marc Gauthier
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/signal.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/string.h>
22#include <linux/types.h>
23#include <linux/ptrace.h>
24#include <linux/bootmem.h>
25#include <linux/swap.h>
26#include <linux/pagemap.h>
27
28#include <asm/pgtable.h>
29#include <asm/bootparam.h>
30#include <asm/mmu_context.h>
31#include <asm/tlb.h>
32#include <asm/tlbflush.h>
33#include <asm/page.h>
34#include <asm/pgalloc.h>
35#include <asm/pgtable.h>
36
37//#define printd(x...) printk(x)
38#define printd(x...) do { } while(0)
39
40/*
41 * Note:
42 * The kernel provides one architecture bit PG_arch_1 in the page flags that
43 * can be used for cache coherency.
44 *
45 * I$-D$ coherency.
46 *
47 * The Xtensa architecture doesn't keep the instruction cache coherent with
48 * the data cache. We use the architecture bit to indicate if the caches
49 * are coherent. The kernel clears this bit whenever a page is added to the
50 * page cache. At that time, the caches might not be in sync. We, therefore,
51 * define this flag as 'clean' if set.
52 *
53 * D-cache aliasing.
54 *
55 * With cache aliasing, we have to always flush the cache when pages are
56 * unmapped (see tlb_start_vma(). So, we use this flag to indicate a dirty
57 * page.
58 *
59 *
60 *
61 */
62
63#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
64
65/*
66 * Any time the kernel writes to a user page cache page, or it is about to
67 * read from a page cache page this routine is called.
68 *
69 */
70
71void flush_dcache_page(struct page *page)
72{
73 struct address_space *mapping = page_mapping(page);
74
75 /*
76 * If we have a mapping but the page is not mapped to user-space
77 * yet, we simply mark this page dirty and defer flushing the
78 * caches until update_mmu().
79 */
80
81 if (mapping && !mapping_mapped(mapping)) {
82 if (!test_bit(PG_arch_1, &page->flags))
83 set_bit(PG_arch_1, &page->flags);
84 return;
85
86 } else {
87
88 unsigned long phys = page_to_phys(page);
89 unsigned long temp = page->index << PAGE_SHIFT;
90 unsigned long alias = !(DCACHE_ALIAS_EQ(temp, phys));
91 unsigned long virt;
92
93 /*
94 * Flush the page in kernel space and user space.
95 * Note that we can omit that step if aliasing is not
96 * an issue, but we do have to synchronize I$ and D$
97 * if we have a mapping.
98 */
99
100 if (!alias && !mapping)
101 return;
102
103 __flush_invalidate_dcache_page((long)page_address(page));
104
105 virt = TLBTEMP_BASE_1 + (temp & DCACHE_ALIAS_MASK);
106
107 if (alias)
108 __flush_invalidate_dcache_page_alias(virt, phys);
109
110 if (mapping)
111 __invalidate_icache_page_alias(virt, phys);
112 }
113
114 /* There shouldn't be an entry in the cache for this page anymore. */
115}
116
117
118/*
119 * For now, flush the whole cache. FIXME??
120 */
121
122void flush_cache_range(struct vm_area_struct* vma,
123 unsigned long start, unsigned long end)
124{
125 __flush_invalidate_dcache_all();
126 __invalidate_icache_all();
127}
128
129/*
130 * Remove any entry in the cache for this page.
131 *
132 * Note that this function is only called for user pages, so use the
133 * alias versions of the cache flush functions.
134 */
135
136void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
137 unsigned long pfn)
138{
139 /* Note that we have to use the 'alias' address to avoid multi-hit */
140
141 unsigned long phys = page_to_phys(pfn_to_page(pfn));
142 unsigned long virt = TLBTEMP_BASE_1 + (address & DCACHE_ALIAS_MASK);
143
144 __flush_invalidate_dcache_page_alias(virt, phys);
145 __invalidate_icache_page_alias(virt, phys);
146}
147
148#endif
149
150void
151update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
152{
153 unsigned long pfn = pte_pfn(pte);
154 struct page *page;
155
156 if (!pfn_valid(pfn))
157 return;
158
159 page = pfn_to_page(pfn);
160
161 /* Invalidate old entry in TLBs */
162
163 invalidate_itlb_mapping(addr);
164 invalidate_dtlb_mapping(addr);
165
166#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
167
168 if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
169
170 unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
171 unsigned long paddr = (unsigned long) page_address(page);
172 unsigned long phys = page_to_phys(page);
173
174 __flush_invalidate_dcache_page(paddr);
175
176 __flush_invalidate_dcache_page_alias(vaddr, phys);
177 __invalidate_icache_page_alias(vaddr, phys);
178
179 clear_bit(PG_arch_1, &page->flags);
180 }
181#else
182 if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
183 && (vma->vm_flags & VM_EXEC) != 0) {
184 unsigned long vaddr = addr & PAGE_MASK;
185 __flush_dcache_page(vaddr);
186 __invalidate_icache_page(vaddr);
187 set_bit(PG_arch_1, &page->flags);
188 }
189#endif
190}
191
192/*
193 * access_process_vm() has called get_user_pages(), which has done a
194 * flush_dcache_page() on the page.
195 */
196
197#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
198
199void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
200 unsigned long vaddr, void *dst, const void *src,
201 unsigned long len)
202{
203 unsigned long phys = page_to_phys(page);
204 unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
205
206 /* Flush and invalidate user page if aliased. */
207
208 if (alias) {
209 unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
210 __flush_invalidate_dcache_page_alias(temp, phys);
211 }
212
213 /* Copy data */
214
215 memcpy(dst, src, len);
216
217 /*
218 * Flush and invalidate kernel page if aliased and synchronize
219 * data and instruction caches for executable pages.
220 */
221
222 if (alias) {
223 unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
224
225 __flush_invalidate_dcache_range((unsigned long) dst, len);
226 if ((vma->vm_flags & VM_EXEC) != 0) {
227 __invalidate_icache_page_alias(temp, phys);
228 }
229
230 } else if ((vma->vm_flags & VM_EXEC) != 0) {
231 __flush_dcache_range((unsigned long)dst,len);
232 __invalidate_icache_range((unsigned long) dst, len);
233 }
234}
235
236extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
237 unsigned long vaddr, void *dst, const void *src,
238 unsigned long len)
239{
240 unsigned long phys = page_to_phys(page);
241 unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
242
243 /*
244 * Flush user page if aliased.
245 * (Note: a simply flush would be sufficient)
246 */
247
248 if (alias) {
249 unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
250 __flush_invalidate_dcache_page_alias(temp, phys);
251 }
252
253 memcpy(dst, src, len);
254}
255
256#endif
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 16004067add3..45d28f217c03 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -24,6 +24,8 @@
24unsigned long asid_cache = ASID_USER_FIRST; 24unsigned long asid_cache = ASID_USER_FIRST;
25void bad_page_fault(struct pt_regs*, unsigned long, int); 25void bad_page_fault(struct pt_regs*, unsigned long, int);
26 26
27#undef DEBUG_PAGE_FAULT
28
27/* 29/*
28 * This routine handles page faults. It determines the address, 30 * This routine handles page faults. It determines the address,
29 * and the problem, and then passes it off to one of the appropriate 31 * and the problem, and then passes it off to one of the appropriate
@@ -64,7 +66,7 @@ void do_page_fault(struct pt_regs *regs)
64 exccause == EXCCAUSE_ITLB_MISS || 66 exccause == EXCCAUSE_ITLB_MISS ||
65 exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0; 67 exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
66 68
67#if 0 69#ifdef DEBUG_PAGE_FAULT
68 printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid, 70 printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
69 address, exccause, regs->pc, is_write? "w":"", is_exec? "x":""); 71 address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
70#endif 72#endif
@@ -219,7 +221,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
219 221
220 /* Are we prepared to handle this kernel fault? */ 222 /* Are we prepared to handle this kernel fault? */
221 if ((entry = search_exception_tables(regs->pc)) != NULL) { 223 if ((entry = search_exception_tables(regs->pc)) != NULL) {
222#if 1 224#ifdef DEBUG_PAGE_FAULT
223 printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n", 225 printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n",
224 current->comm, regs->pc, entry->fixup); 226 current->comm, regs->pc, entry->fixup);
225#endif 227#endif
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 8415c76f11c2..b3086f34a8e7 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -15,40 +15,24 @@
15 * Kevin Chea 15 * Kevin Chea
16 */ 16 */
17 17
18#include <linux/init.h>
19#include <linux/signal.h>
20#include <linux/sched.h>
21#include <linux/kernel.h> 18#include <linux/kernel.h>
22#include <linux/errno.h> 19#include <linux/errno.h>
23#include <linux/string.h>
24#include <linux/types.h>
25#include <linux/ptrace.h>
26#include <linux/bootmem.h> 20#include <linux/bootmem.h>
27#include <linux/swap.h> 21#include <linux/swap.h>
22#include <linux/mman.h>
23#include <linux/nodemask.h>
24#include <linux/mm.h>
25#include <linux/slab.h>
28 26
29#include <asm/pgtable.h> 27#include <asm/pgtable.h>
30#include <asm/bootparam.h> 28#include <asm/bootparam.h>
31#include <asm/mmu_context.h> 29#include <asm/mmu_context.h>
32#include <asm/tlb.h> 30#include <asm/tlb.h>
33#include <asm/tlbflush.h>
34#include <asm/page.h> 31#include <asm/page.h>
35#include <asm/pgalloc.h> 32#include <asm/pgalloc.h>
36#include <asm/pgtable.h>
37
38 33
39#define DEBUG 0
40 34
41DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 35DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
42//static DEFINE_SPINLOCK(tlb_lock);
43
44/*
45 * This flag is used to indicate that the page was mapped and modified in
46 * kernel space, so the cache is probably dirty at that address.
47 * If cache aliasing is enabled and the page color mismatches, update_mmu_cache
48 * synchronizes the caches if this bit is set.
49 */
50
51#define PG_cache_clean PG_arch_1
52 36
53/* References to section boundaries */ 37/* References to section boundaries */
54 38
@@ -323,228 +307,22 @@ void show_mem(void)
323 printk("%d free pages\n", free); 307 printk("%d free pages\n", free);
324} 308}
325 309
326/* ------------------------------------------------------------------------- */ 310struct kmem_cache *pgtable_cache __read_mostly;
327
328#if (DCACHE_WAY_SIZE > PAGE_SIZE)
329
330/*
331 * With cache aliasing, the page color of the page in kernel space and user
332 * space might mismatch. We temporarily map the page to a different virtual
333 * address with the same color and clear the page there.
334 */
335
336void clear_user_page(void *kaddr, unsigned long vaddr, struct page* page)
337{
338
339 /* There shouldn't be any entries for this page. */
340
341 __flush_invalidate_dcache_page_phys(__pa(page_address(page)));
342
343 if (!PAGE_COLOR_EQ(vaddr, kaddr)) {
344 unsigned long v, p;
345
346 /* Temporarily map page to DTLB_WAY_DCACHE_ALIAS0. */
347
348 spin_lock(&tlb_lock);
349
350 p = (unsigned long)pte_val((mk_pte(page,PAGE_KERNEL)));
351 kaddr = (void*)PAGE_COLOR_MAP0(vaddr);
352 v = (unsigned long)kaddr | DTLB_WAY_DCACHE_ALIAS0;
353 __asm__ __volatile__("wdtlb %0,%1; dsync" : :"a" (p), "a" (v));
354
355 clear_page(kaddr);
356
357 spin_unlock(&tlb_lock);
358 } else {
359 clear_page(kaddr);
360 }
361
362 /* We need to make sure that i$ and d$ are coherent. */
363
364 clear_bit(PG_cache_clean, &page->flags);
365}
366
367/*
368 * With cache aliasing, we have to make sure that the page color of the page
369 * in kernel space matches that of the virtual user address before we read
370 * the page. If the page color differ, we create a temporary DTLB entry with
371 * the corrent page color and use this 'temporary' address as the source.
372 * We then use the same approach as in clear_user_page and copy the data
373 * to the kernel space and clear the PG_cache_clean bit to synchronize caches
374 * later.
375 *
376 * Note:
377 * Instead of using another 'way' for the temporary DTLB entry, we could
378 * probably use the same entry that points to the kernel address (after
379 * saving the original value and restoring it when we are done).
380 */
381 311
382void copy_user_page(void* to, void* from, unsigned long vaddr, 312static void pgd_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
383 struct page* to_page)
384{ 313{
385 /* There shouldn't be any entries for the new page. */ 314 pte_t* ptep = (pte_t*)addr;
386 315 int i;
387 __flush_invalidate_dcache_page_phys(__pa(page_address(to_page)));
388
389 spin_lock(&tlb_lock);
390
391 if (!PAGE_COLOR_EQ(vaddr, from)) {
392 unsigned long v, p, t;
393
394 __asm__ __volatile__ ("pdtlb %1,%2; rdtlb1 %0,%1"
395 : "=a"(p), "=a"(t) : "a"(from));
396 from = (void*)PAGE_COLOR_MAP0(vaddr);
397 v = (unsigned long)from | DTLB_WAY_DCACHE_ALIAS0;
398 __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
399 }
400
401 if (!PAGE_COLOR_EQ(vaddr, to)) {
402 unsigned long v, p;
403
404 p = (unsigned long)pte_val((mk_pte(to_page,PAGE_KERNEL)));
405 to = (void*)PAGE_COLOR_MAP1(vaddr);
406 v = (unsigned long)to | DTLB_WAY_DCACHE_ALIAS1;
407 __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
408 }
409 copy_page(to, from);
410
411 spin_unlock(&tlb_lock);
412
413 /* We need to make sure that i$ and d$ are coherent. */
414
415 clear_bit(PG_cache_clean, &to_page->flags);
416}
417
418
419
420/*
421 * Any time the kernel writes to a user page cache page, or it is about to
422 * read from a page cache page this routine is called.
423 *
424 * Note:
425 * The kernel currently only provides one architecture bit in the page
426 * flags that we use for I$/D$ coherency. Maybe, in future, we can
427 * use a sepearte bit for deferred dcache aliasing:
428 * If the page is not mapped yet, we only need to set a flag,
429 * if mapped, we need to invalidate the page.
430 */
431// FIXME: we probably need this for WB caches not only for Page Coloring..
432
433void flush_dcache_page(struct page *page)
434{
435 unsigned long addr = __pa(page_address(page));
436 struct address_space *mapping = page_mapping(page);
437
438 __flush_invalidate_dcache_page_phys(addr);
439
440 if (!test_bit(PG_cache_clean, &page->flags))
441 return;
442
443 /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/
444#if 0
445 if (mapping && !mapping_mapped(mapping))
446 clear_bit(PG_cache_clean, &page->flags);
447 else
448#endif
449 __invalidate_icache_page_phys(addr);
450}
451
452void flush_cache_range(struct vm_area_struct* vma, unsigned long s,
453 unsigned long e)
454{
455 __flush_invalidate_cache_all();
456}
457
458void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
459 unsigned long pfn)
460{
461 struct page *page = pfn_to_page(pfn);
462
463 /* Remove any entry for the old mapping. */
464
465 if (current->active_mm == vma->vm_mm) {
466 unsigned long addr = __pa(page_address(page));
467 __flush_invalidate_dcache_page_phys(addr);
468 if ((vma->vm_flags & VM_EXEC) != 0)
469 __invalidate_icache_page_phys(addr);
470 } else {
471 BUG();
472 }
473}
474
475#endif /* (DCACHE_WAY_SIZE > PAGE_SIZE) */
476
477
478pte_t* pte_alloc_one_kernel (struct mm_struct* mm, unsigned long addr)
479{
480 pte_t* pte = (pte_t*)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 0);
481 if (likely(pte)) {
482 pte_t* ptep = (pte_t*)(pte_val(*pte) + PAGE_OFFSET);
483 int i;
484 for (i = 0; i < 1024; i++, ptep++)
485 pte_clear(mm, addr, ptep);
486 }
487 return pte;
488}
489
490struct page* pte_alloc_one(struct mm_struct *mm, unsigned long addr)
491{
492 struct page *page;
493
494 page = alloc_pages(GFP_KERNEL | __GFP_REPEAT, 0);
495
496 if (likely(page)) {
497 pte_t* ptep = kmap_atomic(page, KM_USER0);
498 int i;
499 316
500 for (i = 0; i < 1024; i++, ptep++) 317 for (i = 0; i < 1024; i++, ptep++)
501 pte_clear(mm, addr, ptep); 318 pte_clear(NULL, 0, ptep);
502 319
503 kunmap_atomic(ptep, KM_USER0);
504 }
505 return page;
506} 320}
507 321
508 322void __init pgtable_cache_init(void)
509/*
510 * Handle D$/I$ coherency.
511 *
512 * Note:
513 * We only have one architecture bit for the page flags, so we cannot handle
514 * cache aliasing, yet.
515 */
516
517void
518update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
519{ 323{
520 unsigned long pfn = pte_pfn(pte); 324 pgtable_cache = kmem_cache_create("pgd",
521 struct page *page; 325 PAGE_SIZE, PAGE_SIZE,
522 unsigned long vaddr = addr & PAGE_MASK; 326 SLAB_HWCACHE_ALIGN,
523 327 pgd_ctor);
524 if (!pfn_valid(pfn))
525 return;
526
527 page = pfn_to_page(pfn);
528
529 invalidate_itlb_mapping(addr);
530 invalidate_dtlb_mapping(addr);
531
532 /* We have a new mapping. Use it. */
533
534 write_dtlb_entry(pte, dtlb_probe(addr));
535
536 /* If the processor can execute from this page, synchronize D$/I$. */
537
538 if ((vma->vm_flags & VM_EXEC) != 0) {
539
540 write_itlb_entry(pte, itlb_probe(addr));
541
542 /* Synchronize caches, if not clean. */
543
544 if (!test_and_set_bit(PG_cache_clean, &page->flags)) {
545 __flush_dcache_page(vaddr);
546 __invalidate_icache_page(vaddr);
547 }
548 }
549} 328}
550
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
index ae085332c607..e1f880368e32 100644
--- a/arch/xtensa/mm/misc.S
+++ b/arch/xtensa/mm/misc.S
@@ -7,29 +7,33 @@
7 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details. 8 * for more details.
9 * 9 *
10 * Copyright (C) 2001 - 2005 Tensilica Inc. 10 * Copyright (C) 2001 - 2007 Tensilica Inc.
11 * 11 *
12 * Chris Zankel <chris@zankel.net> 12 * Chris Zankel <chris@zankel.net>
13 */ 13 */
14 14
15/* Note: we might want to implement some of the loops as zero-overhead-loops,
16 * where applicable and if supported by the processor.
17 */
18 15
19#include <linux/linkage.h> 16#include <linux/linkage.h>
20#include <asm/page.h> 17#include <asm/page.h>
21#include <asm/pgtable.h> 18#include <asm/pgtable.h>
22#include <asm/asmmacro.h> 19#include <asm/asmmacro.h>
23#include <asm/cacheasm.h> 20#include <asm/cacheasm.h>
21#include <asm/tlbflush.h>
22
24 23
25/* clear_page (page) */ 24/*
25 * clear_page and clear_user_page are the same for non-cache-aliased configs.
26 *
27 * clear_page (unsigned long page)
28 * a2
29 */
26 30
27ENTRY(clear_page) 31ENTRY(clear_page)
28 entry a1, 16 32 entry a1, 16
29 addi a4, a2, PAGE_SIZE
30 movi a3, 0
31 33
321: s32i a3, a2, 0 34 movi a3, 0
35 __loopi a2, a7, PAGE_SIZE, 32
36 s32i a3, a2, 0
33 s32i a3, a2, 4 37 s32i a3, a2, 4
34 s32i a3, a2, 8 38 s32i a3, a2, 8
35 s32i a3, a2, 12 39 s32i a3, a2, 12
@@ -37,42 +41,277 @@ ENTRY(clear_page)
37 s32i a3, a2, 20 41 s32i a3, a2, 20
38 s32i a3, a2, 24 42 s32i a3, a2, 24
39 s32i a3, a2, 28 43 s32i a3, a2, 28
40 addi a2, a2, 32 44 __endla a2, a7, 32
41 blt a2, a4, 1b
42 45
43 retw 46 retw
44 47
45/* 48/*
49 * copy_page and copy_user_page are the same for non-cache-aliased configs.
50 *
46 * copy_page (void *to, void *from) 51 * copy_page (void *to, void *from)
47 * a2 a3 52 * a2 a3
48 */ 53 */
49 54
50ENTRY(copy_page) 55ENTRY(copy_page)
51 entry a1, 16 56 entry a1, 16
52 addi a4, a2, PAGE_SIZE
53
541: l32i a5, a3, 0
55 l32i a6, a3, 4
56 l32i a7, a3, 8
57 s32i a5, a2, 0
58 s32i a6, a2, 4
59 s32i a7, a2, 8
60 l32i a5, a3, 12
61 l32i a6, a3, 16
62 l32i a7, a3, 20
63 s32i a5, a2, 12
64 s32i a6, a2, 16
65 s32i a7, a2, 20
66 l32i a5, a3, 24
67 l32i a6, a3, 28
68 s32i a5, a2, 24
69 s32i a6, a2, 28
70 addi a2, a2, 32
71 addi a3, a3, 32
72 blt a2, a4, 1b
73 57
58 __loopi a2, a4, PAGE_SIZE, 32
59
60 l32i a8, a3, 0
61 l32i a9, a3, 4
62 s32i a8, a2, 0
63 s32i a9, a2, 4
64
65 l32i a8, a3, 8
66 l32i a9, a3, 12
67 s32i a8, a2, 8
68 s32i a9, a2, 12
69
70 l32i a8, a3, 16
71 l32i a9, a3, 20
72 s32i a8, a2, 16
73 s32i a9, a2, 20
74
75 l32i a8, a3, 24
76 l32i a9, a3, 28
77 s32i a8, a2, 24
78 s32i a9, a2, 28
79
80 addi a2, a2, 32
81 addi a3, a3, 32
82
83 __endl a2, a4
84
85 retw
86
87/*
88 * If we have to deal with cache aliasing, we use temporary memory mappings
89 * to ensure that the source and destination pages have the same color as
90 * the virtual address. We use way 0 and 1 for temporary mappings in such cases.
91 *
92 * The temporary DTLB entries shouldn't be flushed by interrupts, but are
93 * flushed by preemptive task switches. Special code in the
94 * fast_second_level_miss handler re-established the temporary mapping.
95 * It requires that the PPNs for the destination and source addresses are
96 * in a6, and a7, respectively.
97 */
98
99/* TLB miss exceptions are treated special in the following region */
100
101ENTRY(__tlbtemp_mapping_start)
102
103#if (DCACHE_WAY_SIZE > PAGE_SIZE)
104
105/*
106 * clear_user_page (void *addr, unsigned long vaddr, struct page *page)
107 * a2 a3 a4
108 */
109
110ENTRY(clear_user_page)
111 entry a1, 32
112
113 /* Mark page dirty and determine alias. */
114
115 movi a7, (1 << PG_ARCH_1)
116 l32i a5, a4, PAGE_FLAGS
117 xor a6, a2, a3
118 extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER
119 extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
120 or a5, a5, a7
121 slli a3, a3, PAGE_SHIFT
122 s32i a5, a4, PAGE_FLAGS
123
124 /* Skip setting up a temporary DTLB if not aliased. */
125
126 beqz a6, 1f
127
128 /* Invalidate kernel page. */
129
130 mov a10, a2
131 call8 __invalidate_dcache_page
132
133 /* Setup a temporary DTLB with the color of the VPN */
134
135 movi a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
136 movi a5, TLBTEMP_BASE_1 # virt
137 add a6, a2, a4 # ppn
138 add a2, a5, a3 # add 'color'
139
140 wdtlb a6, a2
141 dsync
142
1431: movi a3, 0
144 __loopi a2, a7, PAGE_SIZE, 32
145 s32i a3, a2, 0
146 s32i a3, a2, 4
147 s32i a3, a2, 8
148 s32i a3, a2, 12
149 s32i a3, a2, 16
150 s32i a3, a2, 20
151 s32i a3, a2, 24
152 s32i a3, a2, 28
153 __endla a2, a7, 32
154
155 bnez a6, 1f
156 retw
157
158 /* We need to invalidate the temporary idtlb entry, if any. */
159
1601: addi a2, a2, -PAGE_SIZE
161 idtlb a2
162 dsync
163
164 retw
165
166/*
167 * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
168 * a2 a3 a4 a5
169 */
170
171ENTRY(copy_user_page)
172
173 entry a1, 32
174
175 /* Mark page dirty and determine alias for destination. */
176
177 movi a8, (1 << PG_ARCH_1)
178 l32i a9, a5, PAGE_FLAGS
179 xor a6, a2, a4
180 xor a7, a3, a4
181 extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER
182 extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
183 extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER
184 or a9, a9, a8
185 slli a4, a4, PAGE_SHIFT
186 s32i a9, a5, PAGE_FLAGS
187 movi a5, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
188
189 beqz a6, 1f
190
191 /* Invalidate dcache */
192
193 mov a10, a2
194 call8 __invalidate_dcache_page
195
196 /* Setup a temporary DTLB with a matching color. */
197
198 movi a8, TLBTEMP_BASE_1 # base
199 add a6, a2, a5 # ppn
200 add a2, a8, a4 # add 'color'
201
202 wdtlb a6, a2
203 dsync
204
205 /* Skip setting up a temporary DTLB for destination if not aliased. */
206
2071: beqz a7, 1f
208
209 /* Setup a temporary DTLB with a matching color. */
210
211 movi a8, TLBTEMP_BASE_2 # base
212 add a7, a3, a5 # ppn
213 add a3, a8, a4
214 addi a8, a3, 1 # way1
215
216 wdtlb a7, a8
217 dsync
218
2191: __loopi a2, a4, PAGE_SIZE, 32
220
221 l32i a8, a3, 0
222 l32i a9, a3, 4
223 s32i a8, a2, 0
224 s32i a9, a2, 4
225
226 l32i a8, a3, 8
227 l32i a9, a3, 12
228 s32i a8, a2, 8
229 s32i a9, a2, 12
230
231 l32i a8, a3, 16
232 l32i a9, a3, 20
233 s32i a8, a2, 16
234 s32i a9, a2, 20
235
236 l32i a8, a3, 24
237 l32i a9, a3, 28
238 s32i a8, a2, 24
239 s32i a9, a2, 28
240
241 addi a2, a2, 32
242 addi a3, a3, 32
243
244 __endl a2, a4
245
246 /* We need to invalidate any temporary mapping! */
247
248 bnez a6, 1f
249 bnez a7, 2f
250 retw
251
2521: addi a2, a2, -PAGE_SIZE
253 idtlb a2
254 dsync
255 bnez a7, 2f
256 retw
257
2582: addi a3, a3, -PAGE_SIZE+1
259 idtlb a3
260 dsync
261
262 retw
263
264#endif
265
266#if (DCACHE_WAY_SIZE > PAGE_SIZE)
267
268/*
269 * void __flush_invalidate_dcache_page_alias (addr, phys)
270 * a2 a3
271 */
272
273ENTRY(__flush_invalidate_dcache_page_alias)
274 entry sp, 16
275
276 movi a7, 0 # required for exception handler
277 addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
278 mov a4, a2
279 wdtlb a6, a2
280 dsync
281
282 ___flush_invalidate_dcache_page a2 a3
283
284 idtlb a4
285 dsync
286
287 retw
288
289#endif
290
291ENTRY(__tlbtemp_mapping_itlb)
292
293#if (ICACHE_WAY_SIZE > PAGE_SIZE)
294
295ENTRY(__invalidate_icache_page_alias)
296 entry sp, 16
297
298 addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
299 mov a4, a2
300 witlb a6, a2
301 isync
302
303 ___invalidate_icache_page a2 a3
304
305 iitlb a4
306 isync
74 retw 307 retw
75 308
309#endif
310
311/* End of special treatment in tlb miss exception */
312
313ENTRY(__tlbtemp_mapping_end)
314
76/* 315/*
77 * void __invalidate_icache_page(ulong start) 316 * void __invalidate_icache_page(ulong start)
78 */ 317 */
@@ -121,8 +360,6 @@ ENTRY(__flush_dcache_page)
121 dsync 360 dsync
122 retw 361 retw
123 362
124
125
126/* 363/*
127 * void __invalidate_icache_range(ulong start, ulong size) 364 * void __invalidate_icache_range(ulong start, ulong size)
128 */ 365 */
@@ -168,7 +405,6 @@ ENTRY(__invalidate_dcache_range)
168 405
169 ___invalidate_dcache_range a2 a3 a4 406 ___invalidate_dcache_range a2 a3 a4
170 407
171
172 retw 408 retw
173 409
174/* 410/*
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 @@
19 19
20#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS) 20#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS)
21#define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS) 21#define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS)
22#define DCACHE_WAY_SHIFT (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH)
23#define ICACHE_WAY_SHIFT (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH)
24
25/* Maximum cache size per way. */
26#if DCACHE_WAY_SIZE >= ICACHE_WAY_SIZE
27# define CACHE_WAY_SIZE DCACHE_WAY_SIZE
28#else
29# define CACHE_WAY_SIZE ICACHE_WAY_SIZE
30#endif
22 31
23 32
24#endif /* _XTENSA_CACHE_H */ 33#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 @@
5 * License. See the file "COPYING" in the main directory of this archive 5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details. 6 * for more details.
7 * 7 *
8 * (C) 2001 - 2006 Tensilica Inc. 8 * (C) 2001 - 2007 Tensilica Inc.
9 */ 9 */
10 10
11#ifndef _XTENSA_CACHEFLUSH_H 11#ifndef _XTENSA_CACHEFLUSH_H
@@ -18,10 +18,7 @@
18#include <asm/page.h> 18#include <asm/page.h>
19 19
20/* 20/*
21 * flush and invalidate data cache, invalidate instruction cache: 21 * Lo-level routines for cache flushing.
22 *
23 * __flush_invalidate_cache_all()
24 * __flush_invalidate_cache_range(from,sze)
25 * 22 *
26 * invalidate data or instruction cache: 23 * invalidate data or instruction cache:
27 * 24 *
@@ -40,26 +37,39 @@
40 * __flush_invalidate_dcache_all() 37 * __flush_invalidate_dcache_all()
41 * __flush_invalidate_dcache_page(adr) 38 * __flush_invalidate_dcache_page(adr)
42 * __flush_invalidate_dcache_range(from,size) 39 * __flush_invalidate_dcache_range(from,size)
40 *
41 * specials for cache aliasing:
42 *
43 * __flush_invalidate_dcache_page_alias(vaddr,paddr)
44 * __invalidate_icache_page_alias(vaddr,paddr)
43 */ 45 */
44 46
45extern void __flush_invalidate_cache_all(void); 47extern void __invalidate_dcache_all(void);
46extern void __flush_invalidate_cache_range(unsigned long, unsigned long);
47extern void __flush_invalidate_dcache_all(void);
48extern void __invalidate_icache_all(void); 48extern void __invalidate_icache_all(void);
49
50extern void __invalidate_dcache_page(unsigned long); 49extern void __invalidate_dcache_page(unsigned long);
51extern void __invalidate_icache_page(unsigned long); 50extern void __invalidate_icache_page(unsigned long);
52extern void __invalidate_icache_range(unsigned long, unsigned long); 51extern void __invalidate_icache_range(unsigned long, unsigned long);
53extern void __invalidate_dcache_range(unsigned long, unsigned long); 52extern void __invalidate_dcache_range(unsigned long, unsigned long);
54 53
54
55#if XCHAL_DCACHE_IS_WRITEBACK 55#if XCHAL_DCACHE_IS_WRITEBACK
56extern void __flush_invalidate_dcache_all(void);
56extern void __flush_dcache_page(unsigned long); 57extern void __flush_dcache_page(unsigned long);
58extern void __flush_dcache_range(unsigned long, unsigned long);
57extern void __flush_invalidate_dcache_page(unsigned long); 59extern void __flush_invalidate_dcache_page(unsigned long);
58extern void __flush_invalidate_dcache_range(unsigned long, unsigned long); 60extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
59#else 61#else
60# define __flush_dcache_page(p) do { } while(0) 62# define __flush_dcache_range(p,s) do { } while(0)
61# define __flush_invalidate_dcache_page(p) do { } while(0) 63# define __flush_dcache_page(p) do { } while(0)
62# define __flush_invalidate_dcache_range(p,s) do { } while(0) 64# define __flush_invalidate_dcache_page(p) __invalidate_dcache_page(p)
65# define __flush_invalidate_dcache_range(p,s) __invalidate_dcache_range(p,s)
66#endif
67
68#if (DCACHE_WAY_SIZE > PAGE_SIZE)
69extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long);
70#endif
71#if (ICACHE_WAY_SIZE > PAGE_SIZE)
72extern void __invalidate_icache_page_alias(unsigned long, unsigned long);
63#endif 73#endif
64 74
65/* 75/*
@@ -71,17 +81,21 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
71 * (see also Documentation/cachetlb.txt) 81 * (see also Documentation/cachetlb.txt)
72 */ 82 */
73 83
74#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK 84#if (DCACHE_WAY_SIZE > PAGE_SIZE)
75 85
76#define flush_cache_all() __flush_invalidate_cache_all(); 86#define flush_cache_all() \
77#define flush_cache_mm(mm) __flush_invalidate_cache_all(); 87 do { \
78#define flush_cache_dup_mm(mm) __flush_invalidate_cache_all(); 88 __flush_invalidate_dcache_all(); \
89 __invalidate_icache_all(); \
90 } while (0)
79 91
80#define flush_cache_vmap(start,end) __flush_invalidate_cache_all(); 92#define flush_cache_mm(mm) flush_cache_all()
81#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all(); 93#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
82 94
83extern void flush_dcache_page(struct page*); 95#define flush_cache_vmap(start,end) flush_cache_all()
96#define flush_cache_vunmap(start,end) flush_cache_all()
84 97
98extern void flush_dcache_page(struct page*);
85extern void flush_cache_range(struct vm_area_struct*, ulong, ulong); 99extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
86extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long); 100extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
87 101
@@ -101,24 +115,39 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
101 115
102#endif 116#endif
103 117
118/* Ensure consistency between data and instruction cache. */
104#define flush_icache_range(start,end) \ 119#define flush_icache_range(start,end) \
105 __invalidate_icache_range(start,(end)-(start)) 120 do { \
121 __flush_dcache_range(start, (end) - (start)); \
122 __invalidate_icache_range(start,(end) - (start)); \
123 } while (0)
106 124
107/* This is not required, see Documentation/cachetlb.txt */ 125/* This is not required, see Documentation/cachetlb.txt */
108 126#define flush_icache_page(vma,page) do { } while (0)
109#define flush_icache_page(vma,page) do { } while(0)
110 127
111#define flush_dcache_mmap_lock(mapping) do { } while (0) 128#define flush_dcache_mmap_lock(mapping) do { } while (0)
112#define flush_dcache_mmap_unlock(mapping) do { } while (0) 129#define flush_dcache_mmap_unlock(mapping) do { } while (0)
113 130
131#if (DCACHE_WAY_SIZE > PAGE_SIZE)
114 132
115#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ 133extern void copy_to_user_page(struct vm_area_struct*, struct page*,
116 memcpy(dst, src, len) 134 unsigned long, void*, const void*, unsigned long);
135extern void copy_from_user_page(struct vm_area_struct*, struct page*,
136 unsigned long, void*, const void*, unsigned long);
137
138#else
139
140#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
141 do { \
142 memcpy(dst, src, len); \
143 __flush_dcache_range((unsigned long) dst, len); \
144 __invalidate_icache_range((unsigned long) dst, len); \
145 } while (0)
117 146
118#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ 147#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
119 memcpy(dst, src, len) 148 memcpy(dst, src, len)
120 149
121#endif /* __KERNEL__ */ 150#endif
122 151
152#endif /* __KERNEL__ */
123#endif /* _XTENSA_CACHEFLUSH_H */ 153#endif /* _XTENSA_CACHEFLUSH_H */
124
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 @@
14#ifdef __KERNEL__ 14#ifdef __KERNEL__
15#include <asm/byteorder.h> 15#include <asm/byteorder.h>
16#include <asm/page.h> 16#include <asm/page.h>
17#include <linux/kernel.h>
17 18
18#include <linux/types.h> 19#include <linux/types.h>
19 20
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
index 2d6ac21136cf..55ce2c9749a3 100644
--- a/include/asm-xtensa/page.h
+++ b/include/asm-xtensa/page.h
@@ -15,6 +15,7 @@
15 15
16#include <asm/processor.h> 16#include <asm/processor.h>
17#include <asm/types.h> 17#include <asm/types.h>
18#include <asm/cache.h>
18 19
19/* 20/*
20 * Fixed TLB translations in the processor. 21 * Fixed TLB translations in the processor.
@@ -39,6 +40,53 @@
39#define MAX_MEM_PFN XCHAL_KSEG_SIZE 40#define MAX_MEM_PFN XCHAL_KSEG_SIZE
40#define PGTABLE_START 0x80000000 41#define PGTABLE_START 0x80000000
41 42
43/*
44 * Cache aliasing:
45 *
46 * If the cache size for one way is greater than the page size, we have to
47 * deal with cache aliasing. The cache index is wider than the page size:
48 *
49 * | |cache| cache index
50 * | pfn |off| virtual address
51 * |xxxx:X|zzz|
52 * | : | |
53 * | \ / | |
54 * |trans.| |
55 * | / \ | |
56 * |yyyy:Y|zzz| physical address
57 *
58 * When the page number is translated to the physical page address, the lowest
59 * bit(s) (X) that are part of the cache index are also translated (Y).
60 * If this translation changes bit(s) (X), the cache index is also afected,
61 * thus resulting in a different cache line than before.
62 * The kernel does not provide a mechanism to ensure that the page color
63 * (represented by this bit) remains the same when allocated or when pages
64 * are remapped. When user pages are mapped into kernel space, the color of
65 * the page might also change.
66 *
67 * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
68 * to temporarily map a patch so we can match the color.
69 */
70
71#if DCACHE_WAY_SIZE > PAGE_SIZE
72# define DCACHE_ALIAS_ORDER (DCACHE_WAY_SHIFT - PAGE_SHIFT)
73# define DCACHE_ALIAS_MASK (PAGE_MASK & (DCACHE_WAY_SIZE - 1))
74# define DCACHE_ALIAS(a) (((a) & DCACHE_ALIAS_MASK) >> PAGE_SHIFT)
75# define DCACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0)
76#else
77# define DCACHE_ALIAS_ORDER 0
78#endif
79
80#if ICACHE_WAY_SIZE > PAGE_SIZE
81# define ICACHE_ALIAS_ORDER (ICACHE_WAY_SHIFT - PAGE_SHIFT)
82# define ICACHE_ALIAS_MASK (PAGE_MASK & (ICACHE_WAY_SIZE - 1))
83# define ICACHE_ALIAS(a) (((a) & ICACHE_ALIAS_MASK) >> PAGE_SHIFT)
84# define ICACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & ICACHE_ALIAS_MASK) == 0)
85#else
86# define ICACHE_ALIAS_ORDER 0
87#endif
88
89
42#ifdef __ASSEMBLY__ 90#ifdef __ASSEMBLY__
43 91
44#define __pgprot(x) (x) 92#define __pgprot(x) (x)
@@ -90,11 +138,11 @@ extern void copy_page(void *to, void *from);
90 * some extra work 138 * some extra work
91 */ 139 */
92 140
93#if (DCACHE_WAY_SIZE > PAGE_SIZE) 141#if DCACHE_WAY_SIZE > PAGE_SIZE
94void clear_user_page(void *addr, unsigned long vaddr, struct page* page); 142extern void clear_user_page(void*, unsigned long, struct page*);
95void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page); 143extern void copy_user_page(void*, void*, unsigned long, struct page*);
96#else 144#else
97# define clear_user_page(page,vaddr,pg) clear_page(page) 145# define clear_user_page(page, vaddr, pg) clear_page(page)
98# define copy_user_page(to, from, vaddr, pg) copy_page(to, from) 146# define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
99#endif 147#endif
100 148
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 @@
1/* 1/*
2 * linux/include/asm-xtensa/pgalloc.h 2 * include/asm-xtensa/pgalloc.h
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 * 7 *
8 * Copyright (C) 2001-2005 Tensilica Inc. 8 * Copyright (C) 2001-2007 Tensilica Inc.
9 */ 9 */
10 10
11#ifndef _XTENSA_PGALLOC_H 11#ifndef _XTENSA_PGALLOC_H
@@ -13,103 +13,54 @@
13 13
14#ifdef __KERNEL__ 14#ifdef __KERNEL__
15 15
16#include <linux/threads.h>
17#include <linux/highmem.h> 16#include <linux/highmem.h>
18#include <asm/processor.h>
19#include <asm/cacheflush.h>
20
21
22/* Cache aliasing:
23 *
24 * If the cache size for one way is greater than the page size, we have to
25 * deal with cache aliasing. The cache index is wider than the page size:
26 *
27 * |cache |
28 * |pgnum |page| virtual address
29 * |xxxxxX|zzzz|
30 * | | |
31 * \ / | |
32 * trans.| |
33 * / \ | |
34 * |yyyyyY|zzzz| physical address
35 *
36 * When the page number is translated to the physical page address, the lowest
37 * bit(s) (X) that are also part of the cache index are also translated (Y).
38 * If this translation changes this bit (X), the cache index is also afected,
39 * thus resulting in a different cache line than before.
40 * The kernel does not provide a mechanism to ensure that the page color
41 * (represented by this bit) remains the same when allocated or when pages
42 * are remapped. When user pages are mapped into kernel space, the color of
43 * the page might also change.
44 *
45 * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
46 * to temporarily map a patch so we can match the color.
47 */
48
49#if (DCACHE_WAY_SIZE > PAGE_SIZE)
50# define PAGE_COLOR_MASK (PAGE_MASK & (DCACHE_WAY_SIZE-1))
51# define PAGE_COLOR(a) \
52 (((unsigned long)(a)&PAGE_COLOR_MASK) >> PAGE_SHIFT)
53# define PAGE_COLOR_EQ(a,b) \
54 ((((unsigned long)(a) ^ (unsigned long)(b)) & PAGE_COLOR_MASK) == 0)
55# define PAGE_COLOR_MAP0(v) \
56 (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK))
57# define PAGE_COLOR_MAP1(v) \
58 (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK) + DCACHE_WAY_SIZE)
59#endif
60 17
61/* 18/*
62 * Allocating and freeing a pmd is trivial: the 1-entry pmd is 19 * Allocating and freeing a pmd is trivial: the 1-entry pmd is
63 * inside the pgd, so has no extra memory associated with it. 20 * inside the pgd, so has no extra memory associated with it.
64 */ 21 */
65 22
66#define pgd_free(pgd) free_page((unsigned long)(pgd)) 23#define pmd_populate_kernel(mm, pmdp, ptep) \
67 24 (pmd_val(*(pmdp)) = ((unsigned long)ptep))
68#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK 25#define pmd_populate(mm, pmdp, page) \
26 (pmd_val(*(pmdp)) = ((unsigned long)page_to_virt(page)))
69 27
70static inline void 28static inline pgd_t*
71pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *pte) 29pgd_alloc(struct mm_struct *mm)
72{ 30{
73 pmd_val(*(pmdp)) = (unsigned long)(pte); 31 return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER);
74 __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
75} 32}
76 33
77static inline void 34static inline void pgd_free(pgd_t *pgd)
78pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *page)
79{ 35{
80 pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page); 36 free_page((unsigned long)pgd);
81 __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
82} 37}
83 38
39/* Use a slab cache for the pte pages (see also sparc64 implementation) */
84 40
41extern struct kmem_cache *pgtable_cache;
85 42
86#else 43static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
87 44 unsigned long address)
88# define pmd_populate_kernel(mm, pmdp, pte) \
89 (pmd_val(*(pmdp)) = (unsigned long)(pte))
90# define pmd_populate(mm, pmdp, page) \
91 (pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page))
92
93#endif
94
95static inline pgd_t*
96pgd_alloc(struct mm_struct *mm)
97{ 45{
98 pgd_t *pgd; 46 return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT);
99 47}
100 pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGD_ORDER);
101
102 if (likely(pgd != NULL))
103 __flush_dcache_page((unsigned long)pgd);
104 48
105 return pgd; 49static inline struct page *pte_alloc_one(struct mm_struct *mm,
50 unsigned long addr)
51{
52 return virt_to_page(pte_alloc_one_kernel(mm, addr));
106} 53}
107 54
108extern pte_t* pte_alloc_one_kernel(struct mm_struct* mm, unsigned long addr); 55static inline void pte_free_kernel(pte_t *pte)
109extern struct page* pte_alloc_one(struct mm_struct* mm, unsigned long addr); 56{
57 kmem_cache_free(pgtable_cache, pte);
58}
110 59
111#define pte_free_kernel(pte) free_page((unsigned long)pte) 60static inline void pte_free(struct page *page)
112#define pte_free(pte) __free_page(pte) 61{
62 kmem_cache_free(pgtable_cache, page_address(page));
63}
113 64
114#endif /* __KERNEL__ */ 65#endif /* __KERNEL__ */
115#endif /* _XTENSA_PGALLOC_H */ 66#endif /* _XTENSA_PGALLOC_H */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index 667a6c46b5a1..c0fcc1c9660c 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * linux/include/asm-xtensa/pgtable.h 2 * include/asm-xtensa/pgtable.h
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -60,16 +60,20 @@
60#define FIRST_USER_ADDRESS 0 60#define FIRST_USER_ADDRESS 0
61#define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT) 61#define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
62 62
63/* virtual memory area. We keep a distance to other memory regions to be 63/*
64 * Virtual memory area. We keep a distance to other memory regions to be
64 * on the safe side. We also use this area for cache aliasing. 65 * on the safe side. We also use this area for cache aliasing.
65 */ 66 */
66 67
67// FIXME: virtual memory area must be configuration-dependent
68
69#define VMALLOC_START 0xC0000000 68#define VMALLOC_START 0xC0000000
70#define VMALLOC_END 0xC7FF0000 69#define VMALLOC_END 0xC6FEFFFF
70#define TLBTEMP_BASE_1 0xC6FF0000
71#define TLBTEMP_BASE_2 0xC6FF8000
72#define MODULE_START 0xC7000000
73#define MODULE_END 0xC7FFFFFF
71 74
72/* Xtensa Linux config PTE layout (when present): 75/*
76 * Xtensa Linux config PTE layout (when present):
73 * 31-12: PPN 77 * 31-12: PPN
74 * 11-6: Software 78 * 11-6: Software
75 * 5-4: RING 79 * 5-4: RING
@@ -126,12 +130,13 @@
126#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE) 130#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE)
127#define PAGE_SHARED_EXEC \ 131#define PAGE_SHARED_EXEC \
128 __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE | _PAGE_HW_EXEC) 132 __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE | _PAGE_HW_EXEC)
129#define PAGE_KERNEL __pgprot(_PAGE_PRESENT) 133#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_HW_WRITE)
134#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC)
130 135
131#if (DCACHE_WAY_SIZE > PAGE_SIZE) 136#if (DCACHE_WAY_SIZE > PAGE_SIZE)
132# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_HW_WRITE) 137# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED)
133#else 138#else
134# define _PAGE_DIRECTORY (_PAGE_VALID|_PAGE_ACCESSED|_PAGE_HW_WRITE|_PAGE_CA_WB) 139# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB)
135#endif 140#endif
136 141
137#else /* no mmu */ 142#else /* no mmu */
@@ -244,6 +249,10 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
244static inline void update_pte(pte_t *ptep, pte_t pteval) 249static inline void update_pte(pte_t *ptep, pte_t pteval)
245{ 250{
246 *ptep = pteval; 251 *ptep = pteval;
252#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
253 __asm__ __volatile__ ("dhwb %0, 0" :: "a" (ptep));
254#endif
255
247} 256}
248 257
249struct mm_struct; 258struct mm_struct;
@@ -383,13 +392,12 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
383 * remap a physical page `pfn' of size `size' with page protection `prot' 392 * remap a physical page `pfn' of size `size' with page protection `prot'
384 * into virtual address `from' 393 * into virtual address `from'
385 */ 394 */
395
386#define io_remap_pfn_range(vma,from,pfn,size,prot) \ 396#define io_remap_pfn_range(vma,from,pfn,size,prot) \
387 remap_pfn_range(vma, from, pfn, size, prot) 397 remap_pfn_range(vma, from, pfn, size, prot)
388 398
389 399
390/* No page table caches to init */ 400extern void pgtable_cache_init(void);
391
392#define pgtable_cache_init() do { } while (0)
393 401
394typedef pte_t *pte_addr_t; 402typedef pte_t *pte_addr_t;
395 403
diff --git a/include/asm-xtensa/tlb.h b/include/asm-xtensa/tlb.h
index 4562b2dcfbc0..4830232017af 100644
--- a/include/asm-xtensa/tlb.h
+++ b/include/asm-xtensa/tlb.h
@@ -11,14 +11,36 @@
11#ifndef _XTENSA_TLB_H 11#ifndef _XTENSA_TLB_H
12#define _XTENSA_TLB_H 12#define _XTENSA_TLB_H
13 13
14#define tlb_start_vma(tlb,vma) do { } while (0) 14#include <asm/cache.h>
15#define tlb_end_vma(tlb,vma) do { } while (0) 15#include <asm/page.h>
16#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0) 16
17#if (DCACHE_WAY_SIZE <= PAGE_SIZE)
18
19/* Note, read http://lkml.org/lkml/2004/1/15/6 */
20
21# define tlb_start_vma(tlb,vma) do { } while (0)
22# define tlb_end_vma(tlb,vma) do { } while (0)
23
24#else
17 25
26# define tlb_start_vma(tlb, vma) \
27 do { \
28 if (!tlb->fullmm) \
29 flush_cache_range(vma, vma->vm_start, vma->vm_end); \
30 } while(0)
31
32# define tlb_end_vma(tlb, vma) \
33 do { \
34 if (!tlb->fullmm) \
35 flush_tlb_range(vma, vma->vm_start, vma->vm_end); \
36 } while(0)
37
38#endif
39
40#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0)
18#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) 41#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
19 42
20#include <asm-generic/tlb.h> 43#include <asm-generic/tlb.h>
21#include <asm/page.h>
22 44
23#define __pte_free_tlb(tlb,pte) pte_free(pte) 45#define __pte_free_tlb(tlb,pte) pte_free(pte)
24 46