xref: /netbsd-src/sys/arch/alpha/pci/apecs_dma.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /* $NetBSD: apecs_dma.c,v 1.19 2010/12/15 01:27:18 matt Exp $ */
2 
3 /*-
4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
34 
35 __KERNEL_RCSID(0, "$NetBSD: apecs_dma.c,v 1.19 2010/12/15 01:27:18 matt Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 
43 #define _ALPHA_BUS_DMA_PRIVATE
44 #include <machine/bus.h>
45 
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcivar.h>
48 #include <alpha/pci/apecsreg.h>
49 #include <alpha/pci/apecsvar.h>
50 
51 bus_dma_tag_t apecs_dma_get_tag(bus_dma_tag_t, alpha_bus_t);
52 
53 int	apecs_bus_dmamap_load_sgmap(bus_dma_tag_t, bus_dmamap_t, void *,
54 	    bus_size_t, struct proc *, int);
55 
56 int	apecs_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t, bus_dmamap_t,
57 	    struct mbuf *, int);
58 
59 int	apecs_bus_dmamap_load_uio_sgmap(bus_dma_tag_t, bus_dmamap_t,
60 	    struct uio *, int);
61 
62 int	apecs_bus_dmamap_load_raw_sgmap(bus_dma_tag_t, bus_dmamap_t,
63 	    bus_dma_segment_t *, int, bus_size_t, int);
64 
65 void	apecs_bus_dmamap_unload_sgmap(bus_dma_tag_t, bus_dmamap_t);
66 
67 /*
68  * Direct-mapped window: 1G at 1G
69  */
70 #define	APECS_DIRECT_MAPPED_BASE (1*1024*1024*1024)
71 #define	APECS_DIRECT_MAPPED_SIZE (1*1024*1024*1024)
72 
73 /*
74  * SGMAP window: 8M at 8M
75  */
76 #define	APECS_SGMAP_MAPPED_BASE	(8*1024*1024)
77 #define	APECS_SGMAP_MAPPED_SIZE	(8*1024*1024)
78 
79 /* APECS has a 256-byte out-bound DMA prefetch threshold. */
80 #define	APECS_SGMAP_PFTHRESH	256
81 
82 /*
83  * Macro to flush APECS scatter/gather TLB.
84  */
85 #define	APECS_TLB_INVALIDATE() \
86 do { \
87 	alpha_mb(); \
88 	REGVAL(EPIC_TBIA) = 0; \
89 	alpha_mb(); \
90 } while (0)
91 
92 void
93 apecs_dma_init(struct apecs_config *acp)
94 {
95 	bus_addr_t tbase;
96 	bus_dma_tag_t t;
97 
98 	/*
99 	 * Initialize the DMA tag used for direct-mapped DMA.
100 	 */
101 	t = &acp->ac_dmat_direct;
102 	t->_cookie = acp;
103 	t->_wbase = APECS_DIRECT_MAPPED_BASE;
104 	t->_wsize = APECS_DIRECT_MAPPED_SIZE;
105 	t->_next_window = NULL;
106 	t->_boundary = 0;
107 	t->_sgmap = NULL;
108 	t->_get_tag = apecs_dma_get_tag;
109 	t->_dmamap_create = _bus_dmamap_create;
110 	t->_dmamap_destroy = _bus_dmamap_destroy;
111 	t->_dmamap_load = _bus_dmamap_load_direct;
112 	t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
113 	t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
114 	t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
115 	t->_dmamap_unload = _bus_dmamap_unload;
116 	t->_dmamap_sync = _bus_dmamap_sync;
117 
118 	t->_dmamem_alloc = _bus_dmamem_alloc;
119 	t->_dmamem_free = _bus_dmamem_free;
120 	t->_dmamem_map = _bus_dmamem_map;
121 	t->_dmamem_unmap = _bus_dmamem_unmap;
122 	t->_dmamem_mmap = _bus_dmamem_mmap;
123 
124 	/*
125 	 * Initialize the DMA tag used for sgmap-mapped DMA.
126 	 */
127 	t = &acp->ac_dmat_sgmap;
128 	t->_cookie = acp;
129 	t->_wbase = APECS_SGMAP_MAPPED_BASE;
130 	t->_wsize = APECS_SGMAP_MAPPED_SIZE;
131 	t->_next_window = NULL;
132 	t->_boundary = 0;
133 	t->_sgmap = &acp->ac_sgmap;
134 	t->_pfthresh = APECS_SGMAP_PFTHRESH;
135 	t->_get_tag = apecs_dma_get_tag;
136 	t->_dmamap_create = alpha_sgmap_dmamap_create;
137 	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
138 	t->_dmamap_load = apecs_bus_dmamap_load_sgmap;
139 	t->_dmamap_load_mbuf = apecs_bus_dmamap_load_mbuf_sgmap;
140 	t->_dmamap_load_uio = apecs_bus_dmamap_load_uio_sgmap;
141 	t->_dmamap_load_raw = apecs_bus_dmamap_load_raw_sgmap;
142 	t->_dmamap_unload = apecs_bus_dmamap_unload_sgmap;
143 	t->_dmamap_sync = _bus_dmamap_sync;
144 
145 	t->_dmamem_alloc = _bus_dmamem_alloc;
146 	t->_dmamem_free = _bus_dmamem_free;
147 	t->_dmamem_map = _bus_dmamem_map;
148 	t->_dmamem_unmap = _bus_dmamem_unmap;
149 	t->_dmamem_mmap = _bus_dmamem_mmap;
150 
151 	/*
152 	 * The firmware has set up window 2 as a 1G direct-mapped DMA
153 	 * window beginning at 1G.  We leave it alone.  Disable
154 	 * window 1.
155 	 */
156 	REGVAL(EPIC_PCI_BASE_1) = 0;
157 	alpha_mb();
158 
159 	/*
160 	 * Initialize the SGMAP.
161 	 */
162 	alpha_sgmap_init(t, &acp->ac_sgmap, "apecs_sgmap",
163 	    APECS_SGMAP_MAPPED_BASE, 0, APECS_SGMAP_MAPPED_SIZE,
164 	    sizeof(u_int64_t), NULL, 0);
165 
166 	/*
167 	 * Set up window 1 as an 8MB SGMAP-mapped window
168 	 * starting at 8MB.
169 	 */
170 	REGVAL(EPIC_PCI_BASE_1) = APECS_SGMAP_MAPPED_BASE |
171 	    EPIC_PCI_BASE_SGEN | EPIC_PCI_BASE_WENB;
172 	alpha_mb();
173 
174 	REGVAL(EPIC_PCI_MASK_1) = EPIC_PCI_MASK_8M;
175 	alpha_mb();
176 
177 	tbase = acp->ac_sgmap.aps_ptpa >> EPIC_TBASE_SHIFT;
178 	if ((tbase & EPIC_TBASE_T_BASE) != tbase)
179 		panic("apecs_dma_init: bad page table address");
180 	REGVAL(EPIC_TBASE_1) = tbase;
181 	alpha_mb();
182 
183 	APECS_TLB_INVALIDATE();
184 
185 	/* XXX XXX BEGIN XXX XXX */
186 	{							/* XXX */
187 		extern paddr_t alpha_XXX_dmamap_or;		/* XXX */
188 		alpha_XXX_dmamap_or = APECS_DIRECT_MAPPED_BASE;	/* XXX */
189 	}							/* XXX */
190 	/* XXX XXX END XXX XXX */
191 }
192 
193 /*
194  * Return the bus dma tag to be used for the specified bus type.
195  * INTERNAL USE ONLY!
196  */
197 bus_dma_tag_t
198 apecs_dma_get_tag(bus_dma_tag_t t, alpha_bus_t bustype)
199 {
200 	struct apecs_config *acp = t->_cookie;
201 
202 	switch (bustype) {
203 	case ALPHA_BUS_PCI:
204 	case ALPHA_BUS_EISA:
205 		/*
206 		 * Systems with an APECS can only support 1G
207 		 * of memory, so we use the direct-mapped window
208 		 * on busses that have 32-bit DMA.
209 		 */
210 		return (&acp->ac_dmat_direct);
211 
212 	case ALPHA_BUS_ISA:
213 		/*
214 		 * ISA doesn't have enough address bits to use
215 		 * the direct-mapped DMA window, so we must use
216 		 * SGMAPs.
217 		 */
218 		return (&acp->ac_dmat_sgmap);
219 
220 	default:
221 		panic("apecs_dma_get_tag: shouldn't be here, really...");
222 	}
223 }
224 
225 /*
226  * Load an APECS SGMAP-mapped DMA map with a linear buffer.
227  */
228 int
229 apecs_bus_dmamap_load_sgmap(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, struct proc *p, int flags)
230 {
231 	int error;
232 
233 	error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
234 	    t->_sgmap);
235 	if (error == 0)
236 		APECS_TLB_INVALIDATE();
237 
238 	return (error);
239 }
240 
241 /*
242  * Load an APECS SGMAP-mapped DMA map with an mbuf chain.
243  */
244 int
245 apecs_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m, int flags)
246 {
247 	int error;
248 
249 	error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, t->_sgmap);
250 	if (error == 0)
251 		APECS_TLB_INVALIDATE();
252 
253 	return (error);
254 }
255 
256 /*
257  * Load an APECS SGMAP-mapped DMA map with a uio.
258  */
259 int
260 apecs_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags)
261 {
262 	int error;
263 
264 	error = pci_sgmap_pte64_load_uio(t, map, uio, flags, t->_sgmap);
265 	if (error == 0)
266 		APECS_TLB_INVALIDATE();
267 
268 	return (error);
269 }
270 
271 /*
272  * Load an APECS SGMAP-mapped DMA map with raw memory.
273  */
274 int
275 apecs_bus_dmamap_load_raw_sgmap(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
276 {
277 	int error;
278 
279 	error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
280 	    t->_sgmap);
281 	if (error == 0)
282 		APECS_TLB_INVALIDATE();
283 
284 	return (error);
285 }
286 
287 /*
288  * Unload an APECS DMA map.
289  */
290 void
291 apecs_bus_dmamap_unload_sgmap(bus_dma_tag_t t, bus_dmamap_t map)
292 {
293 
294 	/*
295 	 * Invalidate any SGMAP page table entries used by this
296 	 * mapping.
297 	 */
298 	pci_sgmap_pte64_unload(t, map, t->_sgmap);
299 	APECS_TLB_INVALIDATE();
300 
301 	/*
302 	 * Do the generic bits of the unload.
303 	 */
304 	_bus_dmamap_unload(t, map);
305 }
306