1 /* $NetBSD: bus_space.c,v 1.11 2020/11/21 17:46:09 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 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.11 2020/11/21 17:46:09 thorpej Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kmem.h> 35 #include <sys/extent.h> 36 37 #define _PLAYSTATION2_BUS_SPACE_PRIVATE 38 #include <machine/bus.h> 39 40 #ifdef BUS_SPACE_DEBUG 41 int bus_space_debug = 0; 42 #define DPRINTF(fmt, args...) \ 43 if (bus_space_debug) \ 44 printf("%s: " fmt, __func__ , ##args) 45 #define DPRINTFN(n, arg) \ 46 if (bus_space_debug > (n)) \ 47 printf("%s: " fmt, __func__ , ##args) 48 #else 49 #define DPRINTF(arg...) ((void)0) 50 #define DPRINTFN(n, arg...) ((void)0) 51 #endif 52 53 #define VADDR(h, o) (h + o) 54 _BUS_SPACE_READ(_default, 1, 8) 55 _BUS_SPACE_READ(_default, 2, 16) 56 _BUS_SPACE_READ(_default, 4, 32) 57 _BUS_SPACE_READ(_default, 8, 64) 58 _BUS_SPACE_READ_MULTI(_default, 1, 8) 59 _BUS_SPACE_READ_MULTI(_default, 2, 16) 60 _BUS_SPACE_READ_MULTI(_default, 4, 32) 61 _BUS_SPACE_READ_MULTI(_default, 8, 64) 62 _BUS_SPACE_READ_REGION(_default, 1, 8) 63 _BUS_SPACE_READ_REGION(_default, 2, 16) 64 _BUS_SPACE_READ_REGION(_default, 4, 32) 65 _BUS_SPACE_READ_REGION(_default, 8, 64) 66 _BUS_SPACE_WRITE(_default, 1, 8) 67 _BUS_SPACE_WRITE(_default, 2, 16) 68 _BUS_SPACE_WRITE(_default, 4, 32) 69 _BUS_SPACE_WRITE(_default, 8, 64) 70 _BUS_SPACE_WRITE_MULTI(_default, 1, 8) 71 _BUS_SPACE_WRITE_MULTI(_default, 2, 16) 72 _BUS_SPACE_WRITE_MULTI(_default, 4, 32) 73 _BUS_SPACE_WRITE_MULTI(_default, 8, 64) 74 _BUS_SPACE_WRITE_REGION(_default, 1, 8) 75 _BUS_SPACE_WRITE_REGION(_default, 2, 16) 76 _BUS_SPACE_WRITE_REGION(_default, 4, 32) 77 _BUS_SPACE_WRITE_REGION(_default, 8, 64) 78 _BUS_SPACE_SET_MULTI(_default, 1, 8) 79 _BUS_SPACE_SET_MULTI(_default, 2, 16) 80 _BUS_SPACE_SET_MULTI(_default, 4, 32) 81 _BUS_SPACE_SET_MULTI(_default, 8, 64) 82 _BUS_SPACE_SET_REGION(_default, 1, 8) 83 _BUS_SPACE_SET_REGION(_default, 2, 16) 84 _BUS_SPACE_SET_REGION(_default, 4, 32) 85 _BUS_SPACE_SET_REGION(_default, 8, 64) 86 _BUS_SPACE_COPY_REGION(_default, 1, 8) 87 _BUS_SPACE_COPY_REGION(_default, 2, 16) 88 _BUS_SPACE_COPY_REGION(_default, 4, 32) 89 _BUS_SPACE_COPY_REGION(_default, 8, 64) 90 #undef VADDR 91 92 static int _default_map(void *, bus_addr_t, bus_size_t, int, 93 bus_space_handle_t *); 94 static void _default_unmap(void *, bus_space_handle_t, bus_size_t); 95 static int _default_subregion(void *, bus_space_handle_t, bus_size_t, 96 bus_size_t, bus_space_handle_t *); 97 static int _default_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t, 98 bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *); 99 static void _default_free(void *, bus_space_handle_t, bus_size_t); 100 static void *_default_vaddr(void *, bus_space_handle_t); 101 102 static const struct playstation2_bus_space _default_bus_space = { 103 pbs_map : _default_map, 104 pbs_unmap : _default_unmap, 105 pbs_subregion : _default_subregion, 106 pbs_alloc : _default_alloc, 107 pbs_free : _default_free, 108 pbs_vaddr : _default_vaddr, 109 pbs_r_1 : _default_read_1, 110 pbs_r_2 : _default_read_2, 111 pbs_r_4 : _default_read_4, 112 pbs_r_8 : _default_read_8, 113 pbs_rm_1 : _default_read_multi_1, 114 pbs_rm_2 : _default_read_multi_2, 115 pbs_rm_4 : _default_read_multi_4, 116 pbs_rm_8 : _default_read_multi_8, 117 pbs_rr_1 : _default_read_region_1, 118 pbs_rr_2 : _default_read_region_2, 119 pbs_rr_4 : _default_read_region_4, 120 pbs_rr_8 : _default_read_region_8, 121 pbs_w_1 : _default_write_1, 122 pbs_w_2 : _default_write_2, 123 pbs_w_4 : _default_write_4, 124 pbs_w_8 : _default_write_8, 125 pbs_wm_1 : _default_write_multi_1, 126 pbs_wm_2 : _default_write_multi_2, 127 pbs_wm_4 : _default_write_multi_4, 128 pbs_wm_8 : _default_write_multi_8, 129 pbs_wr_1 : _default_write_region_1, 130 pbs_wr_2 : _default_write_region_2, 131 pbs_wr_4 : _default_write_region_4, 132 pbs_wr_8 : _default_write_region_8, 133 pbs_sm_1 : _default_set_multi_1, 134 pbs_sm_2 : _default_set_multi_2, 135 pbs_sm_4 : _default_set_multi_4, 136 pbs_sm_8 : _default_set_multi_8, 137 pbs_sr_1 : _default_set_region_1, 138 pbs_sr_2 : _default_set_region_2, 139 pbs_sr_4 : _default_set_region_4, 140 pbs_sr_8 : _default_set_region_8, 141 pbs_c_1 : _default_copy_region_1, 142 pbs_c_2 : _default_copy_region_2, 143 pbs_c_4 : _default_copy_region_4, 144 pbs_c_8 : _default_copy_region_8 145 }; 146 147 /* create default bus_space_tag */ 148 bus_space_tag_t 149 bus_space_create(bus_space_tag_t t, const char *name, 150 bus_addr_t addr, bus_size_t size) 151 { 152 struct playstation2_bus_space *pbs = (void *)__UNCONST(t); 153 154 if (pbs == NULL) 155 pbs = kmem_zalloc(sizeof(*pbs), KM_NOSLEEP); 156 KDASSERT(pbs); 157 158 /* set default method */ 159 *pbs = _default_bus_space; 160 pbs->pbs_cookie = pbs; 161 162 /* set access region */ 163 if (size == 0) { 164 pbs->pbs_base_addr = addr; /* no extent */ 165 } else { 166 pbs->pbs_extent = extent_create(name, addr, addr + size - 1, 167 0, 0, EX_NOWAIT); 168 if (pbs->pbs_extent == 0) { 169 panic("%s:: unable to create bus_space for " 170 "0x%08lx-%#lx", __func__, addr, size); 171 } 172 } 173 174 return (pbs); 175 } 176 177 void 178 bus_space_destroy(bus_space_tag_t t) 179 { 180 struct playstation2_bus_space *pbs = (void *)__UNCONST(t); 181 struct extent *ex = pbs->pbs_extent; 182 183 if (ex != 0) 184 extent_destroy(ex); 185 186 kmem_free(pbs, sizeof(*pbs)); 187 } 188 189 void 190 _bus_space_invalid_access(void) 191 { 192 panic("invalid bus space access."); 193 } 194 195 /* default bus_space tag */ 196 static int 197 _default_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, 198 bus_space_handle_t *bshp) 199 { 200 struct playstation2_bus_space *pbs = t; 201 struct extent *ex = pbs->pbs_extent; 202 int error; 203 204 if (ex == 0) { 205 *bshp = (bus_space_handle_t)(bpa + pbs->pbs_base_addr); 206 return (0); 207 } 208 209 bpa += ex->ex_start; 210 error = extent_alloc_region(ex, bpa, size, EX_NOWAIT | EX_MALLOCOK); 211 212 if (error) { 213 DPRINTF("failed.\n"); 214 return (error); 215 } 216 217 *bshp = (bus_space_handle_t)bpa; 218 219 DPRINTF("success.\n"); 220 221 return (0); 222 } 223 224 static int 225 _default_subregion(void *t, bus_space_handle_t bsh, 226 bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) 227 { 228 *nbshp = bsh + offset; 229 230 return (0); 231 } 232 233 static int 234 _default_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, 235 bus_size_t size, bus_size_t alignment, bus_size_t boundary, 236 int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) 237 { 238 struct playstation2_bus_space *pbs = t; 239 struct extent *ex = pbs->pbs_extent; 240 u_long bpa, base; 241 int error; 242 243 if (ex == 0) { 244 *bshp = *bpap = rstart + pbs->pbs_base_addr; 245 return (0); 246 } 247 248 base = ex->ex_start; 249 250 error = extent_alloc_subregion(ex, rstart + base, rend + base, size, 251 alignment, boundary, 252 EX_FAST | EX_NOWAIT | EX_MALLOCOK, 253 &bpa); 254 255 if (error) { 256 DPRINTF("failed.\n"); 257 return (error); 258 } 259 260 *bshp = (bus_space_handle_t)bpa; 261 262 if (bpap) 263 *bpap = bpa; 264 265 DPRINTF("success.\n"); 266 267 return (0); 268 } 269 270 static void 271 _default_free(void *t, bus_space_handle_t bsh, bus_size_t size) 272 { 273 struct playstation2_bus_space *pbs = t; 274 struct extent *ex = pbs->pbs_extent; 275 276 if (ex != 0) 277 _default_unmap(t, bsh, size); 278 } 279 280 static void 281 _default_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) 282 { 283 struct playstation2_bus_space *pbs = t; 284 struct extent *ex = pbs->pbs_extent; 285 int error; 286 287 if (ex == 0) 288 return; 289 290 error = extent_free(ex, bsh, size, EX_NOWAIT); 291 292 if (error) { 293 DPRINTF("%#lx-%#lx of %s space lost\n", bsh, bsh + size, 294 ex->ex_name); 295 } 296 } 297 298 void * 299 _default_vaddr(void *t, bus_space_handle_t h) 300 { 301 return (void *)h; 302 } 303