Home | History | Annotate | Line # | Download | only in mca
      1 /* $NetBSD: mcadma_machdep.c,v 1.4 2020/11/21 15:52:32 thorpej 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  *
     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 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: mcadma_machdep.c,v 1.4 2020/11/21 15:52:32 thorpej Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/syslog.h>
     38 #include <sys/device.h>
     39 #include <sys/kmem.h>
     40 #include <sys/proc.h>
     41 #include <sys/mbuf.h>
     42 
     43 #define _POWERPC_BUS_DMA_PRIVATE
     44 #include <sys/bus.h>
     45 
     46 #include <machine/pio.h>
     47 
     48 #include <dev/mca/mcavar.h>
     49 #include <dev/mca/mcareg.h>
     50 
     51 struct rs6000_dma_cookie {
     52 	int	id_flags;
     53 	uint32_t	bid;		/* the BID of this IOCC */
     54 	uint32_t	tce_off;	/* offset of the TCE */
     55 	uint32_t	nroftce;
     56 	uint32_t	nrofslaves;	/* nrof slave channels */
     57 	uint32_t	slave_regs;	/* allocation bitmask */
     58 	uint32_t	dma_regs;	/* allocation bitmask */
     59 };
     60 
     61 /*
     62  * Entry points for MCA DMA.  These are mostly wrappers around
     63  * the generic functions that understand how to deal with bounce
     64  * buffers, if necessary.
     65  */
     66 
     67 struct powerpc_bus_dma_tag mca_bus_dma_tag = {
     68 	0,			/* _bounce_thresh */
     69 	_mca_bus_dmamap_create,
     70 	_bus_dmamap_destroy,
     71 	_bus_dmamap_load,
     72 	_bus_dmamap_load_mbuf,
     73 	_bus_dmamap_load_uio,
     74 	_bus_dmamap_load_raw,
     75 	_bus_dmamap_unload,
     76 	NULL,			/* _dmamap_sync */
     77 	_bus_dmamem_alloc,
     78 	_bus_dmamem_free,
     79 	_bus_dmamem_map,
     80 	_bus_dmamem_unmap,
     81 	_bus_dmamem_mmap,
     82 };
     83 
     84 /*
     85  * Allocate a DMA map, and set up DMA channel.
     86  */
     87 static int
     88 _mca_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int flags,
     89     bus_dmamap_t *dmamp, int dmach)
     90 {
     91 	int error;
     92 	struct rs6000_dma_cookie *cookie;
     93 
     94 #ifdef DEBUG
     95 	/* Sanity check */
     96 	if (dmach < 0 || dmach >= MAX_DMA_CHANNELS) {
     97 		printf("mcadma_create: invalid DMA channel %d\n", dmach);
     98 		return EINVAL;
     99 	}
    100 
    101 	if (size > 65536) {
    102 		panic("mca_dmamap_create: dmamap sz %ld > 65536", (long) size);
    103 	}
    104 #endif
    105 
    106 	/*
    107 	 * MCA DMA transfer can be maximum 65536 bytes long and must
    108  	 * be in one chunk. No specific boundary constraints are present.
    109  	 */
    110 	if ((error = _bus_dmamap_create(t, size, 1, 65536, 0, flags, dmamp)))
    111 		return error;
    112 
    113 	cookie = (struct rs6000_dma_cookie *) (*dmamp)->_dm_cookie;
    114 
    115 	if (cookie == NULL) {
    116 		/*
    117  		 * Allocate our cookie if not yet done.
    118 		 */
    119 		cookie = kmem_zalloc(sizeof(struct rs6000_dma_cookie),
    120 		    ((flags & BUS_DMA_NOWAIT) ? KM_NOSLEEP : KM_SLEEP));
    121 		if (cookie == NULL) {
    122 
    123 			return ENOMEM;
    124 		}
    125 		(*dmamp)->_dm_cookie = cookie;
    126 	}
    127 
    128 	/* Encode DMA channel */
    129 	cookie->id_flags &= 0x0f;
    130 	cookie->id_flags |= dmach << 4;
    131 
    132 	/* Mark the dmamap as using DMA controller. Some devices
    133 	 * drive DMA themselves, and don't need the MCA DMA controller.
    134 	 * To distinguish the two, use a flag for dmamaps which use the DMA
    135 	 * controller.
    136 	 */
    137 	(*dmamp)->_dm_flags |= _MCABUS_DMA_USEDMACTRL;
    138 	return 0;
    139 }
    140 
    141 static void
    142 _mca_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
    143 {
    144 	struct rs6000_dma_cookie *cookie = map->_dm_cookie;
    145 
    146 	kmem_free(cookie, sizeof(struct rs6000_dma_cookie));
    147 	_bus_dmamap_destroy(t, map);
    148 }
    149 
    150 /*
    151  * Load an MCA DMA map with a linear buffer.
    152  */
    153 static int
    154 _mca_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
    155     bus_size_t buflen, struct proc *p, int flags)
    156 {
    157 	struct rs6000_dma_cookie *cookie = map->_dm_cookie;
    158 	int error;
    159 
    160 	/* Make sure that on error condition we return "no valid mappings." */
    161 	map->dm_mapsize = 0;
    162 	map->dm_nsegs = 0;
    163 
    164 	error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
    165 	return error;
    166 }
    167 
    168 /*
    169  * Like _mca_bus_dmamap_load(), but for mbufs.
    170  */
    171 static int
    172 _mca_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
    173     int flags)
    174 {
    175 	struct rs6000_dma_cookie *cookie = map->_dm_cookie;
    176 	int error;
    177 
    178 	/* Make sure that on error condition we return "no valid mappings." */
    179 	map->dm_mapsize = 0;
    180 	map->dm_nsegs = 0;
    181 
    182 #ifdef DIAGNOSTIC
    183 	if ((m0->m_flags & M_PKTHDR) == 0)
    184 		panic("_mca_bus_dmamap_load_mbuf: no packet header");
    185 #endif
    186 
    187 	if (m0->m_pkthdr.len > map->_dm_size)
    188 		return EINVAL;
    189 
    190 	error = _bus_dmamap_load_mbuf(t, map, m0, flags);
    191 	return error;
    192 }
    193 
    194 /*
    195  * Like _mca_bus_dmamap_load(), but for uios.
    196  */
    197 static int
    198 _mca_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
    199     int flags)
    200 {
    201 
    202 	panic("_mca_bus_dmamap_load_uio: not implemented");
    203 }
    204 
    205 /*
    206  * Like _mca_bus_dmamap_load(), but for raw memory allocated with
    207  * bus_dmamem_alloc().
    208  */
    209 static int
    210 _mca_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
    211     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
    212 {
    213 
    214 	panic("_mca_bus_dmamap_load_raw: not implemented");
    215 }
    216 
    217 /*
    218  * Unload an MCA DMA map.
    219  */
    220 static void
    221 _mca_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
    222 {
    223 
    224 	_bus_dmamap_unload(t, map);
    225 }
    226 
    227 /*
    228  * Allocate memory safe for MCA DMA.
    229  */
    230 static int
    231 _mca_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
    232     bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
    233     int flags)
    234 {
    235 	paddr_t high;
    236 
    237 	high = trunc_page(avail_end);
    238 
    239 	return _bus_dmamem_alloc_range(t, size, alignment, boundary,
    240 	    segs, nsegs, rsegs, flags, 0, high);
    241 }
    242