xref: /netbsd-src/sys/arch/alpha/pci/ttwoga_dma.c (revision 2980e352a13e8f0b545a366830c411e7a542ada8)
1 /* $NetBSD: ttwoga_dma.c,v 1.4 2008/04/28 20:23:11 martin Exp $ */
2 
3 /*-
4  * Copyright (c) 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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 __KERNEL_RCSID(0, "$NetBSD: ttwoga_dma.c,v 1.4 2008/04/28 20:23:11 martin Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 
41 #include <uvm/uvm_extern.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 
49 #include <alpha/pci/ttwogareg.h>
50 #include <alpha/pci/ttwogavar.h>
51 
52 bus_dma_tag_t ttwoga_dma_get_tag(bus_dma_tag_t, alpha_bus_t);
53 
54 int	ttwoga_bus_dmamap_load_sgmap(bus_dma_tag_t, bus_dmamap_t, void *,
55 	    bus_size_t, struct proc *, int);
56 
57 int	ttwoga_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t, bus_dmamap_t,
58 	    struct mbuf *, int);
59 
60 int	ttwoga_bus_dmamap_load_uio_sgmap(bus_dma_tag_t, bus_dmamap_t,
61 	    struct uio *, int);
62 
63 int	ttwoga_bus_dmamap_load_raw_sgmap(bus_dma_tag_t, bus_dmamap_t,
64 	    bus_dma_segment_t *, int, bus_size_t, int);
65 
66 void	ttwoga_bus_dmamap_unload_sgmap(bus_dma_tag_t, bus_dmamap_t);
67 
68 /*
69  * Direct-mapped window: 1G at 1G
70  */
71 #define	TTWOGA_DIRECT_MAPPED_BASE	(1UL*1024UL*1024UL*1024UL)
72 #define	TTWOGA_DIRECT_MAPPED_SIZE	(1UL*1024UL*1024UL*1024UL)
73 
74 /*
75  * SGMAP window: 8M at 8M
76  */
77 #define	TTWOGA_SGMAP_MAPPED_BASE	(8UL*1024UL*1024UL)
78 #define	TTWOGA_SGMAP_MAPPED_SIZE	(8UL*1024UL*1024UL)
79 
80 /* T2 has a 256-byte out-bound DMA prefetch threshold. */
81 #define	TTWOGA_SGMAP_PFTHRESH		256
82 
83 /*
84  * Macro to flush the T2 Gate Array scatter/gather TLB.
85  */
86 #define	TTWOGA_TLB_INVALIDATE(tcp)					\
87 do {									\
88 	u_int64_t temp;							\
89 									\
90 	alpha_mb();							\
91 	temp = T2GA((tcp), T2_IOCSR);					\
92 	T2GA((tcp), T2_IOCSR) = temp | IOCSR_FTLB;			\
93 	alpha_mb();							\
94 	alpha_mb();	/* MAGIC */					\
95 	T2GA((tcp), T2_IOCSR) = temp;					\
96 	alpha_mb();							\
97 	alpha_mb();	/* MAGIC */					\
98 } while (0)
99 
100 void
101 ttwoga_dma_init(struct ttwoga_config *tcp)
102 {
103 	bus_dma_tag_t t;
104 
105 	/*
106 	 * Initialize the DMA tag used for direct-mapped DMA.
107 	 */
108 	t = &tcp->tc_dmat_direct;
109 	t->_cookie = tcp;
110 	t->_wbase = TTWOGA_DIRECT_MAPPED_BASE;
111 	t->_wsize = TTWOGA_DIRECT_MAPPED_SIZE;
112 	t->_next_window = NULL;
113 	t->_boundary = 0;
114 	t->_sgmap = NULL;
115 	t->_get_tag = ttwoga_dma_get_tag;
116 	t->_dmamap_create = _bus_dmamap_create;
117 	t->_dmamap_destroy = _bus_dmamap_destroy;
118 	t->_dmamap_load = _bus_dmamap_load_direct;
119 	t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
120 	t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
121 	t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
122 	t->_dmamap_unload = _bus_dmamap_unload;
123 	t->_dmamap_sync = _bus_dmamap_sync;
124 
125 	t->_dmamem_alloc = _bus_dmamem_alloc;
126 	t->_dmamem_free = _bus_dmamem_free;
127 	t->_dmamem_map = _bus_dmamem_map;
128 	t->_dmamem_unmap = _bus_dmamem_unmap;
129 	t->_dmamem_mmap = _bus_dmamem_mmap;
130 
131 	/*
132 	 * Initialize the DMA tag used for sgmap-mapped DMA.
133 	 */
134 	t = &tcp->tc_dmat_sgmap;
135 	t->_cookie = tcp;
136 	t->_wbase = TTWOGA_SGMAP_MAPPED_BASE;
137 	t->_wsize = TTWOGA_SGMAP_MAPPED_SIZE;
138 	t->_next_window = NULL;
139 	t->_boundary = 0;
140 	t->_sgmap = &tcp->tc_sgmap;
141 	t->_pfthresh = TTWOGA_SGMAP_PFTHRESH;
142 	t->_get_tag = ttwoga_dma_get_tag;
143 	t->_dmamap_create = alpha_sgmap_dmamap_create;
144 	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
145 	t->_dmamap_load = ttwoga_bus_dmamap_load_sgmap;
146 	t->_dmamap_load_mbuf = ttwoga_bus_dmamap_load_mbuf_sgmap;
147 	t->_dmamap_load_uio = ttwoga_bus_dmamap_load_uio_sgmap;
148 	t->_dmamap_load_raw = ttwoga_bus_dmamap_load_raw_sgmap;
149 	t->_dmamap_unload = ttwoga_bus_dmamap_unload_sgmap;
150 	t->_dmamap_sync = _bus_dmamap_sync;
151 
152 	t->_dmamem_alloc = _bus_dmamem_alloc;
153 	t->_dmamem_free = _bus_dmamem_free;
154 	t->_dmamem_map = _bus_dmamem_map;
155 	t->_dmamem_unmap = _bus_dmamem_unmap;
156 	t->_dmamem_mmap = _bus_dmamem_mmap;
157 
158 	/*
159 	 * Disable the SGMAP TLB, and flush it.  We reenable it if
160 	 * we have a Sable or a Gamma with T3 or T4; Gamma with T2
161 	 * has a TLB bug apparently severe enough to require disabling
162 	 * it.
163 	 */
164 	alpha_mb();
165 	T2GA(tcp, T2_IOCSR) &= ~IOCSR_ETLB;
166 	alpha_mb();
167 	alpha_mb();	/* MAGIC */
168 
169 	TTWOGA_TLB_INVALIDATE(tcp);
170 
171 	/*
172 	 * XXX We might want to make sure our DMA windows don't
173 	 * XXX overlap with PCI memory space!
174 	 */
175 
176 	/*
177 	 * Set up window 1 as a 1G direct-mapped window
178 	 * starting at 1G.
179 	 */
180 	T2GA(tcp, T2_WBASE1) = 0;
181 	alpha_mb();
182 
183 	T2GA(tcp, T2_WMASK1) = (TTWOGA_DIRECT_MAPPED_SIZE - 1) & WMASKx_PWM;
184 	alpha_mb();
185 
186 	T2GA(tcp, T2_TBASE1) = 0;
187 	alpha_mb();
188 
189 	T2GA(tcp, T2_WBASE1) = TTWOGA_DIRECT_MAPPED_BASE |
190 	    ((TTWOGA_DIRECT_MAPPED_BASE + (TTWOGA_DIRECT_MAPPED_SIZE - 1)) >>
191 	     WBASEx_PWxA_SHIFT) | WBASEx_PWE;
192 	alpha_mb();
193 
194 	/*
195 	 * Initialize the SGMAP.
196 	 */
197 	alpha_sgmap_init(t, &tcp->tc_sgmap, "ttwoga_sgmap",
198 	    TTWOGA_SGMAP_MAPPED_BASE, 0, TTWOGA_SGMAP_MAPPED_SIZE,
199 	    sizeof(u_int64_t), NULL, 0);
200 
201 	/*
202 	 * Set up window 2 as an 8MB SGMAP-mapped window
203 	 * starting at 8MB.
204 	 */
205 #ifdef DIAGNOSTIC
206 	if ((TTWOGA_SGMAP_MAPPED_BASE & WBASEx_PWSA) !=
207 	    TTWOGA_SGMAP_MAPPED_BASE)
208 		panic("ttwoga_dma_init: SGMAP base inconsistency");
209 #endif
210 	T2GA(tcp, T2_WBASE2) = 0;
211 	alpha_mb();
212 
213 	T2GA(tcp, T2_WMASK2) = (TTWOGA_SGMAP_MAPPED_SIZE - 1) & WMASKx_PWM;
214 	alpha_mb();
215 
216 	T2GA(tcp, T2_TBASE2) = tcp->tc_sgmap.aps_ptpa >> 1;
217 	alpha_mb();
218 
219 	T2GA(tcp, T2_WBASE2) = TTWOGA_SGMAP_MAPPED_BASE |
220 	    ((TTWOGA_SGMAP_MAPPED_BASE + (TTWOGA_SGMAP_MAPPED_SIZE - 1)) >>
221 	     WBASEx_PWxA_SHIFT) | WBASEx_SGE | WBASEx_PWE;
222 	alpha_mb();
223 
224 	/*
225 	 * Enable SGMAP TLB on Sable or Gamma with T3 or T4; see above.
226 	 */
227 	if (alpha_implver() == ALPHA_IMPLVER_EV4 ||
228 	    tcp->tc_rev >= TRN_T3) {
229 		alpha_mb();
230 		T2GA(tcp, T2_IOCSR) |= IOCSR_ETLB;
231 		alpha_mb();
232 		alpha_mb();	/* MAGIC */
233 		tcp->tc_use_tlb = 1;
234 	}
235 
236 	/* XXX XXX BEGIN XXX XXX */
237 	{							/* XXX */
238 		extern paddr_t alpha_XXX_dmamap_or;		/* XXX */
239 		alpha_XXX_dmamap_or = TTWOGA_DIRECT_MAPPED_BASE;/* XXX */
240 	}							/* XXX */
241 	/* XXX XXX END XXX XXX */
242 }
243 
244 /*
245  * Return the bus dma tag to be used for the specified bus type.
246  * INTERNAL USE ONLY!
247  */
248 bus_dma_tag_t
249 ttwoga_dma_get_tag(bus_dma_tag_t t, alpha_bus_t bustype)
250 {
251 	struct ttwoga_config *tcp = t->_cookie;
252 
253 	switch (bustype) {
254 	case ALPHA_BUS_PCI:
255 	case ALPHA_BUS_EISA:
256 		/*
257 		 * Systems with a T2 Gate Array can have 2G
258 		 * of memory, but we only get a direct-mapped
259 		 * window of 1G!
260 		 *
261 		 * XXX FIX THIS SOMEDAY!
262 		 */
263 		return (&tcp->tc_dmat_direct);
264 
265 	case ALPHA_BUS_ISA:
266 		/*
267 		 * ISA doesn't have enough address bits to use
268 		 * the direct-mapped DMA window, so we must use
269 		 * SGMAPs.
270 		 */
271 		return (&tcp->tc_dmat_sgmap);
272 
273 	default:
274 		panic("ttwoga_dma_get_tag: shouldn't be here, really...");
275 	}
276 }
277 
278 /*
279  * Load a T2 SGMAP-mapped DMA map with a liner buffer.
280  */
281 int
282 ttwoga_bus_dmamap_load_sgmap(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
283     bus_size_t buflen, struct proc *p, int flags)
284 {
285 	struct ttwoga_config *tcp = t->_cookie;
286 	int error;
287 
288 	error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
289 	    t->_sgmap);
290 	if (error == 0 && tcp->tc_use_tlb)
291 		TTWOGA_TLB_INVALIDATE(tcp);
292 
293 	return (error);
294 }
295 
296 /*
297  * Load a T2 SGMAP-mapped DMA map with an mbuf chain.
298  */
299 int
300 ttwoga_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t, bus_dmamap_t map,
301     struct mbuf *m, int flags)
302 {
303 	struct ttwoga_config *tcp = t->_cookie;
304 	int error;
305 
306 	error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, t->_sgmap);
307 	if (error == 0 && tcp->tc_use_tlb)
308 		TTWOGA_TLB_INVALIDATE(tcp);
309 
310 	return (error);
311 }
312 
313 /*
314  * Load a T2 SGMAP-mapped DMA map with a uio.
315  */
316 int
317 ttwoga_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t, bus_dmamap_t map,
318     struct uio *uio, int flags)
319 {
320 	struct ttwoga_config *tcp = t->_cookie;
321 	int error;
322 
323 	error = pci_sgmap_pte64_load_uio(t, map, uio, flags, t->_sgmap);
324 	if (error == 0 && tcp->tc_use_tlb)
325 		TTWOGA_TLB_INVALIDATE(tcp);
326 
327 	return (error);
328 }
329 
330 /*
331  * Load a T2 SGMAP-mapped DMA map with raw memory.
332  */
333 int
334 ttwoga_bus_dmamap_load_raw_sgmap(bus_dma_tag_t t, bus_dmamap_t map,
335     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
336 {
337 	struct ttwoga_config *tcp = t->_cookie;
338 	int error;
339 
340 	error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
341 	    t->_sgmap);
342 	if (error == 0 && tcp->tc_use_tlb)
343 		TTWOGA_TLB_INVALIDATE(tcp);
344 
345 	return (error);
346 }
347 
348 /*
349  * Unload an T2 DMA map.
350  */
351 void
352 ttwoga_bus_dmamap_unload_sgmap(bus_dma_tag_t t, bus_dmamap_t map)
353 {
354 	struct ttwoga_config *tcp = t->_cookie;
355 
356 	/*
357 	 * Invalidate any SGMAP page table entries used by this
358 	 * mapping.
359 	 */
360 	pci_sgmap_pte64_unload(t, map, t->_sgmap);
361 	if (tcp->tc_use_tlb)
362 		TTWOGA_TLB_INVALIDATE(tcp);
363 
364 	/*
365 	 * Do the generic bits of the unload.
366 	 */
367 	_bus_dmamap_unload(t, map);
368 }
369