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