ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / sh / mm / pg-sh4.c
1 /* 
2  * $Id: pg-sh4.c,v 1.1.2.2 2002/11/17 17:56:18 lethal Exp $
3  *
4  *  arch/sh/mm/pg-sh4.c
5  *
6  * Copyright (C) 1999, 2000, 2002  Niibe Yutaka
7  * Copyright (C) 2002  Paul Mundt
8  *
9  * Released under the terms of the GNU GPL v2.0.
10  */
11 #include <linux/config.h>
12 #include <linux/init.h>
13 #include <linux/mman.h>
14 #include <linux/mm.h>
15 #include <linux/threads.h>
16 #include <asm/addrspace.h>
17 #include <asm/page.h>
18 #include <asm/pgtable.h>
19 #include <asm/processor.h>
20 #include <asm/cache.h>
21 #include <asm/io.h>
22 #include <asm/uaccess.h>
23 #include <asm/pgalloc.h>
24 #include <asm/mmu_context.h>
25 #include <asm/cacheflush.h>
26
27 extern struct semaphore p3map_sem[];
28
29 /*
30  * clear_user_page
31  * @to: P1 address
32  * @address: U0 address to be mapped
33  * @page: page (virt_to_page(to))
34  */
35 void clear_user_page(void *to, unsigned long address, struct page *page)
36 {
37         __set_bit(PG_mapped, &page->flags);
38         if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
39                 clear_page(to);
40         else {
41                 pgprot_t pgprot = __pgprot(_PAGE_PRESENT | 
42                                            _PAGE_RW | _PAGE_CACHABLE |
43                                            _PAGE_DIRTY | _PAGE_ACCESSED | 
44                                            _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
45                 unsigned long phys_addr = PHYSADDR(to);
46                 unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
47                 pgd_t *dir = pgd_offset_k(p3_addr);
48                 pmd_t *pmd = pmd_offset(dir, p3_addr);
49                 pte_t *pte = pte_offset_kernel(pmd, p3_addr);
50                 pte_t entry;
51                 unsigned long flags;
52
53                 entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot);
54                 down(&p3map_sem[(address & CACHE_ALIAS)>>12]);
55                 set_pte(pte, entry);
56                 local_irq_save(flags);
57                 __flush_tlb_page(get_asid(), p3_addr);
58                 local_irq_restore(flags);
59                 update_mmu_cache(NULL, p3_addr, entry);
60                 __clear_user_page((void *)p3_addr, to);
61                 pte_clear(pte);
62                 up(&p3map_sem[(address & CACHE_ALIAS)>>12]);
63         }
64 }
65
66 /*
67  * copy_user_page
68  * @to: P1 address
69  * @from: P1 address
70  * @address: U0 address to be mapped
71  * @page: page (virt_to_page(to))
72  */
73 void copy_user_page(void *to, void *from, unsigned long address, 
74                     struct page *page)
75 {
76         __set_bit(PG_mapped, &page->flags);
77         if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
78                 copy_page(to, from);
79         else {
80                 pgprot_t pgprot = __pgprot(_PAGE_PRESENT | 
81                                            _PAGE_RW | _PAGE_CACHABLE |
82                                            _PAGE_DIRTY | _PAGE_ACCESSED | 
83                                            _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
84                 unsigned long phys_addr = PHYSADDR(to);
85                 unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
86                 pgd_t *dir = pgd_offset_k(p3_addr);
87                 pmd_t *pmd = pmd_offset(dir, p3_addr);
88                 pte_t *pte = pte_offset_kernel(pmd, p3_addr);
89                 pte_t entry;
90                 unsigned long flags;
91
92                 entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot);
93                 down(&p3map_sem[(address & CACHE_ALIAS)>>12]);
94                 set_pte(pte, entry);
95                 local_irq_save(flags);
96                 __flush_tlb_page(get_asid(), p3_addr);
97                 local_irq_restore(flags);
98                 update_mmu_cache(NULL, p3_addr, entry);
99                 __copy_user_page((void *)p3_addr, from, to);
100                 pte_clear(pte);
101                 up(&p3map_sem[(address & CACHE_ALIAS)>>12]);
102         }
103 }