1 /* $NetBSD: bus_space.c,v 1.3 2001/09/15 00:49:54 wdk Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 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 Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 9 * Simulation Facility, 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/malloc.h> 43 #include <sys/extent.h> 44 45 #include <uvm/uvm_extern.h> 46 47 #include <machine/bus.h> 48 49 void 50 mipsco_bus_space_init(bst, name, paddr, vaddr, start, size) 51 bus_space_tag_t bst; 52 const char *name; 53 paddr_t paddr; 54 vaddr_t vaddr; 55 bus_addr_t start; 56 bus_size_t size; 57 { 58 bst->bs_name = name; 59 bst->bs_extent = NULL; 60 bst->bs_start = start; 61 bst->bs_size = size; 62 bst->bs_pbase = paddr; 63 bst->bs_vbase = vaddr; 64 bst->bs_compose_handle = mipsco_bus_space_compose_handle; 65 bst->bs_dispose_handle = mipsco_bus_space_dispose_handle; 66 bst->bs_paddr = mipsco_bus_space_paddr; 67 bst->bs_map = mipsco_bus_space_map; 68 bst->bs_unmap = mipsco_bus_space_unmap; 69 bst->bs_subregion = mipsco_bus_space_subregion; 70 bst->bs_mmap = mipsco_bus_space_mmap; 71 bst->bs_alloc = mipsco_bus_space_alloc; 72 bst->bs_free = mipsco_bus_space_free; 73 bst->bs_aux = NULL; 74 bst->bs_bswap = 0; /* No byte swap for stream methods */ 75 mipsco_bus_space_set_aligned_stride(bst, 0); 76 } 77 78 void 79 mipsco_bus_space_init_extent(bst, storage, storagesize) 80 bus_space_tag_t bst; 81 caddr_t storage; 82 size_t storagesize; 83 { 84 bst->bs_extent = extent_create(bst->bs_name, 85 bst->bs_start, bst->bs_start + bst->bs_size, M_DEVBUF, 86 storage, storagesize, EX_NOWAIT); 87 if (bst->bs_extent == NULL) 88 panic("mipsco_bus_space_init_extent: cannot create extent map %s", 89 bst->bs_name); 90 } 91 92 void 93 mipsco_bus_space_set_aligned_stride(bst, shift) 94 bus_space_tag_t bst; 95 unsigned int shift; /* log2(alignment) */ 96 { 97 bst->bs_stride = shift; 98 99 if (shift == 2) { /* XXX Assumes Big Endian & 4B */ 100 bst->bs_offset_1 = 3; 101 bst->bs_offset_2 = 2; 102 } else { 103 bst->bs_offset_1 = 0; 104 bst->bs_offset_2 = 0; 105 } 106 bst->bs_offset_4 = 0; 107 bst->bs_offset_8 = 0; 108 } 109 110 static int malloc_safe = 0; 111 112 void 113 mipsco_bus_space_malloc_set_safe() 114 { 115 malloc_safe = EX_MALLOCOK; 116 } 117 118 int 119 mipsco_bus_space_extent_malloc_flag() 120 { 121 return (malloc_safe); 122 } 123 124 int 125 mipsco_bus_space_compose_handle(bst, addr, size, flags, bshp) 126 bus_space_tag_t bst; 127 bus_addr_t addr; 128 bus_size_t size; 129 int flags; 130 bus_space_handle_t *bshp; 131 { 132 bus_space_handle_t bsh = bst->bs_vbase + 133 ((addr - bst->bs_start) << bst->bs_stride); 134 135 /* 136 * Since all buses can be linearly mappable, we don't have to check 137 * BUS_SPACE_MAP_LINEAR and BUS_SPACE_MAP_PREFETCHABLE. 138 */ 139 if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) { 140 *bshp = bsh; 141 return (0); 142 } 143 if (bsh < MIPS_KSEG1_START) /* KUSEG or KSEG0 */ 144 panic("mipsco_bus_space_compose_handle: bad address 0x%x", bsh); 145 if (bsh < MIPS_KSEG2_START) { /* KSEG1 */ 146 *bshp = MIPS_PHYS_TO_KSEG0(MIPS_KSEG1_TO_PHYS(bsh)); 147 return (0); 148 } 149 /* 150 * KSEG2: 151 * Do not make the page cacheable in this case, since: 152 * - the page which this bus_space belongs might include 153 * other bus_spaces. 154 * or 155 * - this bus might be mapped by wired TLB, in that case, 156 * we cannot manupulate cacheable attribute with page granularity. 157 */ 158 #ifdef DIAGNOSTIC 159 printf("mipsco_bus_space_compose_handle: ignore cacheable 0x%x\n", bsh); 160 #endif 161 *bshp = bsh; 162 return (0); 163 } 164 165 int 166 mipsco_bus_space_dispose_handle(bst, bsh, size) 167 bus_space_tag_t bst; 168 bus_space_handle_t bsh; 169 bus_size_t size; 170 { 171 return (0); 172 } 173 174 int 175 mipsco_bus_space_paddr(bst, bsh, pap) 176 bus_space_tag_t bst; 177 bus_space_handle_t bsh; 178 paddr_t *pap; 179 { 180 if (bsh < MIPS_KSEG0_START) /* KUSEG */ 181 panic("mipsco_bus_space_paddr(%p): bad address", (caddr_t)bsh); 182 else if (bsh < MIPS_KSEG1_START) /* KSEG0 */ 183 *pap = MIPS_KSEG0_TO_PHYS(bsh); 184 else if (bsh < MIPS_KSEG2_START) /* KSEG1 */ 185 *pap = MIPS_KSEG1_TO_PHYS(bsh); 186 else { /* KSEG2 */ 187 /* 188 * Since this region may be mapped by wired TLB, 189 * kvtophys() is not always available. 190 */ 191 *pap = bst->bs_pbase + (bsh - bst->bs_vbase); 192 } 193 return (0); 194 } 195 196 int 197 mipsco_bus_space_map(bst, addr, size, flags, bshp) 198 bus_space_tag_t bst; 199 bus_addr_t addr; 200 bus_size_t size; 201 int flags; 202 bus_space_handle_t *bshp; 203 { 204 int err; 205 206 if (addr < bst->bs_start || addr + size > bst->bs_start + bst->bs_size) 207 return (EINVAL); 208 209 if (bst->bs_extent != NULL) { 210 err = extent_alloc_region(bst->bs_extent, addr, size, 211 EX_NOWAIT | malloc_safe); 212 if (err) 213 return (err); 214 } 215 216 return (bus_space_compose_handle(bst, addr, size, flags, bshp)); 217 } 218 219 void 220 mipsco_bus_space_unmap(bst, bsh, size) 221 bus_space_tag_t bst; 222 bus_space_handle_t bsh; 223 bus_size_t size; 224 { 225 if (bst->bs_extent != NULL) { 226 paddr_t pa; 227 bus_addr_t addr; 228 int err; 229 230 /* bus_space_paddr() becomes unavailable after unmapping */ 231 err = bus_space_paddr(bst, bsh, &pa); 232 if (err) 233 panic("mipsco_bus_space_unmap: %s va %p: error %d\n", 234 bst->bs_name, (caddr_t)bsh, err); 235 addr = (bus_size_t)(pa - bst->bs_pbase) + bst->bs_start; 236 extent_free(bst->bs_extent, addr, size, 237 EX_NOWAIT | malloc_safe); 238 } 239 bus_space_dispose_handle(bst, bsh, size); 240 } 241 242 int 243 mipsco_bus_space_subregion(bst, bsh, offset, size, nbshp) 244 bus_space_tag_t bst; 245 bus_space_handle_t bsh; 246 bus_size_t offset; 247 bus_size_t size; 248 bus_space_handle_t *nbshp; 249 { 250 *nbshp = bsh + (offset << bst->bs_stride); 251 return (0); 252 } 253 254 paddr_t 255 mipsco_bus_space_mmap(bst, addr, off, prot, flags) 256 bus_space_tag_t bst; 257 bus_addr_t addr; 258 off_t off; 259 int prot; 260 int flags; 261 { 262 263 /* 264 * XXX We do not disallow mmap'ing of I/O space here, 265 * XXX which we should be doing. 266 */ 267 268 if (addr < bst->bs_start || 269 (addr + off) >= (bst->bs_start + bst->bs_size)) 270 return (-1); 271 272 return (mips_btop(bst->bs_pbase + (addr - bst->bs_start) + off)); 273 } 274 275 int 276 mipsco_bus_space_alloc(bst, start, end, size, align, boundary, flags, addrp, bshp) 277 bus_space_tag_t bst; 278 bus_addr_t start; 279 bus_addr_t end; 280 bus_size_t size; 281 bus_size_t align; 282 bus_size_t boundary; 283 int flags; 284 bus_addr_t *addrp; 285 bus_space_handle_t *bshp; 286 { 287 u_long addr; 288 int err; 289 290 if (bst->bs_extent == NULL) 291 panic("mipsco_bus_space_alloc: extent map %s not available", 292 bst->bs_name); 293 294 if (start < bst->bs_start || 295 start + size > bst->bs_start + bst->bs_size) 296 return (EINVAL); 297 298 err = extent_alloc_subregion(bst->bs_extent, start, end, size, 299 align, boundary, EX_FAST | EX_NOWAIT | malloc_safe, &addr); 300 if (err) 301 return (err); 302 303 *addrp = addr; 304 return (bus_space_compose_handle(bst, addr, size, flags, bshp)); 305 } 306