xref: /netbsd-src/sys/arch/sparc/dev/vme_machdep.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
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