1 /*        $NetBSD: gapspci_dma.c,v 1.21 2023/12/02 22:42:02 thorpej Exp $       */
2 
3 /*-
4  * Copyright (c) 2001 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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Bus DMA implementation for the SEGA GAPS PCI bridge.
34  *
35  * NOTE: We only implement a small subset of what the bus_dma(9)
36  * API specifies.  Right now, the GAPS PCI bridge is only used for
37  * the Dreamcast Broadband Adatper, so we only provide what the
38  * pci(4) and rtk(4) drivers need.
39  */
40 
41 #include <sys/cdefs.h>                            /* RCS ID & Copyright macro defns */
42 __KERNEL_RCSID(0, "$NetBSD: gapspci_dma.c,v 1.21 2023/12/02 22:42:02 thorpej Exp $");
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/mbuf.h>
48 #include <sys/vmem.h>
49 #include <sys/malloc.h>
50 #include <sys/bus.h>
51 
52 #include <machine/cpu.h>
53 
54 #include <dev/pci/pcivar.h>
55 
56 #include <dreamcast/dev/g2/gapspcivar.h>
57 
58 #include <uvm/uvm.h>
59 
60 int       gaps_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
61               bus_size_t, int, bus_dmamap_t *);
62 void      gaps_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
63 int       gaps_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
64               struct proc *, int);
65 int       gaps_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int);
66 int       gaps_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int);
67 int       gaps_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, bus_dma_segment_t *,
68               int, bus_size_t, int);
69 void      gaps_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
70 void      gaps_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
71               bus_size_t, int);
72 
73 int       gaps_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size,
74               bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
75               int nsegs, int *rsegs, int flags);
76 void      gaps_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs);
77 int       gaps_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs,
78               size_t size, void **kvap, int flags);
79 void      gaps_dmamem_unmap(bus_dma_tag_t tag, void *kva, size_t size);
80 paddr_t   gaps_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs,
81               off_t off, int prot, int flags);
82 
83 void
gaps_dma_init(struct gaps_softc * sc)84 gaps_dma_init(struct gaps_softc *sc)
85 {
86           bus_dma_tag_t t = &sc->sc_dmat;
87 
88           memset(t, 0, sizeof(*t));
89 
90           t->_cookie = sc;
91           t->_dmamap_create = gaps_dmamap_create;
92           t->_dmamap_destroy = gaps_dmamap_destroy;
93           t->_dmamap_load = gaps_dmamap_load;
94           t->_dmamap_load_mbuf = gaps_dmamap_load_mbuf;
95           t->_dmamap_load_uio = gaps_dmamap_load_uio;
96           t->_dmamap_load_raw = gaps_dmamap_load_raw;
97           t->_dmamap_unload = gaps_dmamap_unload;
98           t->_dmamap_sync = gaps_dmamap_sync;
99 
100           t->_dmamem_alloc = gaps_dmamem_alloc;
101           t->_dmamem_free = gaps_dmamem_free;
102           t->_dmamem_map = gaps_dmamem_map;
103           t->_dmamem_unmap = gaps_dmamem_unmap;
104           t->_dmamem_mmap = gaps_dmamem_mmap;
105 
106           /*
107            * The GAPS PCI bridge has 32k of DMA memory.  We manage it
108            * with a vmem arena.
109            */
110           sc->sc_dma_arena = vmem_create("gaps dma",
111                                                sc->sc_dmabase,
112                                                sc->sc_dmasize,
113                                                1024 /* XXX */,        /* quantum */
114                                                NULL,                  /* allocfn */
115                                                NULL,                  /* freefn */
116                                                NULL,                  /* arg */
117                                                0,           /* qcache_max */
118                                                VM_SLEEP,
119                                                IPL_VM);
120 
121           if (bus_space_map(sc->sc_memt, sc->sc_dmabase, sc->sc_dmasize,
122               0, &sc->sc_dma_memh) != 0)
123                     panic("gaps_dma_init: can't map SRAM buffer");
124 }
125 
126 /*
127  * A GAPS DMA map -- has the standard DMA map, plus some extra
128  * housekeeping data.
129  */
130 struct gaps_dmamap {
131           struct dreamcast_bus_dmamap gd_dmamap;
132           void *gd_origbuf;
133           int gd_buftype;
134 };
135 
136 #define   GAPS_DMA_BUFTYPE_INVALID      0
137 #define   GAPS_DMA_BUFTYPE_LINEAR                 1
138 #define   GAPS_DMA_BUFTYPE_MBUF                   2
139 
140 int
gaps_dmamap_create(bus_dma_tag_t t,bus_size_t size,int nsegments,bus_size_t maxsegsz,bus_size_t boundary,int flags,bus_dmamap_t * dmamap)141 gaps_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
142     bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamap)
143 {
144           struct gaps_softc *sc = t->_cookie;
145           struct gaps_dmamap *gmap;
146           bus_dmamap_t map;
147 
148           /*
149            * Allocate an initialize the DMA map.  The end of the map is
150            * a variable-sized array of segments, so we allocate enough
151            * room for them in one shot.  Since the DMA map always includes
152            * one segment, and we only support one segment, this is really
153            * easy.
154            *
155            * Note we don't preserve the WAITOK or NOWAIT flags.  Preservation
156            * of ALLOCNOW notifies others that we've reserved these resources
157            * and they are not to be freed.
158            */
159 
160           gmap = malloc(sizeof(*gmap), M_DMAMAP,
161               (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK);
162           if (gmap == NULL)
163                     return ENOMEM;
164 
165           memset(gmap, 0, sizeof(*gmap));
166 
167           gmap->gd_buftype = GAPS_DMA_BUFTYPE_INVALID;
168 
169           map = &gmap->gd_dmamap;
170 
171           map->_dm_size = size;
172           map->_dm_segcnt = 1;
173           map->_dm_maxmaxsegsz = maxsegsz;
174           map->_dm_boundary = boundary;
175           map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
176           map->dm_maxsegsz = maxsegsz;
177 
178           if (flags & BUS_DMA_ALLOCNOW) {
179                     vmem_addr_t res;
180                     int error;
181 
182                     const vm_flag_t vmflags = VM_BESTFIT |
183                         ((flags & BUS_DMA_NOWAIT) ? VM_NOSLEEP : VM_SLEEP);
184 
185                     error = vmem_xalloc(sc->sc_dma_arena, size,
186                                             0,                        /* alignment */
187                                             0,                        /* phase */
188                                             0,                        /* nocross */
189                                             VMEM_ADDR_MIN,  /* minaddr */
190                                             VMEM_ADDR_MAX,  /* maxaddr */
191                                             vmflags,
192                                             &res);
193                     if (error) {
194                               free(gmap, M_DEVBUF);
195                               return error;
196                     }
197 
198                     map->dm_segs[0].ds_addr = res;
199                     map->dm_segs[0].ds_len = size;
200 
201                     map->dm_mapsize = size;
202                     map->dm_nsegs = 1;
203           } else {
204                     map->dm_mapsize = 0;                    /* no valid mappings */
205                     map->dm_nsegs = 0;
206           }
207 
208           *dmamap = map;
209 
210           return 0;
211 }
212 
213 void
gaps_dmamap_destroy(bus_dma_tag_t t,bus_dmamap_t map)214 gaps_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
215 {
216           struct gaps_softc *sc = t->_cookie;
217 
218           if (map->_dm_flags & BUS_DMA_ALLOCNOW) {
219                     vmem_xfree(sc->sc_dma_arena, map->dm_segs[0].ds_addr,
220                         map->dm_mapsize);
221           }
222           free(map, M_DMAMAP);
223 }
224 
225 int
gaps_dmamap_load(bus_dma_tag_t t,bus_dmamap_t map,void * addr,bus_size_t size,struct proc * p,int flags)226 gaps_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *addr,
227     bus_size_t size, struct proc *p, int flags)
228 {
229           struct gaps_softc *sc = t->_cookie;
230           struct gaps_dmamap *gmap = (void *) map;
231           vmem_addr_t res;
232           int error;
233 
234           if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) {
235                     /*
236                      * Make sure that on error condition we return
237                      * "no valid mappings".
238                      */
239                     map->dm_mapsize = 0;
240                     map->dm_nsegs = 0;
241                     KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz);
242           }
243 
244           /* XXX Don't support DMA to process space right now. */
245           if (p != NULL)
246                     return EINVAL;
247 
248           if (size > map->_dm_size)
249                     return EINVAL;
250 
251           const vm_flag_t vmflags = VM_BESTFIT |
252               ((flags & BUS_DMA_NOWAIT) ? VM_NOSLEEP : VM_SLEEP);
253 
254           error = vmem_xalloc(sc->sc_dma_arena, size,
255                                   0,                        /* alignment */
256                                   0,                        /* phase */
257                                   map->_dm_boundary,        /* nocross */
258                                   VMEM_ADDR_MIN,  /* minaddr */
259                                   VMEM_ADDR_MAX,  /* maxaddr */
260                                   vmflags,
261                                   &res);
262           if (error)
263                     return error;
264 
265           map->dm_segs[0].ds_addr = res;
266           map->dm_segs[0].ds_len = size;
267 
268           gmap->gd_origbuf = addr;
269           gmap->gd_buftype = GAPS_DMA_BUFTYPE_LINEAR;
270 
271           map->dm_mapsize = size;
272           map->dm_nsegs = 1;
273 
274           return 0;
275 }
276 
277 int
gaps_dmamap_load_mbuf(bus_dma_tag_t t,bus_dmamap_t map,struct mbuf * m0,int flags)278 gaps_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
279     int flags)
280 {
281           struct gaps_softc *sc = t->_cookie;
282           struct gaps_dmamap *gmap = (void *) map;
283           vmem_addr_t res;
284           int error;
285 
286           if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) {
287                     /*
288                      * Make sure that on error condition we return
289                      * "no valid mappings".
290                      */
291                     map->dm_mapsize = 0;
292                     map->dm_nsegs = 0;
293                     KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz);
294           }
295 
296 #ifdef DIAGNOSTIC
297           if ((m0->m_flags & M_PKTHDR) == 0)
298                     panic("gaps_dmamap_load_mbuf: no packet header");
299 #endif
300 
301           if (m0->m_pkthdr.len > map->_dm_size)
302                     return EINVAL;
303 
304           const vm_flag_t vmflags = VM_BESTFIT |
305               ((flags & BUS_DMA_NOWAIT) ? VM_NOSLEEP : VM_SLEEP);
306 
307           error = vmem_xalloc(sc->sc_dma_arena, m0->m_pkthdr.len,
308                                   0,                        /* alignment */
309                                   0,                        /* phase */
310                                   map->_dm_boundary,        /* nocross */
311                                   VMEM_ADDR_MIN,  /* minaddr */
312                                   VMEM_ADDR_MAX,  /* maxaddr */
313                                   vmflags,
314                                   &res);
315           if (error)
316                     return error;
317 
318           map->dm_segs[0].ds_addr = res;
319           map->dm_segs[0].ds_len = m0->m_pkthdr.len;
320 
321           gmap->gd_origbuf = m0;
322           gmap->gd_buftype = GAPS_DMA_BUFTYPE_MBUF;
323 
324           map->dm_mapsize = m0->m_pkthdr.len;
325           map->dm_nsegs = 1;
326 
327           return 0;
328 }
329 
330 int
gaps_dmamap_load_uio(bus_dma_tag_t t,bus_dmamap_t map,struct uio * uio,int flags)331 gaps_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
332     int flags)
333 {
334 
335           printf("gaps_dmamap_load_uio: not implemented\n");
336           return EINVAL;
337 }
338 
339 int
gaps_dmamap_load_raw(bus_dma_tag_t t,bus_dmamap_t map,bus_dma_segment_t * segs,int nsegs,bus_size_t size,int flags)340 gaps_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
341     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
342 {
343 
344           printf("gaps_dmamap_load_raw: not implemented\n");
345           return EINVAL;
346 }
347 
348 void
gaps_dmamap_unload(bus_dma_tag_t t,bus_dmamap_t map)349 gaps_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
350 {
351           struct gaps_softc *sc = t->_cookie;
352           struct gaps_dmamap *gmap = (void *) map;
353 
354           if (gmap->gd_buftype == GAPS_DMA_BUFTYPE_INVALID) {
355                     printf("gaps_dmamap_unload: DMA map not loaded!\n");
356                     return;
357           }
358 
359           if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) {
360                     vmem_xfree(sc->sc_dma_arena, map->dm_segs[0].ds_addr,
361                         map->dm_mapsize);
362 
363                     map->dm_maxsegsz = map->_dm_maxmaxsegsz;
364                     map->dm_mapsize = 0;
365                     map->dm_nsegs = 0;
366           }
367 
368           gmap->gd_buftype = GAPS_DMA_BUFTYPE_INVALID;
369 }
370 
371 void
gaps_dmamap_sync(bus_dma_tag_t t,bus_dmamap_t map,bus_addr_t offset,bus_size_t len,int ops)372 gaps_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
373     bus_size_t len, int ops)
374 {
375           struct gaps_softc *sc = t->_cookie;
376           struct gaps_dmamap *gmap = (void *) map;
377           bus_addr_t dmaoff = map->dm_segs[0].ds_addr - sc->sc_dmabase;
378 
379           /*
380            * Mixing PRE and POST operations is not allowed.
381            */
382           if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
383               (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
384                     panic("gaps_dmamap_sync: mix PRE and POST");
385 
386 #ifdef DIAGNOSTIC
387           if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
388                     if (offset >= map->dm_mapsize) {
389                               printf("offset 0x%lx mapsize 0x%lx\n",
390                                   offset, map->dm_mapsize);
391                               panic("gaps_dmamap_sync: bad offset");
392                     }
393                     if (len == 0 || (offset + len) > map->dm_mapsize) {
394                               printf("len 0x%lx offset 0x%lx mapsize 0x%lx\n",
395                                   len, offset, map->dm_mapsize);
396                               panic("gaps_dmamap_sync: bad length");
397                     }
398           }
399 #endif
400 
401           switch (gmap->gd_buftype) {
402           case GAPS_DMA_BUFTYPE_INVALID:
403                     printf("gaps_dmamap_sync: DMA map is not loaded!\n");
404                     return;
405 
406           case GAPS_DMA_BUFTYPE_LINEAR:
407                     /*
408                      * Nothing to do for pre-read.
409                      */
410 
411                     if (ops & BUS_DMASYNC_PREWRITE) {
412                               /*
413                                * Copy the caller's buffer to the SRAM buffer.
414                                */
415                               bus_space_write_region_1(sc->sc_memt,
416                                   sc->sc_dma_memh,
417                                   dmaoff + offset,
418                                   (uint8_t *)gmap->gd_origbuf + offset, len);
419                     }
420 
421                     if (ops & BUS_DMASYNC_POSTREAD) {
422                               /*
423                                * Copy the SRAM buffer to the caller's buffer.
424                                */
425                               bus_space_read_region_1(sc->sc_memt,
426                                   sc->sc_dma_memh,
427                                   dmaoff + offset,
428                                   (uint8_t *)gmap->gd_origbuf + offset, len);
429                     }
430 
431                     /*
432                      * Nothing to do for post-write.
433                      */
434                     break;
435 
436           case GAPS_DMA_BUFTYPE_MBUF:
437               {
438                     struct mbuf *m, *m0 = gmap->gd_origbuf;
439                     bus_size_t minlen, moff;
440 
441                     /*
442                      * Nothing to do for pre-read.
443                      */
444 
445                     if (ops & BUS_DMASYNC_PREWRITE) {
446                               /*
447                                * Copy the caller's buffer into the SRAM buffer.
448                                */
449                               for (moff = offset, m = m0; m != NULL && len != 0;
450                                    m = m->m_next) {
451                                         /* Find the beginning mbuf. */
452                                         if (moff >= m->m_len) {
453                                                   moff -= m->m_len;
454                                                   continue;
455                                         }
456 
457                                         /*
458                                          * Now at the first mbuf to sync; nail
459                                          * each one until we have exhausted the
460                                          * length.
461                                          */
462                                         minlen = len < m->m_len - moff ?
463                                             len : m->m_len - moff;
464 
465                                         bus_space_write_region_1(sc->sc_memt,
466                                             sc->sc_dma_memh, dmaoff + offset,
467                                             mtod(m, uint8_t *) + moff, minlen);
468 
469                                         moff = 0;
470                                         len -= minlen;
471                                         offset += minlen;
472                               }
473                     }
474 
475                     if (ops & BUS_DMASYNC_POSTREAD) {
476                               /*
477                                * Copy the SRAM buffer into the caller's buffer.
478                                */
479                               for (moff = offset, m = m0; m != NULL && len != 0;
480                                    m = m->m_next) {
481                                         /* Find the beginning mbuf. */
482                                         if (moff >= m->m_len) {
483                                                   moff -= m->m_len;
484                                                   continue;
485                                         }
486 
487                                         /*
488                                          * Now at the first mbuf to sync; nail
489                                          * each one until we have exhausted the
490                                          * length.
491                                          */
492                                         minlen = len < m->m_len - moff ?
493                                             len : m->m_len - moff;
494 
495                                         bus_space_read_region_1(sc->sc_memt,
496                                             sc->sc_dma_memh, dmaoff + offset,
497                                             mtod(m, uint8_t *) + moff, minlen);
498 
499                                         moff = 0;
500                                         len -= minlen;
501                                         offset += minlen;
502                               }
503                     }
504 
505                     /*
506                      * Nothing to do for post-write.
507                      */
508                     break;
509               }
510 
511           default:
512                     printf("unknown buffer type %d\n", gmap->gd_buftype);
513                     panic("gaps_dmamap_sync");
514           }
515 }
516 
517 int
gaps_dmamem_alloc(bus_dma_tag_t t,bus_size_t size,bus_size_t alignment,bus_size_t boundary,bus_dma_segment_t * segs,int nsegs,int * rsegs,int flags)518 gaps_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
519     bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
520     int flags)
521 {
522           extern paddr_t avail_start, avail_end;  /* from pmap.c */
523 
524           struct pglist mlist;
525           paddr_t curaddr, lastaddr;
526           struct vm_page *m;
527           int curseg, error;
528 
529           /* Always round the size. */
530           size = round_page(size);
531 
532           /*
533            * Allocate the pages from the VM system.
534            */
535           error = uvm_pglistalloc(size, avail_start, avail_end - PAGE_SIZE,
536               alignment, boundary, &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
537           if (error)
538                     return error;
539 
540           /*
541            * Compute the location, size, and number of segments actually
542            * returned by the VM code.
543            */
544           m = mlist.tqh_first;
545           curseg = 0;
546           lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
547           segs[curseg].ds_len = PAGE_SIZE;
548           m = TAILQ_NEXT(m, pageq.queue);
549 
550           for (; m != NULL; m = TAILQ_NEXT(m, pageq.queue)) {
551                     curaddr = VM_PAGE_TO_PHYS(m);
552                     if (curaddr == (lastaddr + PAGE_SIZE))
553                               segs[curseg].ds_len += PAGE_SIZE;
554                     else {
555                               curseg++;
556                               segs[curseg].ds_addr = curaddr;
557                               segs[curseg].ds_len = PAGE_SIZE;
558                     }
559                     lastaddr = curaddr;
560           }
561 
562           *rsegs = curseg + 1;
563 
564           return 0;
565 }
566 
567 void
gaps_dmamem_free(bus_dma_tag_t t,bus_dma_segment_t * segs,int nsegs)568 gaps_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
569 {
570           struct pglist mlist;
571           struct vm_page *m;
572           bus_addr_t addr;
573           int curseg;
574 
575           /*
576            * Build a list of pages to free back to the VM system.
577            */
578           TAILQ_INIT(&mlist);
579           for (curseg = 0; curseg < nsegs; curseg++) {
580                     for (addr = segs[curseg].ds_addr;
581                          addr < segs[curseg].ds_addr + segs[curseg].ds_len;
582                          addr += PAGE_SIZE) {
583                               m = PHYS_TO_VM_PAGE(addr);
584                               TAILQ_INSERT_TAIL(&mlist, m, pageq.queue);
585                     }
586           }
587 
588           uvm_pglistfree(&mlist);
589 }
590 
591 int
gaps_dmamem_map(bus_dma_tag_t t,bus_dma_segment_t * segs,int nsegs,size_t size,void ** kvap,int flags)592 gaps_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
593     size_t size, void **kvap, int flags)
594 {
595           vaddr_t va;
596           bus_addr_t addr;
597           int curseg;
598           const uvm_flag_t kmflags =
599               (flags & BUS_DMA_NOWAIT) != 0 ? UVM_KMF_NOWAIT : 0;
600 
601           /*
602            * If we're only mapping 1 segment, use P2SEG, to avoid
603            * TLB thrashing.
604            */
605           if (nsegs == 1) {
606                     *kvap = (void *)SH3_PHYS_TO_P2SEG(segs[0].ds_addr);
607                     return 0;
608           }
609 
610           size = round_page(size);
611 
612           va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | kmflags);
613 
614           if (va == 0)
615                     return ENOMEM;
616 
617           *kvap = (void *)va;
618 
619           for (curseg = 0; curseg < nsegs; curseg++) {
620                     for (addr = segs[curseg].ds_addr;
621                          addr < segs[curseg].ds_addr + segs[curseg].ds_len;
622                          addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) {
623                               if (size == 0)
624                                         panic("gaps_dmamem_map: size botch");
625                               pmap_kenter_pa(va, addr,
626                                   VM_PROT_READ | VM_PROT_WRITE, 0);
627                     }
628           }
629           pmap_update(pmap_kernel());
630 
631           return 0;
632 }
633 
634 void
gaps_dmamem_unmap(bus_dma_tag_t t,void * kva,size_t size)635 gaps_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size)
636 {
637 
638 #ifdef DIAGNOSTIC
639           if ((u_long) kva & PAGE_MASK)
640                     panic("gaps_dmamem_unmap");
641 #endif
642 
643           /*
644            * Nothing to do if we mapped it with P2SEG.
645            */
646           if (kva >= (void *)SH3_P2SEG_BASE &&
647               kva <= (void *)SH3_P2SEG_END)
648                     return;
649 
650           size = round_page(size);
651           pmap_kremove((vaddr_t) kva, size);
652           pmap_update(pmap_kernel());
653           uvm_km_free(kernel_map, (vaddr_t) kva, size, UVM_KMF_VAONLY);
654 }
655 
656 paddr_t
gaps_dmamem_mmap(bus_dma_tag_t t,bus_dma_segment_t * segs,int nsegs,off_t off,int prot,int flags)657 gaps_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
658     off_t off, int prot, int flags)
659 {
660 
661           /* Not implemented. */
662           return -1;
663 }
664