Home | History | Annotate | Line # | Download | only in mca
mcadma_machdep.c revision 1.1.4.2
      1 /* $NetBSD: mcadma_machdep.c,v 1.1.4.2 2008/01/02 21:49:53 bouyer Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Tim Rightnour
      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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: mcadma_machdep.c,v 1.1.4.2 2008/01/02 21:49:53 bouyer Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/syslog.h>
     45 #include <sys/device.h>
     46 #include <sys/malloc.h>
     47 #include <sys/proc.h>
     48 #include <sys/mbuf.h>
     49 
     50 #define _POWERPC_BUS_DMA_PRIVATE
     51 #include <machine/bus.h>
     52 
     53 #include <machine/pio.h>
     54 
     55 #include <dev/mca/mcavar.h>
     56 #include <dev/mca/mcareg.h>
     57 
     58 struct rs6000_dma_cookie {
     59 	int	id_flags;
     60 	uint32_t	bid;		/* the BID of this IOCC */
     61 	uint32_t	tce_off;	/* offset of the TCE */
     62 	uint32_t	nroftce;
     63 	uint32_t	nrofslaves;	/* nrof slave channels */
     64 	uint32_t	slave_regs;	/* allocation bitmask */
     65 	uint32_t	dma_regs;	/* allocation bitmask */
     66 };
     67 
     68 /*
     69  * Entry points for MCA DMA.  These are mostly wrappers around
     70  * the generic functions that understand how to deal with bounce
     71  * buffers, if necessary.
     72  */
     73 
     74 struct powerpc_bus_dma_tag mca_bus_dma_tag = {
     75 	0,			/* _bounce_thresh */
     76 	_mca_bus_dmamap_create,
     77 	_bus_dmamap_destroy,
     78 	_bus_dmamap_load,
     79 	_bus_dmamap_load_mbuf,
     80 	_bus_dmamap_load_uio,
     81 	_bus_dmamap_load_raw,
     82 	_bus_dmamap_unload,
     83 	NULL,			/* _dmamap_sync */
     84 	_bus_dmamem_alloc,
     85 	_bus_dmamem_free,
     86 	_bus_dmamem_map,
     87 	_bus_dmamem_unmap,
     88 	_bus_dmamem_mmap,
     89 };
     90 
     91 /*
     92  * Allocate a DMA map, and set up DMA channel.
     93  */
     94 static int
     95 _mca_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int flags,
     96     bus_dmamap_t *dmamp, int dmach)
     97 {
     98 	int error;
     99 	struct rs6000_dma_cookie *cookie;
    100 
    101 #ifdef DEBUG
    102 	/* Sanity check */
    103 	if (dmach < 0 || dmach >= MAX_DMA_CHANNELS) {
    104 		printf("mcadma_create: invalid DMA channel %d\n", dmach);
    105 		return EINVAL;
    106 	}
    107 
    108 	if (size > 65536) {
    109 		panic("mca_dmamap_create: dmamap sz %ld > 65536", (long) size);
    110 	}
    111 #endif
    112 
    113 	/*
    114 	 * MCA DMA transfer can be maximum 65536 bytes long and must
    115  	 * be in one chunk. No specific boundary constraints are present.
    116  	 */
    117 	if ((error = _bus_dmamap_create(t, size, 1, 65536, 0, flags, dmamp)))
    118 		return error;
    119 
    120 	cookie = (struct rs6000_dma_cookie *) (*dmamp)->_dm_cookie;
    121 
    122 	if (cookie == NULL) {
    123 		/*
    124  		 * Allocate our cookie if not yet done.
    125 		 */
    126 		cookie = malloc(sizeof(struct rs6000_dma_cookie), M_DMAMAP,
    127 		    ((flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK) | M_ZERO);
    128 		if (cookie == NULL) {
    129 
    130 			return ENOMEM;
    131 		}
    132 		(*dmamp)->_dm_cookie = cookie;
    133 	}
    134 
    135 	/* Encode DMA channel */
    136 	cookie->id_flags &= 0x0f;
    137 	cookie->id_flags |= dmach << 4;
    138 
    139 	/* Mark the dmamap as using DMA controller. Some devices
    140 	 * drive DMA themselves, and don't need the MCA DMA controller.
    141 	 * To distinguish the two, use a flag for dmamaps which use the DMA
    142 	 * controller.
    143 	 */
    144 	(*dmamp)->_dm_flags |= _MCABUS_DMA_USEDMACTRL;
    145 	return 0;
    146 }
    147 
    148 static void
    149 _mca_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
    150 {
    151 	struct rs6000_dma_cookie *cookie = map->_dm_cookie;
    152 
    153 	free(cookie, M_DMAMAP);
    154 	_bus_dmamap_destroy(t, map);
    155 }
    156 
    157 /*
    158  * Load an MCA DMA map with a linear buffer.
    159  */
    160 static int
    161 _mca_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
    162     bus_size_t buflen, struct proc *p, int flags)
    163 {
    164 	struct rs6000_dma_cookie *cookie = map->_dm_cookie;
    165 	int error;
    166 
    167 	/* Make sure that on error condition we return "no valid mappings." */
    168 	map->dm_mapsize = 0;
    169 	map->dm_nsegs = 0;
    170 
    171 	error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
    172 	return error;
    173 }
    174 
    175 /*
    176  * Like _mca_bus_dmamap_load(), but for mbufs.
    177  */
    178 static int
    179 _mca_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
    180     int flags)
    181 {
    182 	struct rs6000_dma_cookie *cookie = map->_dm_cookie;
    183 	int error;
    184 
    185 	/* Make sure that on error condition we return "no valid mappings." */
    186 	map->dm_mapsize = 0;
    187 	map->dm_nsegs = 0;
    188 
    189 #ifdef DIAGNOSTIC
    190 	if ((m0->m_flags & M_PKTHDR) == 0)
    191 		panic("_mca_bus_dmamap_load_mbuf: no packet header");
    192 #endif
    193 
    194 	if (m0->m_pkthdr.len > map->_dm_size)
    195 		return EINVAL;
    196 
    197 	error = _bus_dmamap_load_mbuf(t, map, m0, flags);
    198 	return error;
    199 }
    200 
    201 /*
    202  * Like _mca_bus_dmamap_load(), but for uios.
    203  */
    204 static int
    205 _mca_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
    206     int flags)
    207 {
    208 
    209 	panic("_mca_bus_dmamap_load_uio: not implemented");
    210 }
    211 
    212 /*
    213  * Like _mca_bus_dmamap_load(), but for raw memory allocated with
    214  * bus_dmamem_alloc().
    215  */
    216 static int
    217 _mca_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
    218     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
    219 {
    220 
    221 	panic("_mca_bus_dmamap_load_raw: not implemented");
    222 }
    223 
    224 /*
    225  * Unload an MCA DMA map.
    226  */
    227 static void
    228 _mca_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
    229 {
    230 
    231 	_bus_dmamap_unload(t, map);
    232 }
    233 
    234 /*
    235  * Allocate memory safe for MCA DMA.
    236  */
    237 static int
    238 _mca_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
    239     bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
    240     int flags)
    241 {
    242 	paddr_t high;
    243 
    244 	high = trunc_page(avail_end);
    245 
    246 	return _bus_dmamem_alloc_range(t, size, alignment, boundary,
    247 	    segs, nsegs, rsegs, flags, 0, high);
    248 }
    249