1 /*	$NetBSD: cache_mipsNN.c,v 1.16 2016/07/11 16:15:36 matt Exp $	*/
2 
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed for the NetBSD Project by
20  *	Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: cache_mipsNN.c,v 1.16 2016/07/11 16:15:36 matt Exp $");
40 
41 #include <sys/param.h>
42 
43 #include <mips/locore.h>
44 #include <mips/cache.h>
45 #include <mips/cache_r4k.h>
46 #include <mips/cache_mipsNN.h>
47 #include <mips/mipsNN.h>
48 
49 #include <uvm/uvm_extern.h>
50 
51 #define	round_line(x,n)		(((x) + (n) - 1) & -(n))
52 #define	trunc_line(x,n)		((x) & -(n))
53 
54 void
mipsNN_cache_init(uint32_t config,uint32_t config1)55 mipsNN_cache_init(uint32_t config, uint32_t config1)
56 {
57 	/* nothing to do */
58 }
59 
60 void
mipsNN_picache_sync_all(void)61 mipsNN_picache_sync_all(void)
62 {
63 	struct mips_cache_info * const mci = &mips_cache_info;
64 
65 	/*
66 	 * Since we're hitting the whole thing, we don't have to
67 	 * worry about the N different "ways".
68 	 */
69 	mips_intern_dcache_sync_all();
70 	mips_intern_icache_sync_range_index(MIPS_KSEG0_START,
71 	    mci->mci_picache_size);
72 }
73 
74 void
mipsNN_pdcache_wbinv_all(void)75 mipsNN_pdcache_wbinv_all(void)
76 {
77 	struct mips_cache_info * const mci = &mips_cache_info;
78 
79 	/*
80 	 * Since we're hitting the whole thing, we don't have to
81 	 * worry about the N different "ways".
82 	 */
83 	mips_intern_pdcache_wbinv_range_index(MIPS_KSEG0_START,
84 	    mci->mci_pdcache_size);
85 }
86 
87 void
mipsNN_sdcache_wbinv_all(void)88 mipsNN_sdcache_wbinv_all(void)
89 {
90 	struct mips_cache_info * const mci = &mips_cache_info;
91 
92 	/*
93 	 * Since we're hitting the whole thing, we don't have to
94 	 * worry about the N different "ways".
95 	 */
96 	mips_intern_sdcache_wbinv_range_index(MIPS_KSEG0_START,
97 	    mci->mci_sdcache_size);
98 }
99 
100 void
mipsNN_picache_sync_range(register_t va,vsize_t size)101 mipsNN_picache_sync_range(register_t va, vsize_t size)
102 {
103 
104 	mips_intern_dcache_sync_range(va, size);
105 	mips_intern_icache_sync_range(va, size);
106 }
107 
108 void
mipsNN_picache_sync_range_index(vaddr_t va,vsize_t size)109 mipsNN_picache_sync_range_index(vaddr_t va, vsize_t size)
110 {
111 	struct mips_cache_info * const mci = &mips_cache_info;
112 	const size_t ways = mci->mci_picache_ways;
113 	const size_t line_size = mci->mci_picache_line_size;
114 	const size_t way_size = mci->mci_picache_way_size;
115 	const size_t way_mask = way_size - 1;
116 	vaddr_t eva;
117 
118 	/*
119 	 * Since we're doing Index ops, we expect to not be able
120 	 * to access the address we've been given.  So, get the
121 	 * bits that determine the cache index, and make a KSEG0
122 	 * address out of them.
123 	 */
124 	va = MIPS_PHYS_TO_KSEG0(va & way_mask);
125 
126 	eva = round_line(va + size, line_size);
127 	va = trunc_line(va, line_size);
128 	size = eva - va;
129 
130 	/*
131 	 * If we are going to flush more than is in a way (or the stride
132 	 * need for that way), we are flushing everything.
133 	 */
134 	if (size >= way_size) {
135 		mipsNN_picache_sync_all();
136 		return;
137 	}
138 
139 	for (size_t way = 0; way < ways; way++) {
140 		mips_intern_dcache_sync_range_index(va, size);
141 		mips_intern_icache_sync_range_index(va, size);
142 		va += way_size;
143 		eva += way_size;
144 	}
145 }
146 
147 void
mipsNN_pdcache_wbinv_range_index(vaddr_t va,vsize_t size)148 mipsNN_pdcache_wbinv_range_index(vaddr_t va, vsize_t size)
149 {
150 	struct mips_cache_info * const mci = &mips_cache_info;
151 	const size_t ways = mci->mci_pdcache_ways;
152 	const size_t line_size = mci->mci_pdcache_line_size;
153 	const vaddr_t way_size = mci->mci_pdcache_way_size;
154 	const vaddr_t way_mask = way_size - 1;
155 	vaddr_t eva;
156 
157 	/*
158 	 * Since we're doing Index ops, we expect to not be able
159 	 * to access the address we've been given.  So, get the
160 	 * bits that determine the cache index, and make a KSEG0
161 	 * address out of them.
162 	 */
163 	va = MIPS_PHYS_TO_KSEG0(va & way_mask);
164 	eva = round_line(va + size, line_size);
165 	va = trunc_line(va, line_size);
166 	size = eva - va;
167 
168 	/*
169 	 * If we are going to flush more than is in a way, we are flushing
170 	 * everything.
171 	 */
172 	if (size >= way_size) {
173 		mips_intern_pdcache_wbinv_range_index(MIPS_KSEG0_START,
174 		    mci->mci_pdcache_size);
175 		return;
176 	}
177 
178 	/*
179 	 * Invalidate each way.  If the address range wraps past the end of
180 	 * the way, we will be invalidating in two ways but eventually things
181 	 * work out since the last way will wrap into the first way.
182 	 */
183 	for (size_t way = 0; way < ways; way++) {
184 		mips_intern_pdcache_wbinv_range_index(va, size);
185 		va += way_size;
186 		eva += way_size;
187 	}
188 }
189 
190 void
mipsNN_sdcache_wbinv_range_index(vaddr_t va,vsize_t size)191 mipsNN_sdcache_wbinv_range_index(vaddr_t va, vsize_t size)
192 {
193 	struct mips_cache_info * const mci = &mips_cache_info;
194 	const size_t ways = mci->mci_sdcache_ways;
195 	const size_t line_size = mci->mci_sdcache_line_size;
196 	const vaddr_t way_size = mci->mci_sdcache_way_size;
197 	const vaddr_t way_mask = way_size - 1;
198 	vaddr_t eva;
199 
200 	/*
201 	 * Since we're doing Index ops, we expect to not be able
202 	 * to access the address we've been given.  So, get the
203 	 * bits that determine the cache index, and make a KSEG0
204 	 * address out of them.
205 	 */
206 	va = MIPS_PHYS_TO_KSEG0(va & way_mask);
207 	eva = round_line(va + size, line_size);
208 	va = trunc_line(va, line_size);
209 	size = eva - va;
210 
211 	/*
212 	 * If we are going to flush more than is in a way, we are flushing
213 	 * everything.
214 	 */
215 	if (size >= way_size) {
216 		mips_intern_sdcache_wbinv_range_index(MIPS_KSEG0_START,
217 		    mci->mci_sdcache_size);
218 		return;
219 	}
220 
221 	/*
222 	 * Invalidate each way.  If the address range wraps past the end of
223 	 * the way, we will be invalidating in two ways but eventually things
224 	 * work out since the last way will wrap into the first way.
225 	 */
226 	for (size_t way = 0; way < ways; way++) {
227 		mips_intern_sdcache_wbinv_range_index(va, size);
228 		va += way_size;
229 		eva += way_size;
230 	}
231 }
232