1 1.31 thorpej /* $NetBSD: vme.c,v 1.31 2024/04/24 02:27:33 thorpej Exp $ */ 2 1.3 drochner 3 1.3 drochner /* 4 1.3 drochner * Copyright (c) 1999 5 1.3 drochner * Matthias Drochner. All rights reserved. 6 1.1 pk * 7 1.1 pk * Redistribution and use in source and binary forms, with or without 8 1.1 pk * modification, are permitted provided that the following conditions 9 1.1 pk * are met: 10 1.1 pk * 1. Redistributions of source code must retain the above copyright 11 1.1 pk * notice, this list of conditions and the following disclaimer. 12 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 pk * notice, this list of conditions and the following disclaimer in the 14 1.1 pk * documentation and/or other materials provided with the distribution. 15 1.3 drochner * 3. The name of the author may not be used to endorse or promote products 16 1.3 drochner * derived from this software without specific prior written permission. 17 1.3 drochner * 18 1.3 drochner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.3 drochner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.3 drochner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.3 drochner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.3 drochner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.3 drochner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.3 drochner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.3 drochner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.3 drochner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.3 drochner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 pk * 29 1.1 pk */ 30 1.4 lukem 31 1.4 lukem #include <sys/cdefs.h> 32 1.31 thorpej __KERNEL_RCSID(0, "$NetBSD: vme.c,v 1.31 2024/04/24 02:27:33 thorpej Exp $"); 33 1.1 pk 34 1.1 pk #include <sys/param.h> 35 1.1 pk #include <sys/systm.h> 36 1.1 pk #include <sys/device.h> 37 1.1 pk #include <sys/malloc.h> 38 1.30 thorpej #include <sys/vmem.h> 39 1.19 ad #include <sys/bus.h> 40 1.3 drochner 41 1.3 drochner #include <dev/vme/vmereg.h> 42 1.3 drochner #include <dev/vme/vmevar.h> 43 1.1 pk 44 1.26 chs static void vme_extractlocators(int*, struct vme_attach_args *); 45 1.26 chs static int vmeprint(struct vme_attach_args *, char *); 46 1.26 chs static int vmesubmatch1(device_t, cfdata_t, const int *, void *); 47 1.26 chs static int vmesubmatch(device_t, cfdata_t, const int *, void *); 48 1.23 cegger int vmematch(device_t, cfdata_t, void *); 49 1.26 chs void vmeattach(device_t, device_t, void *); 50 1.30 thorpej static vmem_t *vme_select_map(struct vmebus_softc*, vme_am_t); 51 1.3 drochner 52 1.3 drochner #define VME_SLAVE_DUMMYDRV "vme_slv" 53 1.3 drochner 54 1.3 drochner #define VME_NUMCFRANGES 3 /* cf. "files.vme" */ 55 1.3 drochner 56 1.26 chs CFATTACH_DECL_NEW(vme, sizeof(struct vmebus_softc), 57 1.9 thorpej vmematch, vmeattach, NULL, NULL); 58 1.3 drochner 59 1.7 thorpej const struct cfattach vme_slv_ca = { 60 1.3 drochner 0 /* never used */ 61 1.3 drochner }; 62 1.3 drochner 63 1.3 drochner static void 64 1.20 dsl vme_extractlocators(int *loc, struct vme_attach_args *aa) 65 1.3 drochner { 66 1.3 drochner int i = 0; 67 1.1 pk 68 1.3 drochner /* XXX can't use constants in locators.h this way */ 69 1.1 pk 70 1.3 drochner while (i < VME_NUMCFRANGES && i < VME_MAXCFRANGES && 71 1.3 drochner loc[i] != -1) { 72 1.3 drochner aa->r[i].offset = (vme_addr_t)loc[i]; 73 1.3 drochner aa->r[i].size = (vme_size_t)loc[3 + i]; 74 1.3 drochner aa->r[i].am = (vme_am_t)loc[6 + i]; 75 1.3 drochner i++; 76 1.3 drochner } 77 1.3 drochner aa->numcfranges = i; 78 1.3 drochner aa->ilevel = loc[9]; 79 1.3 drochner aa->ivector = loc[10]; 80 1.3 drochner } 81 1.1 pk 82 1.3 drochner static int 83 1.20 dsl vmeprint(struct vme_attach_args *v, char *dummy) 84 1.3 drochner { 85 1.3 drochner int i; 86 1.1 pk 87 1.3 drochner for (i = 0; i < v->numcfranges; i++) { 88 1.10 thorpej aprint_normal(" addr %x", v->r[i].offset); 89 1.3 drochner if (v->r[i].size != -1) 90 1.10 thorpej aprint_normal("-%x", v->r[i].offset + v->r[i].size - 1); 91 1.3 drochner if (v->r[i].am != -1) 92 1.10 thorpej aprint_normal(" am %02x", v->r[i].am); 93 1.3 drochner } 94 1.3 drochner if (v->ilevel != -1) { 95 1.10 thorpej aprint_normal(" irq %d", v->ilevel); 96 1.3 drochner if (v->ivector != -1) 97 1.10 thorpej aprint_normal(" vector %x", v->ivector); 98 1.3 drochner } 99 1.1 pk return (UNCONF); 100 1.1 pk } 101 1.1 pk 102 1.3 drochner /* 103 1.3 drochner * This looks for a (dummy) vme device "VME_SLAVE_DUMMYDRV". 104 1.3 drochner * A callback provided by the bus's parent is called for every such 105 1.3 drochner * entry in the config database. 106 1.3 drochner * This is a special hack allowing to communicate the address settings 107 1.3 drochner * of the VME master's slave side to its driver via the normal 108 1.3 drochner * configuration mechanism. 109 1.3 drochner * Needed in following cases: 110 1.3 drochner * -DMA windows are hardware settable but not readable by software 111 1.3 drochner * (driver gets offsets for DMA address calculations this way) 112 1.3 drochner * -DMA windows are software settable, but not persistent 113 1.3 drochner * (hardware is set up from config file entry) 114 1.3 drochner * -other adapter VME slave ranges which should be kept track of 115 1.3 drochner * for address space accounting 116 1.3 drochner * In any case, the adapter driver must get the data before VME 117 1.3 drochner * devices are attached. 118 1.3 drochner */ 119 1.3 drochner static int 120 1.23 cegger vmesubmatch1(device_t bus, cfdata_t dev, const int *ldesc, void *aux) 121 1.3 drochner { 122 1.24 matt struct vmebus_softc *sc = device_private(bus); 123 1.3 drochner struct vme_attach_args v; 124 1.3 drochner 125 1.5 thorpej if (strcmp(dev->cf_name, VME_SLAVE_DUMMYDRV)) 126 1.3 drochner return (0); 127 1.3 drochner 128 1.3 drochner vme_extractlocators(dev->cf_loc, &v); 129 1.3 drochner 130 1.3 drochner v.va_vct = sc->sc_vct; /* for space allocation */ 131 1.3 drochner 132 1.18 thorpej (*sc->slaveconfig)(device_parent(bus), &v); 133 1.3 drochner return (0); 134 1.3 drochner } 135 1.3 drochner 136 1.3 drochner static int 137 1.23 cegger vmesubmatch(device_t bus, cfdata_t dev, const int *ldesc, void *aux) 138 1.3 drochner { 139 1.24 matt struct vmebus_softc *sc = device_private(bus); 140 1.3 drochner struct vme_attach_args v; 141 1.3 drochner 142 1.5 thorpej if (!strcmp(dev->cf_name, VME_SLAVE_DUMMYDRV)) 143 1.3 drochner return (0); 144 1.3 drochner 145 1.3 drochner vme_extractlocators(dev->cf_loc, &v); 146 1.3 drochner 147 1.3 drochner v.va_vct = sc->sc_vct; 148 1.3 drochner v.va_bdt = sc->sc_bdt; 149 1.3 drochner 150 1.28 thorpej if (config_probe(bus, dev, &v)) { 151 1.29 thorpej config_attach(bus, dev, &v, (cfprint_t)vmeprint, CFARGS_NONE); 152 1.3 drochner return (1); 153 1.3 drochner } 154 1.3 drochner return (0); 155 1.3 drochner } 156 1.1 pk 157 1.1 pk int 158 1.23 cegger vmematch(device_t parent, cfdata_t match, void *aux) 159 1.1 pk { 160 1.3 drochner return (1); 161 1.3 drochner } 162 1.3 drochner 163 1.3 drochner void 164 1.23 cegger vmeattach(device_t parent, device_t self, void *aux) 165 1.3 drochner { 166 1.26 chs struct vmebus_softc *sc = device_private(self); 167 1.3 drochner 168 1.26 chs struct vmebus_attach_args *aa = aux; 169 1.3 drochner 170 1.3 drochner sc->sc_vct = aa->va_vct; 171 1.3 drochner sc->sc_bdt = aa->va_bdt; 172 1.3 drochner 173 1.3 drochner /* the "bus" are we ourselves */ 174 1.3 drochner sc->sc_vct->bus = sc; 175 1.3 drochner 176 1.3 drochner sc->slaveconfig = aa->va_slaveconfig; 177 1.3 drochner 178 1.3 drochner printf("\n"); 179 1.3 drochner 180 1.3 drochner /* 181 1.3 drochner * set up address space accounting - assume incomplete decoding 182 1.3 drochner */ 183 1.30 thorpej sc->vme32_arena = vmem_create("vme32", 184 1.30 thorpej 0, /* base */ 185 1.30 thorpej /* XXX loses last byte */ 0xffffffff, /* size */ 186 1.30 thorpej 1, /* quantum */ 187 1.30 thorpej NULL, /* allocfn */ 188 1.30 thorpej NULL, /* releasefn */ 189 1.30 thorpej NULL, /* source */ 190 1.30 thorpej 0, /* qcache_max */ 191 1.30 thorpej VM_SLEEP, 192 1.30 thorpej IPL_NONE); 193 1.30 thorpej if (!sc->vme32_arena) { 194 1.30 thorpej device_printf(self, "error creating A32 map\n"); 195 1.3 drochner return; 196 1.3 drochner } 197 1.3 drochner 198 1.30 thorpej sc->vme24_arena = vmem_create("vme24", 199 1.30 thorpej 0, /* base */ 200 1.30 thorpej 0x01000000, /* size */ 201 1.30 thorpej 1, /* quantum */ 202 1.30 thorpej NULL, /* allocfn */ 203 1.30 thorpej NULL, /* releasefn */ 204 1.30 thorpej NULL, /* source */ 205 1.30 thorpej 0, /* qcache_max */ 206 1.30 thorpej VM_SLEEP, 207 1.30 thorpej IPL_NONE); 208 1.30 thorpej if (!sc->vme24_arena) { 209 1.30 thorpej device_printf(self, "error creating A24 map\n"); 210 1.3 drochner return; 211 1.3 drochner } 212 1.3 drochner 213 1.30 thorpej sc->vme16_arena = vmem_create("vme16", 214 1.30 thorpej 0, /* base */ 215 1.30 thorpej 0x00010000, /* size */ 216 1.30 thorpej 1, /* quantum */ 217 1.30 thorpej NULL, /* allocfn */ 218 1.30 thorpej NULL, /* releasefn */ 219 1.30 thorpej NULL, /* source */ 220 1.30 thorpej 0, /* qcache_max */ 221 1.30 thorpej VM_SLEEP, 222 1.30 thorpej IPL_NONE); 223 1.30 thorpej if (!sc->vme16_arena) { 224 1.30 thorpej device_printf(self, "error creating A16 map\n"); 225 1.3 drochner return; 226 1.3 drochner } 227 1.3 drochner 228 1.3 drochner if (sc->slaveconfig) { 229 1.3 drochner /* first get info about the bus master's slave side, 230 1.3 drochner if present */ 231 1.28 thorpej config_search(self, NULL, 232 1.29 thorpej CFARGS(.search = vmesubmatch1)); 233 1.28 thorpej } 234 1.28 thorpej config_search(self, NULL, 235 1.29 thorpej CFARGS(.search = vmesubmatch)); 236 1.3 drochner 237 1.30 thorpej #if 0 /* XXX VMEDEBUG */ 238 1.30 thorpej if (sc->vme32_arena) 239 1.30 thorpej vmem_print(sc->vme32_arena); 240 1.30 thorpej if (sc->vme24_arena) 241 1.30 thorpej vmem_print(sc->vme24_arena); 242 1.30 thorpej if (sc->vme16_arena) 243 1.30 thorpej vmem_print(sc->vme16_arena); 244 1.3 drochner #endif 245 1.3 drochner } 246 1.3 drochner 247 1.3 drochner #ifdef notyet 248 1.3 drochner int 249 1.23 cegger vmedetach(device_t dev) 250 1.3 drochner { 251 1.26 chs struct vmebus_softc *sc = device_private(dev); 252 1.1 pk 253 1.3 drochner if (sc->slaveconfig) { 254 1.27 msaitoh /* allow bus master to free its bus resources */ 255 1.18 thorpej (*sc->slaveconfig)(device_parent(dev), 0); 256 1.3 drochner } 257 1.3 drochner 258 1.3 drochner /* extent maps should be empty now */ 259 1.3 drochner 260 1.30 thorpej if (sc->vme32_arena) { 261 1.3 drochner #ifdef VMEDEBUG 262 1.30 thorpej vmem_print(sc->vme32_arena); 263 1.3 drochner #endif 264 1.30 thorpej vmem_destroy(sc->vme32_arena); 265 1.3 drochner } 266 1.30 thorpej if (sc->vme24_arena) { 267 1.3 drochner #ifdef VMEDEBUG 268 1.30 thorpej vmem_print(sc->vme24_arena); 269 1.3 drochner #endif 270 1.30 thorpej vmem_destroy(sc->vme24_arena); 271 1.3 drochner } 272 1.30 thorpej if (sc->vme16_arena) { 273 1.3 drochner #ifdef VMEDEBUG 274 1.30 thorpej vmem_print(sc->vme16_arena); 275 1.3 drochner #endif 276 1.30 thorpej vmem_destroy(sc->vme16_arena); 277 1.3 drochner } 278 1.1 pk 279 1.3 drochner return (0); 280 1.3 drochner } 281 1.3 drochner #endif 282 1.1 pk 283 1.30 thorpej static vmem_t * 284 1.20 dsl vme_select_map(struct vmebus_softc *sc, vme_am_t ams) 285 1.3 drochner { 286 1.3 drochner if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A32) 287 1.30 thorpej return (sc->vme32_arena); 288 1.3 drochner else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A24) 289 1.30 thorpej return (sc->vme24_arena); 290 1.3 drochner else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A16) 291 1.30 thorpej return (sc->vme16_arena); 292 1.3 drochner else 293 1.1 pk return (0); 294 1.3 drochner } 295 1.1 pk 296 1.3 drochner int 297 1.21 dsl _vme_space_alloc(struct vmebus_softc *sc, vme_addr_t addr, vme_size_t len, vme_am_t ams) 298 1.3 drochner { 299 1.30 thorpej vmem_t *vm; 300 1.3 drochner 301 1.30 thorpej vm = vme_select_map(sc, ams); 302 1.30 thorpej if (!vm) 303 1.3 drochner return (EINVAL); 304 1.3 drochner 305 1.30 thorpej return vmem_xalloc_addr(vm, addr, len, VM_NOSLEEP); 306 1.3 drochner } 307 1.3 drochner 308 1.3 drochner void 309 1.21 dsl _vme_space_free(struct vmebus_softc *sc, vme_addr_t addr, vme_size_t len, vme_am_t ams) 310 1.3 drochner { 311 1.30 thorpej vmem_t *vm; 312 1.3 drochner 313 1.30 thorpej vm = vme_select_map(sc, ams); 314 1.30 thorpej if (!vm) { 315 1.3 drochner panic("vme_space_free: invalid am %x", ams); 316 1.3 drochner return; 317 1.3 drochner } 318 1.3 drochner 319 1.30 thorpej vmem_xfree(vm, addr, len); 320 1.3 drochner } 321 1.3 drochner 322 1.3 drochner int 323 1.21 dsl _vme_space_get(struct vmebus_softc *sc, vme_size_t len, vme_am_t ams, u_long align, vme_addr_t *addr) 324 1.3 drochner { 325 1.30 thorpej vmem_t *vm; 326 1.30 thorpej vmem_addr_t help; 327 1.12 drochner int res; 328 1.3 drochner 329 1.30 thorpej vm = vme_select_map(sc, ams); 330 1.30 thorpej if (!vm) 331 1.3 drochner return (EINVAL); 332 1.3 drochner 333 1.30 thorpej res = vmem_xalloc(vm, len, 334 1.30 thorpej align, /* align */ 335 1.30 thorpej 0, /* phase */ 336 1.30 thorpej 0, /* nocross */ 337 1.30 thorpej VMEM_ADDR_MIN, /* minaddr */ 338 1.30 thorpej VMEM_ADDR_MAX, /* maxaddr */ 339 1.31 thorpej VM_BESTFIT | VM_NOSLEEP, 340 1.30 thorpej &help); 341 1.12 drochner if (!res) 342 1.12 drochner *addr = help; 343 1.12 drochner return (res); 344 1.1 pk } 345