1/*-
2 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
7 * NASA Ames Research Center.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30/*-
31 * Copyright (c) 1992, 1993
32 *	The Regents of the University of California.  All rights reserved.
33 *
34 * This software was developed by the Computer Systems Engineering group
35 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
36 * contributed to Berkeley.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 4. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 */
62/*-
63 * Copyright (c) 1997, 1998 Justin T. Gibbs.
64 * All rights reserved.
65 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
66 *
67 * Redistribution and use in source and binary forms, with or without
68 * modification, are permitted provided that the following conditions
69 * are met:
70 * 1. Redistributions of source code must retain the above copyright
71 *    notice, this list of conditions, and the following disclaimer,
72 *    without modification, immediately at the beginning of the file.
73 * 2. The name of the author may not be used to endorse or promote products
74 *    derived from this software without specific prior written permission.
75 *
76 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
80 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
86 * SUCH DAMAGE.
87 *
88 *	from: @(#)machdep.c	8.6 (Berkeley) 1/14/94
89 *	from: NetBSD: machdep.c,v 1.221 2008/04/28 20:23:37 martin Exp
90 *	and
91 *	from: FreeBSD: src/sys/i386/i386/busdma_machdep.c,v 1.24 2001/08/15
92 */
93
94#include <sys/cdefs.h>
95__FBSDID("$FreeBSD$");
96
97#include <sys/param.h>
98#include <sys/bus.h>
99#include <sys/lock.h>
100#include <sys/malloc.h>
101#include <sys/mutex.h>
102#include <sys/proc.h>
103#include <sys/rman.h>
104#include <sys/smp.h>
105#include <sys/systm.h>
106
107#include <vm/vm.h>
108#include <vm/vm_extern.h>
109#include <vm/vm_kern.h>
110#include <vm/vm_page.h>
111#include <vm/vm_param.h>
112#include <vm/vm_map.h>
113
114#include <machine/asi.h>
115#include <machine/atomic.h>
116#include <machine/bus.h>
117#include <machine/bus_private.h>
118#include <machine/cache.h>
119#include <machine/smp.h>
120#include <machine/tlb.h>
121
122/* ASIs for bus access */
123const int bus_type_asi[] = {
124	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* nexus */
125	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* SBus */
126	ASI_PHYS_BYPASS_EC_WITH_EBIT_L,		/* PCI configuration space */
127	ASI_PHYS_BYPASS_EC_WITH_EBIT_L,		/* PCI memory space */
128	ASI_PHYS_BYPASS_EC_WITH_EBIT_L,		/* PCI I/O space */
129	0
130};
131
132const int bus_stream_asi[] = {
133	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* nexus */
134	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* SBus */
135	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* PCI configuration space */
136	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* PCI memory space */
137	ASI_PHYS_BYPASS_EC_WITH_EBIT,		/* PCI I/O space */
138	0
139};
140
141/*
142 * Convenience function for manipulating driver locks from busdma (during
143 * busdma_swi, for example).  Drivers that don't provide their own locks
144 * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
145 * non-mutex locking scheme don't have to use this at all.
146 */
147void
148busdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
149{
150	struct mtx *dmtx;
151
152	dmtx = (struct mtx *)arg;
153	switch (op) {
154	case BUS_DMA_LOCK:
155		mtx_lock(dmtx);
156		break;
157	case BUS_DMA_UNLOCK:
158		mtx_unlock(dmtx);
159		break;
160	default:
161		panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
162	}
163}
164
165/*
166 * dflt_lock should never get called.  It gets put into the dma tag when
167 * lockfunc == NULL, which is only valid if the maps that are associated
168 * with the tag are meant to never be defered.
169 * XXX Should have a way to identify which driver is responsible here.
170 */
171static void
172dflt_lock(void *arg, bus_dma_lock_op_t op)
173{
174
175	panic("driver error: busdma dflt_lock called");
176}
177
178/*
179 * Allocate a device specific dma_tag.
180 */
181int
182bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
183    bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
184    bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
185    int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
186    void *lockfuncarg, bus_dma_tag_t *dmat)
187{
188	bus_dma_tag_t newtag;
189
190	/* Return a NULL tag on failure */
191	*dmat = NULL;
192
193	/* Enforce the usage of BUS_GET_DMA_TAG(). */
194	if (parent == NULL)
195		panic("%s: parent DMA tag NULL", __func__);
196
197	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
198	if (newtag == NULL)
199		return (ENOMEM);
200
201	/*
202	 * The method table pointer and the cookie need to be taken over from
203	 * the parent.
204	 */
205	newtag->dt_cookie = parent->dt_cookie;
206	newtag->dt_mt = parent->dt_mt;
207
208	newtag->dt_parent = parent;
209	newtag->dt_alignment = alignment;
210	newtag->dt_boundary = boundary;
211	newtag->dt_lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1);
212	newtag->dt_highaddr = trunc_page((vm_offset_t)highaddr) +
213	    (PAGE_SIZE - 1);
214	newtag->dt_filter = filter;
215	newtag->dt_filterarg = filterarg;
216	newtag->dt_maxsize = maxsize;
217	newtag->dt_nsegments = nsegments;
218	newtag->dt_maxsegsz = maxsegsz;
219	newtag->dt_flags = flags;
220	newtag->dt_ref_count = 1; /* Count ourselves */
221	newtag->dt_map_count = 0;
222
223	if (lockfunc != NULL) {
224		newtag->dt_lockfunc = lockfunc;
225		newtag->dt_lockfuncarg = lockfuncarg;
226	} else {
227		newtag->dt_lockfunc = dflt_lock;
228		newtag->dt_lockfuncarg = NULL;
229	}
230
231	newtag->dt_segments = NULL;
232
233	/* Take into account any restrictions imposed by our parent tag. */
234	newtag->dt_lowaddr = ulmin(parent->dt_lowaddr, newtag->dt_lowaddr);
235	newtag->dt_highaddr = ulmax(parent->dt_highaddr, newtag->dt_highaddr);
236	if (newtag->dt_boundary == 0)
237		newtag->dt_boundary = parent->dt_boundary;
238	else if (parent->dt_boundary != 0)
239		newtag->dt_boundary = ulmin(parent->dt_boundary,
240		    newtag->dt_boundary);
241	atomic_add_int(&parent->dt_ref_count, 1);
242
243	if (newtag->dt_boundary > 0)
244		newtag->dt_maxsegsz = ulmin(newtag->dt_maxsegsz,
245		    newtag->dt_boundary);
246
247	*dmat = newtag;
248	return (0);
249}
250
251int
252bus_dma_tag_destroy(bus_dma_tag_t dmat)
253{
254	bus_dma_tag_t parent;
255
256	if (dmat != NULL) {
257		if (dmat->dt_map_count != 0)
258			return (EBUSY);
259		while (dmat != NULL) {
260			parent = dmat->dt_parent;
261			atomic_subtract_int(&dmat->dt_ref_count, 1);
262			if (dmat->dt_ref_count == 0) {
263				if (dmat->dt_segments != NULL)
264					free(dmat->dt_segments, M_DEVBUF);
265				free(dmat, M_DEVBUF);
266				/*
267				 * Last reference count, so
268				 * release our reference
269				 * count on our parent.
270				 */
271				dmat = parent;
272			} else
273				dmat = NULL;
274		}
275	}
276	return (0);
277}
278
279/* Allocate/free a tag, and do the necessary management work. */
280int
281sparc64_dma_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp)
282{
283
284	if (dmat->dt_segments == NULL) {
285		dmat->dt_segments = (bus_dma_segment_t *)malloc(
286		    sizeof(bus_dma_segment_t) * dmat->dt_nsegments, M_DEVBUF,
287		    M_NOWAIT);
288		if (dmat->dt_segments == NULL)
289			return (ENOMEM);
290	}
291	*mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO);
292	if (*mapp == NULL)
293		return (ENOMEM);
294
295	SLIST_INIT(&(*mapp)->dm_reslist);
296	dmat->dt_map_count++;
297	return (0);
298}
299
300void
301sparc64_dma_free_map(bus_dma_tag_t dmat, bus_dmamap_t map)
302{
303
304	free(map, M_DEVBUF);
305	dmat->dt_map_count--;
306}
307
308static int
309nexus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
310{
311
312	return (sparc64_dma_alloc_map(dmat, mapp));
313}
314
315static int
316nexus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
317{
318
319	sparc64_dma_free_map(dmat, map);
320	return (0);
321}
322
323/*
324 * Add a single contiguous physical range to the segment list.
325 */
326static int
327nexus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
328    bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
329{
330	bus_addr_t baddr, bmask;
331	int seg;
332
333	/*
334	 * Make sure we don't cross any boundaries.
335	 */
336	bmask  = ~(dmat->dt_boundary - 1);
337	if (dmat->dt_boundary > 0) {
338		baddr = (curaddr + dmat->dt_boundary) & bmask;
339		if (sgsize > (baddr - curaddr))
340			sgsize = (baddr - curaddr);
341	}
342
343	/*
344	 * Insert chunk into a segment, coalescing with
345	 * previous segment if possible.
346	 */
347	seg = *segp;
348	if (seg == -1) {
349		seg = 0;
350		segs[seg].ds_addr = curaddr;
351		segs[seg].ds_len = sgsize;
352	} else {
353		if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
354		    (segs[seg].ds_len + sgsize) <= dmat->dt_maxsegsz &&
355		    (dmat->dt_boundary == 0 ||
356		    (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
357			segs[seg].ds_len += sgsize;
358		else {
359			if (++seg >= dmat->dt_nsegments)
360				return (0);
361			segs[seg].ds_addr = curaddr;
362			segs[seg].ds_len = sgsize;
363		}
364	}
365	*segp = seg;
366	return (sgsize);
367}
368
369/*
370 * Utility function to load a physical buffer.  segp contains
371 * the starting segment on entrace, and the ending segment on exit.
372 */
373static int
374nexus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
375    bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp)
376{
377	bus_addr_t curaddr;
378	bus_size_t sgsize;
379
380	if (segs == NULL)
381		segs = dmat->dt_segments;
382
383	curaddr = buf;
384	while (buflen > 0) {
385		sgsize = MIN(buflen, dmat->dt_maxsegsz);
386		sgsize = nexus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
387		    segp);
388		if (sgsize == 0)
389			break;
390		curaddr += sgsize;
391		buflen -= sgsize;
392	}
393
394	/*
395	 * Did we fit?
396	 */
397	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
398}
399
400/*
401 * Utility function to load a linear buffer.  segp contains
402 * the starting segment on entrace, and the ending segment on exit.
403 */
404static int
405nexus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
406    bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
407    int *segp)
408{
409	bus_size_t sgsize;
410	bus_addr_t curaddr;
411	vm_offset_t vaddr = (vm_offset_t)buf;
412
413	if (segs == NULL)
414		segs = dmat->dt_segments;
415
416	while (buflen > 0) {
417		/*
418		 * Get the physical address for this segment.
419		 */
420		if (pmap == kernel_pmap)
421			curaddr = pmap_kextract(vaddr);
422		else
423			curaddr = pmap_extract(pmap, vaddr);
424
425		/*
426		 * Compute the segment size, and adjust counts.
427		 */
428		sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
429		if (sgsize > dmat->dt_maxsegsz)
430			sgsize = dmat->dt_maxsegsz;
431		if (buflen < sgsize)
432			sgsize = buflen;
433
434		sgsize = nexus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
435		    segp);
436		if (sgsize == 0)
437			break;
438
439		vaddr += sgsize;
440		buflen -= sgsize;
441	}
442
443	/*
444	 * Did we fit?
445	 */
446	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
447}
448
449static void
450nexus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
451    struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg)
452{
453
454}
455
456static bus_dma_segment_t *
457nexus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map,
458    bus_dma_segment_t *segs, int nsegs, int error)
459{
460
461	if (segs == NULL)
462		segs = dmat->dt_segments;
463	return (segs);
464}
465
466/*
467 * Common function for unloading a DMA map.  May be called by
468 * bus-specific DMA map unload functions.
469 */
470static void
471nexus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
472{
473
474	map->dm_flags &= ~DMF_LOADED;
475}
476
477/*
478 * Common function for DMA map synchronization.  May be called
479 * by bus-specific DMA map synchronization functions.
480 */
481static void
482nexus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
483{
484
485	/*
486	 * We sync out our caches, but the bus must do the same.
487	 *
488	 * Actually a #Sync is expensive.  We should optimize.
489	 */
490	if ((op & BUS_DMASYNC_PREREAD) || (op & BUS_DMASYNC_PREWRITE)) {
491		/*
492		 * Don't really need to do anything, but flush any pending
493		 * writes anyway.
494		 */
495		membar(Sync);
496	}
497	if (op & BUS_DMASYNC_POSTWRITE) {
498		/* Nothing to do.  Handled by the bus controller. */
499	}
500}
501
502/*
503 * Common function for DMA-safe memory allocation.  May be called
504 * by bus-specific DMA memory allocation functions.
505 */
506static int
507nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags,
508    bus_dmamap_t *mapp)
509{
510	int mflags;
511
512	if (flags & BUS_DMA_NOWAIT)
513		mflags = M_NOWAIT;
514	else
515		mflags = M_WAITOK;
516	if (flags & BUS_DMA_ZERO)
517		mflags |= M_ZERO;
518
519	/*
520	 * XXX:
521	 * (dmat->dt_alignment <= dmat->dt_maxsize) is just a quick hack; the
522	 * exact alignment guarantees of malloc need to be nailed down, and
523	 * the code below should be rewritten to take that into account.
524	 *
525	 * In the meantime, we'll warn the user if malloc gets it wrong.
526	 */
527	if (dmat->dt_maxsize <= PAGE_SIZE &&
528	    dmat->dt_alignment <= dmat->dt_maxsize)
529		*vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags);
530	else {
531		/*
532		 * XXX use contigmalloc until it is merged into this
533		 * facility and handles multi-seg allocations.  Nobody
534		 * is doing multi-seg allocations yet though.
535		 */
536		*vaddr = contigmalloc(dmat->dt_maxsize, M_DEVBUF, mflags,
537		    0ul, dmat->dt_lowaddr,
538		    dmat->dt_alignment ? dmat->dt_alignment : 1UL,
539		    dmat->dt_boundary);
540	}
541	if (*vaddr == NULL)
542		return (ENOMEM);
543	if (vtophys(*vaddr) % dmat->dt_alignment)
544		printf("%s: failed to align memory properly.\n", __func__);
545	return (0);
546}
547
548/*
549 * Common function for freeing DMA-safe memory.  May be called by
550 * bus-specific DMA memory free functions.
551 */
552static void
553nexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
554{
555
556	if (dmat->dt_maxsize <= PAGE_SIZE &&
557	    dmat->dt_alignment < dmat->dt_maxsize)
558		free(vaddr, M_DEVBUF);
559	else
560		contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF);
561}
562
563static struct bus_dma_methods nexus_dma_methods = {
564	nexus_dmamap_create,
565	nexus_dmamap_destroy,
566	nexus_dmamap_load_phys,
567	nexus_dmamap_load_buffer,
568	nexus_dmamap_waitok,
569	nexus_dmamap_complete,
570	nexus_dmamap_unload,
571	nexus_dmamap_sync,
572	nexus_dmamem_alloc,
573	nexus_dmamem_free,
574};
575
576struct bus_dma_tag nexus_dmatag = {
577	NULL,
578	NULL,
579	1,
580	0,
581	~0,
582	~0,
583	NULL,		/* XXX */
584	NULL,
585	~0,
586	~0,
587	~0,
588	0,
589	0,
590	0,
591	NULL,
592	NULL,
593	NULL,
594	&nexus_dma_methods,
595};
596
597/*
598 * Helpers to map/unmap bus memory
599 */
600int
601bus_space_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
602    int flags, bus_space_handle_t *handlep)
603{
604
605	return (sparc64_bus_mem_map(tag, address, size, flags, 0, handlep));
606}
607
608int
609sparc64_bus_mem_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size,
610    int flags, vm_offset_t vaddr, bus_space_handle_t *hp)
611{
612	vm_offset_t sva;
613	vm_offset_t va;
614	vm_paddr_t pa;
615	vm_size_t vsz;
616	u_long pm_flags;
617
618	/*
619	 * Given that we use physical access for bus_space(9) there's no need
620	 * need to map anything in unless BUS_SPACE_MAP_LINEAR is requested.
621	 */
622	if ((flags & BUS_SPACE_MAP_LINEAR) == 0) {
623		*hp = addr;
624		return (0);
625	}
626
627	if (tag->bst_cookie == NULL) {
628		printf("%s: resource cookie not set\n", __func__);
629		return (EINVAL);
630	}
631
632	size = round_page(size);
633	if (size == 0) {
634		printf("%s: zero size\n", __func__);
635		return (EINVAL);
636	}
637
638	switch (tag->bst_type) {
639	case PCI_CONFIG_BUS_SPACE:
640	case PCI_IO_BUS_SPACE:
641	case PCI_MEMORY_BUS_SPACE:
642		pm_flags = TD_IE;
643		break;
644	default:
645		pm_flags = 0;
646		break;
647	}
648
649	if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0)
650		pm_flags |= TD_E;
651
652	if (vaddr != 0L)
653		sva = trunc_page(vaddr);
654	else {
655		if ((sva = kva_alloc(size)) == 0)
656			panic("%s: cannot allocate virtual memory", __func__);
657	}
658
659	pa = trunc_page(addr);
660	if ((flags & BUS_SPACE_MAP_READONLY) == 0)
661		pm_flags |= TD_W;
662
663	va = sva;
664	vsz = size;
665	do {
666		pmap_kenter_flags(va, pa, pm_flags);
667		va += PAGE_SIZE;
668		pa += PAGE_SIZE;
669	} while ((vsz -= PAGE_SIZE) > 0);
670	tlb_range_demap(kernel_pmap, sva, sva + size - 1);
671
672	/* Note: we preserve the page offset. */
673	rman_set_virtual(tag->bst_cookie, (void *)(sva | (addr & PAGE_MASK)));
674	return (0);
675}
676
677void
678bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t handle,
679    bus_size_t size)
680{
681
682	sparc64_bus_mem_unmap(tag, handle, size);
683}
684
685int
686sparc64_bus_mem_unmap(bus_space_tag_t tag, bus_space_handle_t handle,
687    bus_size_t size)
688{
689	vm_offset_t sva;
690	vm_offset_t va;
691	vm_offset_t endva;
692
693	if (tag->bst_cookie == NULL ||
694	    (sva = (vm_offset_t)rman_get_virtual(tag->bst_cookie)) == 0)
695		return (0);
696	sva = trunc_page(sva);
697	endva = sva + round_page(size);
698	for (va = sva; va < endva; va += PAGE_SIZE)
699		pmap_kremove_flags(va);
700	tlb_range_demap(kernel_pmap, sva, sva + size - 1);
701	kva_free(sva, size);
702	return (0);
703}
704
705/*
706 * Fake up a bus tag, for use by console drivers in early boot when the
707 * regular means to allocate resources are not yet available.
708 * Addr is the physical address of the desired start of the handle.
709 */
710bus_space_handle_t
711sparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag)
712{
713
714	ptag->bst_cookie = NULL;
715	ptag->bst_type = space;
716	return (addr);
717}
718
719/*
720 * Allocate a bus tag
721 */
722bus_space_tag_t
723sparc64_alloc_bus_tag(void *cookie, int type)
724{
725	bus_space_tag_t bt;
726
727	bt = malloc(sizeof(struct bus_space_tag), M_DEVBUF, M_NOWAIT);
728	if (bt == NULL)
729		return (NULL);
730	bt->bst_cookie = cookie;
731	bt->bst_type = type;
732	return (bt);
733}
734
735struct bus_space_tag nexus_bustag = {
736	NULL,				/* cookie */
737	NEXUS_BUS_SPACE			/* type */
738};
739