diff options
Diffstat (limited to 'arch/sh/mm/pg-sh4.c')
-rw-r--r-- | arch/sh/mm/pg-sh4.c | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index 25f5c6f6821d..8c7a9ca79879 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c | |||
@@ -9,6 +9,8 @@ | |||
9 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
10 | #include <linux/mutex.h> | 10 | #include <linux/mutex.h> |
11 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
12 | #include <linux/highmem.h> | ||
13 | #include <linux/module.h> | ||
12 | #include <asm/mmu_context.h> | 14 | #include <asm/mmu_context.h> |
13 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
14 | 16 | ||
@@ -50,34 +52,61 @@ static inline void kunmap_coherent(struct page *page) | |||
50 | void clear_user_page(void *to, unsigned long address, struct page *page) | 52 | void clear_user_page(void *to, unsigned long address, struct page *page) |
51 | { | 53 | { |
52 | __set_bit(PG_mapped, &page->flags); | 54 | __set_bit(PG_mapped, &page->flags); |
53 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) | 55 | |
54 | clear_page(to); | 56 | clear_page(to); |
55 | else { | 57 | if ((((address & PAGE_MASK) ^ (unsigned long)to) & CACHE_ALIAS)) |
56 | void *vto = kmap_coherent(page, address); | 58 | __flush_wback_region(to, PAGE_SIZE); |
57 | __clear_user_page(vto, to); | ||
58 | kunmap_coherent(vto); | ||
59 | } | ||
60 | } | 59 | } |
61 | 60 | ||
62 | /* | 61 | void copy_to_user_page(struct vm_area_struct *vma, struct page *page, |
63 | * copy_user_page | 62 | unsigned long vaddr, void *dst, const void *src, |
64 | * @to: P1 address | 63 | unsigned long len) |
65 | * @from: P1 address | ||
66 | * @address: U0 address to be mapped | ||
67 | * @page: page (virt_to_page(to)) | ||
68 | */ | ||
69 | void copy_user_page(void *to, void *from, unsigned long address, | ||
70 | struct page *page) | ||
71 | { | 64 | { |
65 | void *vto; | ||
66 | |||
72 | __set_bit(PG_mapped, &page->flags); | 67 | __set_bit(PG_mapped, &page->flags); |
73 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) | 68 | |
74 | copy_page(to, from); | 69 | vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); |
75 | else { | 70 | memcpy(vto, src, len); |
76 | void *vfrom = kmap_coherent(page, address); | 71 | kunmap_coherent(vto); |
77 | __copy_user_page(vfrom, from, to); | 72 | |
78 | kunmap_coherent(vfrom); | 73 | if (vma->vm_flags & VM_EXEC) |
79 | } | 74 | flush_cache_page(vma, vaddr, page_to_pfn(page)); |
75 | } | ||
76 | |||
77 | void copy_from_user_page(struct vm_area_struct *vma, struct page *page, | ||
78 | unsigned long vaddr, void *dst, const void *src, | ||
79 | unsigned long len) | ||
80 | { | ||
81 | void *vfrom; | ||
82 | |||
83 | __set_bit(PG_mapped, &page->flags); | ||
84 | |||
85 | vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); | ||
86 | memcpy(dst, vfrom, len); | ||
87 | kunmap_coherent(vfrom); | ||
88 | } | ||
89 | |||
90 | void copy_user_highpage(struct page *to, struct page *from, | ||
91 | unsigned long vaddr, struct vm_area_struct *vma) | ||
92 | { | ||
93 | void *vfrom, *vto; | ||
94 | |||
95 | __set_bit(PG_mapped, &to->flags); | ||
96 | |||
97 | vto = kmap_atomic(to, KM_USER1); | ||
98 | vfrom = kmap_coherent(from, vaddr); | ||
99 | copy_page(vto, vfrom); | ||
100 | kunmap_coherent(vfrom); | ||
101 | |||
102 | if (((vaddr ^ (unsigned long)vto) & CACHE_ALIAS)) | ||
103 | __flush_wback_region(vto, PAGE_SIZE); | ||
104 | |||
105 | kunmap_atomic(vto, KM_USER1); | ||
106 | /* Make sure this page is cleared on other CPU's too before using it */ | ||
107 | smp_wmb(); | ||
80 | } | 108 | } |
109 | EXPORT_SYMBOL(copy_user_highpage); | ||
81 | 110 | ||
82 | /* | 111 | /* |
83 | * For SH-4, we have our own implementation for ptep_get_and_clear | 112 | * For SH-4, we have our own implementation for ptep_get_and_clear |