Home | History | Annotate | Line # | Download | only in pmax
      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