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