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