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