]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/sparc64/sparc64/bus_machdep.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / sparc64 / sparc64 / 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/cache.h>
127 #include <machine/smp.h>
128 #include <machine/tlb.h>
129
130 static void nexus_bus_barrier(bus_space_tag_t, bus_space_handle_t,
131     bus_size_t, bus_size_t, int);
132
133 /* ASIs for bus access */
134 const int bus_type_asi[] = {
135         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* nexus */
136         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* SBus */
137         ASI_PHYS_BYPASS_EC_WITH_EBIT_L,         /* PCI configuration space */
138         ASI_PHYS_BYPASS_EC_WITH_EBIT_L,         /* PCI memory space */
139         ASI_PHYS_BYPASS_EC_WITH_EBIT_L,         /* PCI I/O space */
140         0
141 };
142
143 const int bus_stream_asi[] = {
144         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* nexus */
145         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* SBus */
146         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* PCI configuration space */
147         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* PCI memory space */
148         ASI_PHYS_BYPASS_EC_WITH_EBIT,           /* PCI I/O space */
149         0
150 };
151
152 /*
153  * Convenience function for manipulating driver locks from busdma (during
154  * busdma_swi, for example).  Drivers that don't provide their own locks
155  * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
156  * non-mutex locking scheme don't have to use this at all.
157  */
158 void
159 busdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
160 {
161         struct mtx *dmtx;
162
163         dmtx = (struct mtx *)arg;
164         switch (op) {
165         case BUS_DMA_LOCK:
166                 mtx_lock(dmtx);
167                 break;
168         case BUS_DMA_UNLOCK:
169                 mtx_unlock(dmtx);
170                 break;
171         default:
172                 panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
173         }
174 }
175
176 /*
177  * dflt_lock should never get called.  It gets put into the dma tag when
178  * lockfunc == NULL, which is only valid if the maps that are associated
179  * with the tag are meant to never be defered.
180  * XXX Should have a way to identify which driver is responsible here.
181  */
182 static void
183 dflt_lock(void *arg, bus_dma_lock_op_t op)
184 {
185
186         panic("driver error: busdma dflt_lock called");
187 }
188
189 /*
190  * Allocate a device specific dma_tag.
191  */
192 int
193 bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
194     bus_size_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
195     bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
196     int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
197     void *lockfuncarg, bus_dma_tag_t *dmat)
198 {
199         bus_dma_tag_t newtag;
200
201         /* Return a NULL tag on failure */
202         *dmat = NULL;
203
204         /* Enforce the usage of BUS_GET_DMA_TAG(). */
205         if (parent == NULL)
206                 panic("%s: parent DMA tag NULL", __func__);
207
208         newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
209         if (newtag == NULL)
210                 return (ENOMEM);
211
212         /*
213          * The method table pointer and the cookie need to be taken over from
214          * the parent.
215          */
216         newtag->dt_cookie = parent->dt_cookie;
217         newtag->dt_mt = parent->dt_mt;
218
219         newtag->dt_parent = parent;
220         newtag->dt_alignment = alignment;
221         newtag->dt_boundary = boundary;
222         newtag->dt_lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1);
223         newtag->dt_highaddr = trunc_page((vm_offset_t)highaddr) +
224             (PAGE_SIZE - 1);
225         newtag->dt_filter = filter;
226         newtag->dt_filterarg = filterarg;
227         newtag->dt_maxsize = maxsize;
228         newtag->dt_nsegments = nsegments;
229         newtag->dt_maxsegsz = maxsegsz;
230         newtag->dt_flags = flags;
231         newtag->dt_ref_count = 1; /* Count ourselves */
232         newtag->dt_map_count = 0;
233
234         if (lockfunc != NULL) {
235                 newtag->dt_lockfunc = lockfunc;
236                 newtag->dt_lockfuncarg = lockfuncarg;
237         } else {
238                 newtag->dt_lockfunc = dflt_lock;
239                 newtag->dt_lockfuncarg = NULL;
240         }
241
242         newtag->dt_segments = NULL;
243
244         /* Take into account any restrictions imposed by our parent tag. */
245         newtag->dt_lowaddr = ulmin(parent->dt_lowaddr, newtag->dt_lowaddr);
246         newtag->dt_highaddr = ulmax(parent->dt_highaddr, newtag->dt_highaddr);
247         if (newtag->dt_boundary == 0)
248                 newtag->dt_boundary = parent->dt_boundary;
249         else if (parent->dt_boundary != 0)
250                 newtag->dt_boundary = ulmin(parent->dt_boundary,
251                     newtag->dt_boundary);
252         atomic_add_int(&parent->dt_ref_count, 1);
253
254         if (newtag->dt_boundary > 0)
255                 newtag->dt_maxsegsz = ulmin(newtag->dt_maxsegsz,
256                     newtag->dt_boundary);
257
258         *dmat = newtag;
259         return (0);
260 }
261
262 int
263 bus_dma_tag_destroy(bus_dma_tag_t dmat)
264 {
265         bus_dma_tag_t parent;
266
267         if (dmat != NULL) {
268                 if (dmat->dt_map_count != 0)
269                         return (EBUSY);
270                 while (dmat != NULL) {
271                         parent = dmat->dt_parent;
272                         atomic_subtract_int(&dmat->dt_ref_count, 1);
273                         if (dmat->dt_ref_count == 0) {
274                                 if (dmat->dt_segments != NULL)
275                                         free(dmat->dt_segments, M_DEVBUF);
276                                 free(dmat, M_DEVBUF);
277                                 /*
278                                  * Last reference count, so
279                                  * release our reference
280                                  * count on our parent.
281                                  */
282                                 dmat = parent;
283                         } else
284                                 dmat = NULL;
285                 }
286         }
287         return (0);
288 }
289
290 /* Allocate/free a tag, and do the necessary management work. */
291 int
292 sparc64_dma_alloc_map(bus_dma_tag_t dmat, bus_dmamap_t *mapp)
293 {
294
295         if (dmat->dt_segments == NULL) {
296                 dmat->dt_segments = (bus_dma_segment_t *)malloc(
297                     sizeof(bus_dma_segment_t) * dmat->dt_nsegments, M_DEVBUF,
298                     M_NOWAIT);
299                 if (dmat->dt_segments == NULL)
300                         return (ENOMEM);
301         }
302         *mapp = malloc(sizeof(**mapp), M_DEVBUF, M_NOWAIT | M_ZERO);
303         if (*mapp == NULL)
304                 return (ENOMEM);
305
306         SLIST_INIT(&(*mapp)->dm_reslist);
307         dmat->dt_map_count++;
308         return (0);
309 }
310
311 void
312 sparc64_dma_free_map(bus_dma_tag_t dmat, bus_dmamap_t map)
313 {
314
315         free(map, M_DEVBUF);
316         dmat->dt_map_count--;
317 }
318
319 static int
320 nexus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
321 {
322
323         return (sparc64_dma_alloc_map(dmat, mapp));
324 }
325
326 static int
327 nexus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
328 {
329
330         sparc64_dma_free_map(dmat, map);
331         return (0);
332 }
333
334 /*
335  * Utility function to load a linear buffer.  lastaddrp holds state
336  * between invocations (for multiple-buffer loads).  segp contains
337  * the starting segment on entrace, and the ending segment on exit.
338  * first indicates if this is the first invocation of this function.
339  */
340 static int
341 _nexus_dmamap_load_buffer(bus_dma_tag_t dmat, void *buf, bus_size_t buflen,
342     struct thread *td, int flags, bus_addr_t *lastaddrp,
343     bus_dma_segment_t *segs, int *segp, int first)
344 {
345         bus_size_t sgsize;
346         bus_addr_t curaddr, lastaddr, baddr, bmask;
347         vm_offset_t vaddr = (vm_offset_t)buf;
348         int seg;
349         pmap_t pmap;
350
351         if (td != NULL)
352                 pmap = vmspace_pmap(td->td_proc->p_vmspace);
353         else
354                 pmap = NULL;
355
356         lastaddr = *lastaddrp;
357         bmask  = ~(dmat->dt_boundary - 1);
358
359         for (seg = *segp; buflen > 0 ; ) {
360                 /*
361                  * Get the physical address for this segment.
362                  */
363                 if (pmap)
364                         curaddr = pmap_extract(pmap, vaddr);
365                 else
366                         curaddr = pmap_kextract(vaddr);
367
368                 /*
369                  * Compute the segment size, and adjust counts.
370                  */
371                 sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
372                 if (sgsize > dmat->dt_maxsegsz)
373                         sgsize = dmat->dt_maxsegsz;
374                 if (buflen < sgsize)
375                         sgsize = buflen;
376
377                 /*
378                  * Make sure we don't cross any boundaries.
379                  */
380                 if (dmat->dt_boundary > 0) {
381                         baddr = (curaddr + dmat->dt_boundary) & bmask;
382                         if (sgsize > (baddr - curaddr))
383                                 sgsize = (baddr - curaddr);
384                 }
385
386                 /*
387                  * Insert chunk into a segment, coalescing with
388                  * previous segment if possible.
389                  */
390                 if (first) {
391                         segs[seg].ds_addr = curaddr;
392                         segs[seg].ds_len = sgsize;
393                         first = 0;
394                 } else {
395                         if (curaddr == lastaddr &&
396                             (segs[seg].ds_len + sgsize) <= dmat->dt_maxsegsz &&
397                             (dmat->dt_boundary == 0 ||
398                             (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
399                                 segs[seg].ds_len += sgsize;
400                         else {
401                                 if (++seg >= dmat->dt_nsegments)
402                                         break;
403                                 segs[seg].ds_addr = curaddr;
404                                 segs[seg].ds_len = sgsize;
405                         }
406                 }
407
408                 lastaddr = curaddr + sgsize;
409                 vaddr += sgsize;
410                 buflen -= sgsize;
411         }
412
413         *segp = seg;
414         *lastaddrp = lastaddr;
415
416         /*
417          * Did we fit?
418          */
419         return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
420 }
421
422 /*
423  * Common function for loading a DMA map with a linear buffer.  May
424  * be called by bus-specific DMA map load functions.
425  *
426  * Most SPARCs have IOMMUs in the bus controllers.  In those cases
427  * they only need one segment and will use virtual addresses for DVMA.
428  * Those bus controllers should intercept these vectors and should
429  * *NEVER* call nexus_dmamap_load() which is used only by devices that
430  * bypass DVMA.
431  */
432 static int
433 nexus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
434     bus_size_t buflen, bus_dmamap_callback_t *callback, void *callback_arg,
435     int flags)
436 {
437         bus_addr_t lastaddr;
438         int error, nsegs;
439
440         error = _nexus_dmamap_load_buffer(dmat, buf, buflen, NULL, flags,
441             &lastaddr, dmat->dt_segments, &nsegs, 1);
442
443         if (error == 0) {
444                 (*callback)(callback_arg, dmat->dt_segments, nsegs + 1, 0);
445                 map->dm_flags |= DMF_LOADED;
446         } else
447                 (*callback)(callback_arg, NULL, 0, error);
448
449         return (0);
450 }
451
452 /*
453  * Like nexus_dmamap_load(), but for mbufs.
454  */
455 static int
456 nexus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
457     bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
458 {
459         int nsegs, error;
460
461         M_ASSERTPKTHDR(m0);
462
463         nsegs = 0;
464         error = 0;
465         if (m0->m_pkthdr.len <= dmat->dt_maxsize) {
466                 int first = 1;
467                 bus_addr_t lastaddr = 0;
468                 struct mbuf *m;
469
470                 for (m = m0; m != NULL && error == 0; m = m->m_next) {
471                         if (m->m_len > 0) {
472                                 error = _nexus_dmamap_load_buffer(dmat,
473                                     m->m_data, m->m_len,NULL, flags, &lastaddr,
474                                     dmat->dt_segments, &nsegs, first);
475                                 first = 0;
476                         }
477                 }
478         } else {
479                 error = EINVAL;
480         }
481
482         if (error) {
483                 /* force "no valid mappings" in callback */
484                 (*callback)(callback_arg, dmat->dt_segments, 0, 0, error);
485         } else {
486                 map->dm_flags |= DMF_LOADED;
487                 (*callback)(callback_arg, dmat->dt_segments, nsegs + 1,
488                     m0->m_pkthdr.len, error);
489         }
490         return (error);
491 }
492
493 static int
494 nexus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
495     bus_dma_segment_t *segs, int *nsegs, int flags)
496 {
497         int error;
498
499         M_ASSERTPKTHDR(m0);
500
501         *nsegs = 0;
502         error = 0;
503         if (m0->m_pkthdr.len <= dmat->dt_maxsize) {
504                 int first = 1;
505                 bus_addr_t lastaddr = 0;
506                 struct mbuf *m;
507
508                 for (m = m0; m != NULL && error == 0; m = m->m_next) {
509                         if (m->m_len > 0) {
510                                 error = _nexus_dmamap_load_buffer(dmat,
511                                     m->m_data, m->m_len,NULL, flags, &lastaddr,
512                                     segs, nsegs, first);
513                                 first = 0;
514                         }
515                 }
516         } else {
517                 error = EINVAL;
518         }
519
520         ++*nsegs;
521         return (error);
522 }
523
524 /*
525  * Like nexus_dmamap_load(), but for uios.
526  */
527 static int
528 nexus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
529     bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
530 {
531         bus_addr_t lastaddr;
532         int nsegs, error, first, i;
533         bus_size_t resid;
534         struct iovec *iov;
535         struct thread *td = NULL;
536
537         resid = uio->uio_resid;
538         iov = uio->uio_iov;
539
540         if (uio->uio_segflg == UIO_USERSPACE) {
541                 td = uio->uio_td;
542                 KASSERT(td != NULL, ("%s: USERSPACE but no proc", __func__));
543         }
544
545         nsegs = 0;
546         error = 0;
547         first = 1;
548         for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
549                 /*
550                  * Now at the first iovec to load.  Load each iovec
551                  * until we have exhausted the residual count.
552                  */
553                 bus_size_t minlen =
554                         resid < iov[i].iov_len ? resid : iov[i].iov_len;
555                 caddr_t addr = (caddr_t) iov[i].iov_base;
556
557                 if (minlen > 0) {
558                         error = _nexus_dmamap_load_buffer(dmat, addr, minlen,
559                             td, flags, &lastaddr, dmat->dt_segments, &nsegs,
560                             first);
561                         first = 0;
562
563                         resid -= minlen;
564                 }
565         }
566
567         if (error) {
568                 /* force "no valid mappings" in callback */
569                 (*callback)(callback_arg, dmat->dt_segments, 0, 0, error);
570         } else {
571                 map->dm_flags |= DMF_LOADED;
572                 (*callback)(callback_arg, dmat->dt_segments, nsegs + 1,
573                     uio->uio_resid, error);
574         }
575         return (error);
576 }
577
578 /*
579  * Common function for unloading a DMA map.  May be called by
580  * bus-specific DMA map unload functions.
581  */
582 static void
583 nexus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
584 {
585
586         map->dm_flags &= ~DMF_LOADED;
587 }
588
589 /*
590  * Common function for DMA map synchronization.  May be called
591  * by bus-specific DMA map synchronization functions.
592  */
593 static void
594 nexus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
595 {
596
597         /*
598          * We sync out our caches, but the bus must do the same.
599          *
600          * Actually a #Sync is expensive.  We should optimize.
601          */
602         if ((op & BUS_DMASYNC_PREREAD) || (op & BUS_DMASYNC_PREWRITE)) {
603                 /*
604                  * Don't really need to do anything, but flush any pending
605                  * writes anyway.
606                  */
607                 membar(Sync);
608         }
609         if (op & BUS_DMASYNC_POSTWRITE) {
610                 /* Nothing to do.  Handled by the bus controller. */
611         }
612 }
613
614 /*
615  * Common function for DMA-safe memory allocation.  May be called
616  * by bus-specific DMA memory allocation functions.
617  */
618 static int
619 nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags,
620     bus_dmamap_t *mapp)
621 {
622         int mflags;
623
624         if (flags & BUS_DMA_NOWAIT)
625                 mflags = M_NOWAIT;
626         else
627                 mflags = M_WAITOK;
628         if (flags & BUS_DMA_ZERO)
629                 mflags |= M_ZERO;
630
631         /*
632          * XXX:
633          * (dmat->dt_alignment < dmat->dt_maxsize) is just a quick hack; the
634          * exact alignment guarantees of malloc need to be nailed down, and
635          * the code below should be rewritten to take that into account.
636          *
637          * In the meantime, we'll warn the user if malloc gets it wrong.
638          */
639         if (dmat->dt_maxsize <= PAGE_SIZE &&
640             dmat->dt_alignment < dmat->dt_maxsize)
641                 *vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags);
642         else {
643                 /*
644                  * XXX use contigmalloc until it is merged into this
645                  * facility and handles multi-seg allocations.  Nobody
646                  * is doing multi-seg allocations yet though.
647                  */
648                 *vaddr = contigmalloc(dmat->dt_maxsize, M_DEVBUF, mflags,
649                     0ul, dmat->dt_lowaddr,
650                     dmat->dt_alignment ? dmat->dt_alignment : 1UL,
651                     dmat->dt_boundary);
652         }
653         if (*vaddr == NULL)
654                 return (ENOMEM);
655         if ((uintptr_t)*vaddr % dmat->dt_alignment)
656                 printf("%s: failed to align memory properly.\n", __func__);
657         return (0);
658 }
659
660 /*
661  * Common function for freeing DMA-safe memory.  May be called by
662  * bus-specific DMA memory free functions.
663  */
664 static void
665 nexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
666 {
667
668         if (dmat->dt_maxsize <= PAGE_SIZE &&
669             dmat->dt_alignment < dmat->dt_maxsize)
670                 free(vaddr, M_DEVBUF);
671         else
672                 contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF);
673 }
674
675 struct bus_dma_methods nexus_dma_methods = {
676         nexus_dmamap_create,
677         nexus_dmamap_destroy,
678         nexus_dmamap_load,
679         nexus_dmamap_load_mbuf,
680         nexus_dmamap_load_mbuf_sg,
681         nexus_dmamap_load_uio,
682         nexus_dmamap_unload,
683         nexus_dmamap_sync,
684         nexus_dmamem_alloc,
685         nexus_dmamem_free,
686 };
687
688 struct bus_dma_tag nexus_dmatag = {
689         NULL,
690         NULL,
691         1,
692         0,
693         ~0,
694         ~0,
695         NULL,           /* XXX */
696         NULL,
697         ~0,
698         ~0,
699         ~0,
700         0,
701         0,
702         0,
703         NULL,
704         NULL,
705         NULL,
706         &nexus_dma_methods,
707 };
708
709 /*
710  * Helpers to map/unmap bus memory
711  */
712 int
713 sparc64_bus_mem_map(bus_space_tag_t tag, bus_space_handle_t handle,
714     bus_size_t size, int flags, vm_offset_t vaddr, void **hp)
715 {
716         vm_offset_t addr;
717         vm_offset_t sva;
718         vm_offset_t va;
719         vm_paddr_t pa;
720         vm_size_t vsz;
721         u_long pm_flags;
722
723         addr = (vm_offset_t)handle;
724         size = round_page(size);
725         if (size == 0) {
726                 printf("%s: zero size\n", __func__);
727                 return (EINVAL);
728         }
729         switch (tag->bst_type) {
730         case PCI_CONFIG_BUS_SPACE:
731         case PCI_IO_BUS_SPACE:
732         case PCI_MEMORY_BUS_SPACE:
733                 pm_flags = TD_IE;
734                 break;
735         default:
736                 pm_flags = 0;
737                 break;
738         }
739
740         if (!(flags & BUS_SPACE_MAP_CACHEABLE))
741                 pm_flags |= TD_E;
742
743         if (vaddr != 0L)
744                 sva = trunc_page(vaddr);
745         else {
746                 if ((sva = kmem_alloc_nofault(kernel_map, size)) == 0)
747                         panic("%s: cannot allocate virtual memory", __func__);
748         }
749
750         /* Preserve page offset. */
751         *hp = (void *)(sva | ((u_long)addr & PAGE_MASK));
752
753         pa = trunc_page(addr);
754         if ((flags & BUS_SPACE_MAP_READONLY) == 0)
755                 pm_flags |= TD_W;
756
757         va = sva;
758         vsz = size;
759         do {
760                 pmap_kenter_flags(va, pa, pm_flags);
761                 va += PAGE_SIZE;
762                 pa += PAGE_SIZE;
763         } while ((vsz -= PAGE_SIZE) > 0);
764         tlb_range_demap(kernel_pmap, sva, sva + size - 1);
765         return (0);
766 }
767
768 int
769 sparc64_bus_mem_unmap(void *bh, bus_size_t size)
770 {
771         vm_offset_t sva;
772         vm_offset_t va;
773         vm_offset_t endva;
774
775         sva = trunc_page((vm_offset_t)bh);
776         endva = sva + round_page(size);
777         for (va = sva; va < endva; va += PAGE_SIZE)
778                 pmap_kremove_flags(va);
779         tlb_range_demap(kernel_pmap, sva, sva + size - 1);
780         kmem_free(kernel_map, sva, size);
781         return (0);
782 }
783
784 /*
785  * Fake up a bus tag, for use by console drivers in early boot when the
786  * regular means to allocate resources are not yet available.
787  * Addr is the physical address of the desired start of the handle.
788  */
789 bus_space_handle_t
790 sparc64_fake_bustag(int space, bus_addr_t addr, struct bus_space_tag *ptag)
791 {
792
793         ptag->bst_cookie = NULL;
794         ptag->bst_parent = NULL;
795         ptag->bst_type = space;
796         ptag->bst_bus_barrier = nexus_bus_barrier;
797         return (addr);
798 }
799
800 /*
801  * Base bus space handlers.
802  */
803
804 static void
805 nexus_bus_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset,
806     bus_size_t size, int flags)
807 {
808
809         /*
810          * We have lots of alternatives depending on whether we're
811          * synchronizing loads with loads, loads with stores, stores
812          * with loads, or stores with stores.  The only ones that seem
813          * generic are #Sync and #MemIssue.  I'll use #Sync for safety.
814          */
815         switch(flags) {
816         case BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE:
817         case BUS_SPACE_BARRIER_READ:
818         case BUS_SPACE_BARRIER_WRITE:
819                 membar(Sync);
820                 break;
821         default:
822                 panic("%s: unknown flags", __func__);
823         }
824         return;
825 }
826
827 struct bus_space_tag nexus_bustag = {
828         NULL,                           /* cookie */
829         NULL,                           /* parent bus tag */
830         NEXUS_BUS_SPACE,                /* type */
831         nexus_bus_barrier,              /* bus_space_barrier */
832 };