• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * arch/sh/mm/pg-sh7705.c
3  *
4  * Copyright (C) 1999, 2000  Niibe Yutaka
5  * Copyright (C) 2004  Alex Song
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  *
11  */
12 
13 #include <linux/init.h>
14 #include <linux/mman.h>
15 #include <linux/mm.h>
16 #include <linux/threads.h>
17 #include <linux/fs.h>
18 #include <asm/addrspace.h>
19 #include <asm/page.h>
20 #include <asm/pgtable.h>
21 #include <asm/processor.h>
22 #include <asm/cache.h>
23 #include <asm/io.h>
24 #include <asm/uaccess.h>
25 #include <asm/pgalloc.h>
26 #include <asm/mmu_context.h>
27 #include <asm/cacheflush.h>
28 
__flush_purge_virtual_region(void * p1,void * virt,int size)29 static inline void __flush_purge_virtual_region(void *p1, void *virt, int size)
30 {
31 	unsigned long v;
32 	unsigned long begin, end;
33 	unsigned long p1_begin;
34 
35 
36 	begin = L1_CACHE_ALIGN((unsigned long)virt);
37 	end = L1_CACHE_ALIGN((unsigned long)virt + size);
38 
39 	p1_begin = (unsigned long)p1 & ~(L1_CACHE_BYTES - 1);
40 
41 	/* do this the slow way as we may not have TLB entries
42 	 * for virt yet. */
43 	for (v = begin; v < end; v += L1_CACHE_BYTES) {
44 		unsigned long p;
45 	        unsigned long ways, addr;
46 
47 		p = __pa(p1_begin);
48 
49 	        ways = current_cpu_data.dcache.ways;
50 		addr = CACHE_OC_ADDRESS_ARRAY;
51 
52 		do {
53 			unsigned long data;
54 
55 			addr |= (v & current_cpu_data.dcache.entry_mask);
56 
57 			data = ctrl_inl(addr);
58 			if ((data & CACHE_PHYSADDR_MASK) ==
59 			       (p & CACHE_PHYSADDR_MASK)) {
60 				data &= ~(SH_CACHE_UPDATED|SH_CACHE_VALID);
61 				ctrl_outl(data, addr);
62 			}
63 
64 			addr += current_cpu_data.dcache.way_incr;
65 		} while (--ways);
66 
67 		p1_begin += L1_CACHE_BYTES;
68 	}
69 }
70 
71 /*
72  * clear_user_page
73  * @to: P1 address
74  * @address: U0 address to be mapped
75  */
clear_user_page(void * to,unsigned long address,struct page * pg)76 void clear_user_page(void *to, unsigned long address, struct page *pg)
77 {
78 	struct page *page = virt_to_page(to);
79 
80 	__set_bit(PG_mapped, &page->flags);
81 	if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) {
82 		clear_page(to);
83 		__flush_wback_region(to, PAGE_SIZE);
84 	} else {
85 		__flush_purge_virtual_region(to,
86 					     (void *)(address & 0xfffff000),
87 					     PAGE_SIZE);
88 		clear_page(to);
89 		__flush_wback_region(to, PAGE_SIZE);
90 	}
91 }
92 
93 /*
94  * copy_user_page
95  * @to: P1 address
96  * @from: P1 address
97  * @address: U0 address to be mapped
98  */
copy_user_page(void * to,void * from,unsigned long address,struct page * pg)99 void copy_user_page(void *to, void *from, unsigned long address, struct page *pg)
100 {
101 	struct page *page = virt_to_page(to);
102 
103 
104 	__set_bit(PG_mapped, &page->flags);
105 	if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) {
106 		copy_page(to, from);
107 		__flush_wback_region(to, PAGE_SIZE);
108 	} else {
109 		__flush_purge_virtual_region(to,
110 					     (void *)(address & 0xfffff000),
111 					     PAGE_SIZE);
112 		copy_page(to, from);
113 		__flush_wback_region(to, PAGE_SIZE);
114 	}
115 }
116 
117 /*
118  * For SH7705, we have our own implementation for ptep_get_and_clear
119  * Copied from pg-sh4.c
120  */
ptep_get_and_clear(struct mm_struct * mm,unsigned long addr,pte_t * ptep)121 pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
122 {
123 	pte_t pte = *ptep;
124 
125 	pte_clear(mm, addr, ptep);
126 	if (!pte_not_present(pte)) {
127 		unsigned long pfn = pte_pfn(pte);
128 		if (pfn_valid(pfn)) {
129 			struct page *page = pfn_to_page(pfn);
130 			struct address_space *mapping = page_mapping(page);
131 			if (!mapping || !mapping_writably_mapped(mapping))
132 				__clear_bit(PG_mapped, &page->flags);
133 		}
134 	}
135 
136 	return pte;
137 }
138 
139