1 /* $NetBSD: vme.c,v 1.23 2009/05/12 14:47:27 cegger 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.23 2009/05/12 14:47:27 cegger 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 <sys/bus.h> 40 41 #include <dev/vme/vmereg.h> 42 #include <dev/vme/vmevar.h> 43 44 static void vme_extractlocators(int*, struct vme_attach_args*); 45 static int vmeprint(struct vme_attach_args*, char*); 46 static int vmesubmatch1(struct device*, struct cfdata*, 47 const int *, void*); 48 static int vmesubmatch(struct device*, struct cfdata*, 49 const int *, void*); 50 int vmematch(device_t, cfdata_t, void *); 51 void vmeattach(struct device*, struct device*,void*); 52 static struct extent *vme_select_map(struct vmebus_softc*, vme_am_t); 53 54 #ifdef notyet 55 int vmedetach(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(int *loc, 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(struct vme_attach_args *v, char *dummy) 90 { 91 int i; 92 93 for (i = 0; i < v->numcfranges; i++) { 94 aprint_normal(" addr %x", v->r[i].offset); 95 if (v->r[i].size != -1) 96 aprint_normal("-%x", v->r[i].offset + v->r[i].size - 1); 97 if (v->r[i].am != -1) 98 aprint_normal(" am %02x", v->r[i].am); 99 } 100 if (v->ilevel != -1) { 101 aprint_normal(" irq %d", v->ilevel); 102 if (v->ivector != -1) 103 aprint_normal(" 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(device_t bus, cfdata_t dev, const int *ldesc, void *aux) 127 { 128 struct vmebus_softc *sc = (struct vmebus_softc*)bus; 129 struct vme_attach_args v; 130 131 if (strcmp(dev->cf_name, VME_SLAVE_DUMMYDRV)) 132 return (0); 133 134 vme_extractlocators(dev->cf_loc, &v); 135 136 v.va_vct = sc->sc_vct; /* for space allocation */ 137 138 (*sc->slaveconfig)(device_parent(bus), &v); 139 return (0); 140 } 141 142 static int 143 vmesubmatch(device_t bus, cfdata_t dev, const int *ldesc, void *aux) 144 { 145 struct vmebus_softc *sc = (struct vmebus_softc*)bus; 146 struct vme_attach_args v; 147 148 if (!strcmp(dev->cf_name, VME_SLAVE_DUMMYDRV)) 149 return (0); 150 151 vme_extractlocators(dev->cf_loc, &v); 152 153 v.va_vct = sc->sc_vct; 154 v.va_bdt = sc->sc_bdt; 155 156 if (config_match(bus, dev, &v)) { 157 config_attach(bus, dev, &v, (cfprint_t)vmeprint); 158 return (1); 159 } 160 return (0); 161 } 162 163 int 164 vmematch(device_t parent, cfdata_t match, void *aux) 165 { 166 return (1); 167 } 168 169 void 170 vmeattach(device_t parent, device_t self, void *aux) 171 { 172 struct vmebus_softc *sc = (struct vmebus_softc *)self; 173 174 struct vmebus_attach_args *aa = 175 (struct vmebus_attach_args*)aux; 176 177 sc->sc_vct = aa->va_vct; 178 sc->sc_bdt = aa->va_bdt; 179 180 /* the "bus" are we ourselves */ 181 sc->sc_vct->bus = sc; 182 183 sc->slaveconfig = aa->va_slaveconfig; 184 185 printf("\n"); 186 187 /* 188 * set up address space accounting - assume incomplete decoding 189 */ 190 sc->vme32ext = extent_create("vme32", 0, 0xffffffff, 191 M_DEVBUF, 0, 0, 0); 192 if (!sc->vme32ext) { 193 printf("error creating A32 map\n"); 194 return; 195 } 196 197 sc->vme24ext = extent_create("vme24", 0, 0x00ffffff, 198 M_DEVBUF, 0, 0, 0); 199 if (!sc->vme24ext) { 200 printf("error creating A24 map\n"); 201 return; 202 } 203 204 sc->vme16ext = extent_create("vme16", 0, 0x0000ffff, 205 M_DEVBUF, 0, 0, 0); 206 if (!sc->vme16ext) { 207 printf("error creating A16 map\n"); 208 return; 209 } 210 211 if (sc->slaveconfig) { 212 /* first get info about the bus master's slave side, 213 if present */ 214 config_search_ia(vmesubmatch1, self, "vme", 0); 215 } 216 config_search_ia(vmesubmatch, self, "vme", 0); 217 218 #ifdef VMEDEBUG 219 if (sc->vme32ext) 220 extent_print(sc->vme32ext); 221 if (sc->vme24ext) 222 extent_print(sc->vme24ext); 223 if (sc->vme16ext) 224 extent_print(sc->vme16ext); 225 #endif 226 } 227 228 #ifdef notyet 229 int 230 vmedetach(device_t dev) 231 { 232 struct vmebus_softc *sc = (struct vmebus_softc*)dev; 233 234 if (sc->slaveconfig) { 235 /* allow bus master to free its bus ressources */ 236 (*sc->slaveconfig)(device_parent(dev), 0); 237 } 238 239 /* extent maps should be empty now */ 240 241 if (sc->vme32ext) { 242 #ifdef VMEDEBUG 243 extent_print(sc->vme32ext); 244 #endif 245 extent_destroy(sc->vme32ext); 246 } 247 if (sc->vme24ext) { 248 #ifdef VMEDEBUG 249 extent_print(sc->vme24ext); 250 #endif 251 extent_destroy(sc->vme24ext); 252 } 253 if (sc->vme16ext) { 254 #ifdef VMEDEBUG 255 extent_print(sc->vme16ext); 256 #endif 257 extent_destroy(sc->vme16ext); 258 } 259 260 return (0); 261 } 262 #endif 263 264 static struct extent * 265 vme_select_map(struct vmebus_softc *sc, vme_am_t ams) 266 { 267 if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A32) 268 return (sc->vme32ext); 269 else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A24) 270 return (sc->vme24ext); 271 else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A16) 272 return (sc->vme16ext); 273 else 274 return (0); 275 } 276 277 int 278 _vme_space_alloc(struct vmebus_softc *sc, vme_addr_t addr, vme_size_t len, vme_am_t ams) 279 { 280 struct extent *ex; 281 282 ex = vme_select_map(sc, ams); 283 if (!ex) 284 return (EINVAL); 285 286 return (extent_alloc_region(ex, addr, len, EX_NOWAIT)); 287 } 288 289 void 290 _vme_space_free(struct vmebus_softc *sc, vme_addr_t addr, vme_size_t len, vme_am_t ams) 291 { 292 struct extent *ex; 293 294 ex = vme_select_map(sc, ams); 295 if (!ex) { 296 panic("vme_space_free: invalid am %x", ams); 297 return; 298 } 299 300 extent_free(ex, addr, len, EX_NOWAIT); 301 } 302 303 int 304 _vme_space_get(struct vmebus_softc *sc, vme_size_t len, vme_am_t ams, u_long align, vme_addr_t *addr) 305 { 306 struct extent *ex; 307 u_long help; 308 int res; 309 310 ex = vme_select_map(sc, ams); 311 if (!ex) 312 return (EINVAL); 313 314 res = extent_alloc(ex, len, align, EX_NOBOUNDARY, EX_NOWAIT, &help); 315 if (!res) 316 *addr = help; 317 return (res); 318 } 319