apecs_dma.c revision 1.2.2.2 1 /* $NetBSD: apecs_dma.c,v 1.2.2.2 1997/06/07 04:43:08 cgd 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: apecs_dma.c,v 1.2.2.2 1997/06/07 04:43:08 cgd 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/apecsreg.h>
58 #include <alpha/pci/apecsvar.h>
59
60 bus_dma_tag_t apecs_dma_get_tag __P((bus_dma_tag_t, alpha_bus_t));
61
62 int apecs_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 apecs_bus_dmamap_destroy_sgmap __P((bus_dma_tag_t, bus_dmamap_t));
66
67 int apecs_bus_dmamap_load_direct __P((bus_dma_tag_t, bus_dmamap_t, void *,
68 bus_size_t, struct proc *, int));
69 int apecs_bus_dmamap_load_sgmap __P((bus_dma_tag_t, bus_dmamap_t, void *,
70 bus_size_t, struct proc *, int));
71
72 int apecs_bus_dmamap_load_mbuf_direct __P((bus_dma_tag_t, bus_dmamap_t,
73 struct mbuf *, int));
74 int apecs_bus_dmamap_load_mbuf_sgmap __P((bus_dma_tag_t, bus_dmamap_t,
75 struct mbuf *, int));
76
77 int apecs_bus_dmamap_load_uio_direct __P((bus_dma_tag_t, bus_dmamap_t,
78 struct uio *, int));
79 int apecs_bus_dmamap_load_uio_sgmap __P((bus_dma_tag_t, bus_dmamap_t,
80 struct uio *, int));
81
82 int apecs_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 apecs_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 apecs_bus_dmamap_unload_sgmap __P((bus_dma_tag_t, bus_dmamap_t));
88
89 /*
90 * The 1G direct-mapped DMA window begins at this PCI address.
91 */
92 #define APECS_DIRECT_MAPPED_BASE 0x40000000
93
94 /*
95 * The 8M SGMAP-mapped DMA window begins at this PCI address.
96 */
97 #define APECS_SGMAP_MAPPED_BASE (8*1024*1024)
98
99 /*
100 * Macro to flush APECS scatter/gather TLB.
101 */
102 #define APECS_TLB_INVALIDATE() \
103 do { \
104 alpha_mb(); \
105 REGVAL(EPIC_TBIA) = 0; \
106 alpha_mb(); \
107 } while (0)
108
109 void
110 apecs_dma_init(acp)
111 struct apecs_config *acp;
112 {
113 bus_addr_t tbase;
114 bus_dma_tag_t t;
115
116 /*
117 * Initialize the DMA tag used for direct-mapped DMA.
118 */
119 t = &acp->ac_dmat_direct;
120 t->_cookie = acp;
121 t->_get_tag = apecs_dma_get_tag;
122 t->_dmamap_create = _bus_dmamap_create;
123 t->_dmamap_destroy = _bus_dmamap_destroy;
124 t->_dmamap_load = apecs_bus_dmamap_load_direct;
125 t->_dmamap_load_mbuf = apecs_bus_dmamap_load_mbuf_direct;
126 t->_dmamap_load_uio = apecs_bus_dmamap_load_uio_direct;
127 t->_dmamap_load_raw = apecs_bus_dmamap_load_raw_direct;
128 t->_dmamap_unload = _bus_dmamap_unload;
129 t->_dmamap_sync = NULL; /* Nothing to do. */
130
131 t->_dmamem_alloc = _bus_dmamem_alloc;
132 t->_dmamem_free = _bus_dmamem_free;
133 t->_dmamem_map = _bus_dmamem_map;
134 t->_dmamem_unmap = _bus_dmamem_unmap;
135 t->_dmamem_mmap = _bus_dmamem_mmap;
136
137 /*
138 * Initialize the DMA tag used for sgmap-mapped DMA.
139 */
140 t = &acp->ac_dmat_sgmap;
141 t->_cookie = acp;
142 t->_get_tag = apecs_dma_get_tag;
143 t->_dmamap_create = apecs_bus_dmamap_create_sgmap;
144 t->_dmamap_destroy = apecs_bus_dmamap_destroy_sgmap;
145 t->_dmamap_load = apecs_bus_dmamap_load_sgmap;
146 t->_dmamap_load_mbuf = apecs_bus_dmamap_load_mbuf_sgmap;
147 t->_dmamap_load_uio = apecs_bus_dmamap_load_uio_sgmap;
148 t->_dmamap_load_raw = apecs_bus_dmamap_load_raw_sgmap;
149 t->_dmamap_unload = apecs_bus_dmamap_unload_sgmap;
150 t->_dmamap_sync = NULL; /* Nothing to do. */
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 * The firmware has set up window 2 as a 1G direct-mapped DMA
160 * window beginning at 1G. We leave it alone. Disable
161 * window 1.
162 */
163 REGVAL(EPIC_PCI_BASE_1) = 0;
164 alpha_mb();
165
166 /*
167 * Initialize the SGMAP if safe to do so.
168 */
169 if (acp->ac_mallocsafe) {
170 alpha_sgmap_init(t, &acp->ac_sgmap, "apecs_sgmap",
171 APECS_SGMAP_MAPPED_BASE, 0, (8*1024*1024),
172 sizeof(u_int64_t), NULL);
173
174 /*
175 * Set up window 1 as an 8MB SGMAP-mapped window
176 * starting at 8MB.
177 */
178 tbase = acp->ac_sgmap.aps_ptpa >> EPIC_TBASE_SHIFT;
179 if ((tbase & EPIC_TBASE_T_BASE) != tbase)
180 panic("apecs_dma_init: bad page table address");
181 REGVAL(EPIC_TBASE_1) = tbase;
182 REGVAL(EPIC_PCI_MASK_1) = EPIC_PCI_MASK_8M;
183 alpha_mb();
184
185 REGVAL(EPIC_PCI_BASE_1) = APECS_SGMAP_MAPPED_BASE |
186 EPIC_PCI_BASE_SGEN | EPIC_PCI_BASE_WENB;
187 alpha_mb();
188
189 APECS_TLB_INVALIDATE();
190 }
191
192 /* XXX XXX BEGIN XXX XXX */
193 { /* XXX */
194 extern vm_offset_t alpha_XXX_dmamap_or; /* XXX */
195 alpha_XXX_dmamap_or = APECS_DIRECT_MAPPED_BASE; /* XXX */
196 } /* XXX */
197 /* XXX XXX END XXX XXX */
198 }
199
200 /*
201 * Return the bus dma tag to be used for the specified bus type.
202 * INTERNAL USE ONLY!
203 */
204 bus_dma_tag_t
205 apecs_dma_get_tag(t, bustype)
206 bus_dma_tag_t t;
207 alpha_bus_t bustype;
208 {
209 struct apecs_config *acp = t->_cookie;
210
211 switch (bustype) {
212 case ALPHA_BUS_PCI:
213 case ALPHA_BUS_EISA:
214 /*
215 * Systems with an APECS can only support 1G
216 * of memory, so we use the direct-mapped window
217 * on busses that have 32-bit DMA.
218 */
219 return (&acp->ac_dmat_direct);
220
221 case ALPHA_BUS_ISA:
222 /*
223 * ISA doesn't have enough address bits to use
224 * the direct-mapped DMA window, so we must use
225 * SGMAPs.
226 */
227 return (&acp->ac_dmat_sgmap);
228
229 default:
230 panic("apecs_dma_get_tag: shouldn't be here, really...");
231 }
232 }
233
234 /*
235 * Create an APECS SGMAP-mapped DMA map.
236 */
237 int
238 apecs_bus_dmamap_create_sgmap(t, size, nsegments, maxsegsz, boundary,
239 flags, dmamp)
240 bus_dma_tag_t t;
241 bus_size_t size;
242 int nsegments;
243 bus_size_t maxsegsz;
244 bus_size_t boundary;
245 int flags;
246 bus_dmamap_t *dmamp;
247 {
248 struct apecs_config *acp = t->_cookie;
249 struct alpha_sgmap_cookie *a;
250 bus_dmamap_t map;
251 int error;
252
253 error = _bus_dmamap_create(t, size, nsegments, maxsegsz,
254 boundary, flags, dmamp);
255 if (error)
256 return (error);
257
258 map = *dmamp;
259
260 a = malloc(sizeof(struct alpha_sgmap_cookie), M_DEVBUF,
261 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK);
262 if (a == NULL) {
263 _bus_dmamap_destroy(t, map);
264 return (ENOMEM);
265 }
266 bzero(a, sizeof(struct alpha_sgmap_cookie));
267 map->_dm_sgcookie = a;
268
269 if (flags & BUS_DMA_ALLOCNOW) {
270 error = alpha_sgmap_alloc(map, round_page(size),
271 &acp->ac_sgmap, flags);
272 if (error)
273 apecs_bus_dmamap_destroy_sgmap(t, map);
274 }
275
276 return (error);
277 }
278
279 /*
280 * Destroy an APECS SGMAP-mapped DMA map.
281 */
282 void
283 apecs_bus_dmamap_destroy_sgmap(t, map)
284 bus_dma_tag_t t;
285 bus_dmamap_t map;
286 {
287 struct apecs_config *acp = t->_cookie;
288 struct alpha_sgmap_cookie *a = map->_dm_sgcookie;
289
290 if (a->apdc_flags & APDC_HAS_SGMAP)
291 alpha_sgmap_free(&acp->ac_sgmap, a);
292
293 free(a, M_DEVBUF);
294 _bus_dmamap_destroy(t, map);
295 }
296
297 /*
298 * Load an APECS direct-mapped DMA map with a linear buffer.
299 */
300 int
301 apecs_bus_dmamap_load_direct(t, map, buf, buflen, p, flags)
302 bus_dma_tag_t t;
303 bus_dmamap_t map;
304 void *buf;
305 bus_size_t buflen;
306 struct proc *p;
307 int flags;
308 {
309
310 return (_bus_dmamap_load_direct_common(t, map, buf, buflen, p,
311 flags, APECS_DIRECT_MAPPED_BASE));
312 }
313
314 /*
315 * Load an APECS SGMAP-mapped DMA map with a linear buffer.
316 */
317 int
318 apecs_bus_dmamap_load_sgmap(t, map, buf, buflen, p, flags)
319 bus_dma_tag_t t;
320 bus_dmamap_t map;
321 void *buf;
322 bus_size_t buflen;
323 struct proc *p;
324 int flags;
325 {
326 struct apecs_config *acp = t->_cookie;
327 int error;
328
329 error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
330 &acp->ac_sgmap);
331 if (error == 0)
332 APECS_TLB_INVALIDATE();
333
334 return (error);
335 }
336
337 /*
338 * Load an APECS direct-mapped DMA map with an mbuf chain.
339 */
340 int
341 apecs_bus_dmamap_load_mbuf_direct(t, map, m, flags)
342 bus_dma_tag_t t;
343 bus_dmamap_t map;
344 struct mbuf *m;
345 int flags;
346 {
347
348 return (_bus_dmamap_load_mbuf_direct_common(t, map, m,
349 flags, APECS_DIRECT_MAPPED_BASE));
350 }
351
352 /*
353 * Load an APECS SGMAP-mapped DMA map with an mbuf chain.
354 */
355 int
356 apecs_bus_dmamap_load_mbuf_sgmap(t, map, m, flags)
357 bus_dma_tag_t t;
358 bus_dmamap_t map;
359 struct mbuf *m;
360 int flags;
361 {
362 struct apecs_config *acp = t->_cookie;
363 int error;
364
365 error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, &acp->ac_sgmap);
366 if (error == 0)
367 APECS_TLB_INVALIDATE();
368
369 return (error);
370 }
371
372 /*
373 * Load an APECS direct-mapped DMA map with a uio.
374 */
375 int
376 apecs_bus_dmamap_load_uio_direct(t, map, uio, flags)
377 bus_dma_tag_t t;
378 bus_dmamap_t map;
379 struct uio *uio;
380 int flags;
381 {
382
383 return (_bus_dmamap_load_uio_direct_common(t, map, uio,
384 flags, APECS_DIRECT_MAPPED_BASE));
385 }
386
387 /*
388 * Load an APECS SGMAP-mapped DMA map with a uio.
389 */
390 int
391 apecs_bus_dmamap_load_uio_sgmap(t, map, uio, flags)
392 bus_dma_tag_t t;
393 bus_dmamap_t map;
394 struct uio *uio;
395 int flags;
396 {
397 struct apecs_config *acp = t->_cookie;
398 int error;
399
400 error = pci_sgmap_pte64_load_uio(t, map, uio, flags, &acp->ac_sgmap);
401 if (error == 0)
402 APECS_TLB_INVALIDATE();
403
404 return (error);
405 }
406
407 /*
408 * Load an APECS direct-mapped DMA map with raw memory.
409 */
410 int
411 apecs_bus_dmamap_load_raw_direct(t, map, segs, nsegs, size, flags)
412 bus_dma_tag_t t;
413 bus_dmamap_t map;
414 bus_dma_segment_t *segs;
415 int nsegs;
416 bus_size_t size;
417 int flags;
418 {
419
420 return (_bus_dmamap_load_raw_direct_common(t, map, segs, nsegs,
421 size, flags, APECS_DIRECT_MAPPED_BASE));
422 }
423
424 /*
425 * Load an APECS SGMAP-mapped DMA map with raw memory.
426 */
427 int
428 apecs_bus_dmamap_load_raw_sgmap(t, map, segs, nsegs, size, flags)
429 bus_dma_tag_t t;
430 bus_dmamap_t map;
431 bus_dma_segment_t *segs;
432 int nsegs;
433 bus_size_t size;
434 int flags;
435 {
436 struct apecs_config *acp = t->_cookie;
437 int error;
438
439 error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
440 &acp->ac_sgmap);
441 if (error == 0)
442 APECS_TLB_INVALIDATE();
443
444 return (error);
445 }
446
447 /*
448 * Unload an APECS DMA map.
449 */
450 void
451 apecs_bus_dmamap_unload_sgmap(t, map)
452 bus_dma_tag_t t;
453 bus_dmamap_t map;
454 {
455 struct apecs_config *acp = t->_cookie;
456
457 /*
458 * Invalidate any SGMAP page table entries used by this
459 * mapping.
460 */
461 pci_sgmap_pte64_unload(t, map, &acp->ac_sgmap);
462 APECS_TLB_INVALIDATE();
463
464 /*
465 * Do the generic bits of the unload.
466 */
467 _bus_dmamap_unload(t, map);
468 }
469