1 /* $NetBSD: bus_space.c,v 1.20 2020/11/21 21:07:38 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002 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.20 2020/11/21 21:07:38 thorpej Exp $"); 31 32 #include "debug_hpcsh.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kmem.h> 37 #include <sys/extent.h> 38 #include <sys/bus.h> 39 40 /* bus.h turn on BUS_SPACE_DEBUG if the global DEBUG option is enabled. */ 41 #ifdef BUS_SPACE_DEBUG 42 #define DPRINTF_ENABLE 43 #define DPRINTF_DEBUG bus_space_debug 44 #endif 45 #include <machine/debug.h> 46 47 #include <hpcsh/bus_util.h> 48 49 #define _BUS_SPACE_ACCESS_HOOK() ((void)0) 50 _BUS_SPACE_READ(_bus_space, 1, 8) 51 _BUS_SPACE_READ(_bus_space, 2, 16) 52 _BUS_SPACE_READ(_bus_space, 4, 32) 53 _BUS_SPACE_READ(_bus_space, 8, 64) 54 _BUS_SPACE_READ_MULTI(_bus_space, 1, 8) 55 _BUS_SPACE_READ_MULTI(_bus_space, 2, 16) 56 _BUS_SPACE_READ_MULTI(_bus_space, 4, 32) 57 _BUS_SPACE_READ_MULTI(_bus_space, 8, 64) 58 _BUS_SPACE_READ_REGION(_bus_space, 1, 8) 59 _BUS_SPACE_READ_REGION(_bus_space, 2, 16) 60 _BUS_SPACE_READ_REGION(_bus_space, 4, 32) 61 _BUS_SPACE_READ_REGION(_bus_space, 8, 64) 62 _BUS_SPACE_WRITE(_bus_space, 1, 8) 63 _BUS_SPACE_WRITE(_bus_space, 2, 16) 64 _BUS_SPACE_WRITE(_bus_space, 4, 32) 65 _BUS_SPACE_WRITE(_bus_space, 8, 64) 66 _BUS_SPACE_WRITE_MULTI(_bus_space, 1, 8) 67 _BUS_SPACE_WRITE_MULTI(_bus_space, 2, 16) 68 _BUS_SPACE_WRITE_MULTI(_bus_space, 4, 32) 69 _BUS_SPACE_WRITE_MULTI(_bus_space, 8, 64) 70 _BUS_SPACE_WRITE_REGION(_bus_space, 1, 8) 71 _BUS_SPACE_WRITE_REGION(_bus_space, 2, 16) 72 _BUS_SPACE_WRITE_REGION(_bus_space, 4, 32) 73 _BUS_SPACE_WRITE_REGION(_bus_space, 8, 64) 74 _BUS_SPACE_SET_MULTI(_bus_space, 1, 8) 75 _BUS_SPACE_SET_MULTI(_bus_space, 2, 16) 76 _BUS_SPACE_SET_MULTI(_bus_space, 4, 32) 77 _BUS_SPACE_SET_MULTI(_bus_space, 8, 64) 78 _BUS_SPACE_COPY_REGION(_bus_space, 1, 8) 79 _BUS_SPACE_COPY_REGION(_bus_space, 2, 16) 80 _BUS_SPACE_COPY_REGION(_bus_space, 4, 32) 81 _BUS_SPACE_COPY_REGION(_bus_space, 8, 64) 82 #undef _BUS_SPACE_ACCESS_HOOK 83 84 static int _bus_space_map(void *, bus_addr_t, bus_size_t, int, 85 bus_space_handle_t *); 86 static void _bus_space_unmap(void *, bus_space_handle_t, bus_size_t); 87 static int _bus_space_subregion(void *, bus_space_handle_t, bus_size_t, 88 bus_size_t, bus_space_handle_t *); 89 static int _bus_space_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t, 90 bus_size_t, bus_size_t, int, 91 bus_addr_t *, bus_space_handle_t *); 92 static void _bus_space_free(void *, bus_space_handle_t, bus_size_t); 93 static void *_bus_space_vaddr(void *, bus_space_handle_t); 94 95 static struct hpcsh_bus_space __default_bus_space = { 96 .hbs_extent = NULL, 97 .hbs_map = _bus_space_map, 98 .hbs_unmap = _bus_space_unmap, 99 .hbs_subregion = _bus_space_subregion, 100 .hbs_alloc = _bus_space_alloc, 101 .hbs_free = _bus_space_free, 102 .hbs_vaddr = _bus_space_vaddr, 103 .hbs_r_1 = _bus_space_read_1, 104 .hbs_r_2 = _bus_space_read_2, 105 .hbs_r_4 = _bus_space_read_4, 106 .hbs_r_8 = _bus_space_read_8, 107 .hbs_rm_1 = _bus_space_read_multi_1, 108 .hbs_rm_2 = _bus_space_read_multi_2, 109 .hbs_rm_4 = _bus_space_read_multi_4, 110 .hbs_rm_8 = _bus_space_read_multi_8, 111 .hbs_rr_1 = _bus_space_read_region_1, 112 .hbs_rr_2 = _bus_space_read_region_2, 113 .hbs_rr_4 = _bus_space_read_region_4, 114 .hbs_rr_8 = _bus_space_read_region_8, 115 .hbs_w_1 = _bus_space_write_1, 116 .hbs_w_2 = _bus_space_write_2, 117 .hbs_w_4 = _bus_space_write_4, 118 .hbs_w_8 = _bus_space_write_8, 119 .hbs_wm_1 = _bus_space_write_multi_1, 120 .hbs_wm_2 = _bus_space_write_multi_2, 121 .hbs_wm_4 = _bus_space_write_multi_4, 122 .hbs_wm_8 = _bus_space_write_multi_8, 123 .hbs_wr_1 = _bus_space_write_region_1, 124 .hbs_wr_2 = _bus_space_write_region_2, 125 .hbs_wr_4 = _bus_space_write_region_4, 126 .hbs_wr_8 = _bus_space_write_region_8, 127 .hbs_sm_1 = _bus_space_set_multi_1, 128 .hbs_sm_2 = _bus_space_set_multi_2, 129 .hbs_sm_4 = _bus_space_set_multi_4, 130 .hbs_sm_8 = _bus_space_set_multi_8, 131 .hbs_c_1 = _bus_space_copy_region_1, 132 .hbs_c_2 = _bus_space_copy_region_2, 133 .hbs_c_4 = _bus_space_copy_region_4, 134 .hbs_c_8 = _bus_space_copy_region_8 135 }; 136 137 /* create default bus_space_tag */ 138 bus_space_tag_t 139 bus_space_create(struct hpcsh_bus_space *hbs, const char *name, 140 bus_addr_t addr, bus_size_t size) 141 { 142 143 if (hbs == NULL) { 144 hbs = kmem_zalloc(sizeof(*hbs), KM_SLEEP); 145 hbs->hbs_flags = HBS_FLAGS_ALLOCATED; 146 } else 147 memset(hbs, 0, sizeof(*hbs)); 148 KASSERT(hbs); 149 150 /* set default method */ 151 *hbs = __default_bus_space; 152 hbs->hbs_cookie = hbs; 153 154 /* set access region */ 155 if (size == 0) { 156 hbs->hbs_base_addr = addr; /* no extent */ 157 } else { 158 hbs->hbs_extent = extent_create(name, addr, addr + size - 1, 159 0, 0, EX_NOWAIT); 160 if (hbs->hbs_extent == NULL) { 161 panic("%s:: unable to create bus_space for " 162 "0x%08lx-%#lx", __func__, addr, size); 163 } 164 } 165 166 return hbs; 167 } 168 169 void 170 bus_space_destroy(bus_space_tag_t t) 171 { 172 struct hpcsh_bus_space *hbs = t; 173 struct extent *ex = hbs->hbs_extent; 174 175 if (ex != NULL) 176 extent_destroy(ex); 177 178 if (hbs->hbs_flags & HBS_FLAGS_ALLOCATED) 179 kmem_free(hbs, sizeof(*hbs)); 180 } 181 182 /* default bus_space tag */ 183 static int 184 _bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, 185 bus_space_handle_t *bshp) 186 { 187 struct hpcsh_bus_space *hbs = t; 188 struct extent *ex = hbs->hbs_extent; 189 int error; 190 191 if (ex == NULL) { 192 *bshp = (bus_space_handle_t)(bpa + hbs->hbs_base_addr); 193 return (0); 194 } 195 196 bpa += ex->ex_start; 197 error = extent_alloc_region(ex, bpa, size, EX_NOWAIT | EX_MALLOCOK); 198 199 if (error) { 200 DPRINTF("failed.\n"); 201 return (error); 202 } 203 204 *bshp = (bus_space_handle_t)bpa; 205 206 return (0); 207 } 208 209 static int 210 _bus_space_subregion(void *t, bus_space_handle_t bsh, 211 bus_size_t offset, bus_size_t size, 212 bus_space_handle_t *nbshp) 213 { 214 *nbshp = bsh + offset; 215 216 return (0); 217 } 218 219 static int 220 _bus_space_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, 221 bus_size_t size, bus_size_t alignment, bus_size_t boundary, 222 int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) 223 { 224 struct hpcsh_bus_space *hbs = t; 225 struct extent *ex = hbs->hbs_extent; 226 u_long bpa, base; 227 int error; 228 229 if (ex == NULL) { 230 *bshp = *bpap = rstart + hbs->hbs_base_addr; 231 return (0); 232 } 233 234 base = ex->ex_start; 235 236 error = extent_alloc_subregion(ex, rstart + base, rend + base, size, 237 alignment, boundary, 238 EX_FAST | EX_NOWAIT | EX_MALLOCOK, 239 &bpa); 240 241 if (error) { 242 DPRINTF("failed. base=0x%08x rstart=0x%08x, rend=0x%08x" 243 " size=0x%08x\n", (uint32_t)base, (uint32_t)rstart, 244 (uint32_t)rend, (uint32_t)size); 245 return (error); 246 } 247 248 *bshp = (bus_space_handle_t)bpa; 249 250 if (bpap != NULL) 251 *bpap = bpa; 252 253 return (0); 254 } 255 256 static void 257 _bus_space_free(void *t, bus_space_handle_t bsh, bus_size_t size) 258 { 259 struct hpcsh_bus_space *hbs = t; 260 struct extent *ex = hbs->hbs_extent; 261 262 if (ex != NULL) 263 _bus_space_unmap(t, bsh, size); 264 } 265 266 static void 267 _bus_space_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) 268 { 269 struct hpcsh_bus_space *hbs = t; 270 struct extent *ex = hbs->hbs_extent; 271 int error; 272 273 if (ex == NULL) 274 return; 275 276 error = extent_free(ex, bsh, size, EX_NOWAIT); 277 278 if (error) { 279 DPRINTF("%#lx-%#lx of %s space lost\n", bsh, bsh + size, 280 ex->ex_name); 281 } 282 } 283 284 void * 285 _bus_space_vaddr(void *t, bus_space_handle_t h) 286 { 287 return (void *)h; 288 } 289