Deleted Added
full compact
busdma_bounce.c (134934) busdma_bounce.c (136805)
1/*
2 * Copyright (c) 1997, 1998 Justin T. Gibbs.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1997, 1998 Justin T. Gibbs.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/i386/i386/busdma_machdep.c 134934 2004-09-08 04:54:19Z scottl $");
28__FBSDID("$FreeBSD: head/sys/i386/i386/busdma_machdep.c 136805 2004-10-23 10:34:27Z rwatson $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/malloc.h>
33#include <sys/bus.h>
34#include <sys/interrupt.h>
35#include <sys/kernel.h>
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/malloc.h>
33#include <sys/bus.h>
34#include <sys/interrupt.h>
35#include <sys/kernel.h>
36#include <sys/ktr.h>
36#include <sys/lock.h>
37#include <sys/proc.h>
38#include <sys/mutex.h>
39#include <sys/mbuf.h>
40#include <sys/uio.h>
41#include <sys/sysctl.h>
42
43#include <vm/vm.h>

--- 169 unchanged lines hidden (view full) ---

213 /* Basic sanity checking */
214 if (boundary != 0 && boundary < maxsegsz)
215 maxsegsz = boundary;
216
217 /* Return a NULL tag on failure */
218 *dmat = NULL;
219
220 newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
37#include <sys/lock.h>
38#include <sys/proc.h>
39#include <sys/mutex.h>
40#include <sys/mbuf.h>
41#include <sys/uio.h>
42#include <sys/sysctl.h>
43
44#include <vm/vm.h>

--- 169 unchanged lines hidden (view full) ---

214 /* Basic sanity checking */
215 if (boundary != 0 && boundary < maxsegsz)
216 maxsegsz = boundary;
217
218 /* Return a NULL tag on failure */
219 *dmat = NULL;
220
221 newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
221 if (newtag == NULL)
222 if (newtag == NULL) {
223 CTR3(KTR_BUSDMA, "bus_dma_tag_create returned tag %p tag "
224 "flags 0x%x error %d", newtag, 0, error);
222 return (ENOMEM);
225 return (ENOMEM);
226 }
223
224 newtag->parent = parent;
225 newtag->alignment = alignment;
226 newtag->boundary = boundary;
227 newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
228 newtag->highaddr = trunc_page((vm_paddr_t)highaddr) +
229 (PAGE_SIZE - 1);
230 newtag->filter = filter;

--- 60 unchanged lines hidden (view full) ---

291 newtag->flags |= BUS_DMA_MIN_ALLOC_COMP;
292 }
293
294 if (error != 0) {
295 free(newtag, M_DEVBUF);
296 } else {
297 *dmat = newtag;
298 }
227
228 newtag->parent = parent;
229 newtag->alignment = alignment;
230 newtag->boundary = boundary;
231 newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
232 newtag->highaddr = trunc_page((vm_paddr_t)highaddr) +
233 (PAGE_SIZE - 1);
234 newtag->filter = filter;

--- 60 unchanged lines hidden (view full) ---

