bus_machdep.c revision 127977
1139749Simp/*-
2113584Ssimokawa * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
3103285Sikob * All rights reserved.
4103285Sikob *
5103285Sikob * This code is derived from software contributed to The NetBSD Foundation
6103285Sikob * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
7103285Sikob * NASA Ames Research Center.
8103285Sikob *
9103285Sikob * Redistribution and use in source and binary forms, with or without
10103285Sikob * modification, are permitted provided that the following conditions
11103285Sikob * are met:
12103285Sikob * 1. Redistributions of source code must retain the above copyright
13103285Sikob *    notice, this list of conditions and the following disclaimer.
14103285Sikob * 2. Redistributions in binary form must reproduce the above copyright
15103285Sikob *    notice, this list of conditions and the following disclaimer in the
16103285Sikob *    documentation and/or other materials provided with the distribution.
17103285Sikob * 3. All advertising materials mentioning features or use of this software
18103285Sikob *    must display the following acknowledgement:
19103285Sikob *	This product includes software developed by the NetBSD
20103285Sikob *	Foundation, Inc. and its contributors.
21103285Sikob * 4. Neither the name of The NetBSD Foundation nor the names of its
22103285Sikob *    contributors may be used to endorse or promote products derived
23103285Sikob *    from this software without specific prior written permission.
24103285Sikob *
25103285Sikob * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26103285Sikob * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27103285Sikob * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28103285Sikob * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29103285Sikob * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30103285Sikob * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31103285Sikob * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32103285Sikob * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33103285Sikob * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34103285Sikob * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35227843Smarius * POSSIBILITY OF SUCH DAMAGE.
36227843Smarius */
37227843Smarius/*
38103285Sikob * Copyright (c) 1992, 1993
39103285Sikob *	The Regents of the University of California.  All rights reserved.
40103285Sikob *
41103285Sikob * This software was developed by the Computer Systems Engineering group
42193066Sjamie * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43103285Sikob * contributed to Berkeley.
44129879Sphk *
45103285Sikob * Redistribution and use in source and binary forms, with or without
46103285Sikob * modification, are permitted provided that the following conditions
47103285Sikob * are met:
48169806Ssimokawa * 1. Redistributions of source code must retain the above copyright
49103285Sikob *    notice, this list of conditions and the following disclaimer.
50170374Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright
51170374Ssimokawa *    notice, this list of conditions and the following disclaimer in the
52127468Ssimokawa *    documentation and/or other materials provided with the distribution.
53117067Ssimokawa * 4. Neither the name of the University nor the names of its contributors
54117067Ssimokawa *    may be used to endorse or promote products derived from this software
55103285Sikob *    without specific prior written permission.
56103285Sikob *
57113584Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59127468Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60127468Ssimokawa * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61127468Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62127468Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63127468Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64127468Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65127468Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67103285Sikob * SUCH DAMAGE.
68110072Ssimokawa */
69103285Sikob/*
70103285Sikob * Copyright (c) 1997, 1998 Justin T. Gibbs.
71127468Ssimokawa * All rights reserved.
72103285Sikob * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
73116376Ssimokawa *
74116376Ssimokawa * Redistribution and use in source and binary forms, with or without
75116376Ssimokawa * modification, are permitted provided that the following conditions
76116376Ssimokawa * are met:
77116376Ssimokawa * 1. Redistributions of source code must retain the above copyright
78116376Ssimokawa *    notice, this list of conditions, and the following disclaimer,
79116376Ssimokawa *    without modification, immediately at the beginning of the file.
80188704Ssbruno * 2. The name of the author may not be used to endorse or promote products
81103285Sikob *    derived from this software without specific prior written permission.
82108281Ssimokawa *
83109736Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
84109736Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
85109736Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
86120850Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
87120850Ssimokawa * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
88103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
89110195Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
90110269Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
91110195Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
92103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
93103285Sikob * SUCH DAMAGE.
94103285Sikob *
95103285Sikob *	from: @(#)machdep.c	8.6 (Berkeley) 1/14/94
96125238Ssimokawa *	from: NetBSD: machdep.c,v 1.111 2001/09/15 07:13:40 eeh Exp
97125238Ssimokawa *	and
98124169Ssimokawa * 	from: FreeBSD: src/sys/i386/i386/busdma_machdep.c,v 1.24 2001/08/15
99124169Ssimokawa *
100124169Ssimokawa * $FreeBSD: head/sys/sparc64/sparc64/bus_machdep.c 127977 2004-04-07 05:00:01Z imp $
101170374Ssimokawa */
102103285Sikob
103124169Ssimokawa#include <sys/param.h>
104103285Sikob#include <sys/bus.h>
105212413Savg#include <sys/lock.h>
106124169Ssimokawa#include <sys/malloc.h>
107124169Ssimokawa#include <sys/mbuf.h>
108124169Ssimokawa#include <sys/mutex.h>
109124169Ssimokawa#include <sys/proc.h>
110124169Ssimokawa#include <sys/smp.h>
111124169Ssimokawa#include <sys/systm.h>
112169806Ssimokawa#include <sys/uio.h>
113106543Ssimokawa
114124169Ssimokawa#include <vm/vm.h>
115106543Ssimokawa#include <vm/vm_extern.h>
116124169Ssimokawa#include <vm/vm_kern.h>
117170374Ssimokawa#include <vm/vm_page.h>
118103285Sikob#include <vm/vm_param.h>
119103285Sikob#include <vm/vm_map.h>
120103285Sikob
121125238Ssimokawa#include <machine/asi.h>
122125238Ssimokawa#include <machine/atomic.h>
123103285Sikob#include <machine/bus.h>
124103285Sikob#include <machine/bus_private.h>
125108642Ssimokawa#include <machine/cache.h>
126116978Ssimokawa#include <machine/smp.h>
127103285Sikob#include <machine/tlb.h>
128103285Sikob
129103285Sikobstatic void nexus_bus_barrier(bus_space_tag_t, bus_space_handle_t,
130103285Sikob    bus_size_t, bus_size_t, int);
131103285Sikob
132227843Smarius/* ASI's for bus access. */
133103285Sikobint bus_type_asi[] = {
134124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* UPA */
135124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* SBUS */
136124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT_L,		/* PCI configuration space */
137124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT_L,		/* PCI memory space */
138103285Sikob	ASI_PHYS_BYPASS_EC_WITH_EBIT_L,		/* PCI I/O space */
139124251Ssimokawa	0
140124251Ssimokawa};
141124251Ssimokawa
142124251Ssimokawaint bus_stream_asi[] = {
143124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* UPA */
144124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* SBUS */
145124251Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* PCI configuration space */
146114909Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* PCI memory space */
147114909Ssimokawa	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* PCI I/O space */
148114909Ssimokawa	0
149114909Ssimokawa};
150106813Ssimokawa
151103285Sikob/*
152103285Sikob * Convenience function for manipulating driver locks from busdma (during
153103285Sikob * busdma_swi, for example).  Drivers that don't provide their own locks
154103285Sikob * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
155103285Sikob * non-mutex locking scheme don't have to use this at all.
156103285Sikob */
157103285Sikobvoid
158110072Ssimokawabusdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
159103285Sikob{
160106810Ssimokawa	struct mtx *dmtx;
161110072Ssimokawa
162103285Sikob	dmtx = (struct mtx *)arg;
163103285Sikob	switch (op) {
164110072Ssimokawa	case BUS_DMA_LOCK:
165110072Ssimokawa		mtx_lock(dmtx);
166110072Ssimokawa		break;
167110193Ssimokawa	case BUS_DMA_UNLOCK:
168120660Ssimokawa		mtx_unlock(dmtx);
169103285Sikob		break;
170110072Ssimokawa	default:
171110072Ssimokawa		panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
172106810Ssimokawa	}
173103285Sikob}
174106813Ssimokawa
175103285Sikob/*
176110072Ssimokawa * dflt_lock should never get called.  It gets put into the dma tag when
177110072Ssimokawa * lockfunc == NULL, which is only valid if the maps that are associated
178110072Ssimokawa * with the tag are meant to never be defered.
179110582Ssimokawa * XXX Should have a way to identify which driver is responsible here.
180110072Ssimokawa */
181110072Ssimokawastatic void
182110072Ssimokawadflt_lock(void *arg, bus_dma_lock_op_t op)
183110072Ssimokawa{
184110072Ssimokawa#ifdef INVARIANTS
185170374Ssimokawa	panic("driver error: busdma dflt_lock called");
186110193Ssimokawa#else
187110582Ssimokawa	printf("DRIVER_ERROR: busdma dflt_lock called\n");
188110072Ssimokawa#endif
189170374Ssimokawa}
190110072Ssimokawa
191110072Ssimokawa/*
192110072Ssimokawa * Since there is no way for a device to obtain a dma tag from its parent
193110072Ssimokawa * we use this kluge to handle different the different supported bus systems.
194110072Ssimokawa * The sparc64_root_dma_tag is used as parent for tags that have none, so that
195110072Ssimokawa * the correct methods will be used.
196110072Ssimokawa */
197110072Ssimokawabus_dma_tag_t sparc64_root_dma_tag;
198103285Sikob
199103285Sikob/*
200103285Sikob * Allocate a device specific dma_tag.
201103285Sikob */
202103285Sikobint
203103285Sikobbus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
204103285Sikob    bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
205170374Ssimokawa    bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
206103285Sikob    int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
207103285Sikob    void *lockfuncarg, bus_dma_tag_t *dmat)
208103285Sikob{
209103285Sikob	bus_dma_tag_t impptag;
210103285Sikob	bus_dma_tag_t newtag;
211167632Ssimokawa
212167632Ssimokawa	/* Return a NULL tag on failure */
213103285Sikob	*dmat = NULL;
214103285Sikob
215120660Ssimokawa	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
216103285Sikob	if (newtag == NULL)
217103285Sikob		return (ENOMEM);
218103285Sikob
219103285Sikob	impptag = parent != NULL ? parent : sparc64_root_dma_tag;
220124251Ssimokawa	/*
221103285Sikob	 * The method table pointer and the cookie need to be taken over from
222103285Sikob	 * the parent or the root tag.
223170425Ssimokawa	 */
224170425Ssimokawa	newtag->dt_cookie = impptag->dt_cookie;
225170425Ssimokawa	newtag->dt_mt = impptag->dt_mt;
226170425Ssimokawa
227170425Ssimokawa	newtag->dt_parent = parent;
228170425Ssimokawa	newtag->dt_alignment = alignment;
229170425Ssimokawa	newtag->dt_boundary = boundary;
230170425Ssimokawa	newtag->dt_lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1);
231170425Ssimokawa	newtag->dt_highaddr = trunc_page((vm_offset_t)highaddr) +
232170425Ssimokawa	    (PAGE_SIZE - 1);
233170425Ssimokawa	newtag->dt_filter = filter;
234103285Sikob	newtag->dt_filterarg = filterarg;
235103285Sikob	newtag->dt_maxsize = maxsize;
236103285Sikob	newtag->dt_nsegments = nsegments;
237103285Sikob	newtag->dt_maxsegsz = maxsegsz;
238103285Sikob	newtag->dt_flags = flags;
239120660Ssimokawa	newtag->dt_ref_count = 1; /* Count ourselves */
240120660Ssimokawa	newtag->dt_map_count = 0;
241120660Ssimokawa
242120660Ssimokawa	if (lockfunc != NULL) {
243103285Sikob		newtag->dt_lockfunc = lockfunc;
244120660Ssimokawa		newtag->dt_lockfuncarg = lockfuncarg;
245103285Sikob	} else {
246120660Ssimokawa		newtag->dt_lockfunc = dflt_lock;
247120660Ssimokawa		newtag->dt_lockfuncarg = NULL;
248120660Ssimokawa	}
249120660Ssimokawa
250124251Ssimokawa	/* Take into account any restrictions imposed by our parent tag */
251124251Ssimokawa	if (parent != NULL) {
252103285Sikob		newtag->dt_lowaddr = ulmin(parent->dt_lowaddr,
253103285Sikob		    newtag->dt_lowaddr);
254106790Ssimokawa		newtag->dt_highaddr = ulmax(parent->dt_highaddr,
255103285Sikob		    newtag->dt_highaddr);
256103285Sikob		/*
257103285Sikob		 * XXX Not really correct??? Probably need to honor boundary
258103285Sikob		 *     all the way up the inheritence chain.
259103285Sikob		 */
260108655Ssimokawa		newtag->dt_boundary = ulmin(parent->dt_boundary,
261108655Ssimokawa		    newtag->dt_boundary);
262170374Ssimokawa		atomic_add_int(&parent->dt_ref_count, 1);
263103285Sikob	}
264103285Sikob
265170374Ssimokawa	*dmat = newtag;
266103285Sikob	return (0);
267170374Ssimokawa}
268130460Sdfr
269103285Sikobint
270103285Sikobbus_dma_tag_destroy(bus_dma_tag_t dmat)
271103285Sikob{
272103285Sikob	bus_dma_tag_t parent;
273103285Sikob
274103285Sikob	if (dmat != NULL) {
275103285Sikob		if (dmat->dt_map_count != 0)
276103285Sikob			return (EBUSY);
277103285Sikob		while (dmat != NULL) {
278103285Sikob			parent = dmat->dt_parent;
279103285Sikob			atomic_subtract_int(&dmat->dt_ref_count, 1);
280103285Sikob			if (dmat->dt_ref_count == 0) {
281103285Sikob				free(dmat, M_DEVBUF);
282170374Ssimokawa				/*
283170374Ssimokawa				 * Last reference count, so
284170374Ssimokawa				 * release our reference
285170374Ssimokawa				 * count on our parent.
286170374Ssimokawa				 */
287170374Ssimokawa				dmat = parent;
288170374Ssimokawa			} else
289170374Ssimokawa				dmat = NULL;
290103285Sikob		}
291103285Sikob	}
292103285Sikob	return (0);
293103285Sikob}
294170374Ssimokawa
295170374Ssimokawa/* Allocate/free a tag, and do the necessary management work. */
296170374Ssimokawaint
297170374Ssimokawasparc64_dma_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp)
298170374Ssimokawa{
299170374Ssimokawa
300170374Ssimokawa	*mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO);
301170374Ssimokawa	if (*mapp == NULL)
302170374Ssimokawa		return (ENOMEM);
303170374Ssimokawa
304170374Ssimokawa	SLIST_INIT(&(*mapp)->dm_reslist);
305170374Ssimokawa	dmat->dt_map_count++;
306170374Ssimokawa	return (0);
307170374Ssimokawa}
308103285Sikob
309103285Sikobvoid
310103285Sikobsparc64_dma_free_map(bus_dma_tag_t dmat, bus_dmamap_t map)
311106790Ssimokawa{
312106790Ssimokawa
313106790Ssimokawa	free(map, M_DEVBUF);
314103285Sikob	dmat->dt_map_count--;
315103285Sikob}
316170374Ssimokawa
317170374Ssimokawastatic int
318170374Ssimokawanexus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
319170374Ssimokawa{
320103285Sikob
321170374Ssimokawa	return (sparc64_dma_alloc_map(dmat, mapp));
322103285Sikob}
323170374Ssimokawa
324170374Ssimokawastatic int
325103285Sikobnexus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
326103285Sikob{
327103285Sikob
328103285Sikob	sparc64_dma_free_map(dmat, map);
329103285Sikob	return (0);
330103285Sikob}
331106790Ssimokawa
332125238Ssimokawa/*
333125238Ssimokawa * Utility function to load a linear buffer.  lastaddrp holds state
334125238Ssimokawa * between invocations (for multiple-buffer loads).  segp contains
335125238Ssimokawa * the starting segment on entrace, and the ending segment on exit.
336125238Ssimokawa * first indicates if this is the first invocation of this function.
337125238Ssimokawa */
338103285Sikobstatic int
339125238Ssimokawa_nexus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t segs[],
340103285Sikob    void *buf, bus_size_t buflen, struct thread *td, int flags,
341108281Ssimokawa    bus_addr_t *lastaddrp, int *segp, int first)
342125238Ssimokawa{
343103285Sikob	bus_size_t sgsize;
344106790Ssimokawa	bus_addr_t curaddr, lastaddr, baddr, bmask;
345110577Ssimokawa	vm_offset_t vaddr = (vm_offset_t)buf;
346170374Ssimokawa	int seg;
347110577Ssimokawa	pmap_t pmap;
348170374Ssimokawa
349170374Ssimokawa	if (td != NULL)
350110577Ssimokawa		pmap = vmspace_pmap(td->td_proc->p_vmspace);
351110577Ssimokawa	else
352170374Ssimokawa		pmap = NULL;
353111040Ssimokawa
354110577Ssimokawa	lastaddr = *lastaddrp;
355120660Ssimokawa	bmask  = ~(dmat->dt_boundary - 1);
356120660Ssimokawa
357110577Ssimokawa	for (seg = *segp; buflen > 0 ; ) {
358110577Ssimokawa		/*
359110577Ssimokawa		 * Get the physical address for this segment.
360170374Ssimokawa		 */
361110577Ssimokawa		if (pmap)
362111040Ssimokawa			curaddr = pmap_extract(pmap, vaddr);
363171513Ssimokawa		else
364110577Ssimokawa			curaddr = pmap_kextract(vaddr);
365169119Ssimokawa
366170427Ssimokawa		/*
367170427Ssimokawa		 * Compute the segment size, and adjust counts.
368170427Ssimokawa		 */
369110577Ssimokawa		sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
370110577Ssimokawa		if (buflen < sgsize)
371110577Ssimokawa			sgsize = buflen;
372110577Ssimokawa
373170374Ssimokawa		/*
374170374Ssimokawa		 * Make sure we don't cross any boundaries.
375170374Ssimokawa		 */
376110577Ssimokawa		if (dmat->dt_boundary > 0) {
377249291Swill			baddr = (curaddr + dmat->dt_boundary) & bmask;
378170374Ssimokawa			if (sgsize > (baddr - curaddr))
379170374Ssimokawa				sgsize = (baddr - curaddr);
380110577Ssimokawa		}
381110577Ssimokawa
382171513Ssimokawa		/*
383111040Ssimokawa		 * Insert chunk into a segment, coalescing with
384170374Ssimokawa		 * previous segment if possible.
385170374Ssimokawa		 */
386170374Ssimokawa		if (first) {
387170374Ssimokawa			segs[seg].ds_addr = curaddr;
388110577Ssimokawa			segs[seg].ds_len = sgsize;
389110577Ssimokawa			first = 0;
390170374Ssimokawa		} else {
391110577Ssimokawa			if (curaddr == lastaddr &&
392110577Ssimokawa			    (segs[seg].ds_len + sgsize) <= dmat->dt_maxsegsz &&
393110577Ssimokawa			    (dmat->dt_boundary == 0 ||
394110577Ssimokawa			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
395170374Ssimokawa				segs[seg].ds_len += sgsize;
396110577Ssimokawa			else {
397110577Ssimokawa				if (++seg >= dmat->dt_nsegments)
398121463Ssimokawa					break;
399121463Ssimokawa				segs[seg].ds_addr = curaddr;
400121463Ssimokawa				segs[seg].ds_len = sgsize;
401121463Ssimokawa			}
402121463Ssimokawa		}
403121463Ssimokawa
404170374Ssimokawa		lastaddr = curaddr + sgsize;
405170374Ssimokawa		vaddr += sgsize;
406170374Ssimokawa		buflen -= sgsize;
407170374Ssimokawa	}
408121463Ssimokawa
409170374Ssimokawa	*segp = seg;
410110577Ssimokawa	*lastaddrp = lastaddr;
411110577Ssimokawa
412110577Ssimokawa	/*
413103285Sikob	 * Did we fit?
414103285Sikob	 */
415103285Sikob	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
416103285Sikob}
417118455Ssimokawa
418103285Sikob/*
419118455Ssimokawa * Common function for loading a DMA map with a linear buffer.  May
420103285Sikob * be called by bus-specific DMA map load functions.
421103285Sikob *
422103285Sikob * Most SPARCs have IOMMUs in the bus controllers.  In those cases
423103285Sikob * they only need one segment and will use virtual addresses for DVMA.
424103285Sikob * Those bus controllers should intercept these vectors and should
425103285Sikob * *NEVER* call nexus_dmamap_load() which is used only by devices that
426116978Ssimokawa * bypass DVMA.
427103285Sikob */
428118455Ssimokawastatic int
429118455Ssimokawanexus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
430103285Sikob    bus_size_t buflen, bus_dmamap_callback_t *callback, void *callback_arg,
431118455Ssimokawa    int flags)
432118455Ssimokawa{
433187993Ssbruno#ifdef __GNUC__
434187993Ssbruno	bus_dma_segment_t dm_segments[dmat->dt_nsegments];
435187993Ssbruno#else
436187993Ssbruno	bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
437187993Ssbruno#endif
438187993Ssbruno	bus_addr_t lastaddr;
439187993Ssbruno	int error, nsegs;
440187993Ssbruno
441187993Ssbruno	error = _nexus_dmamap_load_buffer(dmat, dm_segments, buf, buflen,
442187993Ssbruno	    NULL, flags, &lastaddr, &nsegs, 1);
443187993Ssbruno
444187993Ssbruno	if (error == 0) {
445187993Ssbruno		(*callback)(callback_arg, dm_segments, nsegs + 1, 0);
446187993Ssbruno		map->dm_flags |= DMF_LOADED;
447187993Ssbruno	} else
448187993Ssbruno		(*callback)(callback_arg, NULL, 0, error);
449187993Ssbruno
450187993Ssbruno	return (0);
451187993Ssbruno}
452187993Ssbruno
453187993Ssbruno/*
454187993Ssbruno * Like nexus_dmamap_load(), but for mbufs.
455187993Ssbruno */
456187993Ssbrunostatic int
457187993Ssbrunonexus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
458170374Ssimokawa    bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
459171513Ssimokawa{
460170374Ssimokawa#ifdef __GNUC__
461170374Ssimokawa	bus_dma_segment_t dm_segments[dmat->dt_nsegments];
462170374Ssimokawa#else
463170374Ssimokawa	bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
464108853Ssimokawa#endif
465110577Ssimokawa	int nsegs, error;
466110577Ssimokawa
467110193Ssimokawa	M_ASSERTPKTHDR(m0);
468169806Ssimokawa
469172836Sjulian	nsegs = 0;
470169806Ssimokawa	error = 0;
471169806Ssimokawa	if (m0->m_pkthdr.len <= dmat->dt_maxsize) {
472103285Sikob		int first = 1;
473103285Sikob		bus_addr_t lastaddr = 0;
474103285Sikob		struct mbuf *m;
475103285Sikob
476103285Sikob		for (m = m0; m != NULL && error == 0; m = m->m_next) {
477103285Sikob			if (m->m_len > 0) {
478103285Sikob				error = _nexus_dmamap_load_buffer(dmat,
479187993Ssbruno				    dm_segments, m->m_data, m->m_len, NULL,
480169117Ssimokawa				    flags, &lastaddr, &nsegs, first);
481187993Ssbruno				first = 0;
482103285Sikob			}
483103285Sikob		}
484103285Sikob	} else {
485103285Sikob		error = EINVAL;
486103285Sikob	}
487103285Sikob
488103285Sikob	if (error) {
489103285Sikob		/* force "no valid mappings" in callback */
490103285Sikob		(*callback)(callback_arg, dm_segments, 0, 0, error);
491212413Savg	} else {
492103285Sikob		map->dm_flags |= DMF_LOADED;
493103285Sikob		(*callback)(callback_arg, dm_segments, nsegs + 1,
494103285Sikob		    m0->m_pkthdr.len, error);
495103285Sikob	}
496103285Sikob	return (error);
497103285Sikob}
498103285Sikob
499103285Sikob/*
500103285Sikob * Like nexus_dmamap_load(), but for uios.
501103285Sikob */
502103285Sikobstatic int
503103285Sikobnexus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
504103285Sikob    bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
505106790Ssimokawa{
506116978Ssimokawa	bus_addr_t lastaddr;
507116978Ssimokawa#ifdef __GNUC__
508116978Ssimokawa	bus_dma_segment_t dm_segments[dmat->dt_nsegments];
509116978Ssimokawa#else
510116978Ssimokawa	bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
511116978Ssimokawa#endif
512116978Ssimokawa	int nsegs, error, first, i;
513116978Ssimokawa	bus_size_t resid;
514116978Ssimokawa	struct iovec *iov;
515116978Ssimokawa	struct thread *td = NULL;
516116978Ssimokawa
517116978Ssimokawa	resid = uio->uio_resid;
518116978Ssimokawa	iov = uio->uio_iov;
519103285Sikob
520103285Sikob	if (uio->uio_segflg == UIO_USERSPACE) {
521103285Sikob		td = uio->uio_td;
522103285Sikob		KASSERT(td != NULL,
523118455Ssimokawa			("nexus_dmamap_load_uio: USERSPACE but no proc"));
524103285Sikob	}
525103285Sikob
526169806Ssimokawa	nsegs = 0;
527111078Ssimokawa	error = 0;
528118455Ssimokawa	first = 1;
529103285Sikob	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
530103285Sikob		/*
531169806Ssimokawa		 * Now at the first iovec to load.  Load each iovec
532170374Ssimokawa		 * until we have exhausted the residual count.
533169806Ssimokawa		 */
534170374Ssimokawa		bus_size_t minlen =
535170374Ssimokawa			resid < iov[i].iov_len ? resid : iov[i].iov_len;
536170374Ssimokawa		caddr_t addr = (caddr_t) iov[i].iov_base;
537170374Ssimokawa
538169806Ssimokawa		if (minlen > 0) {
539178915Ssimokawa			error = _nexus_dmamap_load_buffer(dmat, dm_segments,
540178915Ssimokawa			    addr, minlen, td, flags, &lastaddr, &nsegs, first);
541178915Ssimokawa			first = 0;
542118455Ssimokawa
543118455Ssimokawa			resid -= minlen;
544106790Ssimokawa		}
545118455Ssimokawa	}
546118455Ssimokawa
547111078Ssimokawa	if (error) {
548169806Ssimokawa		/* force "no valid mappings" in callback */
549169806Ssimokawa		(*callback)(callback_arg, dm_segments, 0, 0, error);
550169806Ssimokawa	} else {
551111078Ssimokawa		map->dm_flags |= DMF_LOADED;
552178915Ssimokawa		(*callback)(callback_arg, dm_segments, nsegs + 1,
553169806Ssimokawa		    uio->uio_resid, error);
554111078Ssimokawa	}
555111078Ssimokawa	return (error);
556111078Ssimokawa}
557111078Ssimokawa
558169806Ssimokawa/*
559169806Ssimokawa * Common function for unloading a DMA map.  May be called by
560169806Ssimokawa * bus-specific DMA map unload functions.
561169806Ssimokawa */
562171513Ssimokawastatic void
563170374Ssimokawanexus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
564103285Sikob{
565103285Sikob
566103285Sikob	map->dm_flags &= ~DMF_LOADED;
567103285Sikob}
568103285Sikob
569103285Sikob/*
570103285Sikob * Common function for DMA map synchronization.  May be called
571103285Sikob * by bus-specific DMA map synchronization functions.
572103285Sikob */
573106790Ssimokawastatic void
574110577Ssimokawanexus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
575110577Ssimokawa{
576110798Ssimokawa
577110577Ssimokawa	/*
578110577Ssimokawa	 * We sync out our caches, but the bus must do the same.
579110577Ssimokawa	 *
580110577Ssimokawa	 * Actually a #Sync is expensive.  We should optimize.
581110577Ssimokawa	 */
582170374Ssimokawa	if ((op & BUS_DMASYNC_PREREAD) || (op & BUS_DMASYNC_PREWRITE)) {
583111942Ssimokawa		/*
584170374Ssimokawa		 * Don't really need to do anything, but flush any pending
585110577Ssimokawa		 * writes anyway.
586170374Ssimokawa		 */
587113584Ssimokawa		membar(Sync);
588110577Ssimokawa	}
589110577Ssimokawa#if 0
590110577Ssimokawa	/* Should not be needed. */
591110798Ssimokawa	if (op & BUS_DMASYNC_POSTREAD) {
592110798Ssimokawa		ecache_flush((vm_offset_t)map->buf,
593110798Ssimokawa		    (vm_offset_t)map->buf + map->buflen - 1);
594170374Ssimokawa	}
595170374Ssimokawa#endif
596110798Ssimokawa	if (op & BUS_DMASYNC_POSTWRITE) {
597110798Ssimokawa		/* Nothing to do.  Handled by the bus controller. */
598170374Ssimokawa	}
599170374Ssimokawa}
600170374Ssimokawa
601110798Ssimokawa/*
602110798Ssimokawa * Common function for DMA-safe memory allocation.  May be called
603110798Ssimokawa * by bus-specific DMA memory allocation functions.
604110798Ssimokawa */
605171513Ssimokawastatic int
606170374Ssimokawanexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags,
607171513Ssimokawa    bus_dmamap_t *mapp)
608170374Ssimokawa{
609170374Ssimokawa	int mflags;
610170374Ssimokawa
611170374Ssimokawa	if (flags & BUS_DMA_NOWAIT)
612249291Swill		mflags = M_NOWAIT;
613170374Ssimokawa	else
614170374Ssimokawa		mflags = M_WAITOK;
615170374Ssimokawa	if (flags & BUS_DMA_ZERO)
616170374Ssimokawa		mflags |= M_ZERO;
617171513Ssimokawa
618170374Ssimokawa	if ((dmat->dt_maxsize <= PAGE_SIZE)) {
619170374Ssimokawa		*vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags);
620170374Ssimokawa	} else {
621110798Ssimokawa		/*
622110798Ssimokawa		 * XXX: Use contigmalloc until it is merged into this facility
623116376Ssimokawa		 * and handles multi-seg allocations.  Nobody is doing multi-seg
624116376Ssimokawa		 * allocations yet though.
625103285Sikob		 */
626103285Sikob		*vaddr = contigmalloc(dmat->dt_maxsize, M_DEVBUF, mflags,
627103285Sikob		    0ul, dmat->dt_lowaddr,
628103285Sikob		    dmat->dt_alignment ? dmat->dt_alignment : 1UL,
629103285Sikob		    dmat->dt_boundary);
630103285Sikob	}
631103285Sikob	if (*vaddr == NULL)
632103285Sikob		return (ENOMEM);
633103285Sikob	return (0);
634103285Sikob}
635103285Sikob
636103285Sikob/*
637103285Sikob * Common function for freeing DMA-safe memory.  May be called by
638103285Sikob * bus-specific DMA memory free functions.
639103285Sikob */
640103285Sikobstatic void
641103285Sikobnexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
642103285Sikob{
643103285Sikob
644103285Sikob	if ((dmat->dt_maxsize <= PAGE_SIZE))
645103285Sikob		free(vaddr, M_DEVBUF);
646103285Sikob	else {
647103285Sikob		contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF);
648103285Sikob	}
649103285Sikob}
650103285Sikob
651103285Sikobstruct bus_dma_methods nexus_dma_methods = {
652103285Sikob	nexus_dmamap_create,
653103285Sikob	nexus_dmamap_destroy,
654103285Sikob	nexus_dmamap_load,
655103285Sikob	nexus_dmamap_load_mbuf,
656103285Sikob	nexus_dmamap_load_uio,
657103285Sikob	nexus_dmamap_unload,
658103285Sikob	nexus_dmamap_sync,
659103285Sikob	nexus_dmamem_alloc,
660103285Sikob	nexus_dmamem_free,
661103285Sikob};
662103285Sikob
663103285Sikobstruct bus_dma_tag nexus_dmatag = {
664103285Sikob	NULL,
665103285Sikob	NULL,
666116376Ssimokawa	8,
667113584Ssimokawa	0,
668116376Ssimokawa	0,
669116376Ssimokawa	0x3ffffffff,
670116376Ssimokawa	NULL,		/* XXX */
671116376Ssimokawa	NULL,
672116376Ssimokawa	0x3ffffffff,	/* XXX */
673116376Ssimokawa	0xff,		/* XXX */
674116376Ssimokawa	0xffffffff,	/* XXX */
675116376Ssimokawa	0,
676116376Ssimokawa	0,
677116376Ssimokawa	0,
678116376Ssimokawa	NULL,
679116376Ssimokawa	NULL,
680116376Ssimokawa	&nexus_dma_methods,
681116376Ssimokawa};
682116376Ssimokawa
683116376Ssimokawa/*
684116376Ssimokawa * Helpers to map/unmap bus memory
685116376Ssimokawa */
686116376Ssimokawaint
687116376Ssimokawasparc64_bus_mem_map(bus_space_tag_t tag, bus_space_handle_t handle,
688116376Ssimokawa    bus_size_t size, int flags, vm_offset_t vaddr, void **hp)
689189928Ssbruno{
690189928Ssbruno	vm_offset_t addr;
691116376Ssimokawa	vm_offset_t sva;
692116376Ssimokawa	vm_offset_t va;
693116376Ssimokawa	vm_paddr_t pa;
694116376Ssimokawa	vm_size_t vsz;
695116376Ssimokawa	u_long pm_flags;
696116376Ssimokawa
697116376Ssimokawa	addr = (vm_offset_t)handle;
698116376Ssimokawa	size = round_page(size);
699116376Ssimokawa	if (size == 0) {
700116376Ssimokawa		printf("sparc64_bus_map: zero size\n");
701116376Ssimokawa		return (EINVAL);
702116376Ssimokawa	}
703116376Ssimokawa	switch (tag->bst_type) {
704116376Ssimokawa	case PCI_CONFIG_BUS_SPACE:
705116376Ssimokawa	case PCI_IO_BUS_SPACE:
706116376Ssimokawa	case PCI_MEMORY_BUS_SPACE:
707116376Ssimokawa		pm_flags = TD_IE;
708116376Ssimokawa		break;
709116376Ssimokawa	default:
710116376Ssimokawa		pm_flags = 0;
711116376Ssimokawa		break;
712116376Ssimokawa	}
713116376Ssimokawa
714116376Ssimokawa	if (!(flags & BUS_SPACE_MAP_CACHEABLE))
715116376Ssimokawa		pm_flags |= TD_E;
716116376Ssimokawa
717116376Ssimokawa	if (vaddr != 0L)
718116376Ssimokawa		sva = trunc_page(vaddr);
719116376Ssimokawa	else {
720127468Ssimokawa		if ((sva = kmem_alloc_nofault(kernel_map, size)) == 0)
721127468Ssimokawa			panic("sparc64_bus_map: cannot allocate virtual "
722127468Ssimokawa			    "memory");
723127468Ssimokawa	}
724116376Ssimokawa
725116376Ssimokawa	/* Preserve page offset. */
726127468Ssimokawa	*hp = (void *)(sva | ((u_long)addr & PAGE_MASK));
727193066Sjamie
728194118Sjamie	pa = trunc_page(addr);
729193066Sjamie	if ((flags & BUS_SPACE_MAP_READONLY) == 0)
730116376Ssimokawa		pm_flags |= TD_W;
731116376Ssimokawa
732116376Ssimokawa	va = sva;
733116376Ssimokawa	vsz = size;
734116376Ssimokawa	do {
735116376Ssimokawa		pmap_kenter_flags(va, pa, pm_flags);
736169117Ssimokawa		va += PAGE_SIZE;
737116376Ssimokawa		pa += PAGE_SIZE;
738116376Ssimokawa	} while ((vsz -= PAGE_SIZE) > 0);
739117350Ssimokawa	tlb_range_demap(kernel_pmap, sva, sva + size - 1);
740116376Ssimokawa	return (0);
741189928Ssbruno}
742116376Ssimokawa
743116376Ssimokawaint
744187993Ssbrunosparc64_bus_mem_unmap(void *bh, bus_size_t size)
745187993Ssbruno{
746116376Ssimokawa	vm_offset_t sva;
747187993Ssbruno	vm_offset_t va;
748169117Ssimokawa	vm_offset_t endva;
749116376Ssimokawa
750187993Ssbruno	sva = trunc_page((vm_offset_t)bh);
751187993Ssbruno	endva = sva + round_page(size);
752187993Ssbruno	for (va = sva; va < endva; va += PAGE_SIZE)
753187993Ssbruno		pmap_kremove_flags(va);
754116376Ssimokawa	tlb_range_demap(kernel_pmap, sva, sva + size - 1);
755116376Ssimokawa	kmem_free(kernel_map, sva, size);
756113584Ssimokawa	return (0);
757113584Ssimokawa}
758113584Ssimokawa
759113584Ssimokawa/*
760113584Ssimokawa * Fake up a bus tag, for use by console drivers in early boot when the regular
761113584Ssimokawa * means to allocate resources are not yet available.
762113584Ssimokawa * Addr is the physical address of the desired start of the handle.
763113584Ssimokawa */
764113584Ssimokawabus_space_handle_t
765116376Ssimokawasparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag)
766117350Ssimokawa{
767189928Ssbruno
768189928Ssbruno	ptag->bst_cookie = NULL;
769189928Ssbruno	ptag->bst_parent = NULL;
770189928Ssbruno	ptag->bst_type = space;
771189928Ssbruno	ptag->bst_bus_barrier = nexus_bus_barrier;
772189928Ssbruno	return (addr);
773189928Ssbruno}
774189928Ssbruno
775189928Ssbruno/*
776189928Ssbruno * Base bus space handlers.
777189928Ssbruno */
778189928Ssbruno
779189928Ssbrunostatic void
780189928Ssbrunonexus_bus_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset,
781189928Ssbruno    bus_size_t size, int flags)
782189928Ssbruno{
783189928Ssbruno
784189928Ssbruno	/*
785189928Ssbruno	 * We have lots of alternatives depending on whether we're
786189928Ssbruno	 * synchronizing loads with loads, loads with stores, stores
787189928Ssbruno	 * with loads, or stores with stores.  The only ones that seem
788189928Ssbruno	 * generic are #Sync and #MemIssue.  I'll use #Sync for safety.
789189928Ssbruno	 */
790189928Ssbruno	switch(flags) {
791189928Ssbruno	case BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE:
792103285Sikob	case BUS_SPACE_BARRIER_READ:
793106790Ssimokawa	case BUS_SPACE_BARRIER_WRITE:
794103285Sikob		membar(Sync);
795106790Ssimokawa		break;
796103285Sikob	default:
797103285Sikob		panic("sparc64_bus_barrier: unknown flags");
798106543Ssimokawa	}
799103285Sikob	return;
800103285Sikob}
801106543Ssimokawa
802103285Sikobstruct bus_space_tag nexus_bustag = {
803103285Sikob	NULL,				/* cookie */
804103285Sikob	NULL,				/* parent bus tag */
805103285Sikob	UPA_BUS_SPACE,			/* type */
806103285Sikob	nexus_bus_barrier,		/* bus_space_barrier */
807103285Sikob};
808103285Sikob