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