1/* $NetBSD: bus_space.c,v 1.4 2008/04/28 20:23:18 martin 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.4 2008/04/28 20:23:18 martin Exp $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/malloc.h> 35#include <sys/extent.h> 36 37#define _EWS4800MIPS_BUS_SPACE_PRIVATE 38#include <machine/bus.h> 39#include <machine/sbdvar.h> 40 41#ifdef BUS_SPACE_DEBUG 42int bus_space_debug = 0; 43#define DPRINTF(fmt, args...) \ 44 if (bus_space_debug) \ 45 printf("%s: " fmt, __func__ , ##args) 46#define DPRINTFN(n, arg) \ 47 if (bus_space_debug > (n)) \ 48 printf("%s: " fmt, __func__ , ##args) 49#else 50#define DPRINTF(arg...) ((void)0) 51#define DPRINTFN(n, arg...) ((void)0) 52#endif 53 54#define VADDR(h, o) (h + o) 55_BUS_SPACE_READ(_default, 1, 8) 56_BUS_SPACE_READ(_default, 2, 16) 57_BUS_SPACE_READ(_default, 4, 32) 58_BUS_SPACE_READ(_default, 8, 64) 59_BUS_SPACE_READ_MULTI(_default, 1, 8) 60_BUS_SPACE_READ_MULTI(_default, 2, 16) 61_BUS_SPACE_READ_MULTI(_default, 4, 32) 62_BUS_SPACE_READ_MULTI(_default, 8, 64) 63_BUS_SPACE_READ_REGION(_default, 1, 8) 64_BUS_SPACE_READ_REGION(_default, 2, 16) 65_BUS_SPACE_READ_REGION(_default, 4, 32) 66_BUS_SPACE_READ_REGION(_default, 8, 64) 67_BUS_SPACE_WRITE(_default, 1, 8) 68_BUS_SPACE_WRITE(_default, 2, 16) 69_BUS_SPACE_WRITE(_default, 4, 32) 70_BUS_SPACE_WRITE(_default, 8, 64) 71_BUS_SPACE_WRITE_MULTI(_default, 1, 8) 72_BUS_SPACE_WRITE_MULTI(_default, 2, 16) 73_BUS_SPACE_WRITE_MULTI(_default, 4, 32) 74_BUS_SPACE_WRITE_MULTI(_default, 8, 64) 75_BUS_SPACE_WRITE_REGION(_default, 1, 8) 76_BUS_SPACE_WRITE_REGION(_default, 2, 16) 77_BUS_SPACE_WRITE_REGION(_default, 4, 32) 78_BUS_SPACE_WRITE_REGION(_default, 8, 64) 79_BUS_SPACE_SET_MULTI(_default, 1, 8) 80_BUS_SPACE_SET_MULTI(_default, 2, 16) 81_BUS_SPACE_SET_MULTI(_default, 4, 32) 82_BUS_SPACE_SET_MULTI(_default, 8, 64) 83_BUS_SPACE_SET_REGION(_default, 1, 8) 84_BUS_SPACE_SET_REGION(_default, 2, 16) 85_BUS_SPACE_SET_REGION(_default, 4, 32) 86_BUS_SPACE_SET_REGION(_default, 8, 64) 87_BUS_SPACE_COPY_REGION(_default, 1, 8) 88_BUS_SPACE_COPY_REGION(_default, 2, 16) 89_BUS_SPACE_COPY_REGION(_default, 4, 32) 90_BUS_SPACE_COPY_REGION(_default, 8, 64) 91#undef VADDR 92 93static int _default_map(void *, bus_addr_t, bus_size_t, int, 94 bus_space_handle_t *); 95static void _default_unmap(void *, bus_space_handle_t, bus_size_t); 96static int _default_subregion(void *, bus_space_handle_t, bus_size_t, 97 bus_size_t, bus_space_handle_t *); 98static int _default_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t, 99 bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *); 100static void _default_free(void *, bus_space_handle_t, bus_size_t); 101static void *_default_vaddr(void *, bus_space_handle_t); 102 103static const struct ews4800mips_bus_space _default_bus_space = { 104 .ebs_map = _default_map, 105 .ebs_unmap = _default_unmap, 106 .ebs_subregion = _default_subregion, 107 .ebs_alloc = _default_alloc, 108 .ebs_free = _default_free, 109 .ebs_vaddr = _default_vaddr, 110 .ebs_r_1 = _default_read_1, 111 .ebs_r_2 = _default_read_2, 112 .ebs_r_4 = _default_read_4, 113 .ebs_r_8 = _default_read_8, 114 .ebs_rm_1 = _default_read_multi_1, 115 .ebs_rm_2 = _default_read_multi_2, 116 .ebs_rm_4 = _default_read_multi_4, 117 .ebs_rm_8 = _default_read_multi_8, 118 .ebs_rr_1 = _default_read_region_1, 119 .ebs_rr_2 = _default_read_region_2, 120 .ebs_rr_4 = _default_read_region_4, 121 .ebs_rr_8 = _default_read_region_8, 122 .ebs_w_1 = _default_write_1, 123 .ebs_w_2 = _default_write_2, 124 .ebs_w_4 = _default_write_4, 125 .ebs_w_8 = _default_write_8, 126 .ebs_wm_1 = _default_write_multi_1, 127 .ebs_wm_2 = _default_write_multi_2, 128 .ebs_wm_4 = _default_write_multi_4, 129 .ebs_wm_8 = _default_write_multi_8, 130 .ebs_wr_1 = _default_write_region_1, 131 .ebs_wr_2 = _default_write_region_2, 132 .ebs_wr_4 = _default_write_region_4, 133 .ebs_wr_8 = _default_write_region_8, 134 .ebs_sm_1 = _default_set_multi_1, 135 .ebs_sm_2 = _default_set_multi_2, 136 .ebs_sm_4 = _default_set_multi_4, 137 .ebs_sm_8 = _default_set_multi_8, 138 .ebs_sr_1 = _default_set_region_1, 139 .ebs_sr_2 = _default_set_region_2, 140 .ebs_sr_4 = _default_set_region_4, 141 .ebs_sr_8 = _default_set_region_8, 142 .ebs_c_1 = _default_copy_region_1, 143 .ebs_c_2 = _default_copy_region_2, 144 .ebs_c_4 = _default_copy_region_4, 145 .ebs_c_8 = _default_copy_region_8 146}; 147 148/* create default bus_space_tag */ 149int 150bus_space_create(bus_space_tag_t t, const char *name, 151 bus_addr_t addr, bus_size_t size) 152{ 153 struct ews4800mips_bus_space *ebs = t; 154 155 if (ebs == NULL) 156 return EFAULT; 157 158 /* set default method */ 159 *ebs = _default_bus_space; /* structure assignment */ 160 ebs->ebs_cookie = ebs; 161 162 /* set access region */ 163 if (size == 0) { 164 /* no extent */ 165 ebs->ebs_base_addr = addr; 166 ebs->ebs_size = size; 167 } else { 168 ebs->ebs_extent = extent_create(name, addr, addr + size - 1, 169 0, 0, EX_NOWAIT); 170 if (ebs->ebs_extent == NULL) { 171 panic("%s:: unable to create bus_space for " 172 "0x%08lx-%#lx", __func__, addr, size); 173 } 174 } 175 176 return 0; 177} 178 179void 180bus_space_destroy(bus_space_tag_t t) 181{ 182 struct ews4800mips_bus_space *ebs = t; 183 struct extent *ex = ebs->ebs_extent; 184 185 if (ex != NULL) 186 extent_destroy(ex); 187} 188 189void 190_bus_space_invalid_access(void) 191{ 192 193 panic("invalid bus space access."); 194} 195 196/* default bus_space tag */ 197static int 198_default_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, 199 bus_space_handle_t *bshp) 200{ 201 struct ews4800mips_bus_space *ebs = t; 202 struct extent *ex = ebs->ebs_extent; 203 int error; 204 205 if (ex == NULL) { 206 if (bpa + size > ebs->ebs_size) 207 return EFAULT; 208 *bshp = (bus_space_handle_t)(ebs->ebs_base_addr + bpa); 209 return 0; 210 } 211 212 bpa += ex->ex_start; 213 error = extent_alloc_region(ex, bpa, size, EX_NOWAIT | EX_MALLOCOK); 214 215 if (error) { 216 DPRINTF("failed.\n"); 217 return error; 218 } 219 220 *bshp = (bus_space_handle_t)bpa; 221 222 DPRINTF("success.\n"); 223 224 return 0; 225} 226 227static int 228_default_subregion(void *t, bus_space_handle_t bsh, 229 bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) 230{ 231 232 *nbshp = bsh + offset; 233 234 return 0; 235} 236 237static int 238_default_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, 239 bus_size_t size, bus_size_t alignment, bus_size_t boundary, 240 int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) 241{ 242 struct ews4800mips_bus_space *ebs = t; 243 struct extent *ex = ebs->ebs_extent; 244 u_long bpa, base; 245 int error; 246 247 if (ex == NULL) { 248 if (rend > ebs->ebs_size) 249 return EFAULT; 250 *bshp = *bpap = rstart + ebs->ebs_base_addr; 251 return 0; 252 } 253 254 base = ex->ex_start; 255 256 error = extent_alloc_subregion(ex, rstart + base, rend + base, size, 257 alignment, boundary, 258 EX_FAST | EX_NOWAIT | EX_MALLOCOK, 259 &bpa); 260 261 if (error) { 262 DPRINTF("failed.\n"); 263 return error; 264 } 265 266 *bshp = (bus_space_handle_t)bpa; 267 268 if (bpap) 269 *bpap = bpa; 270 271 DPRINTF("success.\n"); 272 273 return 0; 274} 275 276static void 277_default_free(void *t, bus_space_handle_t bsh, bus_size_t size) 278{ 279 struct ews4800mips_bus_space *ebs = t; 280 struct extent *ex = ebs->ebs_extent; 281 282 if (ex != NULL) 283 _default_unmap(t, bsh, size); 284} 285 286static void 287_default_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) 288{ 289 struct ews4800mips_bus_space *ebs = t; 290 struct extent *ex = ebs->ebs_extent; 291 int error; 292 293 if (ex == NULL) 294 return; 295 296 error = extent_free(ex, bsh, size, EX_NOWAIT); 297 298 if (error) { 299 DPRINTF("%#lx-%#lx of %s space lost\n", bsh, bsh + size, 300 ex->ex_name); 301 } 302} 303 304void * 305_default_vaddr(void *t, bus_space_handle_t h) 306{ 307 308 return (void *)h; 309} 310