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