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