# BRCM_VERSION=3
[bcm963xx.git] / kernel / linux / arch / arm / mm / copypage-v6.c
1 /*
2  *  linux/arch/arm/mm/copypage-v6.c
3  *
4  *  Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/init.h>
11 #include <linux/spinlock.h>
12 #include <linux/mm.h>
13
14 #include <asm/page.h>
15 #include <asm/pgtable.h>
16 #include <asm/shmparam.h>
17 #include <asm/tlbflush.h>
18
19 #if SHMLBA > 16384
20 #error FIX ME
21 #endif
22
23 #define from_address    (0xffff8000)
24 #define from_pgprot     PAGE_KERNEL
25 #define to_address      (0xffffc000)
26 #define to_pgprot       PAGE_KERNEL
27
28 static pte_t *from_pte;
29 static pte_t *to_pte;
30 static spinlock_t v6_lock = SPIN_LOCK_UNLOCKED;
31
32 #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
33
34 /*
35  * Copy the page, taking account of the cache colour.
36  */
37 void v6_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
38 {
39         unsigned int offset = DCACHE_COLOUR(vaddr);
40         unsigned long from, to;
41
42         spin_lock(&v6_lock);
43
44         set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
45         set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
46
47         from = from_address + (offset << PAGE_SHIFT);
48         to   = to_address + (offset << PAGE_SHIFT);
49
50         flush_tlb_kernel_page(from);
51         flush_tlb_kernel_page(to);
52
53         copy_page((void *)to, (void *)from);
54
55         spin_unlock(&v6_lock);
56 }
57
58 void v6_clear_user_page(void *kaddr, unsigned long vaddr)
59 {
60         unsigned int offset = DCACHE_COLOUR(vaddr);
61         unsigned long to = to_address + (offset << PAGE_SHIFT);
62
63         spin_lock(&v6_lock);
64
65         set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
66         flush_tlb_kernel_page(to);
67         clear_page((void *)to);
68
69         spin_unlock(&v6_lock);
70 }
71
72 struct cpu_user_fns v6_user_fns __initdata = {
73         .cpu_clear_user_page    = v6_clear_user_page,
74         .cpu_copy_user_page     = v6_copy_user_page,
75 };
76
77 static int __init v6_userpage_init(void)
78 {
79         pgd_t *pgd;
80         pmd_t *pmd;
81
82         pgd = pgd_offset_k(from_address);
83         pmd = pmd_alloc(&init_mm, pgd, from_address);
84         if (!pmd)
85                 BUG();
86         from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
87         if (!from_pte)
88                 BUG();
89
90         to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
91         if (!to_pte)
92                 BUG();
93
94         return 0;
95 }
96
97 __initcall(v6_userpage_init);
98