1 /* $OpenBSD: sgmap_common.c,v 1.15 2019/05/13 21:27:59 mpi 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 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #define _ALPHA_BUS_DMA_PRIVATE
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/proc.h>
41
42 #include <uvm/uvm_extern.h>
43
44 #include <machine/bus.h>
45
46 #include <alpha/dev/sgmapvar.h>
47
48 /*
49 * Some systems will prefetch the next page during a memory -> device DMA.
50 * This can cause machine checks if there is not a spill page after the
51 * last page of the DMA (thus avoiding hitting an invalid SGMAP PTE).
52 */
53 vaddr_t alpha_sgmap_prefetch_spill_page_va;
54 bus_addr_t alpha_sgmap_prefetch_spill_page_pa;
55
56 void
alpha_sgmap_init(t,sgmap,name,wbase,sgvabase,sgvasize,ptesize,ptva,minptalign)57 alpha_sgmap_init(t, sgmap, name, wbase, sgvabase, sgvasize, ptesize, ptva,
58 minptalign)
59 bus_dma_tag_t t;
60 struct alpha_sgmap *sgmap;
61 const char *name;
62 bus_addr_t wbase;
63 bus_addr_t sgvabase;
64 bus_size_t sgvasize;
65 size_t ptesize;
66 void *ptva;
67 bus_size_t minptalign;
68 {
69 bus_dma_segment_t seg;
70 size_t ptsize;
71 int rseg;
72
73 if (sgvasize & PGOFSET) {
74 printf("size botch for sgmap `%s'\n", name);
75 goto die;
76 }
77
78 sgmap->aps_wbase = wbase;
79 sgmap->aps_sgvabase = sgvabase;
80 sgmap->aps_sgvasize = sgvasize;
81
82 if (ptva != NULL) {
83 /*
84 * We already have a page table; this may be a system
85 * where the page table resides in bridge-resident SRAM.
86 */
87 sgmap->aps_pt = ptva;
88 sgmap->aps_ptpa = 0;
89 } else {
90 /*
91 * Compute the page table size and allocate it. At minimum,
92 * this must be aligned to the page table size. However,
93 * some platforms have more strict alignment requirements.
94 */
95 ptsize = (sgvasize / PAGE_SIZE) * ptesize;
96 if (minptalign != 0) {
97 if (minptalign < ptsize)
98 minptalign = ptsize;
99 } else
100 minptalign = ptsize;
101 if (bus_dmamem_alloc(t, ptsize, minptalign, 0, &seg, 1, &rseg,
102 BUS_DMA_NOWAIT)) {
103 panic("unable to allocate page table for sgmap `%s'",
104 name);
105 goto die;
106 }
107 sgmap->aps_ptpa = seg.ds_addr;
108 sgmap->aps_pt = (caddr_t)ALPHA_PHYS_TO_K0SEG(sgmap->aps_ptpa);
109 }
110
111 /*
112 * Create the extent map used to manage the virtual address
113 * space.
114 */
115 sgmap->aps_ex = extent_create((char *)name, sgvabase, sgvasize - 1,
116 M_DEVBUF, NULL, 0, EX_NOWAIT|EX_NOCOALESCE);
117 if (sgmap->aps_ex == NULL) {
118 printf("unable to create extent map for sgmap `%s'\n",
119 name);
120 goto die;
121 }
122 mtx_init(&sgmap->aps_mtx, IPL_HIGH);
123
124 /*
125 * Allocate a spill page if that hasn't already been done.
126 */
127 if (alpha_sgmap_prefetch_spill_page_va == 0) {
128 if (bus_dmamem_alloc(t, PAGE_SIZE, 0, 0, &seg, 1, &rseg,
129 BUS_DMA_NOWAIT)) {
130 printf("unable to allocate spill page for sgmap `%s'\n",
131 name);
132 goto die;
133 }
134 alpha_sgmap_prefetch_spill_page_pa = seg.ds_addr;
135 alpha_sgmap_prefetch_spill_page_va =
136 ALPHA_PHYS_TO_K0SEG(alpha_sgmap_prefetch_spill_page_pa);
137 bzero((caddr_t)alpha_sgmap_prefetch_spill_page_va, PAGE_SIZE);
138 }
139
140 return;
141 die:
142 panic("alpha_sgmap_init");
143 }
144
145 int
alpha_sgmap_dmamap_setup(map,nsegments,flags)146 alpha_sgmap_dmamap_setup(map, nsegments, flags)
147 bus_dmamap_t map;
148 int nsegments;
149 int flags;
150 {
151 map->_dm_cookie = mallocarray(nsegments, sizeof(struct extent_region),
152 M_DEVBUF, (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK);
153 if (map->_dm_cookie != NULL)
154 map->_dm_cookiesize = nsegments * sizeof(struct extent_region);
155 return (map->_dm_cookie == NULL);
156 }
157
158 int
alpha_sgmap_dmamap_create(t,size,nsegments,maxsegsz,boundary,flags,dmamp)159 alpha_sgmap_dmamap_create(t, size, nsegments, maxsegsz, boundary,
160 flags, dmamp)
161 bus_dma_tag_t t;
162 bus_size_t size;
163 int nsegments;
164 bus_size_t maxsegsz;
165 bus_size_t boundary;
166 int flags;
167 bus_dmamap_t *dmamp;
168 {
169 bus_dmamap_t map;
170 int error;
171
172 error = _bus_dmamap_create(t, size, nsegments, maxsegsz,
173 boundary, flags, dmamp);
174 if (error)
175 return (error);
176
177 map = *dmamp;
178 if (alpha_sgmap_dmamap_setup(map, nsegments, flags)) {
179 _bus_dmamap_destroy(t, map);
180 return (ENOMEM);
181 }
182
183 /* XXX BUS_DMA_ALLOCNOW */
184
185 return (0);
186 }
187
188 void
alpha_sgmap_dmamap_teardown(map)189 alpha_sgmap_dmamap_teardown(map)
190 bus_dmamap_t map;
191 {
192 free(map->_dm_cookie, M_DEVBUF, map->_dm_cookiesize);
193 }
194
195 void
alpha_sgmap_dmamap_destroy(t,map)196 alpha_sgmap_dmamap_destroy(t, map)
197 bus_dma_tag_t t;
198 bus_dmamap_t map;
199 {
200 KASSERT(map->dm_mapsize == 0);
201
202 alpha_sgmap_dmamap_teardown(map);
203 _bus_dmamap_destroy(t, map);
204 }
205