cia_dma.c revision 1.2 1 /* $NetBSD: cia_dma.c,v 1.2 1997/06/06 23:59:24 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1997 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 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <machine/options.h> /* Config options headers */
41 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
42
43 __KERNEL_RCSID(0, "$NetBSD: cia_dma.c,v 1.2 1997/06/06 23:59:24 thorpej Exp $");
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50 #include <vm/vm.h>
51
52 #define _ALPHA_BUS_DMA_PRIVATE
53 #include <machine/bus.h>
54
55 #include <dev/pci/pcireg.h>
56 #include <dev/pci/pcivar.h>
57 #include <alpha/pci/ciareg.h>
58 #include <alpha/pci/ciavar.h>
59
60 bus_dma_tag_t cia_dma_get_tag __P((bus_dma_tag_t, alpha_bus_t));
61
62 int cia_bus_dmamap_create_sgmap __P((bus_dma_tag_t, bus_size_t, int,
63 bus_size_t, bus_size_t, int, bus_dmamap_t *));
64
65 void cia_bus_dmamap_destroy_sgmap __P((bus_dma_tag_t, bus_dmamap_t));
66
67 int cia_bus_dmamap_load_direct __P((bus_dma_tag_t, bus_dmamap_t, void *,
68 bus_size_t, struct proc *, int));
69 int cia_bus_dmamap_load_sgmap __P((bus_dma_tag_t, bus_dmamap_t, void *,
70 bus_size_t, struct proc *, int));
71
72 int cia_bus_dmamap_load_mbuf_direct __P((bus_dma_tag_t, bus_dmamap_t,
73 struct mbuf *, int));
74 int cia_bus_dmamap_load_mbuf_sgmap __P((bus_dma_tag_t, bus_dmamap_t,
75 struct mbuf *, int));
76
77 int cia_bus_dmamap_load_uio_direct __P((bus_dma_tag_t, bus_dmamap_t,
78 struct uio *, int));
79 int cia_bus_dmamap_load_uio_sgmap __P((bus_dma_tag_t, bus_dmamap_t,
80 struct uio *, int));
81
82 int cia_bus_dmamap_load_raw_direct __P((bus_dma_tag_t, bus_dmamap_t,
83 bus_dma_segment_t *, int, bus_size_t, int));
84 int cia_bus_dmamap_load_raw_sgmap __P((bus_dma_tag_t, bus_dmamap_t,
85 bus_dma_segment_t *, int, bus_size_t, int));
86
87 void cia_bus_dmamap_unload_sgmap __P((bus_dma_tag_t, bus_dmamap_t));
88
89 /*
90 * The direct-mapped DMA window begins at this PCI address.
91 */
92 #define CIA_DIRECT_MAPPED_BASE 0x40000000
93
94 /*
95 * The 8M SGMAP-mapped DMA window begins at this PCI address.
96 */
97 #define CIA_SGMAP_MAPPED_BASE (8*1024*1024)
98
99 /*
100 * Macro to flush CIA scatter/gather TLB.
101 */
102 #define CIA_TLB_INVALIDATE() \
103 do { \
104 alpha_mb(); \
105 REGVAL(CIA_PCI_TBIA) = CIA_PCI_TBIA_ALL; \
106 alpha_mb(); \
107 } while (0)
108
109 void
110 cia_dma_init(ccp)
111 struct cia_config *ccp;
112 {
113 bus_addr_t tbase;
114 u_int32_t memcs_en;
115 bus_dma_tag_t t;
116
117 /*
118 * Initialize the DMA tag used for direct-mapped DMA.
119 */
120 t = &ccp->cc_dmat_direct;
121 t->_cookie = ccp;
122 t->_get_tag = cia_dma_get_tag;
123 t->_dmamap_create = _bus_dmamap_create;
124 t->_dmamap_destroy = _bus_dmamap_destroy;
125 t->_dmamap_load = cia_bus_dmamap_load_direct;
126 t->_dmamap_load_mbuf = cia_bus_dmamap_load_mbuf_direct;
127 t->_dmamap_load_uio = cia_bus_dmamap_load_uio_direct;
128 t->_dmamap_load_raw = cia_bus_dmamap_load_raw_direct;
129 t->_dmamap_unload = _bus_dmamap_unload;
130 t->_dmamap_sync = NULL; /* Nothing to do. */
131
132 t->_dmamem_alloc = _bus_dmamem_alloc;
133 t->_dmamem_free = _bus_dmamem_free;
134 t->_dmamem_map = _bus_dmamem_map;
135 t->_dmamem_unmap = _bus_dmamem_unmap;
136 t->_dmamem_mmap = _bus_dmamem_mmap;
137
138 /*
139 * Initialize the DMA tag used for sgmap-mapped DMA.
140 */
141 t = &ccp->cc_dmat_sgmap;
142 t->_cookie = ccp;
143 t->_get_tag = cia_dma_get_tag;
144 t->_dmamap_create = cia_bus_dmamap_create_sgmap;
145 t->_dmamap_destroy = cia_bus_dmamap_destroy_sgmap;
146 t->_dmamap_load = cia_bus_dmamap_load_sgmap;
147 t->_dmamap_load_mbuf = cia_bus_dmamap_load_mbuf_sgmap;
148 t->_dmamap_load_uio = cia_bus_dmamap_load_uio_sgmap;
149 t->_dmamap_load_raw = cia_bus_dmamap_load_raw_sgmap;
150 t->_dmamap_unload = cia_bus_dmamap_unload_sgmap;
151 t->_dmamap_sync = NULL; /* Nothing to do. */
152
153 t->_dmamem_alloc = _bus_dmamem_alloc;
154 t->_dmamem_free = _bus_dmamem_free;
155 t->_dmamem_map = _bus_dmamem_map;
156 t->_dmamem_unmap = _bus_dmamem_unmap;
157 t->_dmamem_mmap = _bus_dmamem_mmap;
158
159 /*
160 * The firmware has set up window 1 as a 1G direct-mapped DMA
161 * window beginning at 1G. We leave it alone. Leave window
162 * 0 alone until we reconfigure it for SGMAP-mapped DMA.
163 * Windows 2 and 3 are already disabled.
164 */
165
166 /*
167 * Initialize the SGMAP if safe to do so.
168 */
169 if (ccp->cc_mallocsafe) {
170 alpha_sgmap_init(t, &ccp->cc_sgmap, "cia_sgmap",
171 CIA_SGMAP_MAPPED_BASE, 0, (8*1024*1024),
172 sizeof(u_int64_t), NULL);
173
174 /* Remember the MEMCS value. */
175 alpha_mb();
176 memcs_en = REGVAL(CIA_PCI_W0BASE) & CIA_PCI_WnBASE_MEMCS_EN;
177
178 /* Now disable window 0. */
179 REGVAL(CIA_PCI_W0BASE) = 0;
180 alpha_mb();
181
182 /*
183 * Set up window 0 as an 8MB SGMAP-mapped window
184 * starting at 8MB.
185 */
186 tbase = ccp->cc_sgmap.aps_ptpa >> CIA_PCI_TnBASE_SHIFT;
187 if ((tbase & CIA_PCI_TnBASE_MASK) != tbase)
188 panic("cia_dma_init: bad page table address");
189 REGVAL(CIA_PCI_T0BASE) = tbase;
190 REGVAL(CIA_PCI_W0MASK) = CIA_PCI_WnMASK_8M;
191 alpha_mb();
192
193 REGVAL(CIA_PCI_W0BASE) = CIA_SGMAP_MAPPED_BASE |
194 CIA_PCI_WnBASE_SG_EN | CIA_PCI_WnBASE_W_EN | memcs_en;
195 alpha_mb();
196
197 CIA_TLB_INVALIDATE();
198 }
199
200 /* XXX XXX BEGIN XXX XXX */
201 { /* XXX */
202 extern vm_offset_t alpha_XXX_dmamap_or; /* XXX */
203 alpha_XXX_dmamap_or = CIA_DIRECT_MAPPED_BASE; /* XXX */
204 } /* XXX */
205 /* XXX XXX END XXX XXX */
206 }
207
208 /*
209 * Return the bus dma tag to be used for the specified bus type.
210 * INTERNAL USE ONLY!
211 */
212 bus_dma_tag_t
213 cia_dma_get_tag(t, bustype)
214 bus_dma_tag_t t;
215 alpha_bus_t bustype;
216 {
217 struct cia_config *ccp = t->_cookie;
218
219 switch (bustype) {
220 case ALPHA_BUS_PCI:
221 case ALPHA_BUS_EISA:
222 /*
223 * Systems with a CIA can only support 1G
224 * of memory, so we use the direct-mapped window
225 * on busses that have 32-bit DMA.
226 */
227 return (&ccp->cc_dmat_direct);
228
229 case ALPHA_BUS_ISA:
230 /*
231 * ISA doesn't have enough address bits to use
232 * the direct-mapped DMA window, so we must use
233 * SGMAPs.
234 */
235 return (&ccp->cc_dmat_sgmap);
236
237 default:
238 panic("cia_dma_get_tag: shouldn't be here, really...");
239 }
240 }
241
242 /*
243 * Create a CIA SGMAP-mapped DMA map.
244 */
245 int
246 cia_bus_dmamap_create_sgmap(t, size, nsegments, maxsegsz, boundary,
247 flags, dmamp)
248 bus_dma_tag_t t;
249 bus_size_t size;
250 int nsegments;
251 bus_size_t maxsegsz;
252 bus_size_t boundary;
253 int flags;
254 bus_dmamap_t *dmamp;
255 {
256 struct cia_config *ccp = t->_cookie;
257 struct alpha_sgmap_cookie *a;
258 bus_dmamap_t map;
259 int error;
260
261 error = _bus_dmamap_create(t, size, nsegments, maxsegsz,
262 boundary, flags, dmamp);
263 if (error)
264 return (error);
265
266 map = *dmamp;
267
268 a = malloc(sizeof(struct alpha_sgmap_cookie), M_DEVBUF,
269 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK);
270 if (a == NULL) {
271 _bus_dmamap_destroy(t, map);
272 return (ENOMEM);
273 }
274 bzero(a, sizeof(struct alpha_sgmap_cookie));
275 map->_dm_sgcookie = a;
276
277 if (flags & BUS_DMA_ALLOCNOW) {
278 error = alpha_sgmap_alloc(map, round_page(size),
279 &ccp->cc_sgmap, flags);
280 if (error)
281 cia_bus_dmamap_destroy_sgmap(t, map);
282 }
283
284 return (error);
285 }
286
287 /*
288 * Destroy a CIA SGMAP-mapped DMA map.
289 */
290 void
291 cia_bus_dmamap_destroy_sgmap(t, map)
292 bus_dma_tag_t t;
293 bus_dmamap_t map;
294 {
295 struct cia_config *ccp = t->_cookie;
296 struct alpha_sgmap_cookie *a = map->_dm_sgcookie;
297
298 if (a->apdc_flags & APDC_HAS_SGMAP)
299 alpha_sgmap_free(&ccp->cc_sgmap, a);
300
301 free(a, M_DEVBUF);
302 _bus_dmamap_destroy(t, map);
303 }
304
305 /*
306 * Load a CIA direct-mapped DMA map with a linear buffer.
307 */
308 int
309 cia_bus_dmamap_load_direct(t, map, buf, buflen, p, flags)
310 bus_dma_tag_t t;
311 bus_dmamap_t map;
312 void *buf;
313 bus_size_t buflen;
314 struct proc *p;
315 int flags;
316 {
317
318 return (_bus_dmamap_load_direct_common(t, map, buf, buflen, p,
319 flags, CIA_DIRECT_MAPPED_BASE));
320 }
321
322 /*
323 * Load a CIA SGMAP-mapped DMA map with a linear buffer.
324 */
325 int
326 cia_bus_dmamap_load_sgmap(t, map, buf, buflen, p, flags)
327 bus_dma_tag_t t;
328 bus_dmamap_t map;
329 void *buf;
330 bus_size_t buflen;
331 struct proc *p;
332 int flags;
333 {
334 struct cia_config *ccp = t->_cookie;
335 int error;
336
337 error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
338 &ccp->cc_sgmap);
339 if (error == 0)
340 CIA_TLB_INVALIDATE();
341
342 return (error);
343 }
344
345 /*
346 * Load a CIA direct-mapped DMA map with an mbuf chain.
347 */
348 int
349 cia_bus_dmamap_load_mbuf_direct(t, map, m, flags)
350 bus_dma_tag_t t;
351 bus_dmamap_t map;
352 struct mbuf *m;
353 int flags;
354 {
355
356 return (_bus_dmamap_load_mbuf_direct_common(t, map, m,
357 flags, CIA_DIRECT_MAPPED_BASE));
358 }
359
360 /*
361 * Load a CIA SGMAP-mapped DMA map with an mbuf chain.
362 */
363 int
364 cia_bus_dmamap_load_mbuf_sgmap(t, map, m, flags)
365 bus_dma_tag_t t;
366 bus_dmamap_t map;
367 struct mbuf *m;
368 int flags;
369 {
370 struct cia_config *ccp = t->_cookie;
371 int error;
372
373 error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, &ccp->cc_sgmap);
374 if (error == 0)
375 CIA_TLB_INVALIDATE();
376
377 return (error);
378 }
379
380 /*
381 * Load a CIA direct-mapped DMA map with a uio.
382 */
383 int
384 cia_bus_dmamap_load_uio_direct(t, map, uio, flags)
385 bus_dma_tag_t t;
386 bus_dmamap_t map;
387 struct uio *uio;
388 int flags;
389 {
390
391 return (_bus_dmamap_load_uio_direct_common(t, map, uio,
392 flags, CIA_DIRECT_MAPPED_BASE));
393 }
394
395 /*
396 * Load a CIA SGMAP-mapped DMA map with a uio.
397 */
398 int
399 cia_bus_dmamap_load_uio_sgmap(t, map, uio, flags)
400 bus_dma_tag_t t;
401 bus_dmamap_t map;
402 struct uio *uio;
403 int flags;
404 {
405 struct cia_config *ccp = t->_cookie;
406 int error;
407
408 error = pci_sgmap_pte64_load_uio(t, map, uio, flags, &ccp->cc_sgmap);
409 if (error == 0)
410 CIA_TLB_INVALIDATE();
411
412 return (error);
413 }
414
415 /*
416 * Load a CIA direct-mapped DMA map with raw memory.
417 */
418 int
419 cia_bus_dmamap_load_raw_direct(t, map, segs, nsegs, size, flags)
420 bus_dma_tag_t t;
421 bus_dmamap_t map;
422 bus_dma_segment_t *segs;
423 int nsegs;
424 bus_size_t size;
425 int flags;
426 {
427
428 return (_bus_dmamap_load_raw_direct_common(t, map, segs, nsegs,
429 size, flags, CIA_DIRECT_MAPPED_BASE));
430 }
431
432 /*
433 * Load a CIA SGMAP-mapped DMA map with raw memory.
434 */
435 int
436 cia_bus_dmamap_load_raw_sgmap(t, map, segs, nsegs, size, flags)
437 bus_dma_tag_t t;
438 bus_dmamap_t map;
439 bus_dma_segment_t *segs;
440 int nsegs;
441 bus_size_t size;
442 int flags;
443 {
444 struct cia_config *ccp = t->_cookie;
445 int error;
446
447 error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
448 &ccp->cc_sgmap);
449 if (error == 0)
450 CIA_TLB_INVALIDATE();
451
452 return (error);
453 }
454
455 /*
456 * Unload a CIA DMA map.
457 */
458 void
459 cia_bus_dmamap_unload_sgmap(t, map)
460 bus_dma_tag_t t;
461 bus_dmamap_t map;
462 {
463 struct cia_config *ccp = t->_cookie;
464
465 /*
466 * Invalidate any SGMAP page table entries used by this
467 * mapping.
468 */
469 pci_sgmap_pte64_unload(t, map, &ccp->cc_sgmap);
470 CIA_TLB_INVALIDATE();
471
472 /*
473 * Do the generic bits of the unload.
474 */
475 _bus_dmamap_unload(t, map);
476 }
477