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