295 newtag->flags |= BUS_DMA_MIN_ALLOC_COMP;
296 }
297
298 if (error != 0) {
299 free(newtag, M_DEVBUF);
300 } else {
301 *dmat = newtag;
302 }
303 CTR3(KTR_BUSDMA, "bus_dma_tag_create returned tag %p tag flags 0x%x "
304 "error %d", newtag, (newtag != NULL ? newtag->flags : 0), error);
299 return (error);
300}
301
302int
303bus_dma_tag_destroy(bus_dma_tag_t dmat)
304{
305 return (error);
306}
307
308int
309bus_dma_tag_destroy(bus_dma_tag_t dmat)
310{
311 bus_dma_tag_t dmat_copy;
312 int error;
313
314 error = 0;
315 dmat_copy = dmat;
316
305 if (dmat != NULL) {
306
317 if (dmat != NULL) {
318
307 if (dmat->map_count != 0)
308 return (EBUSY);
319 if (dmat->map_count != 0) {
320 error = EBUSY;
321 goto out;
322 }
309
310 while (dmat != NULL) {
311 bus_dma_tag_t parent;
312
313 parent = dmat->parent;
314 atomic_subtract_int(&dmat->ref_count, 1);
315 if (dmat->ref_count == 0) {
316 if (dmat->segments != NULL)

--- 4 unchanged lines hidden (view full) ---

321 * release our reference
322 * count on our parent.
323 */
324 dmat = parent;
325 } else
326 dmat = NULL;
327 }
328 }
323
324 while (dmat != NULL) {
325 bus_dma_tag_t parent;
326
327 parent = dmat->parent;
328 atomic_subtract_int(&dmat->ref_count, 1);
329 if (dmat->ref_count == 0) {
330 if (dmat->segments != NULL)

--- 4 unchanged lines hidden (view full) ---

335 * release our reference
336 * count on our parent.
337 */
338 dmat = parent;
339 } else
340 dmat = NULL;
341 }
342 }
329 return (0);
343out:
344 CTR2(KTR_BUSDMA, "bus_dma_tag_destroy tag %p error %d", dmat_copy,
345 error);
346 return (error);
330}
331
332/*
333 * Allocate a handle for mapping from kva/uva/physical
334 * address space into bus device space.
335 */
336int
337bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
338{
339 int error;
340
341 error = 0;
342
343 if (dmat->segments == NULL) {
344 dmat->segments = (bus_dma_segment_t *)malloc(
345 sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
346 M_NOWAIT);
347}
348
349/*
350 * Allocate a handle for mapping from kva/uva/physical
351 * address space into bus device space.
352 */
353int
354bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
355{
356 int error;
357
358 error = 0;
359
360 if (dmat->segments == NULL) {
361 dmat->segments = (bus_dma_segment_t *)malloc(
362 sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
363 M_NOWAIT);
347 if (dmat->segments == NULL)
364 if (dmat->segments == NULL) {
365 CTR2(KTR_BUSDMA, "bus_dmamap_create: tag %p error %d",
366 dmat, ENOMEM);
348 return (ENOMEM);
367 return (ENOMEM);
368 }
349 }
350
351 /*
352 * Bouncing might be required if the driver asks for an active
353 * exclusion region, a data alignment that is stricter than 1, and/or
354 * an active address boundary.
355 */
356 if (dmat->lowaddr < ptoa((vm_paddr_t)Maxmem)
357 || dmat->alignment > 1 || dmat->boundary > 0) {
358 /* Must bounce */
359 int maxpages;
360
361 *mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
362 M_NOWAIT | M_ZERO);
369 }
370
371 /*
372 * Bouncing might be required if the driver asks for an active
373 * exclusion region, a data alignment that is stricter than 1, and/or
374 * an active address boundary.
375 */
376 if (dmat->lowaddr < ptoa((vm_paddr_t)Maxmem)
377 || dmat->alignment > 1 || dmat->boundary > 0) {
378 /* Must bounce */
379 int maxpages;
380
381 *mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
382 M_NOWAIT | M_ZERO);
363 if (*mapp == NULL)
383 if (*mapp == NULL) {
384 CTR2(KTR_BUSDMA, "bus_dmamap_create: tag %p error %d",
385 dmat, ENOMEM);
364 return (ENOMEM);
386 return (ENOMEM);
387 }
365
366 /* Initialize the new map */
367 STAILQ_INIT(&((*mapp)->bpages));
368
369 /*
370 * Attempt to add pages to our pool on a per-instance
371 * basis up to a sane limit.
372 */

--- 22 unchanged lines hidden (view full) ---

395 error = 0;
396 }
397 }
398 } else {
399 *mapp = NULL;
400 }
401 if (error == 0)
402 dmat->map_count++;
388
389 /* Initialize the new map */
390 STAILQ_INIT(&((*mapp)->bpages));
391
392 /*
393 * Attempt to add pages to our pool on a per-instance
394 * basis up to a sane limit.
395 */

--- 22 unchanged lines hidden (view full) ---

