xref: /netbsd-src/sys/arch/alpha/pci/mcpcia_dma.c (revision a7e090f70e491979434963c9a27df4020fe0a18b)
1 /* $NetBSD: mcpcia_dma.c,v 1.18 2009/03/14 15:35:59 dsl Exp $ */
2 
3 /*-
4  * Copyright (c) 1997, 1998, 1999 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 and Matthew Jacob of the Numerical Aerospace Simulation
9  * Facility, 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: mcpcia_dma.c,v 1.18 2009/03/14 15:35:59 dsl 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 #include <uvm/uvm_extern.h>
44 
45 #define _ALPHA_BUS_DMA_PRIVATE
46 #include <machine/bus.h>
47 
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcivar.h>
50 #include <alpha/pci/mcpciareg.h>
51 #include <alpha/pci/mcpciavar.h>
52 #include <alpha/pci/pci_kn300.h>
53 
54 bus_dma_tag_t mcpcia_dma_get_tag(bus_dma_tag_t, alpha_bus_t);
55 
56 int	mcpcia_bus_dmamap_load_sgmap(bus_dma_tag_t, bus_dmamap_t, void *,
57 	    bus_size_t, struct proc *, int);
58 
59 int	mcpcia_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t, bus_dmamap_t,
60 	    struct mbuf *, int);
61 
62 int	mcpcia_bus_dmamap_load_uio_sgmap(bus_dma_tag_t, bus_dmamap_t,
63 	    struct uio *, int);
64 
65 int	mcpcia_bus_dmamap_load_raw_sgmap(bus_dma_tag_t, bus_dmamap_t,
66 	    bus_dma_segment_t *, int, bus_size_t, int);
67 
68 void	mcpcia_bus_dmamap_unload_sgmap(bus_dma_tag_t, bus_dmamap_t);
69 
70 /*
71  * Direct-mapped window: 2G at 2G
72  */
73 #define	MCPCIA_DIRECT_MAPPED_BASE	(2UL*1024UL*1024UL*1024UL)
74 #define	MCPCIA_DIRECT_MAPPED_SIZE	(2UL*1024UL*1024UL*1024UL)
75 
76 /*
77  * SGMAP window for PCI: 1G at 1G
78  */
79 #define	MCPCIA_PCI_SG_MAPPED_BASE	(1UL*1024UL*1024UL*1024UL)
80 #define	MCPCIA_PCI_SG_MAPPED_SIZE	(1UL*1024UL*1024UL*1024UL)
81 
82 /*
83  * SGMAP window for ISA: 8M at 8M
84  */
85 #define	MCPCIA_ISA_SG_MAPPED_BASE	(8*1024*1024)
86 #define	MCPCIA_ISA_SG_MAPPED_SIZE	(8*1024*1024)
87 
88 /* MCPCIA has a 256-byte out-bound DMA prefetch threshold. */
89 #define	MCPCIA_SG_MAPPED_PFTHRESH	256
90 
91 #define	MCPCIA_SGTLB_INVALIDATE(ccp)					\
92 do {									\
93 	alpha_mb();							\
94 	REGVAL(MCPCIA_SG_TBIA(ccp)) = 0xdeadbeef;			\
95 	alpha_mb();							\
96 } while (0)
97 
98 void
99 mcpcia_dma_init(struct mcpcia_config *ccp)
100 {
101 	bus_dma_tag_t t;
102 
103 	/*
104 	 * Initialize the DMA tag used for direct-mapped DMA.
105 	 */
106 	t = &ccp->cc_dmat_direct;
107 	t->_cookie = ccp;
108 	t->_wbase = MCPCIA_DIRECT_MAPPED_BASE;
109 	t->_wsize = MCPCIA_DIRECT_MAPPED_SIZE;
110 	t->_next_window = &ccp->cc_dmat_pci_sgmap;
111 	t->_boundary = 0;
112 	t->_sgmap = NULL;
113 	t->_get_tag = mcpcia_dma_get_tag;
114 	t->_dmamap_create = _bus_dmamap_create;
115 	t->_dmamap_destroy = _bus_dmamap_destroy;
116 	t->_dmamap_load = _bus_dmamap_load_direct;
117 	t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
118 	t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
119 	t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
120 	t->_dmamap_unload = _bus_dmamap_unload;
121 	t->_dmamap_sync = _bus_dmamap_sync;
122 
123 	t->_dmamem_alloc = _bus_dmamem_alloc;
124 	t->_dmamem_free = _bus_dmamem_free;
125 	t->_dmamem_map = _bus_dmamem_map;
126 	t->_dmamem_unmap = _bus_dmamem_unmap;
127 	t->_dmamem_mmap = _bus_dmamem_mmap;
128 
129 	/*
130 	 * Initialize the DMA tag used for sgmap-mapped PCI DMA.
131 	 */
132 	t = &ccp->cc_dmat_pci_sgmap;
133 	t->_cookie = ccp;
134 	t->_wbase = MCPCIA_PCI_SG_MAPPED_BASE;
135 	t->_wsize = MCPCIA_PCI_SG_MAPPED_SIZE;
136 	t->_next_window = NULL;
137 	t->_boundary = 0;
138 	t->_sgmap = &ccp->cc_pci_sgmap;
139 	t->_pfthresh = MCPCIA_SG_MAPPED_PFTHRESH;
140 	t->_get_tag = mcpcia_dma_get_tag;
141 	t->_dmamap_create = alpha_sgmap_dmamap_create;
142 	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
143 	t->_dmamap_load = mcpcia_bus_dmamap_load_sgmap;
144 	t->_dmamap_load_mbuf = mcpcia_bus_dmamap_load_mbuf_sgmap;
145 	t->_dmamap_load_uio = mcpcia_bus_dmamap_load_uio_sgmap;
146 	t->_dmamap_load_raw = mcpcia_bus_dmamap_load_raw_sgmap;
147 	t->_dmamap_unload = mcpcia_bus_dmamap_unload_sgmap;
148 	t->_dmamap_sync = _bus_dmamap_sync;
149 
150 	t->_dmamem_alloc = _bus_dmamem_alloc;
151 	t->_dmamem_free = _bus_dmamem_free;
152 	t->_dmamem_map = _bus_dmamem_map;
153 	t->_dmamem_unmap = _bus_dmamem_unmap;
154 	t->_dmamem_mmap = _bus_dmamem_mmap;
155 
156 	/*
157 	 * Initialize the DMA tag used for sgmap-mapped ISA DMA.
158 	 */
159 	t = &ccp->cc_dmat_isa_sgmap;
160 	t->_cookie = ccp;
161 	t->_wbase = MCPCIA_ISA_SG_MAPPED_BASE;
162 	t->_wsize = MCPCIA_ISA_SG_MAPPED_SIZE;
163 	t->_next_window = NULL;
164 	t->_boundary = 0;
165 	t->_sgmap = &ccp->cc_isa_sgmap;
166 	t->_pfthresh = MCPCIA_SG_MAPPED_PFTHRESH;
167 	t->_get_tag = mcpcia_dma_get_tag;
168 	t->_dmamap_create = alpha_sgmap_dmamap_create;
169 	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
170 	t->_dmamap_load = mcpcia_bus_dmamap_load_sgmap;
171 	t->_dmamap_load_mbuf = mcpcia_bus_dmamap_load_mbuf_sgmap;
172 	t->_dmamap_load_uio = mcpcia_bus_dmamap_load_uio_sgmap;
173 	t->_dmamap_load_raw = mcpcia_bus_dmamap_load_raw_sgmap;
174 	t->_dmamap_unload = mcpcia_bus_dmamap_unload_sgmap;
175 	t->_dmamap_sync = _bus_dmamap_sync;
176 
177 	t->_dmamem_alloc = _bus_dmamem_alloc;
178 	t->_dmamem_free = _bus_dmamem_free;
179 	t->_dmamem_map = _bus_dmamem_map;
180 	t->_dmamem_unmap = _bus_dmamem_unmap;
181 	t->_dmamem_mmap = _bus_dmamem_mmap;
182 
183 	/*
184 	 * Initialize the SGMAPs.
185 	 */
186 	alpha_sgmap_init(&ccp->cc_dmat_pci_sgmap, &ccp->cc_pci_sgmap,
187 	    "mcpcia pci sgmap",
188 	    MCPCIA_PCI_SG_MAPPED_BASE, 0, MCPCIA_PCI_SG_MAPPED_SIZE,
189 	    sizeof(u_int64_t), NULL, 0);
190 
191 	alpha_sgmap_init(&ccp->cc_dmat_isa_sgmap, &ccp->cc_isa_sgmap,
192 	    "mcpcia isa sgmap",
193 	    MCPCIA_ISA_SG_MAPPED_BASE, 0, MCPCIA_ISA_SG_MAPPED_SIZE,
194 	    sizeof(u_int64_t), NULL, 0);
195 
196 	/*
197 	 * Disable windows first.
198 	 */
199 
200 	REGVAL(MCPCIA_W0_BASE(ccp)) = 0;
201 	REGVAL(MCPCIA_W1_BASE(ccp)) = 0;
202 	REGVAL(MCPCIA_W2_BASE(ccp)) = 0;
203 	REGVAL(MCPCIA_W3_BASE(ccp)) = 0;
204 	REGVAL(MCPCIA_T0_BASE(ccp)) = 0;
205 	REGVAL(MCPCIA_T1_BASE(ccp)) = 0;
206 	REGVAL(MCPCIA_T2_BASE(ccp)) = 0;
207 	REGVAL(MCPCIA_T3_BASE(ccp)) = 0;
208 	alpha_mb();
209 
210 	/*
211 	 * Set up window 0 as an 8MB SGMAP-mapped window starting at 8MB.
212 	 */
213 	REGVAL(MCPCIA_W0_MASK(ccp)) = MCPCIA_WMASK_8M;
214 	REGVAL(MCPCIA_T0_BASE(ccp)) =
215 		ccp->cc_isa_sgmap.aps_ptpa >> MCPCIA_TBASEX_SHIFT;
216 	alpha_mb();
217 	REGVAL(MCPCIA_W0_BASE(ccp)) =
218 		MCPCIA_WBASE_EN | MCPCIA_WBASE_SG | MCPCIA_ISA_SG_MAPPED_BASE;
219 	alpha_mb();
220 
221 	MCPCIA_SGTLB_INVALIDATE(ccp);
222 
223 	/*
224 	 * Set up window 1 as a 2 GB Direct-mapped window starting at 2GB.
225 	 */
226 
227 	REGVAL(MCPCIA_W1_MASK(ccp)) = MCPCIA_WMASK_2G;
228 	REGVAL(MCPCIA_T1_BASE(ccp)) = 0;
229 	alpha_mb();
230 	REGVAL(MCPCIA_W1_BASE(ccp)) =
231 		MCPCIA_DIRECT_MAPPED_BASE | MCPCIA_WBASE_EN;
232 	alpha_mb();
233 
234 	/*
235 	 * Set up window 2 as a 1G SGMAP-mapped window starting at 1G.
236 	 */
237 
238 	REGVAL(MCPCIA_W2_MASK(ccp)) = MCPCIA_WMASK_1G;
239 	REGVAL(MCPCIA_T2_BASE(ccp)) =
240 		ccp->cc_pci_sgmap.aps_ptpa >> MCPCIA_TBASEX_SHIFT;
241 	alpha_mb();
242 	REGVAL(MCPCIA_W2_BASE(ccp)) =
243 		MCPCIA_WBASE_EN | MCPCIA_WBASE_SG | MCPCIA_PCI_SG_MAPPED_BASE;
244 	alpha_mb();
245 
246 	/* XXX XXX BEGIN XXX XXX */
247 	{							/* XXX */
248 		extern paddr_t alpha_XXX_dmamap_or;		/* XXX */
249 		alpha_XXX_dmamap_or = MCPCIA_DIRECT_MAPPED_BASE;/* XXX */
250 	}							/* XXX */
251 	/* XXX XXX END XXX XXX */
252 }
253 
254 /*
255  * Return the bus dma tag to be used for the specified bus type.
256  * INTERNAL USE ONLY!
257  */
258 bus_dma_tag_t
259 mcpcia_dma_get_tag(bus_dma_tag_t t, alpha_bus_t bustype)
260 {
261 	struct mcpcia_config *ccp = t->_cookie;
262 
263 	switch (bustype) {
264 	case ALPHA_BUS_PCI:
265 	case ALPHA_BUS_EISA:
266 		/*
267 		 * Start off using the direct-mapped window.  We will
268 		 * automatically fall backed onto the chained PCI SGMAP
269 		 * window if necessary.
270 		 */
271 		return (&ccp->cc_dmat_direct);
272 
273 	case ALPHA_BUS_ISA:
274 		/*
275 		 * ISA doesn't have enough address bits to use
276 		 * the direct-mapped DMA window, so we must use
277 		 * SGMAPs.
278 		 */
279 		return (&ccp->cc_dmat_isa_sgmap);
280 
281 	default:
282 		panic("mcpcia_dma_get_tag: shouldn't be here, really...");
283 	}
284 }
285 
286 /*
287  * Load a MCPCIA SGMAP-mapped DMA map with a linear buffer.
288  */
289 int
290 mcpcia_bus_dmamap_load_sgmap(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, struct proc *p, int flags)
291 {
292 	int error;
293 	struct mcpcia_config *ccp = t->_cookie;
294 
295 	error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
296 	    t->_sgmap);
297 	if (error == 0)
298 		MCPCIA_SGTLB_INVALIDATE(ccp);
299 	return (error);
300 }
301 
302 /*
303  * Load a MCPCIA SGMAP-mapped DMA map with an mbuf chain.
304  */
305 int
306 mcpcia_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m, int flags)
307 {
308 	int error;
309 	struct mcpcia_config *ccp = t->_cookie;
310 
311 	error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, t->_sgmap);
312 	if (error == 0)
313 		MCPCIA_SGTLB_INVALIDATE(ccp);
314 	return (error);
315 }
316 
317 /*
318  * Load a MCPCIA SGMAP-mapped DMA map with a uio.
319  */
320 int
321 mcpcia_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags)
322 {
323 	int error;
324 	struct mcpcia_config *ccp = t->_cookie;
325 
326 	error = pci_sgmap_pte64_load_uio(t, map, uio, flags, t->_sgmap);
327 	if (error == 0)
328 		MCPCIA_SGTLB_INVALIDATE(ccp);
329 	return (error);
330 }
331 
332 /*
333  * Load a MCPCIA SGMAP-mapped DMA map with raw memory.
334  */
335 int
336 mcpcia_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)
337 {
338 	int error;
339 	struct mcpcia_config *ccp = t->_cookie;
340 
341 	error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
342 	    t->_sgmap);
343 	if (error == 0)
344 		MCPCIA_SGTLB_INVALIDATE(ccp);
345 	return (error);
346 }
347 
348 /*
349  * Unload a MCPCIA DMA map.
350  */
351 void
352 mcpcia_bus_dmamap_unload_sgmap(bus_dma_tag_t t, bus_dmamap_t map)
353 {
354 	struct mcpcia_config *ccp = t->_cookie;
355 
356 	/*
357 	 * Invalidate any SGMAP page table entries used by this mapping.
358 	 */
359 	pci_sgmap_pte64_unload(t, map, t->_sgmap);
360 	MCPCIA_SGTLB_INVALIDATE(ccp);
361 
362 	/*
363 	 * Do the generic bits of the unload.
364 	 */
365 	_bus_dmamap_unload(t, map);
366 }
367