1 /* $NetBSD: bus.c,v 1.6 2026/05/19 21:41:21 andvar 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.6 2026/05/19 21:41:21 andvar 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 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 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-through. 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-through, 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