418 error = 0;
419 }
420 }
421 } else {
422 *mapp = NULL;
423 }
424 if (error == 0)
425 dmat->map_count++;
426 CTR3(KTR_BUSDMA, "bus_dmamap_create: tag %p tag flags 0x%x error %d",
427 dmat, dmat->flags, error);
403 return (error);
404}
405
406/*
407 * Destroy a handle for mapping from kva/uva/physical
408 * address space into bus device space.
409 */
410int
411bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
412{
413 if (map != NULL && map != &nobounce_dmamap) {
428 return (error);
429}
430
431/*
432 * Destroy a handle for mapping from kva/uva/physical
433 * address space into bus device space.
434 */
435int
436bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
437{
438 if (map != NULL && map != &nobounce_dmamap) {
414 if (STAILQ_FIRST(&map->bpages) != NULL)
439 if (STAILQ_FIRST(&map->bpages) != NULL) {
440 CTR2(KTR_BUSDMA, "bus_dmamap_destroy: tag %p error %d",
441 dmat, EBUSY);
415 return (EBUSY);
442 return (EBUSY);
443 }
416 free(map, M_DEVBUF);
417 }
418 dmat->map_count--;
444 free(map, M_DEVBUF);
445 }
446 dmat->map_count--;
447 CTR1(KTR_BUSDMA, "bus_dmamap_destroy: tag %p error 0", dmat);
419 return (0);
420}
421
422
423/*
424 * Allocate a piece of memory that can be efficiently mapped into
425 * bus device space based on the constraints lited in the dma tag.
426 * A dmamap to for use with dmamap_load is also allocated.

--- 13 unchanged lines hidden (view full) ---

440
441 /* If we succeed, no mapping/bouncing will be required */
442 *mapp = NULL;
443
444 if (dmat->segments == NULL) {
445 dmat->segments = (bus_dma_segment_t *)malloc(
446 sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
447 M_NOWAIT);
448 return (0);
449}
450
451
452/*
453 * Allocate a piece of memory that can be efficiently mapped into
454 * bus device space based on the constraints lited in the dma tag.
455 * A dmamap to for use with dmamap_load is also allocated.

--- 13 unchanged lines hidden (view full) ---

469
470 /* If we succeed, no mapping/bouncing will be required */
471 *mapp = NULL;
472
473 if (dmat->segments == NULL) {
474 dmat->segments = (bus_dma_segment_t *)malloc(
475 sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
476 M_NOWAIT);
448 if (dmat->segments == NULL)
477 if (dmat->segments == NULL) {
478 CTR3(KTR_BUSDMA, "bus_dmamem_alloc: tag %p tag "
479 "flags 0x%x error %d", dmat, dmat->flags, ENOMEM);
449 return (ENOMEM);
480 return (ENOMEM);
481 }
450 }
451
452 if ((dmat->maxsize <= PAGE_SIZE) &&
453 dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) {
454 *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags);
455 } else {
456 /*
457 * XXX Use Contigmalloc until it is merged into this facility
458 * and handles multi-seg allocations. Nobody is doing
459 * multi-seg allocations yet though.
460 * XXX Certain AGP hardware does.
461 */
462 *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags,
463 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul,
464 dmat->boundary);
465 }
482 }
483
484 if ((dmat->maxsize <= PAGE_SIZE) &&
485 dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) {
486 *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags);
487 } else {
488 /*
489 * XXX Use Contigmalloc until it is merged into this facility
490 * and handles multi-seg allocations. Nobody is doing
491 * multi-seg allocations yet though.
492 * XXX Certain AGP hardware does.
493 */
494 *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags,
495 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul,
496 dmat->boundary);
497 }
466 if (*vaddr == NULL)
498 if (*vaddr == NULL) {
499 CTR3(KTR_BUSDMA, "bus_dmamem_alloc: tag %p tag flags 0x%x "
500 "error %d", dmat, dmat->flags, ENOMEM);
467 return (ENOMEM);
501 return (ENOMEM);
502 }
503 CTR3(KTR_BUSDMA, "bus_dmamem_alloc: tag %p tag flags 0x%x error %d",
504 dmat, dmat->flags, ENOMEM);
468 return (0);
469}
470
471/*
472 * Free a piece of memory and it's allociated dmamap, that was allocated
473 * via bus_dmamem_alloc. Make the same choice for free/contigfree.
474 */
475void

--- 6 unchanged lines hidden (view full) ---

482 if (map != NULL)
483 panic("bus_dmamem_free: Invalid map freed\n");
484 if ((dmat->maxsize <= PAGE_SIZE)
485 && dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem))
486 free(vaddr, M_DEVBUF);
487 else {
488 contigfree(vaddr, dmat->maxsize, M_DEVBUF);
489 }
505 return (0);
506}
507
508/*
509 * Free a piece of memory and it's allociated dmamap, that was allocated
510 * via bus_dmamem_alloc. Make the same choice for free/contigfree.
511 */
512void

--- 6 unchanged lines hidden (view full) ---

519 if (map != NULL)
520 panic("bus_dmamem_free: Invalid map freed\n");
521 if ((dmat->maxsize <= PAGE_SIZE)
522 && dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem))
523 free(vaddr, M_DEVBUF);
524 else {
525 contigfree(vaddr, dmat->maxsize, M_DEVBUF);
526 }
527 CTR2(KTR_BUSDMA, "bus_dmamem_free: tag %p flags 0x%x", dmat,
528 dmat->flags);
490}
491
492/*
493 * Utility function to load a linear buffer. lastaddrp holds state
494 * between invocations (for multiple-buffer loads). segp contains
495 * the starting segment on entrace, and the ending segment on exit.
496 * first indicates if this is the first invocation of this function.
497 */

--- 155 unchanged lines hidden (view full) ---

653 flags |= BUS_DMA_WAITOK;
654 map->callback = callback;
655 map->callback_arg = callback_arg;
656 }
657
658 error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, NULL, flags,
659 &lastaddr, &nsegs, 1);
660
529}
530
531/*
532 * Utility function to load a linear buffer. lastaddrp holds state
533 * between invocations (for multiple-buffer loads). segp contains
534 * the starting segment on entrace, and the ending segment on exit.
535 * first indicates if this is the first invocation of this function.
536 */

--- 155 unchanged lines hidden (view full) ---

