1 /* $NetBSD: bus_space.c,v 1.10 2008/04/28 20:23:13 martin Exp $ */ 2 /* NetBSD: bus_machdep.c,v 1.1 2000/01/26 18:48:00 drochner Exp */ 3 4 /*- 5 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 10 * Simulation Facility, NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.10 2008/04/28 20:23:13 martin Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/extent.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/bus.h> 45 46 void 47 arc_bus_space_init(bus_space_tag_t bst, const char *name, paddr_t paddr, 48 vaddr_t vaddr, bus_addr_t start, bus_size_t size) 49 { 50 51 bst->bs_name = name; 52 bst->bs_extent = NULL; 53 bst->bs_start = start; 54 bst->bs_size = size; 55 bst->bs_pbase = paddr; 56 bst->bs_vbase = vaddr; 57 bst->bs_compose_handle = arc_bus_space_compose_handle; 58 bst->bs_dispose_handle = arc_bus_space_dispose_handle; 59 bst->bs_paddr = arc_bus_space_paddr; 60 bst->bs_map = arc_bus_space_map; 61 bst->bs_unmap = arc_bus_space_unmap; 62 bst->bs_subregion = arc_bus_space_subregion; 63 bst->bs_mmap = arc_bus_space_mmap; 64 bst->bs_alloc = arc_bus_space_alloc; 65 bst->bs_free = arc_bus_space_free; 66 bst->bs_aux = NULL; 67 bst->bs_stride_1 = 0; 68 bst->bs_stride_2 = 0; 69 bst->bs_stride_4 = 0; 70 bst->bs_stride_8 = 0; 71 } 72 73 void 74 arc_bus_space_init_extent(bus_space_tag_t bst, void *storage, 75 size_t storagesize) 76 { 77 78 bst->bs_extent = extent_create(bst->bs_name, 79 bst->bs_start, bst->bs_start + bst->bs_size, M_DEVBUF, 80 storage, storagesize, EX_NOWAIT); 81 if (bst->bs_extent == NULL) 82 panic("arc_bus_space_init_extent: cannot create extent map %s", 83 bst->bs_name); 84 } 85 86 void 87 arc_bus_space_set_aligned_stride(bus_space_tag_t bst, 88 unsigned int alignment_shift) 89 { 90 91 bst->bs_stride_1 = alignment_shift; 92 if (alignment_shift > 0) 93 --alignment_shift; 94 bst->bs_stride_2 = alignment_shift; 95 if (alignment_shift > 0) 96 --alignment_shift; 97 bst->bs_stride_4 = alignment_shift; 98 if (alignment_shift > 0) 99 --alignment_shift; 100 bst->bs_stride_8 = alignment_shift; 101 } 102 103 static int malloc_safe = 0; 104 105 void 106 arc_bus_space_malloc_set_safe(void) 107 { 108 109 malloc_safe = EX_MALLOCOK; 110 } 111 112 int 113 arc_bus_space_extent_malloc_flag(void) 114 { 115 116 return malloc_safe; 117 } 118 119 int 120 arc_bus_space_compose_handle(bus_space_tag_t bst, bus_addr_t addr, 121 bus_size_t size, int flags, bus_space_handle_t *bshp) 122 { 123 bus_space_handle_t bsh = bst->bs_vbase + (addr - bst->bs_start); 124 125 /* 126 * Since all buses can be linearly mappable, we don't have to check 127 * BUS_SPACE_MAP_LINEAR and BUS_SPACE_MAP_PREFETCHABLE. 128 */ 129 if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) { 130 *bshp = bsh; 131 return 0; 132 } 133 if (bsh < MIPS_KSEG1_START) /* KUSEG or KSEG0 */ 134 panic("arc_bus_space_compose_handle: bad address 0x%x", bsh); 135 if (bsh < MIPS_KSEG2_START) { /* KSEG1 */ 136 *bshp = MIPS_PHYS_TO_KSEG0(MIPS_KSEG1_TO_PHYS(bsh)); 137 return 0; 138 } 139 /* 140 * KSEG2: 141 * Do not make the page cacheable in this case, since: 142 * - the page which this bus_space belongs might include 143 * other bus_spaces. 144 * or 145 * - this bus might be mapped by wired TLB, in that case, 146 * we cannot manupulate cacheable attribute with page granularity. 147 */ 148 #ifdef DIAGNOSTIC 149 printf("arc_bus_space_compose_handle: ignore cacheable 0x%x\n", bsh); 150 #endif 151 *bshp = bsh; 152 return 0; 153 } 154 155 int 156 arc_bus_space_dispose_handle(bus_space_tag_t bst, bus_space_handle_t bsh, 157 bus_size_t size) 158 { 159 160 return 0; 161 } 162 163 int 164 arc_bus_space_paddr(bus_space_tag_t bst, bus_space_handle_t bsh, paddr_t *pap) 165 { 166 167 if (bsh < MIPS_KSEG0_START) /* KUSEG */ 168 panic("arc_bus_space_paddr(0x%qx): bad address", 169 (unsigned long long) bsh); 170 else if (bsh < MIPS_KSEG1_START) /* KSEG0 */ 171 *pap = MIPS_KSEG0_TO_PHYS(bsh); 172 else if (bsh < MIPS_KSEG2_START) /* KSEG1 */ 173 *pap = MIPS_KSEG1_TO_PHYS(bsh); 174 else { /* KSEG2 */ 175 /* 176 * Since this region may be mapped by wired TLB, 177 * kvtophys() is not always available. 178 */ 179 *pap = bst->bs_pbase + (bsh - bst->bs_vbase); 180 } 181 return 0; 182 } 183 184 int 185 arc_bus_space_map(bus_space_tag_t bst, bus_addr_t addr, bus_size_t size, 186 int flags, bus_space_handle_t *bshp) 187 { 188 int err; 189 190 if (addr < bst->bs_start || addr + size > bst->bs_start + bst->bs_size) 191 return EINVAL; 192 193 if (bst->bs_extent != NULL) { 194 err = extent_alloc_region(bst->bs_extent, addr, size, 195 EX_NOWAIT | malloc_safe); 196 if (err) 197 return err; 198 } 199 200 return bus_space_compose_handle(bst, addr, size, flags, bshp); 201 } 202 203 void 204 arc_bus_space_unmap(bus_space_tag_t bst, bus_space_handle_t bsh, 205 bus_size_t size) 206 { 207 208 if (bst->bs_extent != NULL) { 209 paddr_t pa; 210 bus_addr_t addr; 211 int err; 212 213 /* bus_space_paddr() becomes unavailable after unmapping */ 214 err = bus_space_paddr(bst, bsh, &pa); 215 if (err) 216 panic("arc_bus_space_unmap: %s va 0x%qx: error %d", 217 bst->bs_name, (unsigned long long) bsh, err); 218 addr = (bus_size_t)(pa - bst->bs_pbase) + bst->bs_start; 219 extent_free(bst->bs_extent, addr, size, 220 EX_NOWAIT | malloc_safe); 221 } 222 bus_space_dispose_handle(bst, bsh, size); 223 } 224 225 int 226 arc_bus_space_subregion(bus_space_tag_t bst, bus_space_handle_t bsh, 227 bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) 228 { 229 230 *nbshp = bsh + offset; 231 return 0; 232 } 233 234 paddr_t 235 arc_bus_space_mmap(bus_space_tag_t bst, bus_addr_t addr, off_t off, int prot, 236 int flags) 237 { 238 239 /* 240 * XXX We do not disallow mmap'ing of EISA/PCI I/O space here, 241 * XXX which we should be doing. 242 */ 243 244 if (addr < bst->bs_start || 245 (addr + off) >= (bst->bs_start + bst->bs_size)) 246 return -1; 247 248 return mips_btop(bst->bs_pbase + (addr - bst->bs_start) + off); 249 } 250 251 int 252 arc_bus_space_alloc(bus_space_tag_t bst, bus_addr_t start, bus_addr_t end, 253 bus_size_t size, bus_size_t align, bus_size_t boundary, int flags, 254 bus_addr_t *addrp, bus_space_handle_t *bshp) 255 { 256 u_long addr; 257 int err; 258 259 if (bst->bs_extent == NULL) 260 panic("arc_bus_space_alloc: extent map %s not available", 261 bst->bs_name); 262 263 if (start < bst->bs_start || 264 start + size > bst->bs_start + bst->bs_size) 265 return EINVAL; 266 267 err = extent_alloc_subregion(bst->bs_extent, start, end, size, 268 align, boundary, EX_FAST | EX_NOWAIT | malloc_safe, &addr); 269 if (err) 270 return err; 271 272 *addrp = addr; 273 return bus_space_compose_handle(bst, addr, size, flags, bshp); 274 } 275