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 51struct 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 67struct 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 */ 87static 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 141static 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 */ 153static 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 */ 171static 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 */ 197static 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 */ 209static 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 */ 220static 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 */ 230static 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