Annotation of sys/arch/alpha/dev/sgmap_typedep.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sgmap_typedep.c,v 1.10 2006/05/21 01:42:43 brad Exp $ */
2: /* $NetBSD: sgmap_typedep.c,v 1.17 2001/07/19 04:27:37 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: #ifdef SGMAP_DEBUG
42: int __C(SGMAP_TYPE,_debug) = 0;
43: #endif
44:
45: SGMAP_PTE_TYPE __C(SGMAP_TYPE,_prefetch_spill_page_pte);
46:
47: int __C(SGMAP_TYPE,_load_buffer)(bus_dma_tag_t,
48: bus_dmamap_t, void *buf, size_t buflen,
49: struct proc *, int, int, struct alpha_sgmap *);
50:
51: void
52: __C(SGMAP_TYPE,_init_spill_page_pte)(void)
53: {
54:
55: __C(SGMAP_TYPE,_prefetch_spill_page_pte) =
56: (alpha_sgmap_prefetch_spill_page_pa >>
57: SGPTE_PGADDR_SHIFT) | SGPTE_VALID;
58: }
59:
60: int
61: __C(SGMAP_TYPE,_load_buffer)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
62: size_t buflen, struct proc *p, int flags, int seg,
63: struct alpha_sgmap *sgmap)
64: {
65: vaddr_t endva, va = (vaddr_t)buf;
66: paddr_t pa;
67: bus_addr_t dmaoffset, sgva;
68: bus_size_t sgvalen, boundary, alignment;
69: SGMAP_PTE_TYPE *pte, *page_table = sgmap->aps_pt;
70: int s, pteidx, error, spill;
71:
72: /* Initialize the spill page PTE if it hasn't been already. */
73: if (__C(SGMAP_TYPE,_prefetch_spill_page_pte) == 0)
74: __C(SGMAP_TYPE,_init_spill_page_pte)();
75:
76: /*
77: * Remember the offset into the first page and the total
78: * transfer length.
79: */
80: dmaoffset = ((u_long)buf) & PGOFSET;
81:
82: #ifdef SGMAP_DEBUG
83: if (__C(SGMAP_TYPE,_debug)) {
84: printf("sgmap_load: ----- buf = %p -----\n", buf);
85: printf("sgmap_load: dmaoffset = 0x%lx, buflen = 0x%lx\n",
86: dmaoffset, buflen);
87: }
88: #endif
89:
90: /*
91: * Allocate the necessary virtual address space for the
92: * mapping. Round the size, since we deal with whole pages.
93: */
94:
95: /*
96: * XXX Always allocate a spill page for now. Note
97: * the spill page is not needed for an in-bound-only
98: * transfer.
99: */
100: if ((flags & BUS_DMA_READ) == 0)
101: spill = 1;
102: else
103: spill = 0;
104:
105: endva = round_page(va + buflen);
106: va = trunc_page(va);
107:
108: boundary = map->_dm_boundary;
109: alignment = PAGE_SIZE;
110:
111: sgvalen = (endva - va);
112: if (spill) {
113: sgvalen += PAGE_SIZE;
114:
115: /*
116: * ARGH! If the addition of the spill page bumped us
117: * over our boundary, we have to 2x the boundary limit.
118: */
119: if (boundary && boundary < sgvalen) {
120: alignment = boundary;
121: do {
122: boundary <<= 1;
123: } while (boundary < sgvalen);
124: }
125: }
126:
127: #if 0
128: printf("len 0x%lx -> 0x%lx, boundary 0x%lx -> 0x%lx -> ",
129: (endva - va), sgvalen, map->_dm_boundary, boundary);
130: #endif
131:
132: s = splvm();
133: error = extent_alloc(sgmap->aps_ex, sgvalen, alignment, 0, boundary,
134: (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK, &sgva);
135: splx(s);
136: if (error)
137: return (error);
138:
139: #if 0
140: printf("error %d sgva 0x%lx\n", error, sgva);
141: #endif
142:
143: pteidx = sgva >> SGMAP_ADDR_PTEIDX_SHIFT;
144: pte = &page_table[pteidx * SGMAP_PTE_SPACING];
145:
146: #ifdef SGMAP_DEBUG
147: if (__C(SGMAP_TYPE,_debug))
148: printf("sgmap_load: sgva = 0x%lx, pteidx = %d, "
149: "pte = %p (pt = %p)\n", sgva, pteidx, pte,
150: page_table);
151: #endif
152:
153: /* Generate the DMA address. */
154: map->dm_segs[seg].ds_addr = sgmap->aps_wbase | sgva | dmaoffset;
155: map->dm_segs[seg].ds_len = buflen;
156:
157: #ifdef SGMAP_DEBUG
158: if (__C(SGMAP_TYPE,_debug))
159: printf("sgmap_load: wbase = 0x%lx, vpage = 0x%x, "
160: "dma addr = 0x%lx\n", sgmap->aps_wbase, sgva,
161: map->dm_segs[seg].ds_addr);
162: #endif
163:
164: for (; va < endva; va += PAGE_SIZE, pteidx++,
165: pte = &page_table[pteidx * SGMAP_PTE_SPACING]) {
166: /* Get the physical address for this segment. */
167: if (p != NULL)
168: (void) pmap_extract(p->p_vmspace->vm_map.pmap, va, &pa);
169: else
170: pa = vtophys(va);
171:
172: /* Load the current PTE with this page. */
173: *pte = (pa >> SGPTE_PGADDR_SHIFT) | SGPTE_VALID;
174: #ifdef SGMAP_DEBUG
175: if (__C(SGMAP_TYPE,_debug))
176: printf("sgmap_load: pa = 0x%lx, pte = %p, "
177: "*pte = 0x%lx\n", pa, pte, (u_long)(*pte));
178: #endif
179: }
180:
181: if (spill) {
182: /* ...and the prefetch-spill page. */
183: *pte = __C(SGMAP_TYPE,_prefetch_spill_page_pte);
184: #ifdef SGMAP_DEBUG
185: if (__C(SGMAP_TYPE,_debug)) {
186: printf("sgmap_load: spill page, pte = %p, "
187: "*pte = 0x%lx\n", pte, *pte);
188: printf("sgmap_load: pte count = %d\n",
189: map->_dm_ptecnt);
190: }
191: #endif
192: }
193:
194: return (0);
195: }
196:
197: int
198: __C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
199: bus_size_t buflen, struct proc *p, int flags, struct alpha_sgmap *sgmap)
200: {
201: int seg, error;
202:
203: /*
204: * Make sure that on error condition we return "no valid mappings".
205: */
206: map->dm_mapsize = 0;
207: map->dm_nsegs = 0;
208:
209: if (buflen > map->_dm_size)
210: return (EINVAL);
211:
212: KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
213: KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
214: (BUS_DMA_READ|BUS_DMA_WRITE));
215:
216: map->_dm_flags |= flags & (BUS_DMA_READ|BUS_DMA_WRITE);
217:
218: seg = 0;
219: error = __C(SGMAP_TYPE,_load_buffer)(t, map, buf, buflen, p,
220: flags, seg, sgmap);
221:
222: alpha_mb();
223:
224: #if defined(SGMAP_DEBUG) && defined(DDB)
225: if (__C(SGMAP_TYPE,_debug) > 1)
226: Debugger();
227: #endif
228:
229: if (error == 0) {
230: map->dm_mapsize = buflen;
231: map->dm_nsegs = 1;
232: map->_dm_window = t;
233: } else {
234: map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
235: if (t->_next_window != NULL) {
236: /* Give the next window a chance. */
237: error = bus_dmamap_load(t->_next_window, map, buf,
238: buflen, p, flags);
239: }
240: }
241: return (error);
242: }
243:
244: int
245: __C(SGMAP_TYPE,_load_mbuf)(bus_dma_tag_t t, bus_dmamap_t map,
246: struct mbuf *m0, int flags, struct alpha_sgmap *sgmap)
247: {
248: struct mbuf *m;
249: int seg, error;
250:
251: /*
252: * Make sure that on error condition we return "no valid mappings".
253: */
254: map->dm_mapsize = 0;
255: map->dm_nsegs = 0;
256:
257: #ifdef DIAGNOSTIC
258: if ((m0->m_flags & M_PKTHDR) == 0)
259: panic(__S(__C(SGMAP_TYPE,_load_mbuf)) ": no packet header");
260: #endif
261:
262: if (m0->m_pkthdr.len > map->_dm_size)
263: return (EINVAL);
264:
265: KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
266: KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
267: (BUS_DMA_READ|BUS_DMA_WRITE));
268:
269: map->_dm_flags |= flags & (BUS_DMA_READ|BUS_DMA_WRITE);
270:
271: seg = 0;
272: error = 0;
273: for (m = m0; m != NULL && error == 0; m = m->m_next) {
274: if (m->m_len == 0)
275: continue;
276: error = __C(SGMAP_TYPE,_load_buffer)(t, map,
277: m->m_data, m->m_len, NULL, flags, seg, sgmap);
278: seg++;
279: }
280:
281: alpha_mb();
282:
283: #if defined(SGMAP_DEBUG) && defined(DDB)
284: if (__C(SGMAP_TYPE,_debug) > 1)
285: Debugger();
286: #endif
287:
288: if (error == 0) {
289: map->dm_mapsize = m0->m_pkthdr.len;
290: map->dm_nsegs = seg;
291: map->_dm_window = t;
292: } else {
293: /* Need to back out what we've done so far. */
294: map->dm_nsegs = seg - 1;
295: __C(SGMAP_TYPE,_unload)(t, map, sgmap);
296: map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
297: if (t->_next_window != NULL) {
298: /* Give the next window a chance. */
299: error = bus_dmamap_load_mbuf(t->_next_window, map,
300: m0, flags);
301: }
302: }
303:
304: return (error);
305: }
306:
307: int
308: __C(SGMAP_TYPE,_load_uio)(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
309: int flags, struct alpha_sgmap *sgmap)
310: {
311: bus_size_t minlen, resid;
312: struct proc *p = NULL;
313: struct iovec *iov;
314: caddr_t addr;
315: int i, seg, error;
316:
317: /*
318: * Make sure that on error condition we return "no valid mappings".
319: */
320: map->dm_mapsize = 0;
321: map->dm_nsegs = 0;
322:
323: KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
324: KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
325: (BUS_DMA_READ|BUS_DMA_WRITE));
326:
327: map->_dm_flags |= flags & (BUS_DMA_READ|BUS_DMA_WRITE);
328:
329: resid = uio->uio_resid;
330: iov = uio->uio_iov;
331:
332: if (uio->uio_segflg == UIO_USERSPACE) {
333: p = uio->uio_procp;
334: #ifdef DIAGNOSTIC
335: if (p == NULL)
336: panic(__S(__C(SGMAP_TYPE,_load_uio))
337: ": USERSPACE but no proc");
338: #endif
339: }
340:
341: seg = 0;
342: error = 0;
343: for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0;
344: i++, seg++) {
345: /*
346: * Now at the first iovec to load. Load each iovec
347: * until we have exhausted the residual count.
348: */
349: minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
350: addr = (caddr_t)iov[i].iov_base;
351:
352: error = __C(SGMAP_TYPE,_load_buffer)(t, map,
353: addr, minlen, p, flags, seg, sgmap);
354:
355: resid -= minlen;
356: }
357:
358: alpha_mb();
359:
360: #if defined(SGMAP_DEBUG) && defined(DDB)
361: if (__C(SGMAP_TYPE,_debug) > 1)
362: Debugger();
363: #endif
364:
365: if (error == 0) {
366: map->dm_mapsize = uio->uio_resid;
367: map->dm_nsegs = seg;
368: } else {
369: /* Need to back out what we've done so far. */
370: map->dm_nsegs = seg - 1;
371: __C(SGMAP_TYPE,_unload)(t, map, sgmap);
372: map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
373: if (t->_next_window != NULL) {
374: /* Give the next window a chance. */
375: error = bus_dmamap_load_uio(t->_next_window, map,
376: uio, flags);
377: }
378: }
379:
380: return (error);
381: }
382:
383: int
384: __C(SGMAP_TYPE,_load_raw)(bus_dma_tag_t t, bus_dmamap_t map,
385: bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags,
386: struct alpha_sgmap *sgmap)
387: {
388: KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
389: KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
390: (BUS_DMA_READ|BUS_DMA_WRITE));
391:
392: panic(__S(__C(SGMAP_TYPE,_load_raw)) ": not implemented");
393: }
394:
395: void
396: __C(SGMAP_TYPE,_unload)(bus_dma_tag_t t, bus_dmamap_t map,
397: struct alpha_sgmap *sgmap)
398: {
399: SGMAP_PTE_TYPE *pte, *page_table = sgmap->aps_pt;
400: bus_addr_t osgva, sgva, esgva;
401: int s, error, spill, seg, pteidx;
402:
403: for (seg = 0; seg < map->dm_nsegs; seg++) {
404: /*
405: * XXX Always allocate a spill page for now. Note
406: * the spill page is not needed for an in-bound-only
407: * transfer.
408: */
409: if ((map->_dm_flags & BUS_DMA_READ) == 0)
410: spill = 1;
411: else
412: spill = 0;
413:
414: sgva = map->dm_segs[seg].ds_addr & ~sgmap->aps_wbase;
415:
416: esgva = round_page(sgva + map->dm_segs[seg].ds_len);
417: osgva = sgva = trunc_page(sgva);
418:
419: if (spill)
420: esgva += PAGE_SIZE;
421:
422: /* Invalidate the PTEs for the mapping. */
423: for (pteidx = sgva >> SGMAP_ADDR_PTEIDX_SHIFT;
424: sgva < esgva; sgva += PAGE_SIZE, pteidx++) {
425: pte = &page_table[pteidx * SGMAP_PTE_SPACING];
426: #ifdef SGMAP_DEBUG
427: if (__C(SGMAP_TYPE,_debug))
428: printf("sgmap_unload: pte = %p, "
429: "*pte = 0x%lx\n", pte, (u_long)(*pte));
430: #endif
431: *pte = 0;
432: }
433:
434: alpha_mb();
435:
436: /* Free the virtual address space used by the mapping. */
437: s = splvm();
438: error = extent_free(sgmap->aps_ex, osgva, (esgva - osgva),
439: EX_NOWAIT);
440: splx(s);
441: if (error != 0)
442: panic(__S(__C(SGMAP_TYPE,_unload)));
443: }
444:
445: map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
446:
447: /* Mark the mapping invalid. */
448: map->dm_mapsize = 0;
449: map->dm_nsegs = 0;
450: map->_dm_window = NULL;
451: }
CVSweb