xref: /openbsd/sys/arch/alpha/dev/sgmap_common.c (revision 5be19075)
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