1 /* $NetBSD: bus_space.c,v 1.6 2015/06/23 21:00:23 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2004, 2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.6 2015/06/23 21:00:23 matt Exp $"); 31 32 #define _EWS4800MIPS_BUS_SPACE_PRIVATE 33 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/extent.h> 37 #include <sys/malloc.h> 38 #include <sys/systm.h> 39 40 #include <mips/locore.h> 41 42 #include <machine/sbdvar.h> 43 44 #ifdef BUS_SPACE_DEBUG 45 int bus_space_debug = 0; 46 #define DPRINTF(fmt, args...) \ 47 if (bus_space_debug) \ 48 printf("%s: " fmt, __func__ , ##args) 49 #define DPRINTFN(n, arg) \ 50 if (bus_space_debug > (n)) \ 51 printf("%s: " fmt, __func__ , ##args) 52 #else 53 #define DPRINTF(arg...) ((void)0) 54 #define DPRINTFN(n, arg...) ((void)0) 55 #endif 56 57 #define VADDR(h, o) (h + o) 58 _BUS_SPACE_READ(_default, 1, 8) 59 _BUS_SPACE_READ(_default, 2, 16) 60 _BUS_SPACE_READ(_default, 4, 32) 61 _BUS_SPACE_READ(_default, 8, 64) 62 _BUS_SPACE_READ_MULTI(_default, 1, 8) 63 _BUS_SPACE_READ_MULTI(_default, 2, 16) 64 _BUS_SPACE_READ_MULTI(_default, 4, 32) 65 _BUS_SPACE_READ_MULTI(_default, 8, 64) 66 _BUS_SPACE_READ_REGION(_default, 1, 8) 67 _BUS_SPACE_READ_REGION(_default, 2, 16) 68 _BUS_SPACE_READ_REGION(_default, 4, 32) 69 _BUS_SPACE_READ_REGION(_default, 8, 64) 70 _BUS_SPACE_WRITE(_default, 1, 8) 71 _BUS_SPACE_WRITE(_default, 2, 16) 72 _BUS_SPACE_WRITE(_default, 4, 32) 73 _BUS_SPACE_WRITE(_default, 8, 64) 74 _BUS_SPACE_WRITE_MULTI(_default, 1, 8) 75 _BUS_SPACE_WRITE_MULTI(_default, 2, 16) 76 _BUS_SPACE_WRITE_MULTI(_default, 4, 32) 77 _BUS_SPACE_WRITE_MULTI(_default, 8, 64) 78 _BUS_SPACE_WRITE_REGION(_default, 1, 8) 79 _BUS_SPACE_WRITE_REGION(_default, 2, 16) 80 _BUS_SPACE_WRITE_REGION(_default, 4, 32) 81 _BUS_SPACE_WRITE_REGION(_default, 8, 64) 82 _BUS_SPACE_SET_MULTI(_default, 1, 8) 83 _BUS_SPACE_SET_MULTI(_default, 2, 16) 84 _BUS_SPACE_SET_MULTI(_default, 4, 32) 85 _BUS_SPACE_SET_MULTI(_default, 8, 64) 86 _BUS_SPACE_SET_REGION(_default, 1, 8) 87 _BUS_SPACE_SET_REGION(_default, 2, 16) 88 _BUS_SPACE_SET_REGION(_default, 4, 32) 89 _BUS_SPACE_SET_REGION(_default, 8, 64) 90 _BUS_SPACE_COPY_REGION(_default, 1, 8) 91 _BUS_SPACE_COPY_REGION(_default, 2, 16) 92 _BUS_SPACE_COPY_REGION(_default, 4, 32) 93 _BUS_SPACE_COPY_REGION(_default, 8, 64) 94 #undef VADDR 95 96 static int _default_map(void *, bus_addr_t, bus_size_t, int, 97 bus_space_handle_t *); 98 static void _default_unmap(void *, bus_space_handle_t, bus_size_t); 99 static int _default_subregion(void *, bus_space_handle_t, bus_size_t, 100 bus_size_t, bus_space_handle_t *); 101 static int _default_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t, 102 bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *); 103 static void _default_free(void *, bus_space_handle_t, bus_size_t); 104 static void *_default_vaddr(void *, bus_space_handle_t); 105 106 static const struct ews4800mips_bus_space _default_bus_space = { 107 .ebs_map = _default_map, 108 .ebs_unmap = _default_unmap, 109 .ebs_subregion = _default_subregion, 110 .ebs_alloc = _default_alloc, 111 .ebs_free = _default_free, 112 .ebs_vaddr = _default_vaddr, 113 .ebs_r_1 = _default_read_1, 114 .ebs_r_2 = _default_read_2, 115 .ebs_r_4 = _default_read_4, 116 .ebs_r_8 = _default_read_8, 117 .ebs_rm_1 = _default_read_multi_1, 118 .ebs_rm_2 = _default_read_multi_2, 119 .ebs_rm_4 = _default_read_multi_4, 120 .ebs_rm_8 = _default_read_multi_8, 121 .ebs_rr_1 = _default_read_region_1, 122 .ebs_rr_2 = _default_read_region_2, 123 .ebs_rr_4 = _default_read_region_4, 124 .ebs_rr_8 = _default_read_region_8, 125 .ebs_w_1 = _default_write_1, 126 .ebs_w_2 = _default_write_2, 127 .ebs_w_4 = _default_write_4, 128 .ebs_w_8 = _default_write_8, 129 .ebs_wm_1 = _default_write_multi_1, 130 .ebs_wm_2 = _default_write_multi_2, 131 .ebs_wm_4 = _default_write_multi_4, 132 .ebs_wm_8 = _default_write_multi_8, 133 .ebs_wr_1 = _default_write_region_1, 134 .ebs_wr_2 = _default_write_region_2, 135 .ebs_wr_4 = _default_write_region_4, 136 .ebs_wr_8 = _default_write_region_8, 137 .ebs_sm_1 = _default_set_multi_1, 138 .ebs_sm_2 = _default_set_multi_2, 139 .ebs_sm_4 = _default_set_multi_4, 140 .ebs_sm_8 = _default_set_multi_8, 141 .ebs_sr_1 = _default_set_region_1, 142 .ebs_sr_2 = _default_set_region_2, 143 .ebs_sr_4 = _default_set_region_4, 144 .ebs_sr_8 = _default_set_region_8, 145 .ebs_c_1 = _default_copy_region_1, 146 .ebs_c_2 = _default_copy_region_2, 147 .ebs_c_4 = _default_copy_region_4, 148 .ebs_c_8 = _default_copy_region_8 149 }; 150 151 /* create default bus_space_tag */ 152 int 153 bus_space_create(bus_space_tag_t t, const char *name, 154 bus_addr_t addr, bus_size_t size) 155 { 156 struct ews4800mips_bus_space *ebs = t; 157 158 if (ebs == NULL) 159 return EFAULT; 160 161 /* set default method */ 162 *ebs = _default_bus_space; /* structure assignment */ 163 ebs->ebs_cookie = ebs; 164 165 /* set access region */ 166 if (size == 0) { 167 /* no extent */ 168 ebs->ebs_base_addr = addr; 169 ebs->ebs_size = size; 170 } else { 171 ebs->ebs_extent = extent_create(name, addr, addr + size - 1, 172 0, 0, EX_NOWAIT); 173 if (ebs->ebs_extent == NULL) { 174 panic("%s:: unable to create bus_space for " 175 "0x%08lx-%#lx", __func__, addr, size); 176 } 177 } 178 179 return 0; 180 } 181 182 void 183 bus_space_destroy(bus_space_tag_t t) 184 { 185 struct ews4800mips_bus_space *ebs = t; 186 struct extent *ex = ebs->ebs_extent; 187 188 if (ex != NULL) 189 extent_destroy(ex); 190 } 191 192 void 193 _bus_space_invalid_access(void) 194 { 195 196 panic("invalid bus space access."); 197 } 198 199 /* default bus_space tag */ 200 static int 201 _default_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, 202 bus_space_handle_t *bshp) 203 { 204 struct ews4800mips_bus_space *ebs = t; 205 struct extent *ex = ebs->ebs_extent; 206 int error; 207 208 if (ex == NULL) { 209 if (bpa + size > ebs->ebs_size) 210 return EFAULT; 211 *bshp = (bus_space_handle_t)(ebs->ebs_base_addr + bpa); 212 return 0; 213 } 214 215 bpa += ex->ex_start; 216 error = extent_alloc_region(ex, bpa, size, EX_NOWAIT | EX_MALLOCOK); 217 218 if (error) { 219 DPRINTF("failed.\n"); 220 return error; 221 } 222 223 *bshp = (bus_space_handle_t)bpa; 224 225 DPRINTF("success.\n"); 226 227 return 0; 228 } 229 230 static int 231 _default_subregion(void *t, bus_space_handle_t bsh, 232 bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) 233 { 234 235 *nbshp = bsh + offset; 236 237 return 0; 238 } 239 240 static int 241 _default_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, 242 bus_size_t size, bus_size_t alignment, bus_size_t boundary, 243 int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) 244 { 245 struct ews4800mips_bus_space *ebs = t; 246 struct extent *ex = ebs->ebs_extent; 247 u_long bpa, base; 248 int error; 249 250 if (ex == NULL) { 251 if (rend > ebs->ebs_size) 252 return EFAULT; 253 *bshp = *bpap = rstart + ebs->ebs_base_addr; 254 return 0; 255 } 256 257 base = ex->ex_start; 258 259 error = extent_alloc_subregion(ex, rstart + base, rend + base, size, 260 alignment, boundary, 261 EX_FAST | EX_NOWAIT | EX_MALLOCOK, 262 &bpa); 263 264 if (error) { 265 DPRINTF("failed.\n"); 266 return error; 267 } 268 269 *bshp = (bus_space_handle_t)bpa; 270 271 if (bpap) 272 *bpap = bpa; 273 274 DPRINTF("success.\n"); 275 276 return 0; 277 } 278 279 static void 280 _default_free(void *t, bus_space_handle_t bsh, bus_size_t size) 281 { 282 struct ews4800mips_bus_space *ebs = t; 283 struct extent *ex = ebs->ebs_extent; 284 285 if (ex != NULL) 286 _default_unmap(t, bsh, size); 287 } 288 289 static void 290 _default_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) 291 { 292 struct ews4800mips_bus_space *ebs = t; 293 struct extent *ex = ebs->ebs_extent; 294 int error; 295 296 if (ex == NULL) 297 return; 298 299 error = extent_free(ex, bsh, size, EX_NOWAIT); 300 301 if (error) { 302 DPRINTF("%#lx-%#lx of %s space lost\n", bsh, bsh + size, 303 ex->ex_name); 304 } 305 } 306 307 void * 308 _default_vaddr(void *t, bus_space_handle_t h) 309 { 310 311 return (void *)h; 312 } 313