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
60void
61Octeon_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
155void
156Octeon_SyncCache(struct cpu_info *ci)
157{
158	mips_sync();
159}
160
161void
162Octeon_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 */
171void
172Octeon_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 */
184void
185Octeon_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
193void
194Octeon_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa)
195{
196}
197
198void
199Octeon_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len)
200{
201}
202
203void
204Octeon_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len)
205{
206}
207
208void
209Octeon_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
222void
223Octeon_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
244void
245Octeon_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