bzr branch
http://suren.me/webbzr/alps/pcitool
45
by root
North West Logick DMA implementation |
1 |
#include <stdio.h> |
2 |
#include <string.h> |
|
3 |
#include <strings.h> |
|
4 |
#include <stdlib.h> |
|
5 |
#include <stdint.h> |
|
6 |
#include <stdarg.h> |
|
7 |
#include <fcntl.h> |
|
8 |
#include <unistd.h> |
|
9 |
#include <sys/ioctl.h> |
|
10 |
#include <sys/mman.h> |
|
11 |
#include <arpa/inet.h> |
|
12 |
#include <errno.h> |
|
13 |
#include <assert.h> |
|
14 |
||
15 |
#include "pcilib.h" |
|
16 |
#include "pci.h" |
|
17 |
#include "kmem.h" |
|
18 |
#include "error.h" |
|
19 |
||
81
by Suren A. Chilingaryan
Support forceful clean-up of kernel memory |
20 |
int pcilib_clean_kernel_memory(pcilib_t *ctx, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) { |
21 |
kmem_handle_t kh = {0}; |
|
22 |
kh.use = use; |
|
23 |
kh.flags = flags|KMEM_FLAG_MASS; |
|
24 |
||
25 |
return ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); |
|
26 |
}
|
|
27 |
||
28 |
||
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
29 |
static int pcilib_free_kernel_buffer(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, size_t i, pcilib_kmem_flags_t flags) { |
30 |
kmem_handle_t kh = {0}; |
|
31 |
||
32 |
if (kbuf->buf.blocks[i].ua) munmap(kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); |
|
33 |
kh.handle_id = kbuf->buf.blocks[i].handle_id; |
|
34 |
kh.pa = kbuf->buf.blocks[i].pa; |
|
35 |
kh.flags = flags; |
|
75
by Suren A. Chilingaryan
Few fixes |
36 |
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
37 |
return ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); |
38 |
}
|
|
39 |
||
40 |
static void pcilib_cancel_kernel_memory(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, pcilib_kmem_flags_t flags, int last_flags) { |
|
41 |
int ret; |
|
42 |
||
43 |
if (!kbuf->buf.n_blocks) return; |
|
44 |
||
45 |
// consistency error during processing of last block, special treatment could be needed
|
|
46 |
if (last_flags) { |
|
47 |
pcilib_kmem_flags_t failed_flags = flags; |
|
48 |
||
49 |
if (last_flags&KMEM_FLAG_REUSED_PERSISTENT) flags&=~PCILIB_KMEM_FLAG_PERSISTENT; |
|
50 |
if (last_flags&KMEM_FLAG_REUSED_HW) flags&=~PCILIB_KMEM_FLAG_HARDWARE; |
|
51 |
||
52 |
if (failed_flags != flags) { |
|
53 |
ret = pcilib_free_kernel_buffer(ctx, kbuf, --kbuf->buf.n_blocks, failed_flags); |
|
54 |
if (ret) pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed"); |
|
55 |
}
|
|
56 |
}
|
|
57 |
||
58 |
pcilib_free_kernel_memory(ctx, kbuf, flags); |
|
59 |
}
|
|
60 |
||
45
by root
North West Logick DMA implementation |
61 |
pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) { |
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
62 |
int err = 0; |
63 |
const char *error = NULL; |
|
64 |
||
45
by root
North West Logick DMA implementation |
65 |
int ret; |
66 |
int i; |
|
67 |
void *addr; |
|
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
68 |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
69 |
pcilib_tristate_t reused = PCILIB_TRISTATE_NO; |
70 |
int persistent = -1; |
|
71 |
int hardware = -1; |
|
45
by root
North West Logick DMA implementation |
72 |
|
73 |
kmem_handle_t kh = {0}; |
|
74 |
||
75 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)malloc(sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t)); |
|
76 |
if (!kbuf) { |
|
77 |
pcilib_error("Memory allocation has failed"); |
|
78 |
return NULL; |
|
79 |
}
|
|
80 |
||
81 |
memset(kbuf, 0, sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t)); |
|
82 |
||
83 |
||
84 |
ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_KMEM ); |
|
85 |
if (ret) { |
|
86 |
pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed"); |
|
87 |
return NULL; |
|
88 |
}
|
|
89 |
||
90 |
kh.type = type; |
|
91 |
kh.size = size; |
|
92 |
kh.align = alignment; |
|
93 |
kh.use = use; |
|
94 |
||
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
95 |
if (type != PCILIB_KMEM_TYPE_PAGE) { |
96 |
kh.size += alignment; |
|
97 |
}
|
|
98 |
||
45
by root
North West Logick DMA implementation |
99 |
for ( i = 0; i < nmemb; i++) { |
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
100 |
kh.item = i; |
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
101 |
kh.flags = flags; |
102 |
||
45
by root
North West Logick DMA implementation |
103 |
ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh); |
104 |
if (ret) { |
|
105 |
kbuf->buf.n_blocks = i; |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
106 |
error = "PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed"; |
107 |
break; |
|
45
by root
North West Logick DMA implementation |
108 |
}
|
109 |
||
110 |
kbuf->buf.blocks[i].handle_id = kh.handle_id; |
|
111 |
kbuf->buf.blocks[i].pa = kh.pa; |
|
112 |
kbuf->buf.blocks[i].size = kh.size; |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
113 |
|
114 |
if (!i) reused = (kh.flags&KMEM_FLAG_REUSED)?PCILIB_TRISTATE_YES:PCILIB_TRISTATE_NO; |
|
115 |
||
116 |
if (kh.flags&KMEM_FLAG_REUSED) { |
|
117 |
if (!i) reused = PCILIB_TRISTATE_YES; |
|
118 |
else if (!reused) reused = PCILIB_TRISTATE_PARTIAL; |
|
119 |
||
120 |
if (persistent) { |
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
121 |
if (persistent < 0) { |
122 |
if ((flags&PCILIB_KMEM_FLAG_PERSISTENT == 0)&&(kh.flags&KMEM_FLAG_REUSED_PERSISTENT)) err = PCILIB_ERROR_INVALID_STATE; |
|
123 |
else persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0; |
|
124 |
} else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT == 0) err = PCILIB_ERROR_INVALID_STATE; |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
125 |
} else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE; |
126 |
||
127 |
if (hardware) { |
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
128 |
if (hardware < 0) { |
129 |
if ((flags&PCILIB_KMEM_FLAG_HARDWARE == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE; |
|
130 |
else hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0; |
|
131 |
} else if (kh.flags&KMEM_FLAG_REUSED_HW == 0) err = PCILIB_ERROR_INVALID_STATE; |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
132 |
} else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE; |
133 |
||
134 |
} else { |
|
135 |
if (!i) reused = PCILIB_TRISTATE_NO; |
|
136 |
else if (reused) reused = PCILIB_TRISTATE_PARTIAL; |
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
137 |
|
138 |
if ((persistent > 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT == 0)) err = PCILIB_ERROR_INVALID_STATE; |
|
139 |
if ((hardware > 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE == 0)) err = PCILIB_ERROR_INVALID_STATE; |
|
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
140 |
}
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
141 |
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
142 |
if (err) { |
143 |
kbuf->buf.n_blocks = i + 1; |
|
144 |
break; |
|
145 |
}
|
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
146 |
|
100
by root
Support exporting data from kernel buffers |
147 |
if ((kh.align)&&(type != PCILIB_KMEM_TYPE_PAGE)) { |
148 |
if (kh.pa % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.pa % kh.align; |
|
149 |
kbuf->buf.blocks[i].size -= kh.align; |
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
150 |
}
|
45
by root
North West Logick DMA implementation |
151 |
|
76
by Suren A. Chilingaryan
Handle correctly reference counting in the driver |
152 |
addr = mmap( 0, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 ); |
45
by root
North West Logick DMA implementation |
153 |
if ((!addr)||(addr == MAP_FAILED)) { |
154 |
kbuf->buf.n_blocks = i + 1; |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
155 |
error = "Failed to mmap allocated kernel memory"; |
156 |
break; |
|
45
by root
North West Logick DMA implementation |
157 |
}
|
158 |
||
159 |
kbuf->buf.blocks[i].ua = addr; |
|
100
by root
Support exporting data from kernel buffers |
160 |
// if (use == PCILIB_KMEM_USE_DMA_PAGES) {
|
161 |
// memset(addr, 10, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset);
|
|
162 |
// }
|
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
163 |
|
164 |
kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask; |
|
45
by root
North West Logick DMA implementation |
165 |
}
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
166 |
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
167 |
if (persistent < 0) persistent = 0; |
168 |
if (hardware < 0) hardware = 0; |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
169 |
|
170 |
if (err||error) { |
|
171 |
pcilib_kmem_flags_t free_flags = 0; |
|
172 |
||
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
173 |
if ((persistent <= 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT)) { |
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
174 |
free_flags |= PCILIB_KMEM_FLAG_PERSISTENT; |
175 |
}
|
|
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
176 |
|
177 |
if ((hardware <= 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE)) { |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
178 |
free_flags |= PCILIB_KMEM_FLAG_HARDWARE; |
179 |
}
|
|
180 |
||
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
181 |
pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, err?kh.flags:0); |
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
182 |
|
183 |
if (err) error = "Reused buffers are inconsistent"; |
|
184 |
pcilib_error(error); |
|
185 |
||
186 |
return NULL; |
|
187 |
}
|
|
188 |
||
45
by root
North West Logick DMA implementation |
189 |
|
190 |
if (nmemb == 1) { |
|
191 |
memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t)); |
|
192 |
}
|
|
193 |
||
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
194 |
kbuf->buf.reused = reused|(persistent?PCILIB_KMEM_REUSE_PERSISTENT:0)|(hardware?PCILIB_KMEM_REUSE_HARDWARE:0); |
45
by root
North West Logick DMA implementation |
195 |
kbuf->buf.n_blocks = nmemb; |
196 |
||
197 |
kbuf->prev = NULL; |
|
198 |
kbuf->next = ctx->kmem_list; |
|
199 |
if (ctx->kmem_list) ctx->kmem_list->prev = kbuf; |
|
200 |
ctx->kmem_list = kbuf; |
|
201 |
||
202 |
return (pcilib_kmem_handle_t*)kbuf; |
|
203 |
}
|
|
204 |
||
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
205 |
void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags) { |
45
by root
North West Logick DMA implementation |
206 |
int ret, err = 0; |
207 |
int i; |
|
208 |
kmem_handle_t kh = {0}; |
|
209 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
210 |
||
211 |
// if linked in to the list
|
|
212 |
if (kbuf->next) kbuf->next->prev = kbuf->prev; |
|
213 |
if (kbuf->prev) kbuf->prev->next = kbuf->next; |
|
214 |
else if (ctx->kmem_list == kbuf) ctx->kmem_list = kbuf->next; |
|
215 |
||
216 |
for (i = 0; i < kbuf->buf.n_blocks; i++) { |
|
75
by Suren A. Chilingaryan
Few fixes |
217 |
ret = pcilib_free_kernel_buffer(ctx, kbuf, i, flags); |
74
by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation |
218 |
if ((ret)&&(!err)) err = ret; |
45
by root
North West Logick DMA implementation |
219 |
}
|
220 |
||
221 |
free(kbuf); |
|
222 |
||
223 |
if (err) { |
|
224 |
pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed"); |
|
225 |
}
|
|
226 |
}
|
|
227 |
||
106
by Suren A. Chilingaryan
Sync only required buffers |
228 |
/*
|
45
by root
North West Logick DMA implementation |
229 |
int pcilib_sync_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir) {
|
230 |
int i;
|
|
231 |
int ret;
|
|
232 |
kmem_sync_t ks;
|
|
233 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
|
|
234 |
|
|
235 |
ks.dir = dir;
|
|
106
by Suren A. Chilingaryan
Sync only required buffers |
236 |
|
45
by root
North West Logick DMA implementation |
237 |
for (i = 0; i < kbuf->buf.n_blocks; i++) {
|
238 |
ks.handle.handle_id = kbuf->buf.blocks[i].handle_id;
|
|
239 |
ks.handle.pa = kbuf->buf.blocks[i].pa;
|
|
240 |
ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_SYNC, &ks);
|
|
241 |
if (ret) {
|
|
242 |
pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed");
|
|
243 |
return PCILIB_ERROR_FAILED;
|
|
244 |
}
|
|
245 |
}
|
|
246 |
|
|
247 |
return 0;
|
|
248 |
}
|
|
249 |
||
106
by Suren A. Chilingaryan
Sync only required buffers |
250 |
*/
|
251 |
||
252 |
int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir, size_t block) { |
|
253 |
int ret; |
|
254 |
kmem_sync_t ks; |
|
255 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
256 |
||
257 |
ks.dir = dir; |
|
258 |
ks.handle.handle_id = kbuf->buf.blocks[block].handle_id; |
|
259 |
ks.handle.pa = kbuf->buf.blocks[block].pa; |
|
260 |
ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_SYNC, &ks); |
|
261 |
if (ret) { |
|
262 |
pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed"); |
|
263 |
return PCILIB_ERROR_FAILED; |
|
264 |
}
|
|
265 |
||
266 |
return 0; |
|
267 |
}
|
|
45
by root
North West Logick DMA implementation |
268 |
|
269 |
void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) { |
|
270 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
271 |
return kbuf->buf.addr.ua + kbuf->buf.addr.alignment_offset + kbuf->buf.addr.mmap_offset; |
45
by root
North West Logick DMA implementation |
272 |
}
|
273 |
||
274 |
uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k) { |
|
275 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
276 |
return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset; |
45
by root
North West Logick DMA implementation |
277 |
}
|
278 |
||
279 |
void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { |
|
280 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
281 |
return kbuf->buf.blocks[block].ua + kbuf->buf.blocks[block].alignment_offset + kbuf->buf.blocks[block].mmap_offset; |
45
by root
North West Logick DMA implementation |
282 |
}
|
283 |
||
284 |
uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { |
|
285 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
52
by Suren A. Chilingaryan
Support alignments in kmem allocation |
286 |
return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset; |
45
by root
North West Logick DMA implementation |
287 |
}
|
288 |
||
289 |
size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { |
|
290 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
|
291 |
return kbuf->buf.blocks[block].size; |
|
292 |
}
|
|
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
293 |
|
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
294 |
pcilib_kmem_reuse_state_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k) { |
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
295 |
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; |
73
by Suren A. Chilingaryan
Implement DMA access synchronization in the driver |
296 |
return kbuf->buf.reused; |
71
by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions |
297 |
}
|