busdma_machdep-v6.c (286969) | busdma_machdep-v6.c (289759) |
---|---|
1/*- 2 * Copyright (c) 2012-2014 Ian Lepore 3 * Copyright (c) 2010 Mark Tinguely 4 * Copyright (c) 2004 Olivier Houchard 5 * Copyright (c) 2002 Peter Grehan 6 * Copyright (c) 1997, 1998 Justin T. Gibbs. 7 * All rights reserved. 8 * --- 17 unchanged lines hidden (view full) --- 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * From i386/busdma_machdep.c 191438 2009-04-23 20:24:19Z jhb 31 */ 32 33#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2012-2014 Ian Lepore 3 * Copyright (c) 2010 Mark Tinguely 4 * Copyright (c) 2004 Olivier Houchard 5 * Copyright (c) 2002 Peter Grehan 6 * Copyright (c) 1997, 1998 Justin T. Gibbs. 7 * All rights reserved. 8 * --- 17 unchanged lines hidden (view full) --- 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * From i386/busdma_machdep.c 191438 2009-04-23 20:24:19Z jhb 31 */ 32 33#include <sys/cdefs.h> |
34__FBSDID("$FreeBSD: head/sys/arm/arm/busdma_machdep-v6.c 286969 2015-08-20 19:39:15Z ian $"); | 34__FBSDID("$FreeBSD: head/sys/arm/arm/busdma_machdep-v6.c 289759 2015-10-22 16:38:01Z jah $"); |
35 36#define _ARM32_BUS_DMA_PRIVATE 37#include <sys/param.h> 38#include <sys/kdb.h> 39#include <ddb/ddb.h> 40#include <ddb/db_output.h> 41#include <sys/systm.h> 42#include <sys/malloc.h> --- 13 unchanged lines hidden (view full) --- 56#include <vm/vm.h> 57#include <vm/vm_page.h> 58#include <vm/vm_map.h> 59#include <vm/vm_extern.h> 60#include <vm/vm_kern.h> 61 62#include <machine/atomic.h> 63#include <machine/bus.h> | 35 36#define _ARM32_BUS_DMA_PRIVATE 37#include <sys/param.h> 38#include <sys/kdb.h> 39#include <ddb/ddb.h> 40#include <ddb/db_output.h> 41#include <sys/systm.h> 42#include <sys/malloc.h> --- 13 unchanged lines hidden (view full) --- 56#include <vm/vm.h> 57#include <vm/vm_page.h> 58#include <vm/vm_map.h> 59#include <vm/vm_extern.h> 60#include <vm/vm_kern.h> 61 62#include <machine/atomic.h> 63#include <machine/bus.h> |
64#include <machine/cpufunc.h> | 64#include <machine/cpu-v6.h> |
65#include <machine/md_var.h> 66 67#define MAX_BPAGES 64 68#define MAX_DMA_SEGMENTS 4096 69#define BUS_DMA_EXCL_BOUNCE BUS_DMA_BUS2 70#define BUS_DMA_ALIGN_BOUNCE BUS_DMA_BUS3 71#define BUS_DMA_COULD_BOUNCE (BUS_DMA_EXCL_BOUNCE | BUS_DMA_ALIGN_BOUNCE) 72#define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 --- 26 unchanged lines hidden (view full) --- 99 struct arm32_dma_range *ranges; 100 int _nranges; 101}; 102 103struct bounce_page { 104 vm_offset_t vaddr; /* kva of bounce buffer */ 105 bus_addr_t busaddr; /* Physical address */ 106 vm_offset_t datavaddr; /* kva of client data */ | 65#include <machine/md_var.h> 66 67#define MAX_BPAGES 64 68#define MAX_DMA_SEGMENTS 4096 69#define BUS_DMA_EXCL_BOUNCE BUS_DMA_BUS2 70#define BUS_DMA_ALIGN_BOUNCE BUS_DMA_BUS3 71#define BUS_DMA_COULD_BOUNCE (BUS_DMA_EXCL_BOUNCE | BUS_DMA_ALIGN_BOUNCE) 72#define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 --- 26 unchanged lines hidden (view full) --- 99 struct arm32_dma_range *ranges; 100 int _nranges; 101}; 102 103struct bounce_page { 104 vm_offset_t vaddr; /* kva of bounce buffer */ 105 bus_addr_t busaddr; /* Physical address */ 106 vm_offset_t datavaddr; /* kva of client data */ |
107 bus_addr_t dataaddr; /* client physical address */ | 107 vm_page_t datapage; /* physical page of client data */ 108 vm_offset_t dataoffs; /* page offset of client data */ |
108 bus_size_t datacount; /* client data count */ 109 STAILQ_ENTRY(bounce_page) links; 110}; 111 112struct sync_list { 113 vm_offset_t vaddr; /* kva of client data */ | 109 bus_size_t datacount; /* client data count */ 110 STAILQ_ENTRY(bounce_page) links; 111}; 112 113struct sync_list { 114 vm_offset_t vaddr; /* kva of client data */ |
114 bus_addr_t busaddr; /* client physical address */ | 115 vm_page_t pages; /* starting page of client data */ 116 vm_offset_t dataoffs; /* page offset of client data */ |
115 bus_size_t datacount; /* client data count */ 116}; 117 118int busdma_swi_pending; 119 120struct bounce_zone { 121 STAILQ_ENTRY(bounce_zone) links; 122 STAILQ_HEAD(bp_list, bounce_page) bounce_page_list; --- 53 unchanged lines hidden (view full) --- 176 "Total bounce pages"); 177 178struct bus_dmamap { 179 struct bp_list bpages; 180 int pagesneeded; 181 int pagesreserved; 182 bus_dma_tag_t dmat; 183 struct memdesc mem; | 117 bus_size_t datacount; /* client data count */ 118}; 119 120int busdma_swi_pending; 121 122struct bounce_zone { 123 STAILQ_ENTRY(bounce_zone) links; 124 STAILQ_HEAD(bp_list, bounce_page) bounce_page_list; --- 53 unchanged lines hidden (view full) --- 178 "Total bounce pages"); 179 180struct bus_dmamap { 181 struct bp_list bpages; 182 int pagesneeded; 183 int pagesreserved; 184 bus_dma_tag_t dmat; 185 struct memdesc mem; |
184 pmap_t pmap; | |
185 bus_dmamap_callback_t *callback; 186 void *callback_arg; 187 int flags; 188#define DMAMAP_COHERENT (1 << 0) 189#define DMAMAP_DMAMEM_ALLOC (1 << 1) 190#define DMAMAP_MBUF (1 << 2) 191 STAILQ_ENTRY(bus_dmamap) links; 192 bus_dma_segment_t *segments; --- 8 unchanged lines hidden (view full) --- 201static int alloc_bounce_zone(bus_dma_tag_t dmat); 202static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); 203static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 204 int commit); 205static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, 206 vm_offset_t vaddr, bus_addr_t addr, 207 bus_size_t size); 208static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); | 186 bus_dmamap_callback_t *callback; 187 void *callback_arg; 188 int flags; 189#define DMAMAP_COHERENT (1 << 0) 190#define DMAMAP_DMAMEM_ALLOC (1 << 1) 191#define DMAMAP_MBUF (1 << 2) 192 STAILQ_ENTRY(bus_dmamap) links; 193 bus_dma_segment_t *segments; --- 8 unchanged lines hidden (view full) --- 202static int alloc_bounce_zone(bus_dma_tag_t dmat); 203static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); 204static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 205 int commit); 206static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, 207 vm_offset_t vaddr, bus_addr_t addr, 208 bus_size_t size); 209static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); |
209static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 210 void *buf, bus_size_t buflen, int flags); | 210static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, pmap_t pmap, 211 bus_dmamap_t map, void *buf, bus_size_t buflen, int flags); |
211static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 212 vm_paddr_t buf, bus_size_t buflen, int flags); 213static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 214 int flags); | 212static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 213 vm_paddr_t buf, bus_size_t buflen, int flags); 214static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 215 int flags); |
216static void dma_preread_safe(vm_offset_t va, vm_paddr_t pa, vm_size_t size); 217static void dma_dcache_sync(struct sync_list *sl, bus_dmasync_op_t op); |
|
215 216static busdma_bufalloc_t coherent_allocator; /* Cache of coherent buffers */ 217static busdma_bufalloc_t standard_allocator; /* Cache of standard buffers */ 218static void 219busdma_init(void *dummy) 220{ 221 int uma_flags; 222 --- 668 unchanged lines hidden (view full) --- 891 /* 892 * Count the number of bounce pages 893 * needed in order to complete this transfer 894 */ 895 curaddr = buf; 896 while (buflen != 0) { 897 sgsize = MIN(buflen, dmat->maxsegsz); 898 if (must_bounce(dmat, map, curaddr, sgsize) != 0) { | 218 219static busdma_bufalloc_t coherent_allocator; /* Cache of coherent buffers */ 220static busdma_bufalloc_t standard_allocator; /* Cache of standard buffers */ 221static void 222busdma_init(void *dummy) 223{ 224 int uma_flags; 225 --- 668 unchanged lines hidden (view full) --- 894 /* 895 * Count the number of bounce pages 896 * needed in order to complete this transfer 897 */ 898 curaddr = buf; 899 while (buflen != 0) { 900 sgsize = MIN(buflen, dmat->maxsegsz); 901 if (must_bounce(dmat, map, curaddr, sgsize) != 0) { |
899 sgsize = MIN(sgsize, PAGE_SIZE); | 902 sgsize = MIN(sgsize, 903 PAGE_SIZE - (curaddr & PAGE_MASK)); |
900 map->pagesneeded++; 901 } 902 curaddr += sgsize; 903 buflen -= sgsize; 904 } 905 CTR1(KTR_BUSDMA, "pagesneeded= %d", map->pagesneeded); 906 } 907} 908 909static void | 904 map->pagesneeded++; 905 } 906 curaddr += sgsize; 907 buflen -= sgsize; 908 } 909 CTR1(KTR_BUSDMA, "pagesneeded= %d", map->pagesneeded); 910 } 911} 912 913static void |
910_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, | 914_bus_dmamap_count_pages(bus_dma_tag_t dmat, pmap_t pmap, bus_dmamap_t map, |
911 void *buf, bus_size_t buflen, int flags) 912{ 913 vm_offset_t vaddr; 914 vm_offset_t vendaddr; 915 bus_addr_t paddr; 916 917 if (map->pagesneeded == 0) { 918 CTR5(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d" 919 " map= %p, pagesneeded= %d", 920 dmat->lowaddr, dmat->boundary, dmat->alignment, 921 map, map->pagesneeded); 922 /* 923 * Count the number of bounce pages 924 * needed in order to complete this transfer 925 */ 926 vaddr = (vm_offset_t)buf; 927 vendaddr = (vm_offset_t)buf + buflen; 928 929 while (vaddr < vendaddr) { | 915 void *buf, bus_size_t buflen, int flags) 916{ 917 vm_offset_t vaddr; 918 vm_offset_t vendaddr; 919 bus_addr_t paddr; 920 921 if (map->pagesneeded == 0) { 922 CTR5(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d" 923 " map= %p, pagesneeded= %d", 924 dmat->lowaddr, dmat->boundary, dmat->alignment, 925 map, map->pagesneeded); 926 /* 927 * Count the number of bounce pages 928 * needed in order to complete this transfer 929 */ 930 vaddr = (vm_offset_t)buf; 931 vendaddr = (vm_offset_t)buf + buflen; 932 933 while (vaddr < vendaddr) { |
930 if (__predict_true(map->pmap == kernel_pmap)) | 934 if (__predict_true(pmap == kernel_pmap)) |
931 paddr = pmap_kextract(vaddr); 932 else | 935 paddr = pmap_kextract(vaddr); 936 else |
933 paddr = pmap_extract(map->pmap, vaddr); | 937 paddr = pmap_extract(pmap, vaddr); |
934 if (must_bounce(dmat, map, paddr, 935 min(vendaddr - vaddr, (PAGE_SIZE - ((vm_offset_t)vaddr & 936 PAGE_MASK)))) != 0) { 937 map->pagesneeded++; 938 } 939 vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK)); 940 941 } --- 96 unchanged lines hidden (view full) --- 1038_bus_dmamap_load_phys(bus_dma_tag_t dmat, 1039 bus_dmamap_t map, 1040 vm_paddr_t buf, bus_size_t buflen, 1041 int flags, 1042 bus_dma_segment_t *segs, 1043 int *segp) 1044{ 1045 bus_addr_t curaddr; | 938 if (must_bounce(dmat, map, paddr, 939 min(vendaddr - vaddr, (PAGE_SIZE - ((vm_offset_t)vaddr & 940 PAGE_MASK)))) != 0) { 941 map->pagesneeded++; 942 } 943 vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK)); 944 945 } --- 96 unchanged lines hidden (view full) --- 1042_bus_dmamap_load_phys(bus_dma_tag_t dmat, 1043 bus_dmamap_t map, 1044 vm_paddr_t buf, bus_size_t buflen, 1045 int flags, 1046 bus_dma_segment_t *segs, 1047 int *segp) 1048{ 1049 bus_addr_t curaddr; |
1050 bus_addr_t sl_end = 0; |
|
1046 bus_size_t sgsize; | 1051 bus_size_t sgsize; |
1052 struct sync_list *sl; |
|
1047 int error; 1048 1049 if (segs == NULL) 1050 segs = map->segments; 1051 1052 counter_u64_add(maploads_total, 1); 1053 counter_u64_add(maploads_physmem, 1); 1054 | 1053 int error; 1054 1055 if (segs == NULL) 1056 segs = map->segments; 1057 1058 counter_u64_add(maploads_total, 1); 1059 counter_u64_add(maploads_physmem, 1); 1060 |
1055 if (might_bounce(dmat, map, buflen, buflen)) { | 1061 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { |
1056 _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); 1057 if (map->pagesneeded != 0) { 1058 counter_u64_add(maploads_bounced, 1); 1059 error = _bus_dmamap_reserve_pages(dmat, map, flags); 1060 if (error) 1061 return (error); 1062 } 1063 } 1064 | 1062 _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); 1063 if (map->pagesneeded != 0) { 1064 counter_u64_add(maploads_bounced, 1); 1065 error = _bus_dmamap_reserve_pages(dmat, map, flags); 1066 if (error) 1067 return (error); 1068 } 1069 } 1070 |
1071 sl = map->slist + map->sync_count - 1; 1072 |
|
1065 while (buflen > 0) { 1066 curaddr = buf; 1067 sgsize = MIN(buflen, dmat->maxsegsz); 1068 if (map->pagesneeded != 0 && must_bounce(dmat, map, curaddr, 1069 sgsize)) { | 1073 while (buflen > 0) { 1074 curaddr = buf; 1075 sgsize = MIN(buflen, dmat->maxsegsz); 1076 if (map->pagesneeded != 0 && must_bounce(dmat, map, curaddr, 1077 sgsize)) { |
1070 sgsize = MIN(sgsize, PAGE_SIZE); | 1078 sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); |
1071 curaddr = add_bounce_page(dmat, map, 0, curaddr, 1072 sgsize); | 1079 curaddr = add_bounce_page(dmat, map, 0, curaddr, 1080 sgsize); |
1081 } else { 1082 if (map->sync_count > 0) 1083 sl_end = VM_PAGE_TO_PHYS(sl->pages) + 1084 sl->dataoffs + sl->datacount; 1085 1086 if (map->sync_count == 0 || curaddr != sl_end) { 1087 if (++map->sync_count > dmat->nsegments) 1088 break; 1089 sl++; 1090 sl->vaddr = 0; 1091 sl->datacount = sgsize; 1092 /* 1093 * PHYS_TO_VM_PAGE() will truncate 1094 * unaligned addresses. 1095 */ 1096 sl->pages = PHYS_TO_VM_PAGE(curaddr); 1097 sl->dataoffs = curaddr & PAGE_MASK; 1098 } else 1099 sl->datacount += sgsize; |
|
1073 } 1074 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 1075 segp); 1076 if (sgsize == 0) 1077 break; 1078 buf += sgsize; 1079 buflen -= sgsize; 1080 } --- 28 unchanged lines hidden (view full) --- 1109 void *buf, bus_size_t buflen, 1110 pmap_t pmap, 1111 int flags, 1112 bus_dma_segment_t *segs, 1113 int *segp) 1114{ 1115 bus_size_t sgsize; 1116 bus_addr_t curaddr; | 1100 } 1101 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 1102 segp); 1103 if (sgsize == 0) 1104 break; 1105 buf += sgsize; 1106 buflen -= sgsize; 1107 } --- 28 unchanged lines hidden (view full) --- 1136 void *buf, bus_size_t buflen, 1137 pmap_t pmap, 1138 int flags, 1139 bus_dma_segment_t *segs, 1140 int *segp) 1141{ 1142 bus_size_t sgsize; 1143 bus_addr_t curaddr; |
1117 vm_offset_t vaddr; | 1144 bus_addr_t sl_pend = 0; 1145 vm_offset_t kvaddr, vaddr, sl_vend = 0; |
1118 struct sync_list *sl; 1119 int error; 1120 1121 counter_u64_add(maploads_total, 1); 1122 if (map->flags & DMAMAP_COHERENT) 1123 counter_u64_add(maploads_coherent, 1); 1124 if (map->flags & DMAMAP_DMAMEM_ALLOC) 1125 counter_u64_add(maploads_dmamem, 1); 1126 1127 if (segs == NULL) 1128 segs = map->segments; 1129 1130 if (flags & BUS_DMA_LOAD_MBUF) { 1131 counter_u64_add(maploads_mbuf, 1); 1132 map->flags |= DMAMAP_MBUF; 1133 } 1134 | 1146 struct sync_list *sl; 1147 int error; 1148 1149 counter_u64_add(maploads_total, 1); 1150 if (map->flags & DMAMAP_COHERENT) 1151 counter_u64_add(maploads_coherent, 1); 1152 if (map->flags & DMAMAP_DMAMEM_ALLOC) 1153 counter_u64_add(maploads_dmamem, 1); 1154 1155 if (segs == NULL) 1156 segs = map->segments; 1157 1158 if (flags & BUS_DMA_LOAD_MBUF) { 1159 counter_u64_add(maploads_mbuf, 1); 1160 map->flags |= DMAMAP_MBUF; 1161 } 1162 |
1135 map->pmap = pmap; 1136 | |
1137 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { | 1163 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { |
1138 _bus_dmamap_count_pages(dmat, map, buf, buflen, flags); | 1164 _bus_dmamap_count_pages(dmat, pmap, map, buf, buflen, flags); |
1139 if (map->pagesneeded != 0) { 1140 counter_u64_add(maploads_bounced, 1); 1141 error = _bus_dmamap_reserve_pages(dmat, map, flags); 1142 if (error) 1143 return (error); 1144 } 1145 } 1146 | 1165 if (map->pagesneeded != 0) { 1166 counter_u64_add(maploads_bounced, 1); 1167 error = _bus_dmamap_reserve_pages(dmat, map, flags); 1168 if (error) 1169 return (error); 1170 } 1171 } 1172 |
1147 sl = NULL; | 1173 sl = map->slist + map->sync_count - 1; |
1148 vaddr = (vm_offset_t)buf; 1149 1150 while (buflen > 0) { 1151 /* 1152 * Get the physical address for this segment. 1153 */ | 1174 vaddr = (vm_offset_t)buf; 1175 1176 while (buflen > 0) { 1177 /* 1178 * Get the physical address for this segment. 1179 */ |
1154 if (__predict_true(map->pmap == kernel_pmap)) | 1180 if (__predict_true(pmap == kernel_pmap)) { |
1155 curaddr = pmap_kextract(vaddr); | 1181 curaddr = pmap_kextract(vaddr); |
1156 else 1157 curaddr = pmap_extract(map->pmap, vaddr); | 1182 kvaddr = vaddr; 1183 } else { 1184 curaddr = pmap_extract(pmap, vaddr); 1185 kvaddr = 0; 1186 } |
1158 1159 /* 1160 * Compute the segment size, and adjust counts. 1161 */ | 1187 1188 /* 1189 * Compute the segment size, and adjust counts. 1190 */ |
1162 sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); | 1191 sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); |
1163 if (sgsize > dmat->maxsegsz) 1164 sgsize = dmat->maxsegsz; 1165 if (buflen < sgsize) 1166 sgsize = buflen; 1167 1168 if (map->pagesneeded != 0 && must_bounce(dmat, map, curaddr, 1169 sgsize)) { | 1192 if (sgsize > dmat->maxsegsz) 1193 sgsize = dmat->maxsegsz; 1194 if (buflen < sgsize) 1195 sgsize = buflen; 1196 1197 if (map->pagesneeded != 0 && must_bounce(dmat, map, curaddr, 1198 sgsize)) { |
1170 curaddr = add_bounce_page(dmat, map, vaddr, curaddr, | 1199 curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, |
1171 sgsize); 1172 } else { | 1200 sgsize); 1201 } else { |
1173 sl = &map->slist[map->sync_count - 1]; | 1202 if (map->sync_count > 0) { 1203 sl_pend = VM_PAGE_TO_PHYS(sl->pages) + 1204 sl->dataoffs + sl->datacount; 1205 sl_vend = sl->vaddr + sl->datacount; 1206 } 1207 |
1174 if (map->sync_count == 0 || | 1208 if (map->sync_count == 0 || |
1175#ifdef ARM_L2_PIPT 1176 curaddr != sl->busaddr + sl->datacount || 1177#endif 1178 vaddr != sl->vaddr + sl->datacount) { | 1209 (kvaddr != 0 && kvaddr != sl_vend) || 1210 (curaddr != sl_pend)) { 1211 |
1179 if (++map->sync_count > dmat->nsegments) 1180 goto cleanup; 1181 sl++; | 1212 if (++map->sync_count > dmat->nsegments) 1213 goto cleanup; 1214 sl++; |
1182 sl->vaddr = vaddr; | 1215 sl->vaddr = kvaddr; |
1183 sl->datacount = sgsize; | 1216 sl->datacount = sgsize; |
1184 sl->busaddr = curaddr; | 1217 /* 1218 * PHYS_TO_VM_PAGE() will truncate 1219 * unaligned addresses. 1220 */ 1221 sl->pages = PHYS_TO_VM_PAGE(curaddr); 1222 sl->dataoffs = curaddr & PAGE_MASK; |
1185 } else 1186 sl->datacount += sgsize; 1187 } 1188 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 1189 segp); 1190 if (sgsize == 0) 1191 break; 1192 vaddr += sgsize; --- 54 unchanged lines hidden (view full) --- 1247 bz->reserved_bpages -= map->pagesreserved; 1248 map->pagesreserved = 0; 1249 map->pagesneeded = 0; 1250 } 1251 map->sync_count = 0; 1252 map->flags &= ~DMAMAP_MBUF; 1253} 1254 | 1223 } else 1224 sl->datacount += sgsize; 1225 } 1226 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 1227 segp); 1228 if (sgsize == 0) 1229 break; 1230 vaddr += sgsize; --- 54 unchanged lines hidden (view full) --- 1285 bz->reserved_bpages -= map->pagesreserved; 1286 map->pagesreserved = 0; 1287 map->pagesneeded = 0; 1288 } 1289 map->sync_count = 0; 1290 map->flags &= ~DMAMAP_MBUF; 1291} 1292 |
1255#ifdef notyetbounceuser 1256/* If busdma uses user pages, then the interrupt handler could 1257 * be use the kernel vm mapping. Both bounce pages and sync list 1258 * do not cross page boundaries. 1259 * Below is a rough sequence that a person would do to fix the 1260 * user page reference in the kernel vmspace. This would be 1261 * done in the dma post routine. 1262 */ 1263void 1264_bus_dmamap_fix_user(vm_offset_t buf, bus_size_t len, 1265 pmap_t pmap, int op) | 1293static void 1294dma_preread_safe(vm_offset_t va, vm_paddr_t pa, vm_size_t size) |
1266{ | 1295{ |
1267 bus_size_t sgsize; 1268 bus_addr_t curaddr; 1269 vm_offset_t va; 1270 | |
1271 /* | 1296 /* |
1272 * each synclist entry is contained within a single page. 1273 * this would be needed if BUS_DMASYNC_POSTxxxx was implemented | 1297 * Write back any partial cachelines immediately before and 1298 * after the DMA region. We don't need to round the address 1299 * down to the nearest cacheline or specify the exact size, 1300 * as dcache_wb_poc() will do the rounding for us and works 1301 * at cacheline granularity. |
1274 */ | 1302 */ |
1275 curaddr = pmap_extract(pmap, buf); 1276 va = pmap_dma_map(curaddr); 1277 switch (op) { 1278 case SYNC_USER_INV: 1279 cpu_dcache_wb_range(va, sgsize); 1280 break; | 1303 if (va & cpuinfo.dcache_line_mask) 1304 dcache_wb_poc(va, pa, 1); 1305 if ((va + size) & cpuinfo.dcache_line_mask) 1306 dcache_wb_poc(va + size, pa + size, 1); |
1281 | 1307 |
1282 case SYNC_USER_COPYTO: 1283 bcopy((void *)va, (void *)bounce, sgsize); 1284 break; | 1308 dcache_dma_preread(va, pa, size); 1309} |
1285 | 1310 |
1286 case SYNC_USER_COPYFROM: 1287 bcopy((void *) bounce, (void *)va, sgsize); 1288 break; | 1311static void 1312dma_dcache_sync(struct sync_list *sl, bus_dmasync_op_t op) 1313{ 1314 uint32_t len, offset; 1315 vm_page_t m; 1316 vm_paddr_t pa; 1317 vm_offset_t va, tempva; 1318 bus_size_t size; |
1289 | 1319 |
1290 default: 1291 break; 1292 } | 1320 offset = sl->dataoffs; 1321 m = sl->pages; 1322 size = sl->datacount; 1323 pa = VM_PAGE_TO_PHYS(m) | offset; |
1293 | 1324 |
1294 pmap_dma_unmap(va); 1295} 1296#endif | 1325 for ( ; size != 0; size -= len, pa += len, offset = 0, ++m) { 1326 tempva = 0; 1327 if (sl->vaddr == 0) { 1328 len = min(PAGE_SIZE - offset, size); 1329 tempva = pmap_quick_enter_page(m); 1330 va = tempva | offset; 1331 } else { 1332 len = sl->datacount; 1333 va = sl->vaddr; 1334 } 1335 KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset), 1336 ("unexpected vm_page_t phys: 0x%08x != 0x%08x", 1337 VM_PAGE_TO_PHYS(m) | offset, pa)); |
1297 | 1338 |
1298#ifdef ARM_L2_PIPT 1299#define l2cache_wb_range(va, pa, size) cpu_l2cache_wb_range(pa, size) 1300#define l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range(pa, size) 1301#define l2cache_inv_range(va, pa, size) cpu_l2cache_inv_range(pa, size) 1302#else 1303#define l2cache_wb_range(va, pa, size) cpu_l2cache_wb_range(va, size) 1304#define l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range(va, size) 1305#define l2cache_inv_range(va, pa, size) cpu_l2cache_inv_range(va, size) 1306#endif | 1339 switch (op) { 1340 case BUS_DMASYNC_PREWRITE: 1341 case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD: 1342 dcache_wb_poc(va, pa, len); 1343 break; 1344 case BUS_DMASYNC_PREREAD: 1345 /* 1346 * An mbuf may start in the middle of a cacheline. There 1347 * will be no cpu writes to the beginning of that line 1348 * (which contains the mbuf header) while dma is in 1349 * progress. Handle that case by doing a writeback of 1350 * just the first cacheline before invalidating the 1351 * overall buffer. Any mbuf in a chain may have this 1352 * misalignment. Buffers which are not mbufs bounce if 1353 * they are not aligned to a cacheline. 1354 */ 1355 dma_preread_safe(va, pa, len); 1356 break; 1357 case BUS_DMASYNC_POSTREAD: 1358 case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: 1359 dcache_inv_poc(va, pa, len); 1360 break; 1361 default: 1362 panic("unsupported combination of sync operations: " 1363 "0x%08x\n", op); 1364 } |
1307 | 1365 |
1366 if (tempva != 0) 1367 pmap_quick_remove_page(tempva); 1368 } 1369} 1370 |
|
1308void 1309_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 1310{ 1311 struct bounce_page *bpage; 1312 struct sync_list *sl, *end; | 1371void 1372_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 1373{ 1374 struct bounce_page *bpage; 1375 struct sync_list *sl, *end; |
1376 vm_offset_t datavaddr, tempvaddr; 1377 1378 if (op == BUS_DMASYNC_POSTWRITE) 1379 return; 1380 |
|
1313 /* 1314 * If the buffer was from user space, it is possible that this is not 1315 * the same vm map, especially on a POST operation. It's not clear that 1316 * dma on userland buffers can work at all right now. To be safe, until 1317 * we're able to test direct userland dma, panic on a map mismatch. 1318 */ 1319 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { | 1381 /* 1382 * If the buffer was from user space, it is possible that this is not 1383 * the same vm map, especially on a POST operation. It's not clear that 1384 * dma on userland buffers can work at all right now. To be safe, until 1385 * we're able to test direct userland dma, panic on a map mismatch. 1386 */ 1387 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { |
1320 if (!pmap_dmap_iscurrent(map->pmap)) 1321 panic("_bus_dmamap_sync: wrong user map for bounce sync."); | |
1322 1323 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 1324 "performing bounce", __func__, dmat, dmat->flags, op); 1325 1326 /* 1327 * For PREWRITE do a writeback. Clean the caches from the 1328 * innermost to the outermost levels. 1329 */ 1330 if (op & BUS_DMASYNC_PREWRITE) { 1331 while (bpage != NULL) { | 1388 1389 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 1390 "performing bounce", __func__, dmat, dmat->flags, op); 1391 1392 /* 1393 * For PREWRITE do a writeback. Clean the caches from the 1394 * innermost to the outermost levels. 1395 */ 1396 if (op & BUS_DMASYNC_PREWRITE) { 1397 while (bpage != NULL) { |
1332 if (bpage->datavaddr != 0) 1333 bcopy((void *)bpage->datavaddr, 1334 (void *)bpage->vaddr, 1335 bpage->datacount); 1336 else 1337 physcopyout(bpage->dataaddr, 1338 (void *)bpage->vaddr, 1339 bpage->datacount); 1340 cpu_dcache_wb_range((vm_offset_t)bpage->vaddr, | 1398 tempvaddr = 0; 1399 datavaddr = bpage->datavaddr; 1400 if (datavaddr == 0) { 1401 tempvaddr = pmap_quick_enter_page( 1402 bpage->datapage); 1403 datavaddr = tempvaddr | bpage->dataoffs; 1404 } 1405 bcopy((void *)datavaddr, (void *)bpage->vaddr, |
1341 bpage->datacount); | 1406 bpage->datacount); |
1342 l2cache_wb_range((vm_offset_t)bpage->vaddr, 1343 (vm_offset_t)bpage->busaddr, | 1407 if (tempvaddr != 0) 1408 pmap_quick_remove_page(tempvaddr); 1409 dcache_wb_poc(bpage->vaddr, bpage->busaddr, |
1344 bpage->datacount); 1345 bpage = STAILQ_NEXT(bpage, links); 1346 } 1347 dmat->bounce_zone->total_bounced++; 1348 } 1349 1350 /* 1351 * Do an invalidate for PREREAD unless a writeback was already --- 4 unchanged lines hidden (view full) --- 1356 * lines and the POSTREAD invalidate handles the rest. The 1357 * invalidate is done from the innermost to outermost level. If 1358 * L2 were done first, a dirty cacheline could be automatically 1359 * evicted from L1 before we invalidated it, re-dirtying the L2. 1360 */ 1361 if ((op & BUS_DMASYNC_PREREAD) && !(op & BUS_DMASYNC_PREWRITE)) { 1362 bpage = STAILQ_FIRST(&map->bpages); 1363 while (bpage != NULL) { | 1410 bpage->datacount); 1411 bpage = STAILQ_NEXT(bpage, links); 1412 } 1413 dmat->bounce_zone->total_bounced++; 1414 } 1415 1416 /* 1417 * Do an invalidate for PREREAD unless a writeback was already --- 4 unchanged lines hidden (view full) --- 1422 * lines and the POSTREAD invalidate handles the rest. The 1423 * invalidate is done from the innermost to outermost level. If 1424 * L2 were done first, a dirty cacheline could be automatically 1425 * evicted from L1 before we invalidated it, re-dirtying the L2. 1426 */ 1427 if ((op & BUS_DMASYNC_PREREAD) && !(op & BUS_DMASYNC_PREWRITE)) { 1428 bpage = STAILQ_FIRST(&map->bpages); 1429 while (bpage != NULL) { |
1364 cpu_dcache_inv_range((vm_offset_t)bpage->vaddr, | 1430 dcache_dma_preread(bpage->vaddr, bpage->busaddr, |
1365 bpage->datacount); | 1431 bpage->datacount); |
1366 l2cache_inv_range((vm_offset_t)bpage->vaddr, 1367 (vm_offset_t)bpage->busaddr, 1368 bpage->datacount); | |
1369 bpage = STAILQ_NEXT(bpage, links); 1370 } 1371 } 1372 1373 /* 1374 * Re-invalidate the caches on a POSTREAD, even though they were 1375 * already invalidated at PREREAD time. Aggressive prefetching 1376 * due to accesses to other data near the dma buffer could have 1377 * brought buffer data into the caches which is now stale. The 1378 * caches are invalidated from the outermost to innermost; the 1379 * prefetches could be happening right now, and if L1 were 1380 * invalidated first, stale L2 data could be prefetched into L1. 1381 */ 1382 if (op & BUS_DMASYNC_POSTREAD) { 1383 while (bpage != NULL) { | 1432 bpage = STAILQ_NEXT(bpage, links); 1433 } 1434 } 1435 1436 /* 1437 * Re-invalidate the caches on a POSTREAD, even though they were 1438 * already invalidated at PREREAD time. Aggressive prefetching 1439 * due to accesses to other data near the dma buffer could have 1440 * brought buffer data into the caches which is now stale. The 1441 * caches are invalidated from the outermost to innermost; the 1442 * prefetches could be happening right now, and if L1 were 1443 * invalidated first, stale L2 data could be prefetched into L1. 1444 */ 1445 if (op & BUS_DMASYNC_POSTREAD) { 1446 while (bpage != NULL) { |
1384 l2cache_inv_range((vm_offset_t)bpage->vaddr, 1385 (vm_offset_t)bpage->busaddr, | 1447 dcache_inv_poc(bpage->vaddr, bpage->busaddr, |
1386 bpage->datacount); | 1448 bpage->datacount); |
1387 cpu_dcache_inv_range((vm_offset_t)bpage->vaddr, | 1449 tempvaddr = 0; 1450 datavaddr = bpage->datavaddr; 1451 if (datavaddr == 0) { 1452 tempvaddr = pmap_quick_enter_page( 1453 bpage->datapage); 1454 datavaddr = tempvaddr | bpage->dataoffs; 1455 } 1456 bcopy((void *)bpage->vaddr, (void *)datavaddr, |
1388 bpage->datacount); | 1457 bpage->datacount); |
1389 if (bpage->datavaddr != 0) 1390 bcopy((void *)bpage->vaddr, 1391 (void *)bpage->datavaddr, 1392 bpage->datacount); 1393 else 1394 physcopyin((void *)bpage->vaddr, 1395 bpage->dataaddr, 1396 bpage->datacount); | 1458 if (tempvaddr != 0) 1459 pmap_quick_remove_page(tempvaddr); |
1397 bpage = STAILQ_NEXT(bpage, links); 1398 } 1399 dmat->bounce_zone->total_bounced++; 1400 } 1401 } 1402 1403 /* 1404 * For COHERENT memory no cache maintenance is necessary, but ensure all --- 14 unchanged lines hidden (view full) --- 1419 /* 1420 * Cache maintenance for normal (non-COHERENT non-bounce) buffers. All 1421 * the comments about the sequences for flushing cache levels in the 1422 * bounce buffer code above apply here as well. In particular, the fact 1423 * that the sequence is inner-to-outer for PREREAD invalidation and 1424 * outer-to-inner for POSTREAD invalidation is not a mistake. 1425 */ 1426 if (map->sync_count != 0) { | 1460 bpage = STAILQ_NEXT(bpage, links); 1461 } 1462 dmat->bounce_zone->total_bounced++; 1463 } 1464 } 1465 1466 /* 1467 * For COHERENT memory no cache maintenance is necessary, but ensure all --- 14 unchanged lines hidden (view full) --- 1482 /* 1483 * Cache maintenance for normal (non-COHERENT non-bounce) buffers. All 1484 * the comments about the sequences for flushing cache levels in the 1485 * bounce buffer code above apply here as well. In particular, the fact 1486 * that the sequence is inner-to-outer for PREREAD invalidation and 1487 * outer-to-inner for POSTREAD invalidation is not a mistake. 1488 */ 1489 if (map->sync_count != 0) { |
1427 if (!pmap_dmap_iscurrent(map->pmap)) 1428 panic("_bus_dmamap_sync: wrong user map for sync."); 1429 | |
1430 sl = &map->slist[0]; 1431 end = &map->slist[map->sync_count]; 1432 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 1433 "performing sync", __func__, dmat, dmat->flags, op); 1434 | 1490 sl = &map->slist[0]; 1491 end = &map->slist[map->sync_count]; 1492 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 1493 "performing sync", __func__, dmat, dmat->flags, op); 1494 |
1435 switch (op) { 1436 case BUS_DMASYNC_PREWRITE: 1437 case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD: 1438 while (sl != end) { 1439 cpu_dcache_wb_range(sl->vaddr, sl->datacount); 1440 l2cache_wb_range(sl->vaddr, sl->busaddr, 1441 sl->datacount); 1442 sl++; 1443 } 1444 break; 1445 1446 case BUS_DMASYNC_PREREAD: 1447 /* 1448 * An mbuf may start in the middle of a cacheline. There 1449 * will be no cpu writes to the beginning of that line 1450 * (which contains the mbuf header) while dma is in 1451 * progress. Handle that case by doing a writeback of 1452 * just the first cacheline before invalidating the 1453 * overall buffer. Any mbuf in a chain may have this 1454 * misalignment. Buffers which are not mbufs bounce if 1455 * they are not aligned to a cacheline. 1456 */ 1457 while (sl != end) { 1458 if (sl->vaddr & arm_dcache_align_mask) { 1459 KASSERT(map->flags & DMAMAP_MBUF, 1460 ("unaligned buffer is not an mbuf")); 1461 cpu_dcache_wb_range(sl->vaddr, 1); 1462 l2cache_wb_range(sl->vaddr, 1463 sl->busaddr, 1); 1464 } 1465 cpu_dcache_inv_range(sl->vaddr, sl->datacount); 1466 l2cache_inv_range(sl->vaddr, sl->busaddr, 1467 sl->datacount); 1468 sl++; 1469 } 1470 break; 1471 1472 case BUS_DMASYNC_POSTWRITE: 1473 break; 1474 1475 case BUS_DMASYNC_POSTREAD: 1476 case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: 1477 while (sl != end) { 1478 l2cache_inv_range(sl->vaddr, sl->busaddr, 1479 sl->datacount); 1480 cpu_dcache_inv_range(sl->vaddr, sl->datacount); 1481 sl++; 1482 } 1483 break; 1484 1485 default: 1486 panic("unsupported combination of sync operations: 0x%08x\n", op); 1487 break; 1488 } | 1495 for ( ; sl != end; ++sl) 1496 dma_dcache_sync(sl, op); |
1489 } 1490} 1491 1492static void 1493init_bounce_pages(void *dummy __unused) 1494{ 1495 1496 total_bpages = 0; --- 177 unchanged lines hidden (view full) --- 1674 mtx_unlock(&bounce_lock); 1675 1676 if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { 1677 /* Page offset needs to be preserved. */ 1678 bpage->vaddr |= addr & PAGE_MASK; 1679 bpage->busaddr |= addr & PAGE_MASK; 1680 } 1681 bpage->datavaddr = vaddr; | 1497 } 1498} 1499 1500static void 1501init_bounce_pages(void *dummy __unused) 1502{ 1503 1504 total_bpages = 0; --- 177 unchanged lines hidden (view full) --- 1682 mtx_unlock(&bounce_lock); 1683 1684 if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { 1685 /* Page offset needs to be preserved. */ 1686 bpage->vaddr |= addr & PAGE_MASK; 1687 bpage->busaddr |= addr & PAGE_MASK; 1688 } 1689 bpage->datavaddr = vaddr; |
1682 bpage->dataaddr = addr; | 1690 /* PHYS_TO_VM_PAGE() will truncate unaligned addresses. */ 1691 bpage->datapage = PHYS_TO_VM_PAGE(addr); 1692 bpage->dataoffs = addr & PAGE_MASK; |
1683 bpage->datacount = size; 1684 STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); 1685 return (bpage->busaddr); 1686} 1687 1688static void 1689free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) 1690{ --- 52 unchanged lines hidden --- | 1693 bpage->datacount = size; 1694 STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); 1695 return (bpage->busaddr); 1696} 1697 1698static void 1699free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) 1700{ --- 52 unchanged lines hidden --- |