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