xref: /netbsd-src/sys/arch/alpha/pci/dwlpx_dma.c (revision d36ffd4ac0c9d2710abf89082675bbb8a107fe98)
1 /* $NetBSD: dwlpx_dma.c,v 1.30 2021/06/19 16:43:11 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 1997, 1998 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  *
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.
31  */
32 
33 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
34 
35 __KERNEL_RCSID(0, "$NetBSD: dwlpx_dma.c,v 1.30 2021/06/19 16:43:11 thorpej Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/kmem.h>
42 
43 #define _ALPHA_BUS_DMA_PRIVATE
44 #include <sys/bus.h>
45 
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcivar.h>
48 #include <alpha/tlsb/tlsbreg.h>
49 #include <alpha/tlsb/kftxxvar.h>
50 #include <alpha/tlsb/kftxxreg.h>
51 #include <alpha/pci/dwlpxreg.h>
52 #include <alpha/pci/dwlpxvar.h>
53 
54 static bus_dma_tag_t dwlpx_dma_get_tag(bus_dma_tag_t, alpha_bus_t);
55 
56 static int	dwlpx_bus_dmamap_load_sgmap(bus_dma_tag_t, bus_dmamap_t, void *,
57 		    bus_size_t, struct proc *, int);
58 
59 static int	dwlpx_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t, bus_dmamap_t,
60 		    struct mbuf *, int);
61 
62 static int	dwlpx_bus_dmamap_load_uio_sgmap(bus_dma_tag_t, bus_dmamap_t,
63 		    struct uio *, int);
64 
65 static int	dwlpx_bus_dmamap_load_raw_sgmap(bus_dma_tag_t, bus_dmamap_t,
66 		    bus_dma_segment_t *, int, bus_size_t, int);
67 
68 static void	dwlpx_bus_dmamap_unload_sgmap(bus_dma_tag_t, bus_dmamap_t);
69 
70 /*
71  * Direct-mapped window: 2G at 2G
72  */
73 #define	DWLPx_DIRECT_MAPPED_BASE	(2UL*1024UL*1024UL*1024UL)
74 #define	DWLPx_DIRECT_MAPPED_SIZE	(2UL*1024UL*1024UL*1024UL)
75 
76 /*
77  * SGMAP window A: 256M or 1G at 1G
78  */
79 #define	DWLPx_SG_MAPPED_BASE		(1*1024*1024*1024)
80 #define	DWLPx_SG_MAPPED_SIZE(x)		((x) * PAGE_SIZE)
81 
82 /* DWLPx has a 256-byte out-bound DMA prefetch threshold. */
83 #define	DWLPx_SG_MAPPED_PFTHRESH	256
84 
85 /*
86  * Set this to always use SGMAPs.
87  */
88 #ifdef DWLPX_ALWAYS_USE_SGMAP
89 int	dwlpx_always_use_sgmap = 1;
90 #else
91 int	dwlpx_always_use_sgmap = 0;
92 #endif
93 
94 void
dwlpx_dma_init(struct dwlpx_config * ccp)95 dwlpx_dma_init(struct dwlpx_config *ccp)
96 {
97 	char *exname;
98 	bus_dma_tag_t t;
99 	uint32_t *page_table;
100 	int i, lim, wmask;
101 
102 	/*
103 	 * Determine size of Window C based on the amount of SGMAP
104 	 * page table SRAM available.
105 	 */
106 	if (ccp->cc_sc->dwlpx_sgmapsz == DWLPX_SG128K) {
107 		lim = 128 * 1024;
108 		wmask = PCIA_WMASK_1G;
109 	} else {
110 		lim = 32 * 1024;
111 		wmask = PCIA_WMASK_256M;
112 	}
113 
114 	/*
115 	 * Initialize the DMA tag used for direct-mapped DMA.  Chain
116 	 * this window to the SGMAP window, because we might have
117 	 * a lot of memory in the machine.
118 	 */
119 	t = &ccp->cc_dmat_direct;
120 	t->_cookie = ccp;
121 	t->_wbase = DWLPx_DIRECT_MAPPED_BASE;
122 	t->_wsize = DWLPx_DIRECT_MAPPED_SIZE;
123 	t->_next_window = &ccp->cc_dmat_sgmap;
124 	t->_boundary = 0;
125 	t->_sgmap = NULL;
126 	t->_get_tag = dwlpx_dma_get_tag;
127 	t->_dmamap_create = _bus_dmamap_create;
128 	t->_dmamap_destroy = _bus_dmamap_destroy;
129 	t->_dmamap_load = _bus_dmamap_load_direct;
130 	t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
131 	t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
132 	t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
133 	t->_dmamap_unload = _bus_dmamap_unload;
134 	t->_dmamap_sync = _bus_dmamap_sync;
135 
136 	t->_dmamem_alloc = _bus_dmamem_alloc;
137 	t->_dmamem_free = _bus_dmamem_free;
138 	t->_dmamem_map = _bus_dmamem_map;
139 	t->_dmamem_unmap = _bus_dmamem_unmap;
140 	t->_dmamem_mmap = _bus_dmamem_mmap;
141 
142 	/*
143 	 * Initialize the DMA tag used for sgmap-mapped DMA.
144 	 */
145 	t = &ccp->cc_dmat_sgmap;
146 	t->_cookie = ccp;
147 	t->_wbase = DWLPx_SG_MAPPED_BASE;
148 	t->_wsize = DWLPx_SG_MAPPED_SIZE(lim);
149 	t->_next_window = NULL;
150 	t->_boundary = 0;
151 	t->_sgmap = &ccp->cc_sgmap;
152 	t->_pfthresh = DWLPx_SG_MAPPED_PFTHRESH;
153 	t->_get_tag = dwlpx_dma_get_tag;
154 	t->_dmamap_create = alpha_sgmap_dmamap_create;
155 	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
156 	t->_dmamap_load = dwlpx_bus_dmamap_load_sgmap;
157 	t->_dmamap_load_mbuf = dwlpx_bus_dmamap_load_mbuf_sgmap;
158 	t->_dmamap_load_uio = dwlpx_bus_dmamap_load_uio_sgmap;
159 	t->_dmamap_load_raw = dwlpx_bus_dmamap_load_raw_sgmap;
160 	t->_dmamap_unload = dwlpx_bus_dmamap_unload_sgmap;
161 	t->_dmamap_sync = _bus_dmamap_sync;
162 
163 	t->_dmamem_alloc = _bus_dmamem_alloc;
164 	t->_dmamem_free = _bus_dmamem_free;
165 	t->_dmamem_map = _bus_dmamem_map;
166 	t->_dmamem_unmap = _bus_dmamem_unmap;
167 	t->_dmamem_mmap = _bus_dmamem_mmap;
168 
169 	/*
170 	 * A few notes about SGMAP-mapped DMA on the DWLPx:
171 	 *
172 	 * The DWLPx has PCIA-resident SRAM that is used for
173 	 * the SGMAP page table; there is no TLB.  The DWLPA
174 	 * has room for 32K entries, yielding a total of 256M
175 	 * of sgva space.  The DWLPB has 32K entries or 128K
176 	 * entries, depending on TBIT, yielding either 256M or
177 	 * 1G of sgva space.
178 	 *
179 	 * This sgva space must be shared across all windows
180 	 * that wish to use SGMAP-mapped DMA; make sure to
181 	 * adjust the "sgvabase" argument to alpha_sgmap_init()
182 	 * accordingly if you create more than one SGMAP-mapped
183 	 * window.  Note that sgvabase != window base.  The former
184 	 * is used to compute indexes into the page table only.
185 	 *
186 	 * In the current implementation the first window is a
187 	 * 2G window direct-mapped mapped at 2G and the second
188 	 * window is disabled and the third window is a 256M
189 	 * or 1GB scatter/gather map at 1GB.
190 	 *
191 	 * We just punt on trying to support ISA DMA.  If you want
192 	 * try that on a TurboLaser, well, you just lose.
193 	 */
194 
195 	/*
196 	 * Initialize the page table.
197 	 */
198 	page_table =
199 	    (uint32_t *)ALPHA_PHYS_TO_K0SEG(PCIA_SGMAP_PT + ccp->cc_sysbase);
200 	for (i = 0; i < lim; i++)
201 		page_table[i * SGMAP_PTE_SPACING] = 0;
202 	alpha_mb();
203 
204 	/*
205 	 * Initialize the SGMAP for window C:
206 	 *
207 	 *	Size: 256M or 1GB
208 	 *	Window base: 1GB
209 	 *	SGVA base: 0
210 	 */
211 	exname = kmem_asprintf("%s_sgmap_a",
212 	    device_xname(ccp->cc_sc->dwlpx_dev));
213 	alpha_sgmap_init(t, &ccp->cc_sgmap, exname, DWLPx_SG_MAPPED_BASE,
214 	    0, DWLPx_SG_MAPPED_SIZE(lim), sizeof(uint32_t),
215 	    (void *)page_table, 0);
216 
217 	/*
218 	 * Set up DMA windows for this DWLPx.
219 	 *
220 	 * Do this even for all HPCs- even for the nonexistent
221 	 * one on hose zero of a KFTIA.
222 	 */
223 	for (i = 0; i < NHPC; i++) {
224 		REGVAL(PCIA_WMASK_A(i) + ccp->cc_sysbase) = PCIA_WMASK_2G;
225 		REGVAL(PCIA_TBASE_A(i) + ccp->cc_sysbase) = 0;
226 		REGVAL(PCIA_WBASE_A(i) + ccp->cc_sysbase) =
227 		    DWLPx_DIRECT_MAPPED_BASE | PCIA_WBASE_W_EN;
228 
229 		REGVAL(PCIA_WMASK_B(i) + ccp->cc_sysbase) = 0;
230 		REGVAL(PCIA_TBASE_B(i) + ccp->cc_sysbase) = 0;
231 		REGVAL(PCIA_WBASE_B(i) + ccp->cc_sysbase) = 0;
232 
233 		REGVAL(PCIA_WMASK_C(i) + ccp->cc_sysbase) = wmask;
234 		REGVAL(PCIA_TBASE_C(i) + ccp->cc_sysbase) = 0;
235 		REGVAL(PCIA_WBASE_C(i) + ccp->cc_sysbase) =
236 		    DWLPx_SG_MAPPED_BASE | PCIA_WBASE_W_EN | PCIA_WBASE_SG_EN;
237 		alpha_mb();
238 	}
239 }
240 
241 /*
242  * Return the bus dma tag to be used for the specified bus type.
243  * INTERNAL USE ONLY!
244  */
245 static bus_dma_tag_t
dwlpx_dma_get_tag(bus_dma_tag_t t,alpha_bus_t bustype)246 dwlpx_dma_get_tag(bus_dma_tag_t t, alpha_bus_t bustype)
247 {
248 	struct dwlpx_config *ccp = t->_cookie;
249 
250 	switch (bustype) {
251 	case ALPHA_BUS_PCI:
252 	case ALPHA_BUS_EISA:
253 		if (dwlpx_always_use_sgmap) {
254 			/*
255 			 * Always use SGMAPs (for testing purposes?)
256 			 */
257 			return (&ccp->cc_dmat_sgmap);
258 		}
259 		/*
260 		 * Give these busses the direct-mapped window; if the
261 		 * address crosses the threshold, it will fall back
262 		 * onto the SGMAP window.
263 		 */
264 		return (&ccp->cc_dmat_direct);
265 
266 	case ALPHA_BUS_ISA:
267 		/*
268 		 * Don't even bother; it's not easy, given how the
269 		 * page table is arranged, and it's not really worth
270 		 * the trouble.
271 		 */
272 		panic("dwlpx_dma_get_tag: ISA DMA?  Forget it...");
273 		/* NOTREACHED */
274 
275 	default:
276 		panic("dwlpx_dma_get_tag: shouldn't be here, really...");
277 	}
278 }
279 
280 /*
281  * Load a DWLPx SGMAP-mapped DMA map with a linear buffer.
282  */
283 static int
dwlpx_bus_dmamap_load_sgmap(bus_dma_tag_t t,bus_dmamap_t map,void * buf,bus_size_t buflen,struct proc * p,int flags)284 dwlpx_bus_dmamap_load_sgmap(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, struct proc *p, int flags)
285 {
286 
287 	return (pci_sgmap_pte32_load(t, map, buf, buflen, p, flags,
288 	    t->_sgmap));
289 }
290 
291 /*
292  * Load a DWLPx SGMAP-mapped DMA map with an mbuf chain.
293  */
294 static int
dwlpx_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t,bus_dmamap_t map,struct mbuf * m,int flags)295 dwlpx_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m, int flags)
296 {
297 
298 	return (pci_sgmap_pte32_load_mbuf(t, map, m, flags, t->_sgmap));
299 }
300 
301 /*
302  * Load a DWLPx SGMAP-mapped DMA map with a uio.
303  */
304 static int
dwlpx_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t,bus_dmamap_t map,struct uio * uio,int flags)305 dwlpx_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags)
306 {
307 
308 	return (pci_sgmap_pte32_load_uio(t, map, uio, flags, t->_sgmap));
309 }
310 
311 /*
312  * Load a DWLPx SGMAP-mapped DMA map with raw memory.
313  */
314 static int
dwlpx_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)315 dwlpx_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)
316 {
317 
318 	return (pci_sgmap_pte32_load_raw(t, map, segs, nsegs, size, flags,
319 	    t->_sgmap));
320 }
321 
322 /*
323  * Unload a DWLPx DMA map.
324  */
325 static void
dwlpx_bus_dmamap_unload_sgmap(bus_dma_tag_t t,bus_dmamap_t map)326 dwlpx_bus_dmamap_unload_sgmap(bus_dma_tag_t t, bus_dmamap_t map)
327 {
328 
329 	/*
330 	 * Invalidate any SGMAP page table entries used by this
331 	 * mapping.
332 	 */
333 	pci_sgmap_pte32_unload(t, map, t->_sgmap);
334 
335 	/*
336 	 * Do the generic bits of the unload.
337 	 */
338 	_bus_dmamap_unload_common(t, map);
339 }
340