xref: /openbsd/sys/arch/mips64/mips64/cache_octeon.c (revision 5f3b292c)
1 /*	$OpenBSD: cache_octeon.c,v 1.13 2018/12/04 16:24:13 visa Exp $	*/
2 /*
3  * Copyright (c) 2010 Takuya ASADA.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 /*
18  * Copyright (c) 1998-2004 Opsycon AB (www.opsycon.se)
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
30  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
33  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 
47 #include <uvm/uvm_extern.h>
48 
49 #include <mips64/cache.h>
50 #include <machine/cpu.h>
51 
52 #define SYNCI() \
53 	asm volatile( \
54 		".set push\n" \
55 		".set mips64r2\n" \
56 		".word 0x041f0000\n" \
57 		"nop\n" \
58 		".set pop")
59 
60 void
Octeon_ConfigCache(struct cpu_info * ci)61 Octeon_ConfigCache(struct cpu_info *ci)
62 {
63 	uint32_t cfg;
64 	uint32_t s, l, a;
65 
66 	switch (ci->ci_hw.type) {
67 	default:
68 		/* OCTEON and OCTEON Plus */
69 
70 		cfg = cp0_get_config_1();
71 
72 		/*
73 		 * Octeon L1 cache information does not follow the mips64
74 		 * standard encoding.
75 		 */
76 
77 	        a = (cfg >> 16) & 0x07;
78 		l = (cfg >> 19) & 0x07;
79 		s = (cfg >> 22) & 0x07;
80 		ci->ci_l1inst.linesize = 2 << l;
81 		ci->ci_l1inst.setsize = (64 << s) * ci->ci_l1inst.linesize;
82 		if (a >= 1)
83 	        	ci->ci_l1inst.sets = 1 << (a - 1);
84 		else
85 			ci->ci_l1inst.sets = 1;
86 		ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize;
87 
88 		ci->ci_l1data.linesize = 128;
89 		ci->ci_l1data.setsize = 2 * 128;
90 		ci->ci_l1data.sets = 64;
91 		ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize;
92 
93 		break;
94 
95 	case MIPS_CN61XX:
96 	case MIPS_CN63XX:
97 	case MIPS_CN66XX:
98 	case MIPS_CN68XX:
99 		/* OCTEON II */
100 
101 		ci->ci_l1inst.linesize = 128;
102 		ci->ci_l1inst.setsize = 8 * 128;
103 		ci->ci_l1inst.sets = 37;
104 		ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize;
105 
106 		ci->ci_l1data.linesize = 128;
107 		ci->ci_l1data.setsize = 8 * 128;
108 		ci->ci_l1data.sets = 32;
109 		ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize;
110 
111 		break;
112 
113 	case MIPS_CN71XX:
114 	case MIPS_CN73XX:
115 	case MIPS_CN78XX:
116 		/* OCTEON III */
117 
118 		ci->ci_l1inst.linesize = 128;
119 		ci->ci_l1inst.setsize = 16 * 128;
120 		ci->ci_l1inst.sets = 39;
121 		ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize;
122 
123 		ci->ci_l1data.linesize = 128;
124 		ci->ci_l1data.setsize = 8 * 128;
125 		ci->ci_l1data.sets = 32;
126 		ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize;
127 
128 		break;
129 	}
130 
131 	cfg = cp0_get_config_2();
132 
133 	a = 1 + ((cfg >> 0) & 0x0f);
134 	l = (cfg >> 4) & 0x0f;
135 	s = (cfg >> 8) & 0x0f;
136 
137 	ci->ci_l2.linesize = 2 << l;
138 	ci->ci_l2.sets = a;
139 	ci->ci_l2.setsize = (64 << s) * ci->ci_l2.linesize;
140 	ci->ci_l2.size = ci->ci_l2.sets * ci->ci_l2.setsize;
141 
142 	memset(&ci->ci_l3, 0, sizeof(struct cache_info));
143 
144 	ci->ci_SyncCache = Octeon_SyncCache;
145 	ci->ci_InvalidateICache = Octeon_InvalidateICache;
146 	ci->ci_InvalidateICachePage = Octeon_InvalidateICachePage;
147 	ci->ci_SyncICache = Octeon_SyncICache;
148 	ci->ci_SyncDCachePage = Octeon_SyncDCachePage;
149 	ci->ci_HitSyncDCachePage = Octeon_SyncDCachePage;
150 	ci->ci_HitSyncDCache = Octeon_HitSyncDCache;
151 	ci->ci_HitInvalidateDCache = Octeon_HitInvalidateDCache;
152 	ci->ci_IOSyncDCache = Octeon_IOSyncDCache;
153 }
154 
155 void
Octeon_SyncCache(struct cpu_info * ci)156 Octeon_SyncCache(struct cpu_info *ci)
157 {
158 	mips_sync();
159 }
160 
161 void
Octeon_InvalidateICache(struct cpu_info * ci,vaddr_t va,size_t len)162 Octeon_InvalidateICache(struct cpu_info *ci, vaddr_t va, size_t len)
163 {
164 	/* A SYNCI flushes the entire icache on OCTEON */
165 	SYNCI();
166 }
167 
168 /*
169  * Register a given page for I$ invalidation.
170  */
171 void
Octeon_InvalidateICachePage(struct cpu_info * ci,vaddr_t va)172 Octeon_InvalidateICachePage(struct cpu_info *ci, vaddr_t va)
173 {
174 	/*
175 	 * Since there is apparently no way to operate on a subset of I$,
176 	 * all we need to do here is remember there are postponed flushes.
177 	 */
178 	ci->ci_cachepending_l1i = 1;
179 }
180 
181 /*
182  * Perform postponed I$ invalidation.
183  */
184 void
Octeon_SyncICache(struct cpu_info * ci)185 Octeon_SyncICache(struct cpu_info *ci)
186 {
187 	if (ci->ci_cachepending_l1i != 0) {
188 		SYNCI(); /* Octeon_InvalidateICache(ci, 0, PAGE_SIZE); */
189 		ci->ci_cachepending_l1i = 0;
190 	}
191 }
192 
193 void
Octeon_SyncDCachePage(struct cpu_info * ci,vaddr_t va,paddr_t pa)194 Octeon_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa)
195 {
196 }
197 
198 void
Octeon_HitSyncDCache(struct cpu_info * ci,vaddr_t va,size_t len)199 Octeon_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len)
200 {
201 }
202 
203 void
Octeon_HitInvalidateDCache(struct cpu_info * ci,vaddr_t va,size_t len)204 Octeon_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len)
205 {
206 }
207 
208 void
Octeon_IOSyncDCache(struct cpu_info * ci,vaddr_t va,size_t len,int how)209 Octeon_IOSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len, int how)
210 {
211 	switch (how) {
212 	default:
213 	case CACHE_SYNC_R:
214 		break;
215 	case CACHE_SYNC_W: /* writeback */
216 	case CACHE_SYNC_X: /* writeback and invalidate */
217 		mips_sync();
218 		break;
219 	}
220 }
221 
222 void
Octeon_lock_secondary_cache(struct cpu_info * ci,paddr_t _pa,size_t _sz)223 Octeon_lock_secondary_cache(struct cpu_info *ci, paddr_t _pa, size_t _sz)
224 {
225 	size_t linesize = ci->ci_l2.linesize;
226 	size_t sz;
227 	paddr_t pa;
228 	vaddr_t end, va;
229 
230 	pa = _pa & ~(linesize - 1);
231 	sz = ((_pa + _sz + linesize - 1) & ~(linesize - 1)) - pa;
232 
233 	va = PHYS_TO_XKPHYS(pa, 0ul);
234 	end = va + sz;
235 	while (va < end) {
236 		asm volatile ("cache 31, (%0)" : : "r" (va));
237 		va += linesize;
238 	}
239 
240 	/* Wait for the lock operations to finish. */
241 	mips_sync();
242 }
243 
244 void
Octeon_unlock_secondary_cache(struct cpu_info * ci,paddr_t _pa,size_t _sz)245 Octeon_unlock_secondary_cache(struct cpu_info *ci, paddr_t _pa, size_t _sz)
246 {
247 	size_t linesize = ci->ci_l2.linesize;
248 	size_t sz;
249 	paddr_t pa;
250 	vaddr_t end, va;
251 
252 	pa = _pa & ~(linesize - 1);
253 	sz = ((_pa + _sz + linesize - 1) & ~(linesize - 1)) - pa;
254 
255 	va = PHYS_TO_XKPHYS(pa, 0ul);
256 	end = va + sz;
257 	while (va < end) {
258 		asm volatile ("cache 23, (%0)" : : "r" (va));
259 		va += linesize;
260 	}
261 }
262