1 /* $OpenBSD: sgmap_common.c,v 1.2 2001/07/05 10:00:25 art 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 <vm/vm.h> 48 #include <uvm/uvm_extern.h> 49 50 #include <machine/bus.h> 51 52 #include <alpha/dev/sgmapvar.h> 53 54 /* 55 * Some systems will prefetch the next page during a memory -> device DMA. 56 * This can cause machine checks if there is not a spill page after the 57 * last page of the DMA (thus avoiding hitting an invalid SGMAP PTE). 58 */ 59 vaddr_t alpha_sgmap_prefetch_spill_page_va; 60 bus_addr_t alpha_sgmap_prefetch_spill_page_pa; 61 62 void 63 alpha_sgmap_init(t, sgmap, name, wbase, sgvabase, sgvasize, ptesize, ptva, 64 minptalign) 65 bus_dma_tag_t t; 66 struct alpha_sgmap *sgmap; 67 const char *name; 68 bus_addr_t wbase; 69 bus_addr_t sgvabase; 70 bus_size_t sgvasize; 71 size_t ptesize; 72 void *ptva; 73 bus_size_t minptalign; 74 { 75 bus_dma_segment_t seg; 76 size_t ptsize; 77 int rseg; 78 79 if (sgvasize & PGOFSET) { 80 printf("size botch for sgmap `%s'\n", name); 81 goto die; 82 } 83 84 sgmap->aps_wbase = wbase; 85 sgmap->aps_sgvabase = sgvabase; 86 sgmap->aps_sgvasize = sgvasize; 87 88 if (ptva != NULL) { 89 /* 90 * We already have a page table; this may be a system 91 * where the page table resides in bridge-resident SRAM. 92 */ 93 sgmap->aps_pt = ptva; 94 sgmap->aps_ptpa = 0; 95 } else { 96 /* 97 * Compute the page table size and allocate it. At minimum, 98 * this must be aligned to the page table size. However, 99 * some platforms have more strict alignment reqirements. 100 */ 101 ptsize = (sgvasize / NBPG) * ptesize; 102 if (minptalign != 0) { 103 if (minptalign < ptsize) 104 minptalign = ptsize; 105 } else 106 minptalign = ptsize; 107 if (bus_dmamem_alloc(t, ptsize, minptalign, 0, &seg, 1, &rseg, 108 BUS_DMA_NOWAIT)) { 109 panic("unable to allocate page table for sgmap `%s'\n", 110 name); 111 goto die; 112 } 113 sgmap->aps_ptpa = seg.ds_addr; 114 sgmap->aps_pt = (caddr_t)ALPHA_PHYS_TO_K0SEG(sgmap->aps_ptpa); 115 } 116 117 /* 118 * Create the extent map used to manage the virtual address 119 * space. 120 */ 121 sgmap->aps_ex = extent_create((char *)name, sgvabase, sgvasize - 1, 122 M_DEVBUF, NULL, 0, EX_NOWAIT|EX_NOCOALESCE); 123 if (sgmap->aps_ex == NULL) { 124 printf("unable to create extent map for sgmap `%s'\n", 125 name); 126 goto die; 127 } 128 129 /* 130 * Allocate a spill page if that hasn't already been done. 131 */ 132 if (alpha_sgmap_prefetch_spill_page_va == 0) { 133 if (bus_dmamem_alloc(t, NBPG, 0, 0, &seg, 1, &rseg, 134 BUS_DMA_NOWAIT)) { 135 printf("unable to allocate spill page for sgmap `%s'\n", 136 name); 137 goto die; 138 } 139 alpha_sgmap_prefetch_spill_page_pa = seg.ds_addr; 140 alpha_sgmap_prefetch_spill_page_va = 141 ALPHA_PHYS_TO_K0SEG(alpha_sgmap_prefetch_spill_page_pa); 142 bzero((caddr_t)alpha_sgmap_prefetch_spill_page_va, NBPG); 143 } 144 145 return; 146 die: 147 panic("alpha_sgmap_init"); 148 } 149 150 int 151 alpha_sgmap_alloc(map, origlen, sgmap, flags) 152 bus_dmamap_t map; 153 bus_size_t origlen; 154 struct alpha_sgmap *sgmap; 155 int flags; 156 { 157 int error; 158 bus_size_t len = origlen, boundary, alignment; 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 error = extent_alloc(sgmap->aps_ex, map->_dm_sgvalen, alignment, 0, 195 boundary, (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK, 196 &map->_dm_sgva); 197 #if 0 198 printf("error %d _dm_sgva %x\n", error, map->_dm_sgva); 199 #endif 200 201 if (error == 0) 202 map->_dm_flags |= DMAMAP_HAS_SGMAP; 203 else 204 map->_dm_flags &= ~DMAMAP_HAS_SGMAP; 205 206 return (error); 207 } 208 209 void 210 alpha_sgmap_free(map, sgmap) 211 bus_dmamap_t map; 212 struct alpha_sgmap *sgmap; 213 { 214 215 #ifdef DIAGNOSTIC 216 if ((map->_dm_flags & DMAMAP_HAS_SGMAP) == 0) 217 panic("alpha_sgmap_free: no sgva space to free"); 218 #endif 219 220 if (extent_free(sgmap->aps_ex, map->_dm_sgva, map->_dm_sgvalen, 221 EX_NOWAIT)) 222 panic("alpha_sgmap_free"); 223 224 map->_dm_flags &= ~DMAMAP_HAS_SGMAP; 225 } 226