0001
0002
0003
0004
0005
0006
0007 #include <linux/init.h>
0008 #include <linux/spinlock.h>
0009 #include <linux/mm.h>
0010 #include <linux/highmem.h>
0011 #include <linux/pagemap.h>
0012
0013 #include <asm/shmparam.h>
0014 #include <asm/tlbflush.h>
0015 #include <asm/cacheflush.h>
0016 #include <asm/cachetype.h>
0017
0018 #include "mm.h"
0019
0020 #if SHMLBA > 16384
0021 #error FIX ME
0022 #endif
0023
0024 static DEFINE_RAW_SPINLOCK(v6_lock);
0025
0026
0027
0028
0029
0030 static void v6_copy_user_highpage_nonaliasing(struct page *to,
0031 struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
0032 {
0033 void *kto, *kfrom;
0034
0035 kfrom = kmap_atomic(from);
0036 kto = kmap_atomic(to);
0037 copy_page(kto, kfrom);
0038 kunmap_atomic(kto);
0039 kunmap_atomic(kfrom);
0040 }
0041
0042
0043
0044
0045
0046 static void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr)
0047 {
0048 void *kaddr = kmap_atomic(page);
0049 clear_page(kaddr);
0050 kunmap_atomic(kaddr);
0051 }
0052
0053
0054
0055
0056
0057 static void discard_old_kernel_data(void *kto)
0058 {
0059 __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06"
0060 :
0061 : "r" (kto),
0062 "r" ((unsigned long)kto + PAGE_SIZE - 1)
0063 : "cc");
0064 }
0065
0066
0067
0068
0069 static void v6_copy_user_highpage_aliasing(struct page *to,
0070 struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
0071 {
0072 unsigned int offset = CACHE_COLOUR(vaddr);
0073 unsigned long kfrom, kto;
0074
0075 if (!test_and_set_bit(PG_dcache_clean, &from->flags))
0076 __flush_dcache_page(page_mapping_file(from), from);
0077
0078
0079 discard_old_kernel_data(page_address(to));
0080
0081
0082
0083
0084
0085 raw_spin_lock(&v6_lock);
0086
0087 kfrom = COPYPAGE_V6_FROM + (offset << PAGE_SHIFT);
0088 kto = COPYPAGE_V6_TO + (offset << PAGE_SHIFT);
0089
0090 set_top_pte(kfrom, mk_pte(from, PAGE_KERNEL));
0091 set_top_pte(kto, mk_pte(to, PAGE_KERNEL));
0092
0093 copy_page((void *)kto, (void *)kfrom);
0094
0095 raw_spin_unlock(&v6_lock);
0096 }
0097
0098
0099
0100
0101
0102
0103 static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr)
0104 {
0105 unsigned long to = COPYPAGE_V6_TO + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
0106
0107
0108 discard_old_kernel_data(page_address(page));
0109
0110
0111
0112
0113
0114 raw_spin_lock(&v6_lock);
0115
0116 set_top_pte(to, mk_pte(page, PAGE_KERNEL));
0117 clear_page((void *)to);
0118
0119 raw_spin_unlock(&v6_lock);
0120 }
0121
0122 struct cpu_user_fns v6_user_fns __initdata = {
0123 .cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing,
0124 .cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing,
0125 };
0126
0127 static int __init v6_userpage_init(void)
0128 {
0129 if (cache_is_vipt_aliasing()) {
0130 cpu_user.cpu_clear_user_highpage = v6_clear_user_highpage_aliasing;
0131 cpu_user.cpu_copy_user_highpage = v6_copy_user_highpage_aliasing;
0132 }
0133
0134 return 0;
0135 }
0136
0137 core_initcall(v6_userpage_init);