xref: /netbsd-src/sys/arch/pmax/pmax/bus.c (revision 43c66247297bd801ed622fb9844f922d89127ac0)
1 /*	$NetBSD: bus.c,v 1.5 2021/12/05 03:07:16 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.5 2021/12/05 03:07:16 msaitoh Exp $");
35 
36 #include "opt_cputype.h"
37 
38 #define _MIPS_BUS_DMA_PRIVATE
39 
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/mbuf.h>
43 #include <sys/proc.h>
44 #include <sys/systm.h>
45 
46 #include <sys/bus.h>
47 #include <machine/cpu.h>
48 
49 #include <uvm/uvm_extern.h>
50 
51 #include <mips/cpuregs.h>
52 #include <mips/locore.h>
53 #include <mips/cache.h>
54 
55 /*
56  * The default DMA tag for all busses on the DECstation.
57  */
58 struct mips_bus_dma_tag pmax_default_bus_dma_tag = {
59 	._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER,
60 	._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER,
61 	._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER,
62 };
63 
64 static void normal_bus_mem_init(bus_space_tag_t, void *);
65 #ifdef MIPS1
66 static void _bus_dmamap_sync_r3k(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
67 				 bus_size_t, int);
68 #endif
69 #if 0
70 static void _bus_dmamap_sync_r4k(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
71 				 bus_size_t, int);
72 #endif
73 
74 static struct mips_bus_space	normal_mbst;
75 bus_space_tag_t	normal_memt = NULL;
76 
77 
78 void
pmax_bus_dma_init(void)79 pmax_bus_dma_init(void)
80 {
81 
82 	normal_bus_mem_init(&normal_mbst, NULL);
83 	normal_memt = &normal_mbst;
84 
85 #ifdef MIPS1
86 	if (CPUISMIPS3 == 0)
87 		pmax_default_bus_dma_tag._dmamap_ops.dmamap_sync = _bus_dmamap_sync_r3k;
88 #endif
89 #if 0
90 	/* the common dmamap_sync() method should work on those */
91 #ifdef MIPS3
92 	if (CPUISMIPS3)
93 		pmax_default_bus_dma_tag._dmamap_ops.dmamap_sync = _bus_dmamap_sync_r4k;
94 #endif
95 #endif
96 }
97 
98 #ifdef MIPS1
99 /*
100  * Common function for DMA map synchronization.  May be called
101  * by chipset-specific DMA map synchronization functions.
102  *
103  * This is the R3000 version.
104  */
105 static void
_bus_dmamap_sync_r3k(bus_dma_tag_t t,bus_dmamap_t map,bus_addr_t offset,bus_size_t len,int ops)106 _bus_dmamap_sync_r3k(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
107     bus_size_t len, int ops)
108 {
109 	bus_size_t minlen;
110 	bus_addr_t addr;
111 	int i;
112 
113 	/*
114 	 * Mixing PRE and POST operations is not allowed.
115 	 */
116 	if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
117 	    (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
118 		panic("_bus_dmamap_sync_r3k: mix PRE and POST");
119 
120 #ifdef DIAGNOSTIC
121 	if (offset >= map->dm_mapsize)
122 		panic("%s: bad offset %ju (map size is %ju)", __func__,
123 		      (uintmax_t)offset, (uintmax_t)map->dm_mapsize);
124 	if (len == 0 || (offset + len) > map->dm_mapsize)
125 		panic("%s: bad length", __func__);
126 #endif
127 
128 	/*
129 	 * The R3000 cache is write-though.  Therefore, we only need
130 	 * to drain the write buffer on PREWRITE.  The cache is not
131 	 * coherent, however, so we need to invalidate the data cache
132 	 * on PREREAD (should we do it POSTREAD instead?).
133 	 *
134 	 * POSTWRITE (and POSTREAD, currently) are noops.
135 	 */
136 
137 	if (ops & BUS_DMASYNC_PREWRITE) {
138 		/*
139 		 * Flush the write buffer.
140 		 */
141 		wbflush();
142 	}
143 
144 	/*
145 	 * If we're not doing PREREAD, nothing more to do.
146 	 */
147 	if ((ops & BUS_DMASYNC_PREREAD) == 0)
148 		return;
149 
150 	/*
151 	 * No cache invalidation is necessary if the DMA map covers
152 	 * COHERENT DMA-safe memory (which is mapped un-cached).
153 	 */
154 	if (map->_dm_flags & _BUS_DMAMAP_COHERENT)
155 		return;
156 
157 	/*
158 	 * If we are going to hit something as large or larger
159 	 * than the entire data cache, just nail the whole thing.
160 	 *
161 	 * NOTE: Even though this is `wbinv_all', since the cache is
162 	 * write-though, it just invalidates it.
163 	 */
164 	if (len >= mips_cache_info.mci_pdcache_size) {
165 		mips_dcache_wbinv_all();
166 		return;
167 	}
168 
169 	for (i = 0; i < map->dm_nsegs && len != 0; i++) {
170 		/* Find the beginning segment. */
171 		if (offset >= map->dm_segs[i].ds_len) {
172 			offset -= map->dm_segs[i].ds_len;
173 			continue;
174 		}
175 
176 		/*
177 		 * Now at the first segment to sync; nail
178 		 * each segment until we have exhausted the
179 		 * length.
180 		 */
181 		minlen = len < map->dm_segs[i].ds_len - offset ?
182 		    len : map->dm_segs[i].ds_len - offset;
183 
184 		addr = map->dm_segs[i].ds_addr;
185 
186 #ifdef BUS_DMA_DEBUG
187 		printf("%s: flushing segment %d (%#jx..%#jx) ...", __func__, i,
188 		    (intmax_t)addr + offset,
189 		    (intmax_t)addr + offset + minlen - 1);
190 #endif
191 		mips_dcache_inv_range(
192 		    MIPS_PHYS_TO_KSEG0(addr + offset), minlen);
193 #ifdef BUS_DMA_DEBUG
194 		printf("\n");
195 #endif
196 		offset = 0;
197 		len -= minlen;
198 	}
199 }
200 #endif /* MIPS1 */
201 
202 #if 0
203 #ifdef MIPS3
204 /*
205  * Common function for DMA map synchronization.  May be called
206  * by chipset-specific DMA map synchronization functions.
207  *
208  * This is the R4000 version.
209  */
210 static void
211 _bus_dmamap_sync_r4k(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
212     bus_size_t len, int ops)
213 {
214 	bus_size_t minlen;
215 	bus_addr_t addr;
216 	int i, useindex;
217 
218 	/*
219 	 * Mixing PRE and POST operations is not allowed.
220 	 */
221 	if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
222 	    (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
223 		panic("_bus_dmamap_sync_r4k: mix PRE and POST");
224 
225 #ifdef DIAGNOSTIC
226 	if (offset >= map->dm_mapsize)
227 		panic("%s: bad offset %ju (map size is %ju)", __func__,
228 		      (uintmax_t)offset, (uintmax_t)map->dm_mapsize);
229 	if (len == 0 || (offset + len) > map->dm_mapsize)
230 		panic("%s: bad length", __func__);
231 #endif
232 
233 	/*
234 	 * The R4000 cache is virtually-indexed, write-back.  This means
235 	 * we need to do the following things:
236 	 *
237 	 *	PREREAD -- Invalidate D-cache.  Note we might have
238 	 *	to also write-back here if we have to use an Index
239 	 *	op, or if the buffer start/end is not cache-line aligned.
240 	 *
241 	 *	PREWRITE -- Write-back the D-cache.  If we have to use
242 	 *	an Index op, we also have to invalidate.  Note that if
243 	 *	we are doing PREREAD|PREWRITE, we can collapse everything
244 	 *	into a single op.
245 	 *
246 	 *	POSTREAD -- Nothing.
247 	 *
248 	 *	POSTWRITE -- Nothing.
249 	 */
250 
251 	/*
252 	 * Flush the write buffer.
253 	 * XXX Is this always necessary?
254 	 */
255 	wbflush();
256 
257 	ops &= (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
258 	if (ops == 0)
259 		return;
260 
261 	/*
262 	 * If the mapping is of COHERENT DMA-safe memory, no cache
263 	 * flush is necessary.
264 	 */
265 	if (map->_dm_flags & _BUS_DMAMAP_COHERENT)
266 		return;
267 
268 	/*
269 	 * If the mapping belongs to the kernel, or if it belongs
270 	 * to the currently-running process (XXX actually, vmspace),
271 	 * then we can use Hit ops.  Otherwise, Index ops.
272 	 *
273 	 * This should be true the vast majority of the time.
274 	 */
275 	if (__predict_true(VMSPACE_IS_KERNEL_P(map->_dm_vmspace) ||
276 	    map->_dm_vmspace == curproc->p_vmspace))
277 		useindex = 0;
278 	else
279 		useindex = 1;
280 
281 	for (i = 0; i < map->dm_nsegs && len != 0; i++) {
282 		/* Find the beginning segment. */
283 		if (offset >= map->dm_segs[i].ds_len) {
284 			offset -= map->dm_segs[i].ds_len;
285 			continue;
286 		}
287 
288 		/*
289 		 * Now at the first segment to sync; nail
290 		 * each segment until we have exhausted the
291 		 * length.
292 		 */
293 		minlen = len < map->dm_segs[i].ds_len - offset ?
294 		    len : map->dm_segs[i].ds_len - offset;
295 
296 		addr = map->dm_segs[i]._ds_vaddr;
297 
298 #ifdef BUS_DMA_DEBUG
299 		printf("%s: flushing segment %d (%#jx..%#jx) ...",
300 		    __func__, i, (intmax_t)addr + offset,
301 		    (intmax_t)ddr + offset + minlen - 1);
302 #endif
303 
304 		/*
305 		 * If we are forced to use Index ops, it's always a
306 		 * Write-back,Invalidate, so just do one test.
307 		 */
308 		if (__predict_false(useindex)) {
309 			mips_dcache_wbinv_range_index(addr + offset, minlen);
310 #ifdef BUS_DMA_DEBUG
311 			printf("\n");
312 #endif
313 			offset = 0;
314 			len -= minlen;
315 			continue;
316 		}
317 
318 		switch (ops) {
319 		case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
320 			mips_dcache_wbinv_range(addr + offset, minlen);
321 			break;
322 
323 		case BUS_DMASYNC_PREREAD:
324 #if 1
325 			mips_dcache_wbinv_range(addr + offset, minlen);
326 #else
327 			mips_dcache_inv_range(addr + offset, minlen);
328 #endif
329 			break;
330 
331 		case BUS_DMASYNC_PREWRITE:
332 			mips_dcache_wb_range(addr + offset, minlen);
333 			break;
334 		}
335 #ifdef BUS_DMA_DEBUG
336 		printf("\n");
337 #endif
338 		offset = 0;
339 		len -= minlen;
340 	}
341 }
342 #endif /* MIPS3 */
343 #endif
344 
345 /*
346  * XXX
347  * I have no idea what kind of limits to apply here, so for now allow
348  * everything
349  */
350 
351 #define CHIP	   		normal
352 #define	CHIP_MEM		/* defined */
353 #define	CHIP_W1_BUS_START(v)	0x00000000UL
354 #define CHIP_W1_BUS_END(v)	0xffffffffUL
355 #define	CHIP_W1_SYS_START(v)	0x00000000UL
356 #define	CHIP_W1_SYS_END(v)	0xffffffffUL
357 
358 #include <mips/mips/bus_space_alignstride_chipdep.c>
359