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