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