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