]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sun4v/sun4v/bus_machdep.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / sun4v / sun4v / bus_machdep.c
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  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the NetBSD
20  *      Foundation, Inc. and its contributors.
21  * 4. Neither the name of The NetBSD Foundation nor the names of its
22  *    contributors may be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 /*-
38  * Copyright (c) 1992, 1993
39  *      The Regents of the University of California.  All rights reserved.
40  *
41  * This software was developed by the Computer Systems Engineering group
42  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43  * contributed to Berkeley.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  * 1. Redistributions of source code must retain the above copyright
49  *    notice, this list of conditions and the following disclaimer.
50  * 2. Redistributions in binary form must reproduce the above copyright
51  *    notice, this list of conditions and the following disclaimer in the
52  *    documentation and/or other materials provided with the distribution.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  */
69 /*-
70  * Copyright (c) 1997, 1998 Justin T. Gibbs.
71  * All rights reserved.
72  * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
73  *
74  * Redistribution and use in source and binary forms, with or without
75  * modification, are permitted provided that the following conditions
76  * are met:
77  * 1. Redistributions of source code must retain the above copyright
78  *    notice, this list of conditions, and the following disclaimer,
79  *    without modification, immediately at the beginning of the file.
80  * 2. The name of the author may not be used to endorse or promote products
81  *    derived from this software without specific prior written permission.
82  *
83  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
84  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
85  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
86  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
87  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
88  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
89  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
90  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
91  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
92  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
93  * SUCH DAMAGE.
94  *
95  *      from: @(#)machdep.c     8.6 (Berkeley) 1/14/94
96  *      from: NetBSD: machdep.c,v 1.111 2001/09/15 07:13:40 eeh Exp
97  *      and
98  *      from: FreeBSD: src/sys/i386/i386/busdma_machdep.c,v 1.24 2001/08/15
99  */
100
101 #include <sys/cdefs.h>
102 __FBSDID("$FreeBSD$");
103
104 #include <sys/param.h>
105 #include <sys/bus.h>
106 #include <sys/lock.h>
107 #include <sys/malloc.h>
108 #include <sys/mbuf.h>
109 #include <sys/mutex.h>
110 #include <sys/proc.h>
111 #include <sys/smp.h>
112 #include <sys/systm.h>
113 #include <sys/uio.h>
114
115 #include <vm/vm.h>
116 #include <vm/vm_extern.h>
117 #include <vm/vm_kern.h>
118 #include <vm/vm_page.h>
119 #include <vm/vm_param.h>
120 #include <vm/vm_map.h>
121
122 #include <machine/asi.h>
123 #include <machine/atomic.h>
124 #include <machine/bus.h>
125 #include <machine/bus_private.h>
126 #include <machine/smp.h>
127 #include <machine/tlb.h>
128
129 static void nexus_bus_barrier(bus_space_tag_t, bus_space_handle_t,
130     bus_size_t, bus_size_t, int);
131
132 /* ASIs for bus access */
133 const int bus_type_asi[] = {
134         ASI_REAL_IO,            /* nexus */
135         ASI_REAL_IO,            /* SBus */
136         ASI_REAL_IO_L,          /* PCI configuration space */
137         ASI_REAL_IO_L,          /* PCI memory space */
138         ASI_REAL_IO_L,          /* PCI I/O space */
139         0
140 };
141
142 const int bus_stream_asi[] = {
143         ASI_REAL_IO,            /* nexus */
144         ASI_REAL_IO,            /* SBus */
145         ASI_REAL_IO,            /* PCI configuration space */
146         ASI_REAL_IO,            /* PCI memory space */
147         ASI_REAL_IO,            /* PCI I/O space */
148         0
149 };
150
151 /*
152  * Convenience function for manipulating driver locks from busdma (during
153  * busdma_swi, for example).  Drivers that don't provide their own locks
154  * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
155  * non-mutex locking scheme don't have to use this at all.
156  */
157 void
158 busdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
159 {
160         struct mtx *dmtx;
161
162         dmtx = (struct mtx *)arg;
163         switch (op) {
164         case BUS_DMA_LOCK:
165                 mtx_lock(dmtx);
166                 break;
167         case BUS_DMA_UNLOCK:
168                 mtx_unlock(dmtx);
169                 break;
170         default:
171                 panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
172         }
173 }
174
175 /*
176  * dflt_lock should never get called.  It gets put into the dma tag when
177  * lockfunc == NULL, which is only valid if the maps that are associated
178  * with the tag are meant to never be defered.
179  * XXX Should have a way to identify which driver is responsible here.
180  */
181 static void
182 dflt_lock(void *arg, bus_dma_lock_op_t op)
183 {
184 #ifdef INVARIANTS
185         panic("driver error: busdma dflt_lock called");
186 #else
187         printf("DRIVER_ERROR: busdma dflt_lock called\n");
188 #endif
189 }
190
191 /*
192  * Since there is no way for a device to obtain a dma tag from its parent
193  * we use this kluge to handle different the different supported bus systems.
194  * The sparc64_root_dma_tag is used as parent for tags that have none, so that
195  * the correct methods will be used.
196  */
197 bus_dma_tag_t sparc64_root_dma_tag;
198
199 /*
200  * Allocate a device specific dma_tag.
201  */
202 int
203 bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
204     bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
205     bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
206     int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
207     void *lockfuncarg, bus_dma_tag_t *dmat)
208 {
209         bus_dma_tag_t impptag;
210         bus_dma_tag_t newtag;
211
212         /* Return a NULL tag on failure */
213         *dmat = NULL;
214
215         newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
216         if (newtag == NULL)
217                 return (ENOMEM);
218
219         impptag = parent != NULL ? parent : sparc64_root_dma_tag;
220         /*
221          * The method table pointer and the cookie need to be taken over from
222          * the parent or the root tag.
223          */
224         newtag->dt_cookie = impptag->dt_cookie;
225         newtag->dt_mt = impptag->dt_mt;
226
227         newtag->dt_parent = parent;
228         newtag->dt_alignment = alignment;
229         newtag->dt_boundary = boundary;
230         newtag->dt_lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1);
231         newtag->dt_highaddr = trunc_page((vm_offset_t)highaddr) +
232             (PAGE_SIZE - 1);
233         newtag->dt_filter = filter;
234         newtag->dt_filterarg = filterarg;
235         newtag->dt_maxsize = maxsize;
236         newtag->dt_nsegments = nsegments;
237         newtag->dt_maxsegsz = maxsegsz;
238         newtag->dt_flags = flags;
239         newtag->dt_ref_count = 1; /* Count ourselves */
240         newtag->dt_map_count = 0;
241
242         if (lockfunc != NULL) {
243                 newtag->dt_lockfunc = lockfunc;
244                 newtag->dt_lockfuncarg = lockfuncarg;
245         } else {
246                 newtag->dt_lockfunc = dflt_lock;
247                 newtag->dt_lockfuncarg = NULL;
248         }
249
250         newtag->dt_segments = NULL;
251
252         /* Take into account any restrictions imposed by our parent tag. */
253         if (parent != NULL) {
254                 newtag->dt_lowaddr = ulmin(parent->dt_lowaddr,
255                     newtag->dt_lowaddr);
256                 newtag->dt_highaddr = ulmax(parent->dt_highaddr,
257                     newtag->dt_highaddr);
258                 if (newtag->dt_boundary == 0)
259                         newtag->dt_boundary = parent->dt_boundary;
260                 else if (parent->dt_boundary != 0)
261                         newtag->dt_boundary = ulmin(parent->dt_boundary,
262                             newtag->dt_boundary);
263                 atomic_add_int(&parent->dt_ref_count, 1);
264         }
265
266         if (newtag->dt_boundary > 0)
267                 newtag->dt_maxsegsz = ulmin(newtag->dt_maxsegsz,
268                     newtag->dt_boundary);
269
270         *dmat = newtag;
271         return (0);
272 }
273
274 int
275 bus_dma_tag_destroy(bus_dma_tag_t dmat)
276 {
277         bus_dma_tag_t parent;
278
279         if (dmat != NULL) {
280                 if (dmat->dt_map_count != 0)
281                         return (EBUSY);
282                 while (dmat != NULL) {
283                         parent = dmat->dt_parent;
284                         atomic_subtract_int(&dmat->dt_ref_count, 1);
285                         if (dmat->dt_ref_count == 0) {
286                                 if (dmat->dt_segments != NULL)
287                                         free(dmat->dt_segments, M_DEVBUF);
288                                 free(dmat, M_DEVBUF);
289                                 /*
290                                  * Last reference count, so
291                                  * release our reference
292                                  * count on our parent.
293                                  */
294                                 dmat = parent;
295                         } else
296                                 dmat = NULL;
297                 }
298         }
299         return (0);
300 }
301
302 /* Allocate/free a tag, and do the necessary management work. */
303 int
304 sparc64_dma_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp)
305 {
306
307         if (dmat->dt_segments == NULL) {
308                 dmat->dt_segments = (bus_dma_segment_t *)malloc(
309                     sizeof(bus_dma_segment_t) * dmat->dt_nsegments, M_DEVBUF,
310                     M_NOWAIT);
311                 if (dmat->dt_segments == NULL)
312                         return (ENOMEM);
313         }
314         *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO);
315         if (*mapp == NULL)
316                 return (ENOMEM);
317
318         SLIST_INIT(&(*mapp)->dm_reslist);
319         dmat->dt_map_count++;
320         return (0);
321 }
322
323 void
324 sparc64_dma_free_map(bus_dma_tag_t dmat, bus_dmamap_t map)
325 {
326
327         free(map, M_DEVBUF);
328         dmat->dt_map_count--;
329 }
330
331 static int
332 nexus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
333 {
334
335         return (sparc64_dma_alloc_map(dmat, mapp));
336 }
337
338 static int
339 nexus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
340 {
341
342         sparc64_dma_free_map(dmat, map);
343         return (0);
344 }
345
346 /*
347  * Utility function to load a linear buffer.  lastaddrp holds state
348  * between invocations (for multiple-buffer loads).  segp contains
349  * the starting segment on entrace, and the ending segment on exit.
350  * first indicates if this is the first invocation of this function.
351  */
352 static int
353 _nexus_dmamap_load_buffer(bus_dma_tag_t dmat, void *buf, bus_size_t buflen,
354     struct thread *td, int flags, bus_addr_t *lastaddrp,
355     bus_dma_segment_t *segs, int *segp, int first)
356 {
357         bus_size_t sgsize;
358         bus_addr_t curaddr, lastaddr, baddr, bmask;
359         vm_offset_t vaddr = (vm_offset_t)buf;
360         int seg;
361         pmap_t pmap;
362
363         if (td != NULL)
364                 pmap = vmspace_pmap(td->td_proc->p_vmspace);
365         else
366                 pmap = NULL;
367
368         lastaddr = *lastaddrp;
369         bmask  = ~(dmat->dt_boundary - 1);
370
371         for (seg = *segp; buflen > 0 ; ) {
372                 /*
373                  * Get the physical address for this segment.
374                  */
375                 if (pmap)
376                         curaddr = pmap_extract(pmap, vaddr);
377                 else
378                         curaddr = pmap_kextract(vaddr);
379
380                 /*
381                  * Compute the segment size, and adjust counts.
382                  */
383                 sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
384                 if (sgsize > dmat->dt_maxsegsz)
385                         sgsize = dmat->dt_maxsegsz;
386                 if (buflen < sgsize)
387                         sgsize = buflen;
388
389                 /*
390                  * Make sure we don't cross any boundaries.
391                  */
392                 if (dmat->dt_boundary > 0) {
393                         baddr = (curaddr + dmat->dt_boundary) & bmask;
394                         if (sgsize > (baddr - curaddr))
395                                 sgsize = (baddr - curaddr);
396                 }
397
398                 /*
399                  * Insert chunk into a segment, coalescing with
400                  * previous segment if possible.
401                  */
402                 if (first) {
403                         segs[seg].ds_addr = curaddr;
404                         segs[seg].ds_len = sgsize;
405                         first = 0;
406                 } else {
407                         if (curaddr == lastaddr &&
408                             (segs[seg].ds_len + sgsize) <= dmat->dt_maxsegsz &&
409                             (dmat->dt_boundary == 0 ||
410                             (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
411                                 segs[seg].ds_len += sgsize;
412                         else {
413                                 if (++seg >= dmat->dt_nsegments)
414                                         break;
415                                 segs[seg].ds_addr = curaddr;
416                                 segs[seg].ds_len = sgsize;
417                         }
418                 }
419
420                 lastaddr = curaddr + sgsize;
421                 vaddr += sgsize;
422                 buflen -= sgsize;
423         }
424
425         *segp = seg;
426         *lastaddrp = lastaddr;
427
428         /*
429          * Did we fit?
430          */
431         return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
432 }
433
434 /*
435  * Common function for loading a DMA map with a linear buffer.  May
436  * be called by bus-specific DMA map load functions.
437  *
438  * Most SPARCs have IOMMUs in the bus controllers.  In those cases
439  * they only need one segment and will use virtual addresses for DVMA.
440  * Those bus controllers should intercept these vectors and should
441  * *NEVER* call nexus_dmamap_load() which is used only by devices that
442  * bypass DVMA.
443  */
444 static int
445 nexus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
446     bus_size_t buflen, bus_dmamap_callback_t *callback, void *callback_arg,
447     int flags)
448 {
449         bus_addr_t lastaddr;
450         int error, nsegs;
451
452         error = _nexus_dmamap_load_buffer(dmat, buf, buflen, NULL, flags,
453             &lastaddr, dmat->dt_segments, &nsegs, 1);
454
455         if (error == 0) {
456                 (*callback)(callback_arg, dmat->dt_segments, nsegs + 1, 0);
457                 map->dm_flags |= DMF_LOADED;
458         } else
459                 (*callback)(callback_arg, NULL, 0, error);
460
461         return (0);
462 }
463
464 /*
465  * Like nexus_dmamap_load(), but for mbufs.
466  */
467 static int
468 nexus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
469     bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
470 {
471         int nsegs, error;
472
473         M_ASSERTPKTHDR(m0);
474
475         nsegs = 0;
476         error = 0;
477         if (m0->m_pkthdr.len <= dmat->dt_maxsize) {
478                 int first = 1;
479                 bus_addr_t lastaddr = 0;
480                 struct mbuf *m;
481
482                 for (m = m0; m != NULL && error == 0; m = m->m_next) {
483                         if (m->m_len > 0) {
484                                 error = _nexus_dmamap_load_buffer(dmat,
485                                     m->m_data, m->m_len,NULL, flags, &lastaddr,
486                                     dmat->dt_segments, &nsegs, first);
487                                 first = 0;
488                         }
489                 }
490         } else {
491                 error = EINVAL;
492         }
493
494         if (error) {
495                 /* force "no valid mappings" in callback */
496                 (*callback)(callback_arg, dmat->dt_segments, 0, 0, error);
497         } else {
498                 map->dm_flags |= DMF_LOADED;
499                 (*callback)(callback_arg, dmat->dt_segments, nsegs + 1,
500                     m0->m_pkthdr.len, error);
501         }
502         return (error);
503 }
504
505 static int
506 nexus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
507     bus_dma_segment_t *segs, int *nsegs, int flags)
508 {
509         int error;
510
511         M_ASSERTPKTHDR(m0);
512
513         *nsegs = 0;
514         error = 0;
515         if (m0->m_pkthdr.len <= dmat->dt_maxsize) {
516                 int first = 1;
517                 bus_addr_t lastaddr = 0;
518                 struct mbuf *m;
519
520                 for (m = m0; m != NULL && error == 0; m = m->m_next) {
521                         if (m->m_len > 0) {
522                                 error = _nexus_dmamap_load_buffer(dmat,
523                                     m->m_data, m->m_len,NULL, flags, &lastaddr,
524                                     segs, nsegs, first);
525                                 first = 0;
526                         }
527                 }
528         } else {
529                 error = EINVAL;
530         }
531
532         ++*nsegs;
533         return (error);
534 }
535
536 /*
537  * Like nexus_dmamap_load(), but for uios.
538  */
539 static int
540 nexus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
541     bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
542 {
543         bus_addr_t lastaddr;
544         int nsegs, error, first, i;
545         bus_size_t resid;
546         struct iovec *iov;
547         struct thread *td = NULL;
548
549         resid = uio->uio_resid;
550         iov = uio->uio_iov;
551
552         if (uio->uio_segflg == UIO_USERSPACE) {
553                 td = uio->uio_td;
554                 KASSERT(td != NULL, ("%s: USERSPACE but no proc", __func__));
555         }
556
557         nsegs = 0;
558         error = 0;
559         first = 1;
560         for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
561                 /*
562                  * Now at the first iovec to load.  Load each iovec
563                  * until we have exhausted the residual count.
564                  */
565                 bus_size_t minlen =
566                         resid < iov[i].iov_len ? resid : iov[i].iov_len;
567                 caddr_t addr = (caddr_t) iov[i].iov_base;
568
569                 if (minlen > 0) {
570                         error = _nexus_dmamap_load_buffer(dmat, addr, minlen,
571                             td, flags, &lastaddr, dmat->dt_segments, &nsegs,
572                             first);
573                         first = 0;
574
575                         resid -= minlen;
576                 }
577         }
578
579         if (error) {
580                 /* force "no valid mappings" in callback */
581                 (*callback)(callback_arg, dmat->dt_segments, 0, 0, error);
582         } else {
583                 map->dm_flags |= DMF_LOADED;
584                 (*callback)(callback_arg, dmat->dt_segments, nsegs + 1,
585                     uio->uio_resid, error);
586         }
587         return (error);
588 }
589
590 /*
591  * Common function for unloading a DMA map.  May be called by
592  * bus-specific DMA map unload functions.
593  */
594 static void
595 nexus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
596 {
597
598         map->dm_flags &= ~DMF_LOADED;
599 }
600
601 /*
602  * Common function for DMA map synchronization.  May be called
603  * by bus-specific DMA map synchronization functions.
604  */
605 static void
606 nexus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
607 {
608
609         /*
610          * We sync out our caches, but the bus must do the same.
611          *
612          * Actually a #Sync is expensive.  We should optimize.
613          */
614         if ((op & BUS_DMASYNC_PREREAD) || (op & BUS_DMASYNC_PREWRITE)) {
615                 /*
616                  * Don't really need to do anything, but flush any pending
617                  * writes anyway.
618                  */
619                 membar(Sync);
620         }
621 #if 0
622         /* Should not be needed. */
623         if (op & BUS_DMASYNC_POSTREAD) {
624                 ecache_flush((vm_offset_t)map->buf,
625                     (vm_offset_t)map->buf + map->buflen - 1);
626         }
627 #endif
628         if (op & BUS_DMASYNC_POSTWRITE) {
629                 /* Nothing to do.  Handled by the bus controller. */
630         }
631 }
632
633 /*
634  * Common function for DMA-safe memory allocation.  May be called
635  * by bus-specific DMA memory allocation functions.
636  */
637 static int
638 nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags,
639     bus_dmamap_t *mapp)
640 {
641         int mflags;
642
643         if (flags & BUS_DMA_NOWAIT)
644                 mflags = M_NOWAIT;
645         else
646                 mflags = M_WAITOK;
647         if (flags & BUS_DMA_ZERO)
648                 mflags |= M_ZERO;
649
650         if ((dmat->dt_maxsize <= PAGE_SIZE)) {
651                 *vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags);
652         } else {
653                 /*
654                  * XXX use contigmalloc until it is merged into this
655                  * facility and handles multi-seg allocations.  Nobody
656                  * is doing multi-seg allocations yet though.
657                  */
658                 *vaddr = contigmalloc(dmat->dt_maxsize, M_DEVBUF, mflags,
659                     0ul, dmat->dt_lowaddr,
660                     dmat->dt_alignment ? dmat->dt_alignment : 1UL,
661                     dmat->dt_boundary);
662         }
663         if (*vaddr == NULL)
664                 return (ENOMEM);
665         return (0);
666 }
667
668 /*
669  * Common function for freeing DMA-safe memory.  May be called by
670  * bus-specific DMA memory free functions.
671  */
672 static void
673 nexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
674 {
675
676         if ((dmat->dt_maxsize <= PAGE_SIZE))
677                 free(vaddr, M_DEVBUF);
678         else {
679                 contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF);
680         }
681 }
682
683 struct bus_dma_methods nexus_dma_methods = {
684         nexus_dmamap_create,
685         nexus_dmamap_destroy,
686         nexus_dmamap_load,
687         nexus_dmamap_load_mbuf,
688         nexus_dmamap_load_mbuf_sg,
689         nexus_dmamap_load_uio,
690         nexus_dmamap_unload,
691         nexus_dmamap_sync,
692         nexus_dmamem_alloc,
693         nexus_dmamem_free,
694 };
695
696 struct bus_dma_tag nexus_dmatag = {
697         NULL,
698         NULL,
699         8,
700         0,
701         0,
702         0x3ffffffff,
703         NULL,           /* XXX */
704         NULL,
705         0x3ffffffff,    /* XXX */
706         0xff,           /* XXX */
707         0xffffffff,     /* XXX */
708         0,
709         0,
710         0,
711         NULL,
712         NULL,
713         NULL,
714         &nexus_dma_methods,
715 };
716
717 /*
718  * Helpers to map/unmap bus memory
719  */
720 int
721 sparc64_bus_mem_map(bus_space_tag_t tag, bus_space_handle_t handle,
722     bus_size_t size, int flags, vm_offset_t vaddr, void **hp)
723 {
724 #if 0
725         vm_offset_t addr;
726         vm_offset_t sva;
727         vm_offset_t va;
728         vm_paddr_t pa;
729         vm_size_t vsz;
730         u_long pm_flags;
731
732         addr = (vm_offset_t)handle;
733         size = round_page(size);
734         if (size == 0) {
735                 printf("%s: zero size\n", __func__);
736                 return (EINVAL);
737         }
738         switch (tag->bst_type) {
739         case PCI_CONFIG_BUS_SPACE:
740         case PCI_IO_BUS_SPACE:
741         case PCI_MEMORY_BUS_SPACE:
742                 pm_flags = TD_IE;
743                 break;
744         default:
745                 pm_flags = 0;
746                 break;
747         }
748
749         if (!(flags & BUS_SPACE_MAP_CACHEABLE))
750                 pm_flags |= TD_E;
751
752         if (vaddr != 0L)
753                 sva = trunc_page(vaddr);
754         else {
755                 if ((sva = kmem_alloc_nofault(kernel_map, size)) == 0)
756                         panic("%s: cannot allocate virtual memory", __func__);
757         }
758
759         /* Preserve page offset. */
760         *hp = (void *)(sva | ((u_long)addr & PAGE_MASK));
761
762         pa = trunc_page(addr);
763         if ((flags & BUS_SPACE_MAP_READONLY) == 0)
764                 pm_flags |= TD_W;
765
766         va = sva;
767         vsz = size;
768         do {
769                 pmap_kenter_flags(va, pa, pm_flags);
770                 va += PAGE_SIZE;
771                 pa += PAGE_SIZE;
772         } while ((vsz -= PAGE_SIZE) > 0);
773         tlb_range_demap(kernel_pmap, sva, sva + size - 1);
774 #endif
775         return (0);
776 }
777
778 int
779 sparc64_bus_mem_unmap(void *bh, bus_size_t size)
780 {
781 #if 0
782         vm_offset_t sva;
783         vm_offset_t va;
784         vm_offset_t endva;
785
786         sva = trunc_page((vm_offset_t)bh);
787         endva = sva + round_page(size);
788         for (va = sva; va < endva; va += PAGE_SIZE)
789                 pmap_kremove_flags(va);
790         tlb_range_demap(kernel_pmap, sva, sva + size - 1);
791         kmem_free(kernel_map, sva, size);
792 #endif
793         return (0);
794 }
795
796 /*
797  * Fake up a bus tag, for use by console drivers in early boot when the
798  * regular means to allocate resources are not yet available.
799  * Addr is the physical address of the desired start of the handle.
800  */
801 bus_space_handle_t
802 sparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag)
803 {
804
805         ptag->bst_cookie = NULL;
806         ptag->bst_parent = NULL;
807         ptag->bst_type = space;
808         ptag->bst_bus_barrier = nexus_bus_barrier;
809         return (addr);
810 }
811
812 /*
813  * Base bus space handlers.
814  */
815
816 static void
817 nexus_bus_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset,
818     bus_size_t size, int flags)
819 {
820
821         /*
822          * We have lots of alternatives depending on whether we're
823          * synchronizing loads with loads, loads with stores, stores
824          * with loads, or stores with stores.  The only ones that seem
825          * generic are #Sync and #MemIssue.  I'll use #Sync for safety.
826          */
827         switch(flags) {
828         case BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE:
829         case BUS_SPACE_BARRIER_READ:
830         case BUS_SPACE_BARRIER_WRITE:
831                 membar(Sync);
832                 break;
833         default:
834                 panic("%s: unknown flags", __func__);
835         }
836         return;
837 }
838
839 struct bus_space_tag nexus_bustag = {
840         NULL,                           /* cookie */
841         NULL,                           /* parent bus tag */
842         NEXUS_BUS_SPACE,                /* type */
843         nexus_bus_barrier,              /* bus_space_barrier */
844 };