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