1 /* $NetBSD: vme_machdep.c,v 1.63 2011/01/14 02:06:31 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998 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. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: vme_machdep.c,v 1.63 2011/01/14 02:06:31 rmind Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/extent.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/errno.h> 41 42 #include <sys/proc.h> 43 #include <sys/syslog.h> 44 45 #include <uvm/uvm_extern.h> 46 47 #define _SPARC_BUS_DMA_PRIVATE 48 #include <machine/bus.h> 49 #include <sparc/sparc/iommuvar.h> 50 #include <machine/autoconf.h> 51 #include <machine/oldmon.h> 52 #include <machine/cpu.h> 53 #include <machine/ctlreg.h> 54 #include <machine/pcb.h> 55 56 #include <dev/vme/vmereg.h> 57 #include <dev/vme/vmevar.h> 58 59 #include <sparc/sparc/asm.h> 60 #include <sparc/sparc/vaddrs.h> 61 #include <sparc/sparc/cpuvar.h> 62 #include <sparc/dev/vmereg.h> 63 64 struct sparcvme_softc { 65 struct device sc_dev; /* base device */ 66 bus_space_tag_t sc_bustag; 67 bus_dma_tag_t sc_dmatag; 68 struct vmebusreg *sc_reg; /* VME control registers */ 69 struct vmebusvec *sc_vec; /* VME interrupt vector */ 70 struct rom_range *sc_range; /* ROM range property */ 71 int sc_nrange; 72 volatile uint32_t *sc_ioctags; /* VME IO-cache tag registers */ 73 volatile uint32_t *sc_iocflush;/* VME IO-cache flush registers */ 74 int (*sc_vmeintr)(void *); 75 }; 76 struct sparcvme_softc *sparcvme_sc;/*XXX*/ 77 78 /* autoconfiguration driver */ 79 static int vmematch_iommu(device_t, cfdata_t, void *); 80 static void vmeattach_iommu(device_t, device_t, void *); 81 static int vmematch_mainbus(device_t, cfdata_t, void *); 82 static void vmeattach_mainbus(device_t, device_t, void *); 83 #if defined(SUN4) 84 int vmeintr4(void *); 85 #endif 86 #if defined(SUN4M) 87 int vmeintr4m(void *); 88 static int sparc_vme_error(void); 89 #endif 90 91 92 static int sparc_vme_probe(void *, vme_addr_t, vme_size_t, 93 vme_am_t, vme_datasize_t, 94 int (*)(void *, 95 bus_space_tag_t, bus_space_handle_t), 96 void *); 97 static int sparc_vme_map(void *, vme_addr_t, vme_size_t, vme_am_t, 98 vme_datasize_t, vme_swap_t, 99 bus_space_tag_t *, bus_space_handle_t *, 100 vme_mapresc_t *); 101 static void sparc_vme_unmap(void *, vme_mapresc_t); 102 static int sparc_vme_intr_map(void *, int, int, vme_intr_handle_t *); 103 static const struct evcnt *sparc_vme_intr_evcnt(void *, vme_intr_handle_t); 104 static void * sparc_vme_intr_establish(void *, vme_intr_handle_t, int, 105 int (*)(void *), void *); 106 static void sparc_vme_intr_disestablish(void *, void *); 107 108 static int vmebus_translate(struct sparcvme_softc *, vme_am_t, 109 vme_addr_t, bus_addr_t *); 110 #ifdef notyet 111 #if defined(SUN4M) 112 static void sparc_vme_iommu_barrier(bus_space_tag_t, bus_space_handle_t, 113 bus_size_t, bus_size_t, int); 114 115 #endif /* SUN4M */ 116 #endif 117 118 /* 119 * DMA functions. 120 */ 121 #if defined(SUN4) || defined(SUN4M) 122 static void sparc_vct_dmamap_destroy(void *, bus_dmamap_t); 123 #endif 124 125 #if defined(SUN4) 126 static int sparc_vct4_dmamap_create(void *, vme_size_t, vme_am_t, 127 vme_datasize_t, vme_swap_t, int, vme_size_t, vme_addr_t, 128 int, bus_dmamap_t *); 129 static int sparc_vme4_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, 130 bus_size_t, struct proc *, int); 131 static void sparc_vme4_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); 132 static void sparc_vme4_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, 133 bus_addr_t, bus_size_t, int); 134 #endif /* SUN4 */ 135 136 #if defined(SUN4M) 137 static int sparc_vct_iommu_dmamap_create(void *, vme_size_t, vme_am_t, 138 vme_datasize_t, vme_swap_t, int, vme_size_t, vme_addr_t, 139 int, bus_dmamap_t *); 140 static int sparc_vme_iommu_dmamap_create(bus_dma_tag_t, bus_size_t, 141 int, bus_size_t, bus_size_t, int, bus_dmamap_t *); 142 143 static int sparc_vme_iommu_dmamap_load(bus_dma_tag_t, bus_dmamap_t, 144 void *, bus_size_t, struct proc *, int); 145 static void sparc_vme_iommu_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); 146 static void sparc_vme_iommu_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, 147 bus_addr_t, bus_size_t, int); 148 #endif /* SUN4M */ 149 150 #if defined(SUN4) || defined(SUN4M) 151 static int sparc_vme_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, 152 int, size_t, void **, int); 153 #endif 154 155 #if 0 156 static void sparc_vme_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); 157 static void sparc_vme_dmamem_unmap(bus_dma_tag_t, void *, size_t); 158 static paddr_t sparc_vme_dmamem_mmap(bus_dma_tag_t, 159 bus_dma_segment_t *, int, off_t, int, int); 160 #endif 161 162 int sparc_vme_mmap_cookie(vme_addr_t, vme_am_t, bus_space_handle_t *); 163 164 CFATTACH_DECL(vme_mainbus, sizeof(struct sparcvme_softc), 165 vmematch_mainbus, vmeattach_mainbus, NULL, NULL); 166 167 CFATTACH_DECL(vme_iommu, sizeof(struct sparcvme_softc), 168 vmematch_iommu, vmeattach_iommu, NULL, NULL); 169 170 static int vme_attached; 171 172 int (*vmeerr_handler)(void); 173 174 #define VMEMOD_D32 0x40 /* ??? */ 175 176 /* If the PROM does not provide the `ranges' property, we make up our own */ 177 struct rom_range vmebus_translations[] = { 178 #define _DS (VME_AM_MBO | VME_AM_SUPER | VME_AM_DATA) 179 { VME_AM_A16|_DS, 0, PMAP_VME16, 0xffff0000, 0 }, 180 { VME_AM_A24|_DS, 0, PMAP_VME16, 0xff000000, 0 }, 181 { VME_AM_A32|_DS, 0, PMAP_VME16, 0x00000000, 0 }, 182 { VME_AM_A16|VMEMOD_D32|_DS, 0, PMAP_VME32, 0xffff0000, 0 }, 183 { VME_AM_A24|VMEMOD_D32|_DS, 0, PMAP_VME32, 0xff000000, 0 }, 184 { VME_AM_A32|VMEMOD_D32|_DS, 0, PMAP_VME32, 0x00000000, 0 } 185 #undef _DS 186 }; 187 188 /* 189 * The VME bus logic on sun4 machines maps DMA requests in the first MB 190 * of VME space to the last MB of DVMA space. `vme_dvmamap' is used 191 * for DVMA space allocations. The DMA addresses returned by 192 * bus_dmamap_load*() must be relocated by -VME4_DVMA_BASE. 193 */ 194 struct extent *vme_dvmamap; 195 196 /* 197 * The VME hardware on the sun4m IOMMU maps the first 8MB of 32-bit 198 * VME space to the last 8MB of DVMA space and the first 1MB of 199 * 24-bit VME space to the first 1MB of the last 8MB of DVMA space 200 * (thus 24-bit VME space overlaps the first 1MB of of 32-bit space). 201 * The following constants define subregions in the IOMMU DVMA map 202 * for VME DVMA allocations. The DMA addresses returned by 203 * bus_dmamap_load*() must be relocated by -VME_IOMMU_DVMA_BASE. 204 */ 205 #define VME_IOMMU_DVMA_BASE 0xff800000 206 #define VME_IOMMU_DVMA_AM24_BASE VME_IOMMU_DVMA_BASE 207 #define VME_IOMMU_DVMA_AM24_END 0xff900000 208 #define VME_IOMMU_DVMA_AM32_BASE VME_IOMMU_DVMA_BASE 209 #define VME_IOMMU_DVMA_AM32_END IOMMU_DVMA_END 210 211 struct vme_chipset_tag sparc_vme_chipset_tag = { 212 NULL, 213 sparc_vme_map, 214 sparc_vme_unmap, 215 sparc_vme_probe, 216 sparc_vme_intr_map, 217 sparc_vme_intr_evcnt, 218 sparc_vme_intr_establish, 219 sparc_vme_intr_disestablish, 220 0, 0, 0 /* bus specific DMA stuff */ 221 }; 222 223 224 #if defined(SUN4) 225 struct sparc_bus_dma_tag sparc_vme4_dma_tag = { 226 NULL, /* cookie */ 227 _bus_dmamap_create, 228 _bus_dmamap_destroy, 229 sparc_vme4_dmamap_load, 230 _bus_dmamap_load_mbuf, 231 _bus_dmamap_load_uio, 232 _bus_dmamap_load_raw, 233 sparc_vme4_dmamap_unload, 234 sparc_vme4_dmamap_sync, 235 236 _bus_dmamem_alloc, 237 _bus_dmamem_free, 238 sparc_vme_dmamem_map, 239 _bus_dmamem_unmap, 240 _bus_dmamem_mmap 241 }; 242 #endif 243 244 #if defined(SUN4M) 245 struct sparc_bus_dma_tag sparc_vme_iommu_dma_tag = { 246 NULL, /* cookie */ 247 sparc_vme_iommu_dmamap_create, 248 _bus_dmamap_destroy, 249 sparc_vme_iommu_dmamap_load, 250 _bus_dmamap_load_mbuf, 251 _bus_dmamap_load_uio, 252 _bus_dmamap_load_raw, 253 sparc_vme_iommu_dmamap_unload, 254 sparc_vme_iommu_dmamap_sync, 255 256 _bus_dmamem_alloc, 257 _bus_dmamem_free, 258 sparc_vme_dmamem_map, 259 _bus_dmamem_unmap, 260 _bus_dmamem_mmap 261 }; 262 #endif 263 264 265 static int 266 vmematch_mainbus(device_t parent, cfdata_t cf, void *aux) 267 { 268 struct mainbus_attach_args *ma = aux; 269 270 if (!CPU_ISSUN4 || vme_attached) 271 return (0); 272 273 return (strcmp("vme", ma->ma_name) == 0); 274 } 275 276 static int 277 vmematch_iommu(device_t parent, cfdata_t cf, void *aux) 278 { 279 struct iommu_attach_args *ia = aux; 280 281 if (vme_attached) 282 return 0; 283 284 return (strcmp("vme", ia->iom_name) == 0); 285 } 286 287 288 static void 289 vmeattach_mainbus(device_t parent, device_t self, void *aux) 290 { 291 #if defined(SUN4) 292 struct mainbus_attach_args *ma = aux; 293 struct sparcvme_softc *sc = device_private(self); 294 struct vmebus_attach_args vba; 295 296 vme_attached = 1; 297 298 sc->sc_bustag = ma->ma_bustag; 299 sc->sc_dmatag = ma->ma_dmatag; 300 301 /* VME interrupt entry point */ 302 sc->sc_vmeintr = vmeintr4; 303 304 /*XXX*/ sparc_vme_chipset_tag.cookie = sc; 305 /*XXX*/ sparc_vme_chipset_tag.vct_dmamap_create = sparc_vct4_dmamap_create; 306 /*XXX*/ sparc_vme_chipset_tag.vct_dmamap_destroy = sparc_vct_dmamap_destroy; 307 /*XXX*/ sparc_vme4_dma_tag._cookie = sc; 308 309 vba.va_vct = &sparc_vme_chipset_tag; 310 vba.va_bdt = &sparc_vme4_dma_tag; 311 vba.va_slaveconfig = 0; 312 313 /* Fall back to our own `range' construction */ 314 sc->sc_range = vmebus_translations; 315 sc->sc_nrange = 316 sizeof(vmebus_translations)/sizeof(vmebus_translations[0]); 317 318 vme_dvmamap = extent_create("vmedvma", VME4_DVMA_BASE, VME4_DVMA_END, 319 M_DEVBUF, 0, 0, EX_NOWAIT); 320 if (vme_dvmamap == NULL) 321 panic("vme: unable to allocate DVMA map"); 322 323 printf("\n"); 324 (void)config_found(self, &vba, 0); 325 326 #endif /* SUN4 */ 327 return; 328 } 329 330 /* sun4m vmebus */ 331 static void 332 vmeattach_iommu(struct device *parent, struct device *self, void *aux) 333 { 334 #if defined(SUN4M) 335 struct sparcvme_softc *sc = device_private(self); 336 struct iommu_attach_args *ia = aux; 337 struct vmebus_attach_args vba; 338 bus_space_handle_t bh; 339 int node; 340 int cline; 341 342 sc->sc_bustag = ia->iom_bustag; 343 sc->sc_dmatag = ia->iom_dmatag; 344 345 /* VME interrupt entry point */ 346 sc->sc_vmeintr = vmeintr4m; 347 348 /*XXX*/ sparc_vme_chipset_tag.cookie = sc; 349 /*XXX*/ sparc_vme_chipset_tag.vct_dmamap_create = sparc_vct_iommu_dmamap_create; 350 /*XXX*/ sparc_vme_chipset_tag.vct_dmamap_destroy = sparc_vct_dmamap_destroy; 351 /*XXX*/ sparc_vme_iommu_dma_tag._cookie = sc; 352 353 vba.va_vct = &sparc_vme_chipset_tag; 354 vba.va_bdt = &sparc_vme_iommu_dma_tag; 355 vba.va_slaveconfig = 0; 356 357 node = ia->iom_node; 358 359 /* 360 * Map VME control space 361 */ 362 if (ia->iom_nreg < 2) { 363 printf("%s: only %d register sets\n", device_xname(self), 364 ia->iom_nreg); 365 return; 366 } 367 368 if (bus_space_map(ia->iom_bustag, 369 (bus_addr_t) BUS_ADDR(ia->iom_reg[0].oa_space, 370 ia->iom_reg[0].oa_base), 371 (bus_size_t)ia->iom_reg[0].oa_size, 372 BUS_SPACE_MAP_LINEAR, 373 &bh) != 0) { 374 panic("%s: can't map vmebusreg", device_xname(self)); 375 } 376 sc->sc_reg = (struct vmebusreg *)bh; 377 378 if (bus_space_map(ia->iom_bustag, 379 (bus_addr_t) BUS_ADDR(ia->iom_reg[1].oa_space, 380 ia->iom_reg[1].oa_base), 381 (bus_size_t)ia->iom_reg[1].oa_size, 382 BUS_SPACE_MAP_LINEAR, 383 &bh) != 0) { 384 panic("%s: can't map vmebusvec", device_xname(self)); 385 } 386 sc->sc_vec = (struct vmebusvec *)bh; 387 388 /* 389 * Map VME IO cache tags and flush control. 390 */ 391 if (bus_space_map(ia->iom_bustag, 392 (bus_addr_t) BUS_ADDR( 393 ia->iom_reg[1].oa_space, 394 ia->iom_reg[1].oa_base + VME_IOC_TAGOFFSET), 395 VME_IOC_SIZE, 396 BUS_SPACE_MAP_LINEAR, 397 &bh) != 0) { 398 panic("%s: can't map IOC tags", device_xname(self)); 399 } 400 sc->sc_ioctags = (uint32_t *)bh; 401 402 if (bus_space_map(ia->iom_bustag, 403 (bus_addr_t) BUS_ADDR( 404 ia->iom_reg[1].oa_space, 405 ia->iom_reg[1].oa_base + VME_IOC_FLUSHOFFSET), 406 VME_IOC_SIZE, 407 BUS_SPACE_MAP_LINEAR, 408 &bh) != 0) { 409 panic("%s: can't map IOC flush registers", device_xname(self)); 410 } 411 sc->sc_iocflush = (uint32_t *)bh; 412 413 /* 414 * Get "range" property. 415 */ 416 if (prom_getprop(node, "ranges", sizeof(struct rom_range), 417 &sc->sc_nrange, &sc->sc_range) != 0) { 418 panic("%s: can't get ranges property", device_xname(self)); 419 } 420 421 sparcvme_sc = sc; 422 vmeerr_handler = sparc_vme_error; 423 424 /* 425 * Invalidate all IO-cache entries. 426 */ 427 for (cline = VME_IOC_SIZE/VME_IOC_LINESZ; cline > 0;) { 428 sc->sc_ioctags[--cline] = 0; 429 } 430 431 /* Enable IO-cache */ 432 sc->sc_reg->vmebus_cr |= VMEBUS_CR_C; 433 434 printf(": version 0x%x\n", 435 sc->sc_reg->vmebus_cr & VMEBUS_CR_IMPL); 436 437 (void)config_found(self, &vba, 0); 438 #endif /* SUN4M */ 439 } 440 441 #if defined(SUN4M) 442 static int 443 sparc_vme_error(void) 444 { 445 struct sparcvme_softc *sc = sparcvme_sc; 446 uint32_t afsr, afpa; 447 char bits[64]; 448 449 afsr = sc->sc_reg->vmebus_afsr; 450 afpa = sc->sc_reg->vmebus_afar; 451 snprintb(bits, sizeof(bits), VMEBUS_AFSR_BITS, afsr); 452 printf("VME error:\n\tAFSR %s\n", bits); 453 printf("\taddress: 0x%x%x\n", afsr, afpa); 454 return (0); 455 } 456 #endif 457 458 static int 459 vmebus_translate(struct sparcvme_softc *sc, vme_am_t mod, vme_addr_t addr, 460 bus_addr_t *bap) 461 { 462 int i; 463 464 for (i = 0; i < sc->sc_nrange; i++) { 465 struct rom_range *rp = &sc->sc_range[i]; 466 467 if (rp->cspace != mod) 468 continue; 469 470 /* We've found the connection to the parent bus */ 471 *bap = BUS_ADDR(rp->pspace, rp->poffset + addr); 472 return (0); 473 } 474 return (ENOENT); 475 } 476 477 struct vmeprobe_myarg { 478 int (*cb)(void *, bus_space_tag_t, bus_space_handle_t); 479 void *cbarg; 480 bus_space_tag_t tag; 481 int res; /* backwards */ 482 }; 483 484 static int vmeprobe_mycb(void *, void *); 485 486 static int 487 vmeprobe_mycb(void *bh, void *arg) 488 { 489 struct vmeprobe_myarg *a = arg; 490 491 a->res = (*a->cb)(a->cbarg, a->tag, (bus_space_handle_t)bh); 492 return (!a->res); 493 } 494 495 static int 496 sparc_vme_probe(void *cookie, vme_addr_t addr, vme_size_t len, vme_am_t mod, 497 vme_datasize_t datasize, 498 int (*callback)(void *, bus_space_tag_t, bus_space_handle_t), 499 void *arg) 500 { 501 struct sparcvme_softc *sc = cookie; 502 bus_addr_t paddr; 503 bus_size_t size; 504 struct vmeprobe_myarg myarg; 505 int res, i; 506 507 if (vmebus_translate(sc, mod, addr, &paddr) != 0) 508 return (EINVAL); 509 510 size = (datasize == VME_D8 ? 1 : (datasize == VME_D16 ? 2 : 4)); 511 512 if (callback) { 513 myarg.cb = callback; 514 myarg.cbarg = arg; 515 myarg.tag = sc->sc_bustag; 516 myarg.res = 0; 517 res = bus_space_probe(sc->sc_bustag, paddr, size, 0, 518 0, vmeprobe_mycb, &myarg); 519 return (res ? 0 : (myarg.res ? myarg.res : EIO)); 520 } 521 522 for (i = 0; i < len / size; i++) { 523 myarg.res = 0; 524 res = bus_space_probe(sc->sc_bustag, paddr, size, 0, 525 0, 0, 0); 526 if (res == 0) 527 return (EIO); 528 paddr += size; 529 } 530 return (0); 531 } 532 533 static int 534 sparc_vme_map(void *cookie, vme_addr_t addr, vme_size_t size, vme_am_t mod, 535 vme_datasize_t datasize, vme_swap_t swap, 536 bus_space_tag_t *tp, bus_space_handle_t *hp, vme_mapresc_t *rp) 537 { 538 struct sparcvme_softc *sc = cookie; 539 bus_addr_t paddr; 540 int error; 541 542 error = vmebus_translate(sc, mod, addr, &paddr); 543 if (error != 0) 544 return (error); 545 546 *tp = sc->sc_bustag; 547 return (bus_space_map(sc->sc_bustag, paddr, size, 0, hp)); 548 } 549 550 int 551 sparc_vme_mmap_cookie(vme_addr_t addr, vme_am_t mod, bus_space_handle_t *hp) 552 { 553 struct sparcvme_softc *sc = sparcvme_sc; 554 bus_addr_t paddr; 555 int error; 556 557 error = vmebus_translate(sc, mod, addr, &paddr); 558 if (error != 0) 559 return (error); 560 561 return (bus_space_mmap(sc->sc_bustag, paddr, 0, 562 0/*prot is ignored*/, 0)); 563 } 564 565 #ifdef notyet 566 #if defined(SUN4M) 567 static void 568 sparc_vme_iommu_barrier(bus_space_tag_t t, bus_space_handle_t h, 569 bus_size_t offset, bus_size_t size. 570 int flags) 571 { 572 struct vmebusreg *vbp = t->cookie; 573 574 /* Read async fault status to flush write-buffers */ 575 (*(volatile int *)&vbp->vmebus_afsr); 576 } 577 #endif /* SUN4M */ 578 #endif 579 580 581 582 /* 583 * VME Interrupt Priority Level to sparc Processor Interrupt Level. 584 */ 585 static int vme_ipl_to_pil[] = { 586 0, 587 2, 588 3, 589 5, 590 7, 591 9, 592 11, 593 13 594 }; 595 596 597 /* 598 * All VME device interrupts go through vmeintr(). This function reads 599 * the VME vector from the bus, then dispatches the device interrupt 600 * handler. All handlers for devices that map to the same Processor 601 * Interrupt Level (according to the table above) are on a linked list 602 * of `sparc_vme_intr_handle' structures. The head of which is passed 603 * down as the argument to `vmeintr(void *arg)'. 604 */ 605 struct sparc_vme_intr_handle { 606 struct intrhand ih; 607 struct sparc_vme_intr_handle *next; 608 int vec; /* VME interrupt vector */ 609 int pri; /* VME interrupt priority */ 610 struct sparcvme_softc *sc;/*XXX*/ 611 }; 612 613 #if defined(SUN4) 614 int 615 vmeintr4(void *arg) 616 { 617 struct sparc_vme_intr_handle *ihp = (vme_intr_handle_t)arg; 618 int level, vec; 619 int rv = 0; 620 621 level = (ihp->pri << 1) | 1; 622 623 vec = ldcontrolb((void *)(AC_VMEINTVEC | level)); 624 625 if (vec == -1) { 626 #ifdef DEBUG 627 /* 628 * This seems to happen only with the i82586 based 629 * `ie1' boards. 630 */ 631 printf("vme: spurious interrupt at VME level %d\n", ihp->pri); 632 #endif 633 return (1); /* XXX - pretend we handled it, for now */ 634 } 635 636 for (; ihp; ihp = ihp->next) 637 if (ihp->vec == vec && ihp->ih.ih_fun) { 638 splx(ihp->ih.ih_classipl); 639 rv |= (ihp->ih.ih_fun)(ihp->ih.ih_arg); 640 } 641 642 return (rv); 643 } 644 #endif 645 646 #if defined(SUN4M) 647 int 648 vmeintr4m(void *arg) 649 { 650 struct sparc_vme_intr_handle *ihp = (vme_intr_handle_t)arg; 651 int level, vec; 652 int rv = 0; 653 654 level = (ihp->pri << 1) | 1; 655 656 #if 0 657 int pending; 658 659 /* Flush VME <=> Sbus write buffers */ 660 (*(volatile int *)&ihp->sc->sc_reg->vmebus_afsr); 661 662 pending = *((int*)ICR_SI_PEND); 663 if ((pending & SINTR_VME(ihp->pri)) == 0) { 664 printf("vmeintr: non pending at pri %x(p 0x%x)\n", 665 ihp->pri, pending); 666 return (0); 667 } 668 #endif 669 #if 0 670 /* Why gives this a bus timeout sometimes? */ 671 vec = ihp->sc->sc_vec->vmebusvec[level]; 672 #else 673 /* so, arrange to catch the fault... */ 674 { 675 extern int fkbyte(volatile char *, struct pcb *); 676 volatile char *addr = &ihp->sc->sc_vec->vmebusvec[level]; 677 struct pcb *xpcb; 678 void *saveonfault; 679 int s; 680 681 s = splhigh(); 682 683 xpcb = lwp_getpcb(curlwp); 684 saveonfault = xpcb->pcb_onfault; 685 vec = fkbyte(addr, xpcb); 686 xpcb->pcb_onfault = saveonfault; 687 688 splx(s); 689 } 690 #endif 691 692 if (vec == -1) { 693 #ifdef DEBUG 694 /* 695 * This seems to happen only with the i82586 based 696 * `ie1' boards. 697 */ 698 printf("vme: spurious interrupt at VME level %d\n", ihp->pri); 699 printf(" ICR_SI_PEND=0x%x; VME AFSR=0x%x; VME AFAR=0x%x\n", 700 *((int*)ICR_SI_PEND), 701 ihp->sc->sc_reg->vmebus_afsr, 702 ihp->sc->sc_reg->vmebus_afar); 703 #endif 704 return (1); /* XXX - pretend we handled it, for now */ 705 } 706 707 for (; ihp; ihp = ihp->next) 708 if (ihp->vec == vec && ihp->ih.ih_fun) { 709 splx(ihp->ih.ih_classipl); 710 rv |= (ihp->ih.ih_fun)(ihp->ih.ih_arg); 711 } 712 713 return (rv); 714 } 715 #endif /* SUN4M */ 716 717 static int 718 sparc_vme_intr_map(void *cookie, int level, int vec, 719 vme_intr_handle_t *ihp) 720 { 721 struct sparc_vme_intr_handle *ih; 722 723 ih = (vme_intr_handle_t) 724 malloc(sizeof(struct sparc_vme_intr_handle), M_DEVBUF, M_NOWAIT); 725 ih->pri = level; 726 ih->vec = vec; 727 ih->sc = cookie;/*XXX*/ 728 *ihp = ih; 729 return (0); 730 } 731 732 static const struct evcnt * 733 sparc_vme_intr_evcnt(void *cookie, vme_intr_handle_t vih) 734 { 735 736 /* XXX for now, no evcnt parent reported */ 737 return NULL; 738 } 739 740 static void * 741 sparc_vme_intr_establish(void *cookie, vme_intr_handle_t vih, int level, 742 int (*func)(void *), void *arg) 743 { 744 struct sparcvme_softc *sc = cookie; 745 struct sparc_vme_intr_handle *svih = 746 (struct sparc_vme_intr_handle *)vih; 747 struct intrhand *ih; 748 int pil; 749 750 /* Translate VME priority to processor IPL */ 751 pil = vme_ipl_to_pil[svih->pri]; 752 753 if (level < pil) 754 panic("vme_intr_establish: class lvl (%d) < pil (%d)\n", 755 level, pil); 756 757 svih->ih.ih_fun = func; 758 svih->ih.ih_arg = arg; 759 svih->ih.ih_classipl = level; /* note: used slightly differently 760 than in intr.c (no shift) */ 761 svih->next = NULL; 762 763 /* ensure the interrupt subsystem will call us at this level */ 764 for (ih = intrhand[pil]; ih != NULL; ih = ih->ih_next) 765 if (ih->ih_fun == sc->sc_vmeintr) 766 break; 767 768 if (ih == NULL) { 769 ih = malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT|M_ZERO); 770 if (ih == NULL) 771 panic("vme_addirq"); 772 ih->ih_fun = sc->sc_vmeintr; 773 ih->ih_arg = vih; 774 intr_establish(pil, 0, ih, NULL, false); 775 } else { 776 svih->next = (vme_intr_handle_t)ih->ih_arg; 777 ih->ih_arg = vih; 778 } 779 return (NULL); 780 } 781 782 static void 783 sparc_vme_unmap(void *cookie, vme_mapresc_t resc) 784 { 785 786 /* Not implemented */ 787 panic("sparc_vme_unmap"); 788 } 789 790 static void 791 sparc_vme_intr_disestablish(void *cookie, void *a) 792 { 793 794 /* Not implemented */ 795 panic("sparc_vme_intr_disestablish"); 796 } 797 798 799 800 /* 801 * VME DMA functions. 802 */ 803 804 #if defined(SUN4) || defined(SUN4M) 805 static void 806 sparc_vct_dmamap_destroy(void *cookie, bus_dmamap_t map) 807 { 808 struct sparcvme_softc *sc = cookie; 809 810 bus_dmamap_destroy(sc->sc_dmatag, map); 811 } 812 #endif 813 814 #if defined(SUN4) 815 static int 816 sparc_vct4_dmamap_create(void *cookie, vme_size_t size, vme_am_t am, 817 vme_datasize_t datasize, vme_swap_t swap, 818 int nsegments, vme_size_t maxsegsz, 819 vme_addr_t boundary, int flags, 820 bus_dmamap_t *dmamp) 821 { 822 struct sparcvme_softc *sc = cookie; 823 824 /* Allocate a base map through parent bus ops */ 825 return (bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz, 826 boundary, flags, dmamp)); 827 } 828 829 static int 830 sparc_vme4_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, 831 void *buf, bus_size_t buflen, 832 struct proc *p, int flags) 833 { 834 bus_addr_t dva; 835 bus_size_t sgsize; 836 u_long ldva; 837 vaddr_t va, voff; 838 pmap_t pmap; 839 int pagesz = PAGE_SIZE; 840 int error; 841 842 cache_flush(buf, buflen); /* XXX - move to bus_dma_sync */ 843 844 va = (vaddr_t)buf; 845 voff = va & (pagesz - 1); 846 va &= -pagesz; 847 848 /* 849 * Allocate an integral number of pages from DVMA space 850 * covering the passed buffer. 851 */ 852 sgsize = (buflen + voff + pagesz - 1) & -pagesz; 853 error = extent_alloc(vme_dvmamap, sgsize, pagesz, 854 map->_dm_boundary, 855 (flags & BUS_DMA_NOWAIT) == 0 856 ? EX_WAITOK 857 : EX_NOWAIT, 858 &ldva); 859 if (error != 0) 860 return (error); 861 dva = (bus_addr_t)ldva; 862 863 map->dm_mapsize = buflen; 864 map->dm_nsegs = 1; 865 /* Adjust DVMA address to VME view */ 866 map->dm_segs[0].ds_addr = dva + voff - VME4_DVMA_BASE; 867 map->dm_segs[0].ds_len = buflen; 868 map->dm_segs[0]._ds_sgsize = sgsize; 869 870 pmap = (p == NULL) ? pmap_kernel() : p->p_vmspace->vm_map.pmap; 871 872 for (; sgsize != 0; ) { 873 paddr_t pa; 874 /* 875 * Get the physical address for this page. 876 */ 877 (void) pmap_extract(pmap, va, &pa); 878 879 #ifdef notyet 880 if (have_iocache) 881 pa |= PG_IOC; 882 #endif 883 pmap_enter(pmap_kernel(), dva, 884 pa | PMAP_NC, 885 VM_PROT_READ|VM_PROT_WRITE, PMAP_WIRED); 886 887 dva += pagesz; 888 va += pagesz; 889 sgsize -= pagesz; 890 } 891 pmap_update(pmap_kernel()); 892 893 return (0); 894 } 895 896 static void 897 sparc_vme4_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 898 { 899 bus_dma_segment_t *segs = map->dm_segs; 900 int nsegs = map->dm_nsegs; 901 bus_addr_t dva; 902 bus_size_t len; 903 int i, s, error; 904 905 for (i = 0; i < nsegs; i++) { 906 /* Go from VME to CPU view */ 907 dva = segs[i].ds_addr + VME4_DVMA_BASE; 908 dva &= -PAGE_SIZE; 909 len = segs[i]._ds_sgsize; 910 911 /* Remove double-mapping in DVMA space */ 912 pmap_remove(pmap_kernel(), dva, dva + len); 913 914 /* Release DVMA space */ 915 s = splhigh(); 916 error = extent_free(vme_dvmamap, dva, len, EX_NOWAIT); 917 splx(s); 918 if (error != 0) 919 printf("warning: %ld of DVMA space lost\n", len); 920 } 921 pmap_update(pmap_kernel()); 922 923 /* Mark the mappings as invalid. */ 924 map->dm_mapsize = 0; 925 map->dm_nsegs = 0; 926 } 927 928 static void 929 sparc_vme4_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, 930 bus_addr_t offset, bus_size_t len, int ops) 931 { 932 933 /* 934 * XXX Should perform cache flushes as necessary (e.g. 4/200 W/B). 935 * Currently the cache is flushed in bus_dma_load()... 936 */ 937 } 938 #endif /* SUN4 */ 939 940 #if defined(SUN4M) 941 static int 942 sparc_vme_iommu_dmamap_create(bus_dma_tag_t t, bus_size_t size, 943 int nsegments, bus_size_t maxsegsz, 944 bus_size_t boundary, int flags, 945 bus_dmamap_t *dmamp) 946 { 947 948 printf("sparc_vme_dmamap_create: please use `vme_dmamap_create'\n"); 949 return (EINVAL); 950 } 951 952 static int 953 sparc_vct_iommu_dmamap_create(void *cookie, vme_size_t size, vme_am_t am, 954 vme_datasize_t datasize, vme_swap_t swap, 955 int nsegments, vme_size_t maxsegsz, 956 vme_addr_t boundary, int flags, 957 bus_dmamap_t *dmamp) 958 { 959 struct sparcvme_softc *sc = cookie; 960 bus_dmamap_t map; 961 int error; 962 963 /* Allocate a base map through parent bus ops */ 964 error = bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz, 965 boundary, flags, &map); 966 if (error != 0) 967 return (error); 968 969 /* 970 * Each I/O cache line maps to a 8K section of VME DVMA space, so 971 * we must ensure that DVMA alloctions are always 8K aligned. 972 */ 973 map->_dm_align = VME_IOC_PAGESZ; 974 975 /* Set map region based on Address Modifier */ 976 switch ((am & VME_AM_ADRSIZEMASK)) { 977 case VME_AM_A16: 978 case VME_AM_A24: 979 /* 1 MB of DVMA space */ 980 map->_dm_ex_start = VME_IOMMU_DVMA_AM24_BASE; 981 map->_dm_ex_end = VME_IOMMU_DVMA_AM24_END; 982 break; 983 case VME_AM_A32: 984 /* 8 MB of DVMA space */ 985 map->_dm_ex_start = VME_IOMMU_DVMA_AM32_BASE; 986 map->_dm_ex_end = VME_IOMMU_DVMA_AM32_END; 987 break; 988 } 989 990 *dmamp = map; 991 return (0); 992 } 993 994 static int 995 sparc_vme_iommu_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, 996 void *buf, bus_size_t buflen, 997 struct proc *p, int flags) 998 { 999 struct sparcvme_softc *sc = t->_cookie; 1000 volatile uint32_t *ioctags; 1001 int error; 1002 1003 /* Round request to a multiple of the I/O cache size */ 1004 buflen = (buflen + VME_IOC_PAGESZ - 1) & -VME_IOC_PAGESZ; 1005 error = bus_dmamap_load(sc->sc_dmatag, map, buf, buflen, p, flags); 1006 if (error != 0) 1007 return (error); 1008 1009 /* Allocate I/O cache entries for this range */ 1010 ioctags = sc->sc_ioctags + VME_IOC_LINE(map->dm_segs[0].ds_addr); 1011 while (buflen > 0) { 1012 *ioctags = VME_IOC_IC | VME_IOC_W; 1013 ioctags += VME_IOC_LINESZ/sizeof(*ioctags); 1014 buflen -= VME_IOC_PAGESZ; 1015 } 1016 1017 /* 1018 * Adjust DVMA address to VME view. 1019 * Note: the DVMA base address is the same for all 1020 * VME address spaces. 1021 */ 1022 map->dm_segs[0].ds_addr -= VME_IOMMU_DVMA_BASE; 1023 return (0); 1024 } 1025 1026 1027 static void 1028 sparc_vme_iommu_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 1029 { 1030 struct sparcvme_softc *sc = t->_cookie; 1031 volatile uint32_t *flushregs; 1032 int len; 1033 1034 /* Go from VME to CPU view */ 1035 map->dm_segs[0].ds_addr += VME_IOMMU_DVMA_BASE; 1036 1037 /* Flush VME I/O cache */ 1038 len = map->dm_segs[0]._ds_sgsize; 1039 flushregs = sc->sc_iocflush + VME_IOC_LINE(map->dm_segs[0].ds_addr); 1040 while (len > 0) { 1041 *flushregs = 0; 1042 flushregs += VME_IOC_LINESZ/sizeof(*flushregs); 1043 len -= VME_IOC_PAGESZ; 1044 } 1045 1046 /* 1047 * Start a read from `tag space' which will not complete until 1048 * all cache flushes have finished 1049 */ 1050 (*sc->sc_ioctags); 1051 1052 bus_dmamap_unload(sc->sc_dmatag, map); 1053 } 1054 1055 static void 1056 sparc_vme_iommu_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, 1057 bus_addr_t offset, bus_size_t len, int ops) 1058 { 1059 1060 /* 1061 * XXX Should perform cache flushes as necessary. 1062 */ 1063 } 1064 #endif /* SUN4M */ 1065 1066 #if defined(SUN4) || defined(SUN4M) 1067 static int 1068 sparc_vme_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 1069 size_t size, void **kvap, int flags) 1070 { 1071 struct sparcvme_softc *sc = t->_cookie; 1072 1073 return (bus_dmamem_map(sc->sc_dmatag, segs, nsegs, size, kvap, flags)); 1074 } 1075 #endif /* SUN4 || SUN4M */ 1076