1 /* $NetBSD: bus.c,v 1.70 2023/12/20 15:29:07 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 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.70 2023/12/20 15:29:07 thorpej Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/endian.h> 39 #include <sys/bswap.h> 40 #include <sys/kernel.h> 41 #include <sys/device.h> 42 #include <sys/proc.h> 43 #include <sys/mbuf.h> 44 45 #define _MIPS_BUS_DMA_PRIVATE 46 47 #include <sys/bus.h> 48 #include <machine/cpu.h> 49 #include <machine/machtype.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <mips/cpuregs.h> 54 #include <mips/locore.h> 55 #include <mips/cache.h> 56 57 #include <sgimips/mace/macereg.h> 58 59 #include "opt_sgimace.h" 60 61 struct mips_bus_dma_tag sgimips_default_bus_dma_tag = { 62 ._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER, 63 ._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER, 64 ._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER, 65 }; 66 67 static void normal_bus_mem_init(bus_space_tag_t, void *); 68 69 static struct mips_bus_space normal_mbst; 70 bus_space_tag_t normal_memt = NULL; 71 72 /* 73 * XXX 74 * I'm not sure how well the common MIPS bus_dma.c handles MIPS-I and I don't 75 * have any IP1x hardware, so I'll leave this in just in case it needs to be 76 * put back 77 */ 78 79 void 80 sgimips_bus_dma_init(void) 81 { 82 normal_bus_mem_init(&normal_mbst, NULL); 83 normal_memt = &normal_mbst; 84 85 #ifdef MIPS1 86 switch (mach_type) { 87 /* R2000/R3000 */ 88 case MACH_SGI_IP6 | MACH_SGI_IP10: /* same number... */ 89 case MACH_SGI_IP12: 90 sgimips_default_bus_dma_tag._dmamap_ops.dmamap_sync = 91 _bus_dmamap_sync_mips1; 92 break; 93 } 94 #endif 95 } 96 97 /* 98 * XXX 99 * left in for illustrative purposes 100 */ 101 102 #if 0 103 u_int8_t 104 bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) 105 { 106 wbflush(); /* XXX ? */ 107 108 switch (t) { 109 case SGIMIPS_BUS_SPACE_NORMAL: 110 return *(volatile u_int8_t *)(vaddr_t)(h + o); 111 case SGIMIPS_BUS_SPACE_IP6_DPCLOCK: 112 return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2)); 113 case SGIMIPS_BUS_SPACE_HPC: 114 return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2) + 3); 115 case SGIMIPS_BUS_SPACE_MEM: 116 case SGIMIPS_BUS_SPACE_IO: 117 return *(volatile u_int8_t *)(vaddr_t)(h + (o | 3) - (o & 3)); 118 case SGIMIPS_BUS_SPACE_MACE: 119 return *(volatile u_int8_t *)(vaddr_t)(h + (o << 8) + 7); 120 default: 121 panic("no bus tag"); 122 } 123 } 124 #endif 125 126 #ifdef MIPS1 127 /* Common function from DMA map synchronization. May be called 128 * by chipset-specific DMA map synchronization functions. 129 * 130 * This is the R3000 version. 131 */ 132 void 133 _bus_dmamap_sync_mips1(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 134 bus_size_t len, int ops) 135 { 136 bus_size_t minlen; 137 bus_addr_t addr; 138 int i; 139 140 /* 141 * Mixing PRE and POST operations is not allowed. 142 */ 143 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 && 144 (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0) 145 panic("_bus_dmamap_sync_mips1: mix PRE and POST"); 146 147 #ifdef DIAGNOSTIC 148 if (offset >= map->dm_mapsize) 149 panic("_bus_dmamap_sync_mips1: bad offset %"PRIxPSIZE 150 " (map size is %"PRIxPSIZE")" 151 , offset, map->dm_mapsize); 152 if (len == 0 || (offset + len) > map->dm_mapsize) 153 panic("_bus_dmamap_sync_mips1: bad length"); 154 #endif 155 156 /* 157 * The R3000 cache is write-through. Therefore, we only need 158 * to drain the write buffer on PREWRITE. The cache is not 159 * coherent, however, so we need to invalidate the data cache 160 * on PREREAD (should we do it POSTREAD instead?). 161 * 162 * POSTWRITE (and POSTREAD, currently) are noops. 163 */ 164 165 if (ops & BUS_DMASYNC_PREWRITE) { 166 /* 167 * Flush the write buffer. 168 */ 169 wbflush(); 170 } 171 172 /* 173 * If we're not doing PREREAD, nothing more to do. 174 */ 175 if ((ops & BUS_DMASYNC_PREREAD) == 0) 176 return; 177 178 /* 179 * No cache invalidation is necessary if the DMA map covers 180 * COHERENT DMA-safe memory (which is mapped un-cached). 181 */ 182 if (map->_dm_flags & SGIMIPS_DMAMAP_COHERENT) 183 return; 184 185 /* 186 * If we are going to hit something as large or larger 187 * than the entire data cache, just nail the whole thing. 188 * 189 * NOTE: Even though this is `wbinv_all', since the cache is 190 * write-through, it just invalidates it. 191 */ 192 if (len >= mips_cache_info.mci_pdcache_size) { 193 mips_dcache_wbinv_all(); 194 return; 195 } 196 197 for (i = 0; i < map->dm_nsegs && len != 0; i++) { 198 /* Find the beginning segment. */ 199 if (offset >= map->dm_segs[i].ds_len) { 200 offset -= map->dm_segs[i].ds_len; 201 continue; 202 } 203 204 /* 205 * Now at the first segment to sync; nail 206 * each segment until we have exhausted the 207 * length. 208 */ 209 minlen = len < map->dm_segs[i].ds_len - offset ? 210 len : map->dm_segs[i].ds_len - offset; 211 212 addr = map->dm_segs[i].ds_addr; 213 214 #ifdef BUS_DMA_DEBUG 215 printf("bus_dmamap_sync_mips1: flushing segment %d " 216 "(0x%"PRIxBUSADDR"..0x%"PRIxBUSADDR") ...", i, 217 addr + offset, addr + offset + minlen - 1); 218 #endif 219 mips_dcache_inv_range( 220 MIPS_PHYS_TO_KSEG0(addr + offset), minlen); 221 #ifdef BUS_DMA_DEBUG 222 printf("\n"); 223 #endif 224 offset = 0; 225 len -= minlen; 226 } 227 } 228 #endif 229 230 #define CHIP normal 231 #define CHIP_MEM /* defined */ 232 #define CHIP_W1_BUS_START(v) 0x00000000UL 233 #define CHIP_W1_BUS_END(v) 0xffffffffUL 234 #define CHIP_W1_SYS_START(v) 0x00000000UL 235 #define CHIP_W1_SYS_END(v) 0xffffffffUL 236 237 #include <mips/mips/bus_space_alignstride_chipdep.c> 238