1 /* $NetBSD: cia_dma.c,v 1.24 2009/03/14 15:35:59 dsl Exp $ */
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
35 __KERNEL_RCSID(0, "$NetBSD: cia_dma.c,v 1.24 2009/03/14 15:35:59 dsl Exp $");
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>
43 #include <uvm/uvm_extern.h>
45 #define _ALPHA_BUS_DMA_PRIVATE
46 #include <machine/bus.h>
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcivar.h>
50 #include <alpha/pci/ciareg.h>
51 #include <alpha/pci/ciavar.h>
53 bus_dma_tag_t
cia_dma_get_tag(bus_dma_tag_t
, alpha_bus_t
);
55 int cia_bus_dmamap_create_direct(bus_dma_tag_t
, bus_size_t
, int,
56 bus_size_t
, bus_size_t
, int, bus_dmamap_t
*);
58 int cia_bus_dmamap_load_sgmap(bus_dma_tag_t
, bus_dmamap_t
, void *,
59 bus_size_t
, struct proc
*, int);
61 int cia_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t
, bus_dmamap_t
,
64 int cia_bus_dmamap_load_uio_sgmap(bus_dma_tag_t
, bus_dmamap_t
,
67 int cia_bus_dmamap_load_raw_sgmap(bus_dma_tag_t
, bus_dmamap_t
,
68 bus_dma_segment_t
*, int, bus_size_t
, int);
70 void cia_bus_dmamap_unload_sgmap(bus_dma_tag_t
, bus_dmamap_t
);
73 * Direct-mapped window: 1G at 1G
75 #define CIA_DIRECT_MAPPED_BASE (1*1024*1024*1024)
76 #define CIA_DIRECT_MAPPED_SIZE (1*1024*1024*1024)
79 * SGMAP window: 8M at 8M
81 #define CIA_SGMAP_MAPPED_BASE (8*1024*1024)
82 #define CIA_SGMAP_MAPPED_SIZE (8*1024*1024)
84 /* ALCOR/ALGOR2/PYXIS have a 256-byte out-bound DMA prefetch threshold. */
85 #define CIA_SGMAP_PFTHRESH 256
87 void cia_tlb_invalidate(void);
88 void cia_broken_pyxis_tlb_invalidate(void);
90 void (*cia_tlb_invalidate_fn
)(void);
92 #define CIA_TLB_INVALIDATE() (*cia_tlb_invalidate_fn)()
94 struct alpha_sgmap cia_pyxis_bug_sgmap
;
95 #define CIA_PYXIS_BUG_BASE (128*1024*1024)
96 #define CIA_PYXIS_BUG_SIZE (2*1024*1024)
99 cia_dma_init(struct cia_config
*ccp
)
105 * Initialize the DMA tag used for direct-mapped DMA.
107 t
= &ccp
->cc_dmat_direct
;
109 t
->_wbase
= CIA_DIRECT_MAPPED_BASE
;
110 t
->_wsize
= CIA_DIRECT_MAPPED_SIZE
;
111 t
->_next_window
= &ccp
->cc_dmat_sgmap
;
114 t
->_get_tag
= cia_dma_get_tag
;
115 t
->_dmamap_create
= cia_bus_dmamap_create_direct
;
116 t
->_dmamap_destroy
= _bus_dmamap_destroy
;
117 t
->_dmamap_load
= _bus_dmamap_load_direct
;
118 t
->_dmamap_load_mbuf
= _bus_dmamap_load_mbuf_direct
;
119 t
->_dmamap_load_uio
= _bus_dmamap_load_uio_direct
;
120 t
->_dmamap_load_raw
= _bus_dmamap_load_raw_direct
;
121 t
->_dmamap_unload
= _bus_dmamap_unload
;
122 t
->_dmamap_sync
= _bus_dmamap_sync
;
124 t
->_dmamem_alloc
= _bus_dmamem_alloc
;
125 t
->_dmamem_free
= _bus_dmamem_free
;
126 t
->_dmamem_map
= _bus_dmamem_map
;
127 t
->_dmamem_unmap
= _bus_dmamem_unmap
;
128 t
->_dmamem_mmap
= _bus_dmamem_mmap
;
131 * Initialize the DMA tag used for sgmap-mapped DMA.
133 t
= &ccp
->cc_dmat_sgmap
;
135 t
->_wbase
= CIA_SGMAP_MAPPED_BASE
;
136 t
->_wsize
= CIA_SGMAP_MAPPED_SIZE
;
137 t
->_next_window
= NULL
;
139 t
->_sgmap
= &ccp
->cc_sgmap
;
140 t
->_pfthresh
= CIA_SGMAP_PFTHRESH
;
141 t
->_get_tag
= cia_dma_get_tag
;
142 t
->_dmamap_create
= alpha_sgmap_dmamap_create
;
143 t
->_dmamap_destroy
= alpha_sgmap_dmamap_destroy
;
144 t
->_dmamap_load
= cia_bus_dmamap_load_sgmap
;
145 t
->_dmamap_load_mbuf
= cia_bus_dmamap_load_mbuf_sgmap
;
146 t
->_dmamap_load_uio
= cia_bus_dmamap_load_uio_sgmap
;
147 t
->_dmamap_load_raw
= cia_bus_dmamap_load_raw_sgmap
;
148 t
->_dmamap_unload
= cia_bus_dmamap_unload_sgmap
;
149 t
->_dmamap_sync
= _bus_dmamap_sync
;
151 t
->_dmamem_alloc
= _bus_dmamem_alloc
;
152 t
->_dmamem_free
= _bus_dmamem_free
;
153 t
->_dmamem_map
= _bus_dmamem_map
;
154 t
->_dmamem_unmap
= _bus_dmamem_unmap
;
155 t
->_dmamem_mmap
= _bus_dmamem_mmap
;
158 * The firmware has set up window 1 as a 1G direct-mapped DMA
159 * window beginning at 1G. We leave it alone. Leave window
160 * 0 alone until we reconfigure it for SGMAP-mapped DMA.
161 * Windows 2 and 3 are already disabled.
165 * Initialize the SGMAP. Must align page table to 32k
168 alpha_sgmap_init(t
, &ccp
->cc_sgmap
, "cia_sgmap",
169 CIA_SGMAP_MAPPED_BASE
, 0, CIA_SGMAP_MAPPED_SIZE
,
170 sizeof(u_int64_t
), NULL
, (32*1024));
173 * Set up window 0 as an 8MB SGMAP-mapped window
176 REGVAL(CIA_PCI_W0BASE
) = CIA_SGMAP_MAPPED_BASE
|
177 CIA_PCI_WnBASE_SG_EN
| CIA_PCI_WnBASE_W_EN
;
180 REGVAL(CIA_PCI_W0MASK
) = CIA_PCI_WnMASK_8M
;
183 tbase
= ccp
->cc_sgmap
.aps_ptpa
>> CIA_PCI_TnBASE_SHIFT
;
184 if ((tbase
& CIA_PCI_TnBASE_MASK
) != tbase
)
185 panic("cia_dma_init: bad page table address");
186 REGVAL(CIA_PCI_T0BASE
) = tbase
;
190 * Pass 1 and 2 (i.e. revision <= 1) of the Pyxis have a
191 * broken scatter/gather TLB; it cannot be invalidated. To
192 * work around this problem, we configure window 2 as an SG
193 * 2M window at 128M, which we use in DMA loopback mode to
194 * read a spill page. This works by causing TLB misses,
195 * causing the old entries to be purged to make room for
196 * the new entries coming in for the spill page.
198 if ((ccp
->cc_flags
& CCF_ISPYXIS
) != 0 && ccp
->cc_rev
<= 1) {
199 u_int64_t
*page_table
;
202 cia_tlb_invalidate_fn
=
203 cia_broken_pyxis_tlb_invalidate
;
205 alpha_sgmap_init(t
, &cia_pyxis_bug_sgmap
,
206 "pyxis_bug_sgmap", CIA_PYXIS_BUG_BASE
, 0,
207 CIA_PYXIS_BUG_SIZE
, sizeof(u_int64_t
), NULL
,
210 REGVAL(CIA_PCI_W2BASE
) = CIA_PYXIS_BUG_BASE
|
211 CIA_PCI_WnBASE_SG_EN
| CIA_PCI_WnBASE_W_EN
;
214 REGVAL(CIA_PCI_W2MASK
) = CIA_PCI_WnMASK_2M
;
217 tbase
= cia_pyxis_bug_sgmap
.aps_ptpa
>>
218 CIA_PCI_TnBASE_SHIFT
;
219 if ((tbase
& CIA_PCI_TnBASE_MASK
) != tbase
)
220 panic("cia_dma_init: bad page table address");
221 REGVAL(CIA_PCI_T2BASE
) = tbase
;
225 * Initialize the page table to point at the spill
226 * page. Leave the last entry invalid.
228 pci_sgmap_pte64_init_spill_page_pte();
229 for (i
= 0, page_table
= cia_pyxis_bug_sgmap
.aps_pt
;
230 i
< (CIA_PYXIS_BUG_SIZE
/ PAGE_SIZE
) - 1; i
++) {
232 pci_sgmap_pte64_prefetch_spill_page_pte
;
236 cia_tlb_invalidate_fn
= cia_tlb_invalidate
;
238 CIA_TLB_INVALIDATE();
240 /* XXX XXX BEGIN XXX XXX */
242 extern paddr_t alpha_XXX_dmamap_or
; /* XXX */
243 alpha_XXX_dmamap_or
= CIA_DIRECT_MAPPED_BASE
; /* XXX */
245 /* XXX XXX END XXX XXX */
249 * Return the bus dma tag to be used for the specified bus type.
253 cia_dma_get_tag(bus_dma_tag_t t
, alpha_bus_t bustype
)
255 struct cia_config
*ccp
= t
->_cookie
;
261 * Systems with a CIA can only support 1G
262 * of memory, so we use the direct-mapped window
263 * on busses that have 32-bit DMA.
265 * Ahem: I have a PWS 500au with 1.5G of memory, and it
266 * had problems doing DMA because it was not falling back
267 * to using SGMAPs. I've fixed that and my PWS now works with
268 * 1.5G. There have been other reports about failures with
269 * more than 1.0G of memory. Michael Hitch
271 return (&ccp
->cc_dmat_direct
);
275 * ISA doesn't have enough address bits to use
276 * the direct-mapped DMA window, so we must use
279 return (&ccp
->cc_dmat_sgmap
);
282 panic("cia_dma_get_tag: shouldn't be here, really...");
287 * Create a CIA direct-mapped DMA map.
290 cia_bus_dmamap_create_direct(t
, size
, nsegments
, maxsegsz
, boundary
,
300 struct cia_config
*ccp
= t
->_cookie
;
304 error
= _bus_dmamap_create(t
, size
, nsegments
, maxsegsz
,
305 boundary
, flags
, dmamp
);
311 if ((ccp
->cc_flags
& CCF_PYXISBUG
) != 0 &&
312 map
->_dm_segcnt
> 1) {
314 * We have a Pyxis with the DMA page crossing bug, make
315 * sure we don't coalesce adjacent DMA segments.
317 * NOTE: We can only do this if the max segment count
318 * is greater than 1. This is because many network
319 * drivers allocate large contiguous blocks of memory
320 * for control data structures, even though they won't
321 * do any single DMA that crosses a page coundary.
322 * -- thorpej@NetBSD.org, 2/5/2000
324 map
->_dm_flags
|= DMAMAP_NO_COALESCE
;
331 * Load a CIA SGMAP-mapped DMA map with a linear buffer.
334 cia_bus_dmamap_load_sgmap(bus_dma_tag_t t
, bus_dmamap_t map
, void *buf
, bus_size_t buflen
, struct proc
*p
, int flags
)
338 error
= pci_sgmap_pte64_load(t
, map
, buf
, buflen
, p
, flags
,
341 CIA_TLB_INVALIDATE();
347 * Load a CIA SGMAP-mapped DMA map with an mbuf chain.
350 cia_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t
, bus_dmamap_t map
, struct mbuf
*m
, int flags
)
354 error
= pci_sgmap_pte64_load_mbuf(t
, map
, m
, flags
, t
->_sgmap
);
356 CIA_TLB_INVALIDATE();
362 * Load a CIA SGMAP-mapped DMA map with a uio.
365 cia_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t
, bus_dmamap_t map
, struct uio
*uio
, int flags
)
369 error
= pci_sgmap_pte64_load_uio(t
, map
, uio
, flags
, t
->_sgmap
);
371 CIA_TLB_INVALIDATE();
377 * Load a CIA SGMAP-mapped DMA map with raw memory.
380 cia_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
)
384 error
= pci_sgmap_pte64_load_raw(t
, map
, segs
, nsegs
, size
, flags
,
387 CIA_TLB_INVALIDATE();
393 * Unload a CIA DMA map.
396 cia_bus_dmamap_unload_sgmap(bus_dma_tag_t t
, bus_dmamap_t map
)
400 * Invalidate any SGMAP page table entries used by this
403 pci_sgmap_pte64_unload(t
, map
, t
->_sgmap
);
404 CIA_TLB_INVALIDATE();
407 * Do the generic bits of the unload.
409 _bus_dmamap_unload(t
, map
);
413 * Flush the CIA scatter/gather TLB.
416 cia_tlb_invalidate(void)
420 REGVAL(CIA_PCI_TBIA
) = CIA_PCI_TBIA_ALL
;
425 * Flush the scatter/gather TLB on broken Pyxis chips.
428 cia_broken_pyxis_tlb_invalidate(void)
430 volatile u_int64_t dummy
;
437 * Put the Pyxis into PCI loopback mode.
440 ctrl
= REGVAL(CIA_CSR_CTRL
);
441 REGVAL(CIA_CSR_CTRL
) = ctrl
| CTRL_PCI_LOOP_EN
;
445 * Now, read from PCI dense memory space at offset 128M (our
446 * target window base), skipping 64k on each read. This forces
449 * XXX Looks like the TLB entries are `not quite LRU'. We need
450 * XXX to read more times than there are actual tags!
452 for (i
= 0; i
< CIA_TLB_NTAGS
+ 4; i
++) {
453 dummy
= *((volatile u_int64_t
*)
454 ALPHA_PHYS_TO_K0SEG(CIA_PCI_DENSE
+ CIA_PYXIS_BUG_BASE
+
459 * Restore normal PCI operation.
462 REGVAL(CIA_CSR_CTRL
) = ctrl
;