1 /* $NetBSD: bus_dma_jazz.c,v 1.4 2001/11/14 18:15:15 thorpej Exp $ */ 2 3 /*- 4 * Copyright (C) 2000 Shuichiro URATA. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/mbuf.h> 32 #include <sys/device.h> 33 34 #include <uvm/uvm_extern.h> 35 36 #define _ARC_BUS_DMA_PRIVATE 37 #include <machine/bus.h> 38 39 #include <arc/jazz/jazzdmatlbreg.h> 40 #include <arc/jazz/jazzdmatlbvar.h> 41 42 static int jazz_bus_dmamap_alloc_sgmap __P((bus_dma_tag_t, 43 bus_dma_segment_t *, int, bus_size_t, struct proc *, int)); 44 static void jazz_bus_dmamap_free_sgmap __P((bus_dma_tag_t, 45 bus_dma_segment_t *, int)); 46 47 int jazz_bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, 48 bus_size_t, struct proc *, int)); 49 int jazz_bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t, 50 struct mbuf *, int)); 51 int jazz_bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t, 52 struct uio *, int)); 53 int jazz_bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t, 54 bus_dma_segment_t *, int, bus_size_t, int)); 55 void jazz_bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t)); 56 void jazz_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, 57 bus_addr_t, bus_size_t, int)); 58 59 void 60 jazz_bus_dma_tag_init(t) 61 bus_dma_tag_t t; 62 { 63 _bus_dma_tag_init(t); 64 65 t->_dmamap_load = jazz_bus_dmamap_load; 66 t->_dmamap_load_mbuf = jazz_bus_dmamap_load_mbuf; 67 t->_dmamap_load_uio = jazz_bus_dmamap_load_uio; 68 t->_dmamap_load_raw = jazz_bus_dmamap_load_raw; 69 t->_dmamap_unload = jazz_bus_dmamap_unload; 70 t->_dmamap_sync = jazz_bus_dmamap_sync; 71 t->_dmamem_alloc = _bus_dmamem_alloc; 72 t->_dmamem_free = _bus_dmamem_free; 73 } 74 75 static int 76 jazz_bus_dmamap_alloc_sgmap(t, segs, nsegs, boundary, p, flags) 77 bus_dma_tag_t t; 78 bus_dma_segment_t *segs; 79 int nsegs; 80 bus_size_t boundary; 81 struct proc *p; 82 int flags; 83 { 84 jazz_dma_pte_t *dmapte; 85 bus_addr_t addr; 86 bus_size_t off; 87 int i, npte; 88 89 for (i = 0; i < nsegs; i++) { 90 off = jazz_dma_page_offs(segs[i]._ds_paddr); 91 npte = jazz_dma_page_round(segs[i].ds_len + off) / 92 JAZZ_DMA_PAGE_SIZE; 93 dmapte = jazz_dmatlb_alloc(npte, boundary, flags, &addr); 94 if (dmapte == NULL) 95 return (ENOMEM); 96 segs[i].ds_addr = addr + off; 97 98 jazz_dmatlb_map_pa(segs[i]._ds_paddr, segs[i].ds_len, dmapte); 99 } 100 return (0); 101 } 102 103 static void 104 jazz_bus_dmamap_free_sgmap(t, segs, nsegs) 105 bus_dma_tag_t t; 106 bus_dma_segment_t *segs; 107 int nsegs; 108 { 109 int i, npte; 110 bus_addr_t addr; 111 112 for (i = 0; i < nsegs; i++) { 113 addr = (segs[i].ds_addr - t->dma_offset) & JAZZ_DMA_PAGE_NUM; 114 npte = jazz_dma_page_round(segs[i].ds_len + 115 jazz_dma_page_offs(segs[i].ds_addr)) / JAZZ_DMA_PAGE_SIZE; 116 jazz_dmatlb_free(addr, npte); 117 } 118 } 119 120 /* 121 * function for loading a direct-mapped DMA map with a linear buffer. 122 */ 123 int 124 jazz_bus_dmamap_load(t, map, buf, buflen, p, flags) 125 bus_dma_tag_t t; 126 bus_dmamap_t map; 127 void *buf; 128 bus_size_t buflen; 129 struct proc *p; 130 int flags; 131 { 132 int error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 133 134 if (error == 0) { 135 error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, 136 map->dm_nsegs, map->_dm_boundary, p, flags); 137 } 138 return (error); 139 } 140 141 /* 142 * Like jazz_bus_dmamap_load(), but for mbufs. 143 */ 144 int 145 jazz_bus_dmamap_load_mbuf(t, map, m0, flags) 146 bus_dma_tag_t t; 147 bus_dmamap_t map; 148 struct mbuf *m0; 149 int flags; 150 { 151 int error = _bus_dmamap_load_mbuf(t, map, m0, flags); 152 153 if (error == 0) { 154 error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, 155 map->dm_nsegs, map->_dm_boundary, NULL, flags); 156 } 157 return (error); 158 } 159 160 /* 161 * Like jazz_bus_dmamap_load(), but for uios. 162 */ 163 int 164 jazz_bus_dmamap_load_uio(t, map, uio, flags) 165 bus_dma_tag_t t; 166 bus_dmamap_t map; 167 struct uio *uio; 168 int flags; 169 { 170 int error = jazz_bus_dmamap_load_uio(t, map, uio, flags); 171 172 if (error == 0) { 173 error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, 174 map->dm_nsegs, map->_dm_boundary, 175 uio->uio_segflg == UIO_USERSPACE ? uio->uio_procp : NULL, 176 flags); 177 } 178 return (error); 179 } 180 181 /* 182 * Like _bus_dmamap_load(), but for raw memory. 183 */ 184 int 185 jazz_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags) 186 bus_dma_tag_t t; 187 bus_dmamap_t map; 188 bus_dma_segment_t *segs; 189 int nsegs; 190 bus_size_t size; 191 int flags; 192 { 193 int error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); 194 195 if (error == 0) { 196 error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, 197 map->dm_nsegs, map->_dm_boundary, NULL, flags); 198 } 199 return (error); 200 } 201 202 /* 203 * unload a DMA map. 204 */ 205 void 206 jazz_bus_dmamap_unload(t, map) 207 bus_dma_tag_t t; 208 bus_dmamap_t map; 209 { 210 jazz_bus_dmamap_free_sgmap(t, map->dm_segs, map->dm_nsegs); 211 _bus_dmamap_unload(t, map); 212 } 213 214 /* 215 * Function for MIPS3 DMA map synchronization. 216 */ 217 void 218 jazz_bus_dmamap_sync(t, map, offset, len, ops) 219 bus_dma_tag_t t; 220 bus_dmamap_t map; 221 bus_addr_t offset; 222 bus_size_t len; 223 int ops; 224 { 225 /* Flush DMA TLB */ 226 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0) 227 jazz_dmatlb_flush(); 228 229 return (_bus_dmamap_sync(t, map, offset, len, ops)); 230 } 231