1 /* $NetBSD: vsbus.c,v 1.57 2009/10/26 19:16:58 cegger Exp $ */
3 * Copyright (c) 1996, 1999 Ludd, University of Lule}, Sweden.
6 * This code is derived from software contributed to Ludd by Bertram Barth.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed at Ludd, University of
19 * Lule}, Sweden and its contributors.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: vsbus.c,v 1.57 2009/10/26 19:16:58 cegger Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
43 #include <sys/ioctl.h>
45 #include <sys/device.h>
46 #include <sys/disklabel.h>
47 #include <sys/syslog.h>
50 #include <uvm/uvm_extern.h>
52 #define _VAX_BUS_DMA_PRIVATE
53 #include <machine/bus.h>
54 #include <machine/pte.h>
55 #include <machine/sid.h>
56 #include <machine/scb.h>
57 #include <machine/cpu.h>
58 #include <machine/trap.h>
59 #include <machine/nexus.h>
61 #include <machine/uvax.h>
62 #include <machine/ka410.h>
63 #include <machine/ka420.h>
64 #include <machine/ka43.h>
66 #include <machine/mainbus.h>
67 #include <machine/vsbus.h>
71 #include "opt_cputype.h"
73 static int vsbus_match(device_t
, cfdata_t
, void *);
74 static void vsbus_attach(device_t
, device_t
, void *);
75 static int vsbus_print(void *, const char *);
76 static int vsbus_search(device_t
, cfdata_t
, const int *, void *);
78 static SIMPLEQ_HEAD(, vsbus_dma
) vsbus_dma
;
80 CFATTACH_DECL_NEW(vsbus
, sizeof(struct vsbus_softc
),
81 vsbus_match
, vsbus_attach
, NULL
, NULL
);
83 static struct vax_bus_dma_tag vsbus_bus_dma_tag
= {
84 ._dmamap_create
= _bus_dmamap_create
,
85 ._dmamap_destroy
= _bus_dmamap_destroy
,
86 ._dmamap_load
= _bus_dmamap_load
,
87 ._dmamap_load_mbuf
= _bus_dmamap_load_mbuf
,
88 ._dmamap_load_uio
= _bus_dmamap_load_uio
,
89 ._dmamap_load_raw
= _bus_dmamap_load_raw
,
90 ._dmamap_unload
= _bus_dmamap_unload
,
91 ._dmamap_sync
= _bus_dmamap_sync
,
92 ._dmamem_alloc
= _bus_dmamem_alloc
,
93 ._dmamem_free
= _bus_dmamem_free
,
94 ._dmamem_map
= _bus_dmamem_map
,
95 ._dmamem_unmap
= _bus_dmamem_unmap
,
96 ._dmamem_mmap
= _bus_dmamem_mmap
,
100 vsbus_print(void *aux
, const char *name
)
102 struct vsbus_attach_args
* const va
= aux
;
104 aprint_normal(" csr 0x%lx vec %o ipl %x maskbit %d", va
->va_paddr
,
105 va
->va_cvec
& 511, va
->va_br
, va
->va_maskno
- 1);
110 vsbus_match(device_t parent
, cfdata_t cf
, void *aux
)
112 struct mainbus_attach_args
* const ma
= aux
;
114 return !strcmp("vsbus", ma
->ma_type
);
118 vsbus_attach(device_t parent
, device_t self
, void *aux
)
120 struct mainbus_attach_args
* const ma
= aux
;
121 struct vsbus_softc
*sc
= device_private(self
);
127 sc
->sc_iot
= ma
->ma_iot
;
128 sc
->sc_dmatag
= vsbus_bus_dma_tag
;
130 switch (vax_boardtype
) {
134 sc
->sc_vsregs
= vax_map_physmem(0x25c00000, 1);
135 sc
->sc_intreq
= (char *)sc
->sc_vsregs
+ 12;
136 sc
->sc_intclr
= (char *)sc
->sc_vsregs
+ 12;
137 sc
->sc_intmsk
= (char *)sc
->sc_vsregs
+ 8;
138 vsbus_dma_init(sc
, 8192);
145 sc
->sc_vsregs
= vax_map_physmem(VS_REGS
, 1);
146 sc
->sc_intreq
= (char *)sc
->sc_vsregs
+ 15;
147 sc
->sc_intclr
= (char *)sc
->sc_vsregs
+ 15;
148 sc
->sc_intmsk
= (char *)sc
->sc_vsregs
+ 12;
149 vsbus_dma_init(sc
, 32768);
153 sc
->sc_vsregs
= vax_map_physmem(VS_REGS
, 1);
154 sc
->sc_intreq
= (char *)sc
->sc_vsregs
+ 15;
155 sc
->sc_intclr
= (char *)sc
->sc_vsregs
+ 15;
156 sc
->sc_intmsk
= (char *)sc
->sc_vsregs
+ 12;
157 if (vax_boardtype
== VAX_BTYP_410
) {
158 dbase
= KA410_DMA_BASE
;
159 dsize
= KA410_DMA_SIZE
;
161 dbase
= KA420_DMA_BASE
;
162 dsize
= KA420_DMA_SIZE
;
163 *(char *)(sc
->sc_vsregs
+ 0xe0) = 1; /* Big DMA */
165 sc
->sc_dmasize
= dsize
;
166 sc
->sc_dmaaddr
= uvm_km_alloc(kernel_map
, dsize
, 0,
168 ioaccess(sc
->sc_dmaaddr
, dbase
, dsize
/VAX_NBPG
);
172 SIMPLEQ_INIT(&vsbus_dma
);
174 * First: find which interrupts we won't care about.
175 * There are interrupts that interrupt on a periodic basic
176 * that we don't want to interfere with the rest of the
180 *sc
->sc_intclr
= 0xff;
181 DELAY(1000000); /* Wait a second */
182 sc
->sc_mask
= *sc
->sc_intreq
;
183 aprint_normal_dev(self
, "interrupt mask %x\n", sc
->sc_mask
);
185 * now check for all possible devices on this "bus"
187 config_search_ia(vsbus_search
, self
, "vsbus", NULL
);
189 /* Autoconfig finished, enable interrupts */
190 *sc
->sc_intmsk
= ~sc
->sc_mask
;
194 vsbus_search(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
196 struct vsbus_softc
*sc
= device_private(parent
);
197 struct vsbus_attach_args va
;
201 va
.va_paddr
= cf
->cf_loc
[VSBUSCF_CSR
];
202 va
.va_addr
= vax_map_physmem(va
.va_paddr
, 1);
203 va
.va_dmat
= &sc
->sc_dmatag
;
204 va
.va_memt
= sc
->sc_iot
;
207 *sc
->sc_intclr
= 0xff;
208 scb_vecref(0, 0); /* Clear vector ref */
210 i
= config_match(parent
, cf
, &va
);
211 vax_unmap_physmem(va
.va_addr
, 1);
212 c
= *sc
->sc_intreq
& ~sc
->sc_mask
;
216 c
= sc
->sc_mask
; /* Fooling interrupt */
223 va
.va_maskno
= ffs((u_int
)c
);
224 i
= scb_vecref(&vec
, &br
);
232 va
.va_dmaaddr
= sc
->sc_dmaaddr
;
233 va
.va_dmasize
= sc
->sc_dmasize
;
234 *sc
->sc_intmsk
= c
; /* Allow interrupts during attach */
235 config_attach(parent
, cf
, &va
, vsbus_print
);
240 printf("%s%d at %s csr 0x%x %s\n",
241 cf
->cf_name
, cf
->cf_unit
, device_xname(parent
),
242 cf
->cf_loc
[VSBUSCF_CSR
], (i
? "zero vector" : "didn't interrupt"));
248 * Sets a new interrupt mask. Returns the old one.
249 * Works like spl functions.
252 vsbus_setmask(int mask
)
254 struct vsbus_softc
* const sc
= device_lookup_private(&vsbus_cd
, 0);
261 *sc
->sc_intmsk
= mask
;
266 * Clears the interrupts in mask.
269 vsbus_clrintr(int mask
)
271 struct vsbus_softc
* const sc
= device_lookup_private(&vsbus_cd
, 0);
275 *sc
->sc_intclr
= mask
;
279 * Copy data from/to a user process' space from the DMA area.
280 * Use the physical memory directly.
283 vsbus_copytoproc(struct proc
*p
, void *fromv
, void *tov
, int len
)
285 char *from
= fromv
, *to
= tov
;
289 if ((vaddr_t
)to
& KERNBASE
) { /* In kernel space */
290 memcpy(to
, from
, len
);
296 panic("vsbus_copytoproc: no proc");
299 if ((vaddr_t
)to
& 0x40000000)
300 pte
= &p
->p_vmspace
->vm_map
.pmap
->pm_p1br
[vax_btop((vaddr_t
)to
& ~0x40000000)];
302 pte
= &p
->p_vmspace
->vm_map
.pmap
->pm_p0br
[vax_btop((vaddr_t
)to
)];
303 if ((vaddr_t
)to
& PGOFSET
) {
304 int cz
= round_page((vaddr_t
)to
) - (vaddr_t
)to
;
306 pa
= (pte
->pg_pfn
<< VAX_PGSHIFT
) | (PAGE_SIZE
- cz
) | KERNBASE
;
307 memcpy((void *)pa
, from
, min(cz
, len
));
314 pa
= (pte
->pg_pfn
<< VAX_PGSHIFT
) | KERNBASE
;
315 memcpy((void *)pa
, from
, min(PAGE_SIZE
, len
));
324 vsbus_copyfromproc(struct proc
*p
, void *fromv
, void *tov
, int len
)
326 char *from
= fromv
, *to
= tov
;
330 if ((vaddr_t
)from
& KERNBASE
) { /* In kernel space */
331 memcpy(to
, from
, len
);
337 panic("vsbus_copyfromproc: no proc");
340 if ((vaddr_t
)from
& 0x40000000)
341 pte
= &p
->p_vmspace
->vm_map
.pmap
->pm_p1br
[vax_btop((vaddr_t
)from
& ~0x40000000)];
343 pte
= &p
->p_vmspace
->vm_map
.pmap
->pm_p0br
[vax_btop((vaddr_t
)from
)];
344 if ((vaddr_t
)from
& PGOFSET
) {
345 int cz
= round_page((vaddr_t
)from
) - (vaddr_t
)from
;
347 pa
= (pte
->pg_pfn
<< VAX_PGSHIFT
) | (PAGE_SIZE
- cz
) | KERNBASE
;
348 memcpy(to
, (void *)pa
, min(cz
, len
));
355 pa
= (pte
->pg_pfn
<< VAX_PGSHIFT
) | KERNBASE
;
356 memcpy(to
, (void *)pa
, min(PAGE_SIZE
, len
));
365 * There can only be one user of the DMA area on VS2k/VS3100 at one
366 * time, so keep track of it here.
368 static int vsbus_active
= 0;
371 vsbus_dma_start(struct vsbus_dma
*vd
)
374 SIMPLEQ_INSERT_TAIL(&vsbus_dma
, vd
, vd_q
);
376 if (vsbus_active
== 0)
383 struct vsbus_dma
*vd
;
385 vd
= SIMPLEQ_FIRST(&vsbus_dma
);
391 SIMPLEQ_REMOVE_HEAD(&vsbus_dma
, vd_q
);
392 (*vd
->vd_go
)(vd
->vd_arg
);