1 /* $OpenBSD: sgmap_common.c,v 1.6 2003/10/18 20:14:41 jmc Exp $ */ 2 /* $NetBSD: sgmap_common.c,v 1.13 2000/06/29 09:02:57 mrg Exp $ */ 3 4 /*- 5 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/proc.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <machine/bus.h> 50 51 #include <alpha/dev/sgmapvar.h> 52 53 /* 54 * Some systems will prefetch the next page during a memory -> device DMA. 55 * This can cause machine checks if there is not a spill page after the 56 * last page of the DMA (thus avoiding hitting an invalid SGMAP PTE). 57 */ 58 vaddr_t alpha_sgmap_prefetch_spill_page_va; 59 bus_addr_t alpha_sgmap_prefetch_spill_page_pa; 60 61 void 62 alpha_sgmap_init(t, sgmap, name, wbase, sgvabase, sgvasize, ptesize, ptva, 63 minptalign) 64 bus_dma_tag_t t; 65 struct alpha_sgmap *sgmap; 66 const char *name; 67 bus_addr_t wbase; 68 bus_addr_t sgvabase; 69 bus_size_t sgvasize; 70 size_t ptesize; 71 void *ptva; 72 bus_size_t minptalign; 73 { 74 bus_dma_segment_t seg; 75 size_t ptsize; 76 int rseg; 77 78 if (sgvasize & PGOFSET) { 79 printf("size botch for sgmap `%s'\n", name); 80 goto die; 81 } 82 83 sgmap->aps_wbase = wbase; 84 sgmap->aps_sgvabase = sgvabase; 85 sgmap->aps_sgvasize = sgvasize; 86 87 if (ptva != NULL) { 88 /* 89 * We already have a page table; this may be a system 90 * where the page table resides in bridge-resident SRAM. 91 */ 92 sgmap->aps_pt = ptva; 93 sgmap->aps_ptpa = 0; 94 } else { 95 /* 96 * Compute the page table size and allocate it. At minimum, 97 * this must be aligned to the page table size. However, 98 * some platforms have more strict alignment requirements. 99 */ 100 ptsize = (sgvasize / NBPG) * ptesize; 101 if (minptalign != 0) { 102 if (minptalign < ptsize) 103 minptalign = ptsize; 104 } else 105 minptalign = ptsize; 106 if (bus_dmamem_alloc(t, ptsize, minptalign, 0, &seg, 1, &rseg, 107 BUS_DMA_NOWAIT)) { 108 panic("unable to allocate page table for sgmap `%s'", 109 name); 110 goto die; 111 } 112 sgmap->aps_ptpa = seg.ds_addr; 113 sgmap->aps_pt = (caddr_t)ALPHA_PHYS_TO_K0SEG(sgmap->aps_ptpa); 114 } 115 116 /* 117 * Create the extent map used to manage the virtual address 118 * space. 119 */ 120 sgmap->aps_ex = extent_create((char *)name, sgvabase, sgvasize - 1, 121 M_DEVBUF, NULL, 0, EX_NOWAIT|EX_NOCOALESCE); 122 if (sgmap->aps_ex == NULL) { 123 printf("unable to create extent map for sgmap `%s'\n", 124 name); 125 goto die; 126 } 127 128 /* 129 * Allocate a spill page if that hasn't already been done. 130 */ 131 if (alpha_sgmap_prefetch_spill_page_va == 0) { 132 if (bus_dmamem_alloc(t, NBPG, 0, 0, &seg, 1, &rseg, 133 BUS_DMA_NOWAIT)) { 134 printf("unable to allocate spill page for sgmap `%s'\n", 135 name); 136 goto die; 137 } 138 alpha_sgmap_prefetch_spill_page_pa = seg.ds_addr; 139 alpha_sgmap_prefetch_spill_page_va = 140 ALPHA_PHYS_TO_K0SEG(alpha_sgmap_prefetch_spill_page_pa); 141 bzero((caddr_t)alpha_sgmap_prefetch_spill_page_va, NBPG); 142 } 143 144 return; 145 die: 146 panic("alpha_sgmap_init"); 147 } 148 149 int 150 alpha_sgmap_alloc(map, origlen, sgmap, flags) 151 bus_dmamap_t map; 152 bus_size_t origlen; 153 struct alpha_sgmap *sgmap; 154 int flags; 155 { 156 int error; 157 bus_size_t len = origlen, boundary, alignment; 158 int s; 159 160 #ifdef DIAGNOSTIC 161 if (map->_dm_flags & DMAMAP_HAS_SGMAP) 162 panic("alpha_sgmap_alloc: already have sgva space"); 163 #endif 164 /* 165 * Add a range for spill page. 166 */ 167 len += NBPG; 168 169 /* 170 * And add an additional amount in case of ALLOCNOW. 171 */ 172 if (flags & BUS_DMA_ALLOCNOW) 173 len += NBPG; 174 175 map->_dm_sgvalen = round_page(len); 176 177 /* 178 * ARGH! If the addition of spill pages bumped us over our 179 * boundary, we have to 2x the boundary limit. 180 */ 181 boundary = map->_dm_boundary; 182 if (boundary && boundary < map->_dm_sgvalen) { 183 alignment = boundary; 184 do { 185 boundary <<= 1; 186 } while (boundary < map->_dm_sgvalen); 187 } else 188 alignment = NBPG; 189 #if 0 190 printf("len %x -> %x, _dm_sgvalen %x _dm_boundary %x boundary %x -> ", 191 origlen, len, map->_dm_sgvalen, map->_dm_boundary, boundary); 192 #endif 193 194 s = splvm(); 195 error = extent_alloc(sgmap->aps_ex, map->_dm_sgvalen, alignment, 0, 196 boundary, (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK, 197 &map->_dm_sgva); 198 splx(s); 199 #if 0 200 printf("error %d _dm_sgva %x\n", error, map->_dm_sgva); 201 #endif 202 203 if (error == 0) 204 map->_dm_flags |= DMAMAP_HAS_SGMAP; 205 else 206 map->_dm_flags &= ~DMAMAP_HAS_SGMAP; 207 208 return (error); 209 } 210 211 void 212 alpha_sgmap_free(map, sgmap) 213 bus_dmamap_t map; 214 struct alpha_sgmap *sgmap; 215 { 216 int s; 217 218 #ifdef DIAGNOSTIC 219 if ((map->_dm_flags & DMAMAP_HAS_SGMAP) == 0) 220 panic("alpha_sgmap_free: no sgva space to free"); 221 #endif 222 223 s = splvm(); 224 if (extent_free(sgmap->aps_ex, map->_dm_sgva, map->_dm_sgvalen, 225 EX_NOWAIT)) 226 panic("alpha_sgmap_free"); 227 splx(s); 228 229 map->_dm_flags &= ~DMAMAP_HAS_SGMAP; 230 } 231