| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: bus_dma.c,v 1.73 2013/02/04 13:26:19 macallan Exp $ */ | | 1 | /* $NetBSD: bus_dma.c,v 1.74 2013/02/13 23:08:45 matt Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | | 8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. | | 9 | * NASA Ames Research Center. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -23,27 +23,27 @@ | | | @@ -23,27 +23,27 @@ |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #define _ARM32_BUS_DMA_PRIVATE | | 33 | #define _ARM32_BUS_DMA_PRIVATE |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.73 2013/02/04 13:26:19 macallan Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.74 2013/02/13 23:08:45 matt Exp $"); |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/systm.h> | | 39 | #include <sys/systm.h> |
40 | #include <sys/kernel.h> | | 40 | #include <sys/kernel.h> |
41 | #include <sys/proc.h> | | 41 | #include <sys/proc.h> |
42 | #include <sys/buf.h> | | 42 | #include <sys/buf.h> |
43 | #include <sys/reboot.h> | | 43 | #include <sys/reboot.h> |
44 | #include <sys/conf.h> | | 44 | #include <sys/conf.h> |
45 | #include <sys/file.h> | | 45 | #include <sys/file.h> |
46 | #include <sys/malloc.h> | | 46 | #include <sys/malloc.h> |
47 | #include <sys/mbuf.h> | | 47 | #include <sys/mbuf.h> |
48 | #include <sys/vnode.h> | | 48 | #include <sys/vnode.h> |
49 | #include <sys/device.h> | | 49 | #include <sys/device.h> |
| @@ -441,27 +441,29 @@ _bus_dmamap_load(bus_dma_tag_t t, bus_dm | | | @@ -441,27 +441,29 @@ _bus_dmamap_load(bus_dma_tag_t t, bus_dm |
441 | map->_dm_flags &= ~_BUS_DMAMAP_IS_BOUNCING; | | 441 | map->_dm_flags &= ~_BUS_DMAMAP_IS_BOUNCING; |
442 | } | | 442 | } |
443 | } else | | 443 | } else |
444 | #endif | | 444 | #endif |
445 | STAT_INCR(unloads); | | 445 | STAT_INCR(unloads); |
446 | } | | 446 | } |
447 | | | 447 | |
448 | /* | | 448 | /* |
449 | * Make sure that on error condition we return "no valid mappings". | | 449 | * Make sure that on error condition we return "no valid mappings". |
450 | */ | | 450 | */ |
451 | map->dm_mapsize = 0; | | 451 | map->dm_mapsize = 0; |
452 | map->dm_nsegs = 0; | | 452 | map->dm_nsegs = 0; |
453 | map->_dm_buftype = _BUS_DMA_BUFTYPE_INVALID; | | 453 | map->_dm_buftype = _BUS_DMA_BUFTYPE_INVALID; |
454 | KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); | | 454 | KASSERTMSG(map->dm_maxsegsz <= map->_dm_maxmaxsegsz, |
| | | 455 | "dm_maxsegsz %lu _dm_maxmaxsegsz %lu", |
| | | 456 | map->dm_maxsegsz, map->_dm_maxmaxsegsz); |
455 | | | 457 | |
456 | if (buflen > map->_dm_size) | | 458 | if (buflen > map->_dm_size) |
457 | return (EINVAL); | | 459 | return (EINVAL); |
458 | | | 460 | |
459 | if (p != NULL) { | | 461 | if (p != NULL) { |
460 | vm = p->p_vmspace; | | 462 | vm = p->p_vmspace; |
461 | } else { | | 463 | } else { |
462 | vm = vmspace_kernel(); | | 464 | vm = vmspace_kernel(); |
463 | } | | 465 | } |
464 | | | 466 | |
465 | /* _bus_dmamap_load_buffer() clears this if we're not... */ | | 467 | /* _bus_dmamap_load_buffer() clears this if we're not... */ |
466 | map->_dm_flags |= _BUS_DMAMAP_COHERENT; | | 468 | map->_dm_flags |= _BUS_DMAMAP_COHERENT; |
467 | | | 469 | |
| @@ -508,27 +510,29 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, b | | | @@ -508,27 +510,29 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, b |
508 | map->_dm_flags &= ~_BUS_DMAMAP_IS_BOUNCING; | | 510 | map->_dm_flags &= ~_BUS_DMAMAP_IS_BOUNCING; |
509 | } | | 511 | } |
510 | } else | | 512 | } else |
511 | #endif | | 513 | #endif |
512 | STAT_INCR(unloads); | | 514 | STAT_INCR(unloads); |
513 | } | | 515 | } |
514 | | | 516 | |
515 | /* | | 517 | /* |
516 | * Make sure that on error condition we return "no valid mappings." | | 518 | * Make sure that on error condition we return "no valid mappings." |
517 | */ | | 519 | */ |
518 | map->dm_mapsize = 0; | | 520 | map->dm_mapsize = 0; |
519 | map->dm_nsegs = 0; | | 521 | map->dm_nsegs = 0; |
520 | map->_dm_buftype = _BUS_DMA_BUFTYPE_INVALID; | | 522 | map->_dm_buftype = _BUS_DMA_BUFTYPE_INVALID; |
521 | KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); | | 523 | KASSERTMSG(map->dm_maxsegsz <= map->_dm_maxmaxsegsz, |
| | | 524 | "dm_maxsegsz %lu _dm_maxmaxsegsz %lu", |
| | | 525 | map->dm_maxsegsz, map->_dm_maxmaxsegsz); |
522 | | | 526 | |
523 | #ifdef DIAGNOSTIC | | 527 | #ifdef DIAGNOSTIC |
524 | if ((m0->m_flags & M_PKTHDR) == 0) | | 528 | if ((m0->m_flags & M_PKTHDR) == 0) |
525 | panic("_bus_dmamap_load_mbuf: no packet header"); | | 529 | panic("_bus_dmamap_load_mbuf: no packet header"); |
526 | #endif /* DIAGNOSTIC */ | | 530 | #endif /* DIAGNOSTIC */ |
527 | | | 531 | |
528 | if (m0->m_pkthdr.len > map->_dm_size) | | 532 | if (m0->m_pkthdr.len > map->_dm_size) |
529 | return (EINVAL); | | 533 | return (EINVAL); |
530 | | | 534 | |
531 | /* _bus_dmamap_load_paddr() clears this if we're not... */ | | 535 | /* _bus_dmamap_load_paddr() clears this if we're not... */ |
532 | map->_dm_flags |= _BUS_DMAMAP_COHERENT; | | 536 | map->_dm_flags |= _BUS_DMAMAP_COHERENT; |
533 | | | 537 | |
534 | error = 0; | | 538 | error = 0; |
| @@ -630,27 +634,29 @@ int | | | @@ -630,27 +634,29 @@ int |
630 | _bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, | | 634 | _bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, |
631 | int flags) | | 635 | int flags) |
632 | { | | 636 | { |
633 | int i, error; | | 637 | int i, error; |
634 | bus_size_t minlen, resid; | | 638 | bus_size_t minlen, resid; |
635 | struct iovec *iov; | | 639 | struct iovec *iov; |
636 | void *addr; | | 640 | void *addr; |
637 | | | 641 | |
638 | /* | | 642 | /* |
639 | * Make sure that on error condition we return "no valid mappings." | | 643 | * Make sure that on error condition we return "no valid mappings." |
640 | */ | | 644 | */ |
641 | map->dm_mapsize = 0; | | 645 | map->dm_mapsize = 0; |
642 | map->dm_nsegs = 0; | | 646 | map->dm_nsegs = 0; |
643 | KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); | | 647 | KASSERTMSG(map->dm_maxsegsz <= map->_dm_maxmaxsegsz, |
| | | 648 | "dm_maxsegsz %lu _dm_maxmaxsegsz %lu", |
| | | 649 | map->dm_maxsegsz, map->_dm_maxmaxsegsz); |
644 | | | 650 | |
645 | resid = uio->uio_resid; | | 651 | resid = uio->uio_resid; |
646 | iov = uio->uio_iov; | | 652 | iov = uio->uio_iov; |
647 | | | 653 | |
648 | /* _bus_dmamap_load_buffer() clears this if we're not... */ | | 654 | /* _bus_dmamap_load_buffer() clears this if we're not... */ |
649 | map->_dm_flags |= _BUS_DMAMAP_COHERENT; | | 655 | map->_dm_flags |= _BUS_DMAMAP_COHERENT; |
650 | | | 656 | |
651 | error = 0; | | 657 | error = 0; |
652 | for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { | | 658 | for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { |
653 | /* | | 659 | /* |
654 | * Now at the first iovec to load. Load each iovec | | 660 | * Now at the first iovec to load. Load each iovec |
655 | * until we have exhausted the residual count. | | 661 | * until we have exhausted the residual count. |
656 | */ | | 662 | */ |
| @@ -947,41 +953,42 @@ _bus_dmamap_sync(bus_dma_tag_t t, bus_dm | | | @@ -947,41 +953,42 @@ _bus_dmamap_sync(bus_dma_tag_t t, bus_dm |
947 | * here in case a write-back is required by the back-end. | | 953 | * here in case a write-back is required by the back-end. |
948 | * | | 954 | * |
949 | * PREWRITE -- Write-back the D-cache. Note that if | | 955 | * PREWRITE -- Write-back the D-cache. Note that if |
950 | * we are doing a PREREAD|PREWRITE, we can collapse | | 956 | * we are doing a PREREAD|PREWRITE, we can collapse |
951 | * the whole thing into a single Wb-Inv. | | 957 | * the whole thing into a single Wb-Inv. |
952 | * | | 958 | * |
953 | * POSTREAD -- Re-invalidate the D-cache in case speculative | | 959 | * POSTREAD -- Re-invalidate the D-cache in case speculative |
954 | * memory accesses caused cachelines to become valid with now | | 960 | * memory accesses caused cachelines to become valid with now |
955 | * invalid data. | | 961 | * invalid data. |
956 | * | | 962 | * |
957 | * POSTWRITE -- Nothing. | | 963 | * POSTWRITE -- Nothing. |
958 | */ | | 964 | */ |
959 | #ifdef _ARM32_NEED_BUS_DMA_BOUNCE | | 965 | #ifdef _ARM32_NEED_BUS_DMA_BOUNCE |
960 | const bool bouncing = (map->_dm_flags & _BUS_DMA_IS_BOUNCING); | | 966 | const bool bouncing = (map->_dm_flags & _BUS_DMAMAP_IS_BOUNCING); |
961 | #else | | 967 | #else |
962 | const bool bouncing = false; | | 968 | const bool bouncing = false; |
963 | #endif | | 969 | #endif |
964 | | | 970 | |
965 | const int pre_ops = ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 971 | const int pre_ops = ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
966 | #ifdef CPU_CORTEX | | 972 | #ifdef CPU_CORTEX |
967 | const int post_ops = ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | | 973 | const int post_ops = ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
968 | #else | | 974 | #else |
969 | const int post_ops = 0; | | 975 | const int post_ops = 0; |
970 | #endif | | 976 | #endif |
971 | if (!bouncing && pre_ops == 0 && post_ops == BUS_DMASYNC_POSTWRITE) { | | 977 | if (!bouncing && pre_ops == 0 && post_ops == BUS_DMASYNC_POSTWRITE) { |
972 | return; | | 978 | return; |
973 | } | | 979 | } |
974 | KASSERT(pre_ops != 0 || (post_ops & BUS_DMASYNC_POSTREAD)); | | 980 | KASSERTMSG(bouncing || pre_ops != 0 || (post_ops & BUS_DMASYNC_POSTREAD), |
| | | 981 | "pre_ops %#x post_ops %#x", pre_ops, post_ops); |
975 | #ifdef _ARM32_NEED_BUS_DMA_BOUNCE | | 982 | #ifdef _ARM32_NEED_BUS_DMA_BOUNCE |
976 | if (bouncing && (ops & BUS_DMASYNC_PREWRITE)) { | | 983 | if (bouncing && (ops & BUS_DMASYNC_PREWRITE)) { |
977 | struct arm32_bus_dma_cookie * const cookie = map->_dm_cookie; | | 984 | struct arm32_bus_dma_cookie * const cookie = map->_dm_cookie; |
978 | STAT_INCR(write_bounces); | | 985 | STAT_INCR(write_bounces); |
979 | char * const dataptr = (char *)cookie->id_bouncebuf + offset; | | 986 | char * const dataptr = (char *)cookie->id_bouncebuf + offset; |
980 | /* | | 987 | /* |
981 | * Copy the caller's buffer to the bounce buffer. | | 988 | * Copy the caller's buffer to the bounce buffer. |
982 | */ | | 989 | */ |
983 | switch (map->_dm_buftype) { | | 990 | switch (map->_dm_buftype) { |
984 | case _BUS_DMA_BUFTYPE_LINEAR: | | 991 | case _BUS_DMA_BUFTYPE_LINEAR: |
985 | memcpy(dataptr, cookie->id_origlinearbuf + offset, len); | | 992 | memcpy(dataptr, cookie->id_origlinearbuf + offset, len); |
986 | break; | | 993 | break; |
987 | case _BUS_DMA_BUFTYPE_MBUF: | | 994 | case _BUS_DMA_BUFTYPE_MBUF: |
| @@ -999,27 +1006,28 @@ _bus_dmamap_sync(bus_dma_tag_t t, bus_dm | | | @@ -999,27 +1006,28 @@ _bus_dmamap_sync(bus_dma_tag_t t, bus_dm |
999 | panic("_bus_dmamap_sync(pre): _BUS_DMA_BUFTYPE_INVALID"); | | 1006 | panic("_bus_dmamap_sync(pre): _BUS_DMA_BUFTYPE_INVALID"); |
1000 | break; | | 1007 | break; |
1001 | | | 1008 | |
1002 | default: | | 1009 | default: |
1003 | panic("_bus_dmamap_sync(pre): map %p: unknown buffer type %d\n", | | 1010 | panic("_bus_dmamap_sync(pre): map %p: unknown buffer type %d\n", |
1004 | map, map->_dm_buftype); | | 1011 | map, map->_dm_buftype); |
1005 | break; | | 1012 | break; |
1006 | #endif /* DIAGNOSTIC */ | | 1013 | #endif /* DIAGNOSTIC */ |
1007 | } | | 1014 | } |
1008 | } | | 1015 | } |
1009 | #endif /* _ARM32_NEED_BUS_DMA_BOUNCE */ | | 1016 | #endif /* _ARM32_NEED_BUS_DMA_BOUNCE */ |
1010 | | | 1017 | |
1011 | /* Skip cache frobbing if mapping was COHERENT. */ | | 1018 | /* Skip cache frobbing if mapping was COHERENT. */ |
1012 | if (!bouncing && (map->_dm_flags & _BUS_DMAMAP_COHERENT)) { | | 1019 | if (!bouncing && pre_ops == 0 |
| | | 1020 | && (map->_dm_flags & _BUS_DMAMAP_COHERENT)) { |
1013 | /* Drain the write buffer. */ | | 1021 | /* Drain the write buffer. */ |
1014 | cpu_drain_writebuf(); | | 1022 | cpu_drain_writebuf(); |
1015 | return; | | 1023 | return; |
1016 | } | | 1024 | } |
1017 | | | 1025 | |
1018 | #ifdef _ARM32_NEED_BUS_DMA_BOUNCE | | 1026 | #ifdef _ARM32_NEED_BUS_DMA_BOUNCE |
1019 | if (bouncing && ((map->_dm_flags & _BUS_DMAMAP_COHERENT) || pre_ops == 0)) { | | 1027 | if (bouncing && ((map->_dm_flags & _BUS_DMAMAP_COHERENT) || pre_ops == 0)) { |
1020 | goto bounce_it; | | 1028 | goto bounce_it; |
1021 | } | | 1029 | } |
1022 | #endif /* _ARM32_NEED_BUS_DMA_BOUNCE */ | | 1030 | #endif /* _ARM32_NEED_BUS_DMA_BOUNCE */ |
1023 | | | 1031 | |
1024 | /* | | 1032 | /* |
1025 | * If the mapping belongs to a non-kernel vmspace, and the | | 1033 | * If the mapping belongs to a non-kernel vmspace, and the |