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