1 /* $NetBSD: vme_sun68k.c,v 1.11 2005/12/11 12:19:29 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg and Matthew Fredette. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: vme_sun68k.c,v 1.11 2005/12/11 12:19:29 christos Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/extent.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/malloc.h> 47 #include <sys/errno.h> 48 49 #include <sys/proc.h> 50 #include <sys/user.h> 51 #include <sys/syslog.h> 52 53 #include <uvm/uvm_extern.h> 54 55 #define _SUN68K_BUS_DMA_PRIVATE 56 #include <machine/bus.h> 57 #include <machine/autoconf.h> 58 #include <machine/pmap.h> 59 #include <machine/dvma.h> 60 61 #include <dev/vme/vmereg.h> 62 #include <dev/vme/vmevar.h> 63 64 #include <sun68k/sun68k/vme_sun68k.h> 65 66 struct sun68kvme_softc { 67 struct device sc_dev; /* base device */ 68 bus_space_tag_t sc_bustag; 69 bus_dma_tag_t sc_dmatag; 70 }; 71 struct sun68kvme_softc *sun68kvme_sc;/*XXX*/ 72 73 /* autoconfiguration driver */ 74 static int sun68kvme_match(struct device *, struct cfdata *, void *); 75 static void sun68kvme_attach(struct device *, struct device *, void *); 76 77 static int sun68k_vme_probe(void *, vme_addr_t, vme_size_t, vme_am_t, 78 vme_datasize_t, 79 int (*)(void *, bus_space_tag_t, bus_space_handle_t), void *); 80 static int sun68k_vme_map(void *, vme_addr_t, vme_size_t, vme_am_t, 81 vme_datasize_t, vme_swap_t, bus_space_tag_t *, bus_space_handle_t *, 82 vme_mapresc_t *); 83 static void sun68k_vme_unmap(void *, vme_mapresc_t); 84 static int sun68k_vme_intr_map(void *, int, int, vme_intr_handle_t *); 85 static const struct evcnt *sun68k_vme_intr_evcnt(void *, vme_intr_handle_t); 86 static void * sun68k_vme_intr_establish(void *, vme_intr_handle_t, int, 87 int (*)(void *), void *); 88 static void sun68k_vme_intr_disestablish(void *, void *); 89 90 /* 91 * DMA functions. 92 */ 93 static void sun68k_vct_dmamap_destroy(void *, bus_dmamap_t); 94 95 static int sun68k_vct_dmamap_create(void *, vme_size_t, vme_am_t, 96 vme_datasize_t, vme_swap_t, int, vme_size_t, vme_addr_t, 97 int, bus_dmamap_t *); 98 static int sun68k_vme_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, 99 bus_size_t, struct proc *, int); 100 static int sun68k_vme_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, 101 bus_dma_segment_t *, int, bus_size_t, int); 102 103 paddr_t sun68k_vme_mmap_cookie(vme_addr_t, vme_am_t, bus_space_handle_t *); 104 105 CFATTACH_DECL(sun68kvme, sizeof(struct sun68kvme_softc), 106 sun68kvme_match, sun68kvme_attach, NULL, NULL); 107 108 static int sun68kvme_attached; 109 110 /* 111 * The VME bus logic on sun68k machines maps DMA requests in the first MB 112 * of VME space to the last MB of DVMA space. The base bus_dma code 113 * in machdep.c manages DVMA space; all we must do is adjust the DMA 114 * addresses returned by bus_dmamap_load*() by ANDing them with 115 * DVMA_VME_SLAVE_MASK. 116 */ 117 118 struct vme_chipset_tag sun68k_vme_chipset_tag = { 119 NULL, 120 sun68k_vme_map, 121 sun68k_vme_unmap, 122 sun68k_vme_probe, 123 sun68k_vme_intr_map, 124 sun68k_vme_intr_evcnt, 125 sun68k_vme_intr_establish, 126 sun68k_vme_intr_disestablish, 127 sun68k_vct_dmamap_create, 128 sun68k_vct_dmamap_destroy 129 }; 130 131 struct sun68k_bus_dma_tag sun68k_vme_dma_tag; 132 133 /* Does this machine have a VME bus? */ 134 extern int cpu_has_vme; 135 136 /* 137 * Probe the VME bus. 138 */ 139 int 140 sun68kvme_match(struct device *parent, struct cfdata *cf, void *aux) 141 { 142 struct mainbus_attach_args *ma = aux; 143 144 if (sun68kvme_attached) 145 return 0; 146 147 return (cpu_has_vme && 148 (ma->ma_name == NULL || strcmp(cf->cf_name, ma->ma_name) == 0)); 149 } 150 151 /* 152 * Attach the VME bus. 153 */ 154 void 155 sun68kvme_attach(struct device *parent, struct device *self, void *aux) 156 { 157 struct mainbus_attach_args *ma = aux; 158 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)self; 159 struct vmebus_attach_args vba; 160 161 sun68kvme_attached = 1; 162 163 sun68kvme_sc = sc; 164 165 sc->sc_bustag = ma->ma_bustag; 166 sc->sc_dmatag = ma->ma_dmatag; 167 168 sun68k_vme_chipset_tag.cookie = self; 169 sun68k_vme_dma_tag = *ma->ma_dmatag; 170 sun68k_vme_dma_tag._cookie = self; 171 sun68k_vme_dma_tag._dmamap_load = sun68k_vme_dmamap_load; 172 sun68k_vme_dma_tag._dmamap_load_raw = sun68k_vme_dmamap_load_raw; 173 174 vba.va_vct = &sun68k_vme_chipset_tag; 175 vba.va_bdt = &sun68k_vme_dma_tag; 176 vba.va_slaveconfig = 0; 177 178 printf("\n"); 179 (void)config_found(self, &vba, 0); 180 } 181 182 /* 183 * Probes for a device on the VME bus. 184 * Returns zero on success. 185 */ 186 int 187 sun68k_vme_probe(void *cookie, vme_addr_t addr, vme_size_t len, vme_am_t mod, 188 vme_datasize_t datasize, 189 int (*callback)(void *, bus_space_tag_t, bus_space_handle_t), void *arg) 190 { 191 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 192 bus_type_t iospace; 193 bus_addr_t paddr; 194 bus_space_handle_t handle; 195 bus_size_t size; 196 bus_size_t off, max_off; 197 int error; 198 199 /* Map in the space. */ 200 error = vmebus_translate(mod, addr, &iospace, &paddr); 201 if (error == 0) 202 error = bus_space_map2(sc->sc_bustag, iospace, paddr, len, 203 0, 0, &handle); 204 if (error) 205 return (error); 206 207 /* Probe the space. */ 208 size = (datasize == VME_D8 ? 1 : (datasize == VME_D16 ? 2 : 4)); 209 max_off = (callback ? size : len); 210 for (off = 0; off < max_off; off += size) { 211 error = _bus_space_peek(sc->sc_bustag, handle, off, size, NULL); 212 if (error) 213 break; 214 } 215 if (error == 0 && callback) 216 error = (*callback)(arg, sc->sc_bustag, handle); 217 218 /* Unmap the space. */ 219 bus_space_unmap(sc->sc_bustag, handle, len); 220 221 return (error); 222 } 223 224 /* 225 * Maps in a device on the VME bus. 226 */ 227 int 228 sun68k_vme_map(void *cookie, vme_addr_t addr, vme_size_t size, vme_am_t mod, 229 vme_datasize_t datasize, vme_swap_t swap, bus_space_tag_t *tp, 230 bus_space_handle_t *hp, vme_mapresc_t *rp) 231 { 232 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 233 bus_type_t iospace; 234 bus_addr_t paddr; 235 int error; 236 237 error = vmebus_translate(mod, addr, &iospace, &paddr); 238 if (error != 0) 239 return (error); 240 241 *tp = sc->sc_bustag; 242 return (bus_space_map2(sc->sc_bustag, iospace, paddr, size, 0, 0, hp)); 243 } 244 245 /* 246 * Assists in mmap'ing a device on the VME bus. 247 */ 248 paddr_t 249 sun68k_vme_mmap_cookie(vme_addr_t addr, vme_am_t mod, bus_space_handle_t *hp) 250 { 251 struct sun68kvme_softc *sc = sun68kvme_sc; 252 bus_type_t iospace; 253 bus_addr_t paddr; 254 int error; 255 256 error = vmebus_translate(mod, addr, &iospace, &paddr); 257 if (error != 0) 258 return (error); 259 260 return (bus_space_mmap2(sc->sc_bustag, iospace, paddr, 0, 0, 0)); 261 } 262 263 struct sun68k_vme_intr_handle { 264 int vec; /* VME interrupt vector */ 265 int pri; /* VME interrupt priority */ 266 }; 267 268 /* 269 * This maps a VME interrupt level and vector pair into 270 * a data structure that can subsequently be used to 271 * establish an interrupt handler. 272 */ 273 int 274 sun68k_vme_intr_map(void *cookie, int level, int vec, vme_intr_handle_t *ihp) 275 { 276 struct sun68k_vme_intr_handle *svih; 277 278 svih = (vme_intr_handle_t) 279 malloc(sizeof(struct sun68k_vme_intr_handle), M_DEVBUF, M_NOWAIT); 280 svih->pri = level; 281 svih->vec = vec; 282 *ihp = svih; 283 return (0); 284 } 285 286 const struct evcnt * 287 sun68k_vme_intr_evcnt(void *cookie, vme_intr_handle_t vih) 288 { 289 290 /* XXX for now, no evcnt parent reported */ 291 return NULL; 292 } 293 294 /* 295 * Establish a VME bus interrupt. 296 */ 297 void * 298 sun68k_vme_intr_establish(void *cookie, vme_intr_handle_t vih, int pri, 299 int (*func)(void *), void *arg) 300 { 301 struct sun68k_vme_intr_handle *svih = 302 (struct sun68k_vme_intr_handle *)vih; 303 304 /* Install interrupt handler. */ 305 isr_add_vectored(func, (void *)arg, 306 svih->pri, svih->vec); 307 308 return (NULL); 309 } 310 311 void 312 sun68k_vme_unmap(void * cookie, vme_mapresc_t resc) 313 { 314 /* Not implemented */ 315 panic("sun68k_vme_unmap"); 316 } 317 318 void 319 sun68k_vme_intr_disestablish(void *cookie, void *a) 320 { 321 /* Not implemented */ 322 panic("sun68k_vme_intr_disestablish"); 323 } 324 325 /* 326 * VME DMA functions. 327 */ 328 329 static void 330 sun68k_vct_dmamap_destroy(void *cookie, bus_dmamap_t map) 331 { 332 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 333 bus_dmamap_destroy(sc->sc_dmatag, map); 334 } 335 336 static int 337 sun68k_vct_dmamap_create(void *cookie, vme_size_t size, vme_am_t am, 338 vme_datasize_t datasize, vme_swap_t swap, int nsegments, 339 vme_size_t maxsegsz, vme_addr_t boundary, int flags, bus_dmamap_t *dmamp) 340 { 341 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 342 343 /* Allocate a base map through parent bus ops */ 344 return (bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz, 345 boundary, flags, dmamp)); 346 } 347 348 int 349 sun68k_vme_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 350 bus_size_t buflen, struct proc *p, int flags) 351 { 352 int error; 353 354 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 355 if (error == 0) 356 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 357 return (error); 358 } 359 360 int 361 sun68k_vme_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 362 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 363 { 364 int error; 365 366 error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); 367 if (error == 0) 368 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 369 return (error); 370 } 371 372