692 flags |= BUS_DMA_WAITOK;
693 map->callback = callback;
694 map->callback_arg = callback_arg;
695 }
696
697 error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, NULL, flags,
698 &lastaddr, &nsegs, 1);
699
661 if (error == EINPROGRESS)
700 if (error == EINPROGRESS) {
701 CTR3(KTR_BUSDMA, "bus_dmamap_load: tag %p tag flags 0x%x "
702 "error %d", dmat, dmat->flags, error);
662 return (error);
703 return (error);
704 }
663
664 if (error)
665 (*callback)(callback_arg, dmat->segments, 0, error);
666 else
667 (*callback)(callback_arg, dmat->segments, nsegs + 1, 0);
668
705
706 if (error)
707 (*callback)(callback_arg, dmat->segments, 0, error);
708 else
709 (*callback)(callback_arg, dmat->segments, nsegs + 1, 0);
710
711 CTR2(KTR_BUSDMA, "bus_dmamap_load: tag %p tag flags 0x%x error 0",
712 dmat, dmat->flags);
669 return (0);
670}
671
672
673/*
674 * Like _bus_dmamap_load(), but for mbufs.
675 */
676int

--- 29 unchanged lines hidden (view full) ---

706
707 if (error) {
708 /* force "no valid mappings" in callback */
709 (*callback)(callback_arg, dmat->segments, 0, 0, error);
710 } else {
711 (*callback)(callback_arg, dmat->segments,
712 nsegs+1, m0->m_pkthdr.len, error);
713 }
713 return (0);
714}
715
716
717/*
718 * Like _bus_dmamap_load(), but for mbufs.
719 */
720int

--- 29 unchanged lines hidden (view full) ---

750
751 if (error) {
752 /* force "no valid mappings" in callback */
753 (*callback)(callback_arg, dmat->segments, 0, 0, error);
754 } else {
755 (*callback)(callback_arg, dmat->segments,
756 nsegs+1, m0->m_pkthdr.len, error);
757 }
758 CTR3(KTR_BUSDMA, "bus_dmamap_load_mbuf: tag %p tag flags 0x%x "
759 "error %d", dmat, dmat->flags, error);
714 return (error);
715}
716
717/*
718 * Like _bus_dmamap_load(), but for uios.
719 */
720int
721bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map,

--- 41 unchanged lines hidden (view full) ---

763
764 if (error) {
765 /* force "no valid mappings" in callback */
766 (*callback)(callback_arg, dmat->segments, 0, 0, error);
767 } else {
768 (*callback)(callback_arg, dmat->segments,
769 nsegs+1, uio->uio_resid, error);
770 }
760 return (error);
761}
762
763/*
764 * Like _bus_dmamap_load(), but for uios.
765 */
766int
767bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map,

--- 41 unchanged lines hidden (view full) ---

809
810 if (error) {
811 /* force "no valid mappings" in callback */
812 (*callback)(callback_arg, dmat->segments, 0, 0, error);
813 } else {
814 (*callback)(callback_arg, dmat->segments,
815 nsegs+1, uio->uio_resid, error);
816 }
817 CTR3(KTR_BUSDMA, "bus_dmamap_load_uio: tag %p tag flags 0x%x "
818 "error %d", dmat, dmat->flags, error);
771 return (error);
772}
773
774/*
775 * Release the mapping held by map.
776 */
777void
778_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)

--- 13 unchanged lines hidden (view full) ---

792
793 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
794 /*
795 * Handle data bouncing. We might also
796 * want to add support for invalidating
797 * the caches on broken hardware
798 */
799 total_bounced++;
819 return (error);
820}
821
822/*
823 * Release the mapping held by map.
824 */
825void
826_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)

--- 13 unchanged lines hidden (view full) ---

840
841 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
842 /*
843 * Handle data bouncing. We might also
844 * want to add support for invalidating
845 * the caches on broken hardware
846 */
847 total_bounced++;
848 CTR3(KTR_BUSDMA, "_bus_dmamap_sync: tag %p tag flags 0x%x "
849 "op 0x%x performing bounce", op, dmat, dmat->flags);
800
801 if (op & BUS_DMASYNC_PREWRITE) {
802 while (bpage != NULL) {
803 bcopy((void *)bpage->datavaddr,
804 (void *)bpage->vaddr,
805 bpage->datacount);
806 bpage = STAILQ_NEXT(bpage, links);
807 }

--- 157 unchanged lines hidden ---
850
851 if (op & BUS_DMASYNC_PREWRITE) {
852 while (bpage != NULL) {
853 bcopy((void *)bpage->datavaddr,
854 (void *)bpage->vaddr,
855 bpage->datacount);
856 bpage = STAILQ_NEXT(bpage, links);
857 }

--- 157 unchanged lines hidden ---