47
47
pcilib_kmem_flags_t failed_flags = flags;
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;
49
if (last_flags&KMEM_FLAG_REUSED_PERSISTENT) failed_flags&=~PCILIB_KMEM_FLAG_PERSISTENT;
50
if (last_flags&KMEM_FLAG_REUSED_HW) failed_flags&=~PCILIB_KMEM_FLAG_HARDWARE;
52
52
if (failed_flags != flags) {
53
53
ret = pcilib_free_kernel_buffer(ctx, kbuf, --kbuf->buf.n_blocks, failed_flags);
61
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) {
63
const char *error = NULL;
66
size_t i, allocated = nmemb;
69
69
pcilib_tristate_t reused = PCILIB_TRISTATE_NO;
115
118
ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
117
120
kbuf->buf.n_blocks = i;
118
error = "PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed";
121
if ((i < nmemb)||(errno != ENOENT)) {
122
err = PCILIB_ERROR_FAILED;
123
if (errno == EINVAL) {
125
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), we have requested type %u but buffer is of type %lu", use, i, type, kh.type);
126
else if (kh.size != size)
127
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), we have requested size %lu but buffer is of size %lu", use, i, size, kh.size);
128
else if (kh.align != alignment)
129
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), we have requested alignment %lu but buffer is of alignment %lu", use, i, size, kh.size);
130
else if ((kh.flags&KMEM_FLAG_EXCLUSIVE) != (flags&KMEM_FLAG_EXCLUSIVE))
131
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), we have requested size %s but buffer is of size %s", use, i, ((flags&KMEM_FLAG_EXCLUSIVE)?"exclusive":"non-exclusive"), ((kh.flags&KMEM_FLAG_EXCLUSIVE)?"exclusive":"non exclusive"));
133
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), unknown consistency error", use, i);
134
} else if (errno == EBUSY) {
135
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), reuse counter of kmem_entry is overflown", use, i);
136
} else if (errno == ENOMEM) {
137
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), memory allocation (%zu bytes) failed", use, i, size);
139
sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu), PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed with errno %i", use, i, errno);
145
if (i >= allocated) {
146
void *kbuf_new = realloc(kbuf, sizeof(pcilib_kmem_list_t) + 2 * allocated * sizeof(pcilib_kmem_addr_t));
148
kbuf->buf.n_blocks = i;
149
err = PCILIB_ERROR_MEMORY;
150
sprintf(error, "Failed to allocate extra %zu bytes of user-space memory for kmem structures", allocated * sizeof(pcilib_kmem_addr_t));
153
memset(kbuf_new + sizeof(pcilib_kmem_list_t) + allocated * sizeof(pcilib_kmem_addr_t) , 0, allocated * sizeof(pcilib_kmem_addr_t));
122
158
kbuf->buf.blocks[i].handle_id = kh.handle_id;
123
159
kbuf->buf.blocks[i].pa = kh.pa;
124
160
kbuf->buf.blocks[i].size = kh.size;
135
171
else*/ persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0;
136
172
} else if ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT) == 0) err = PCILIB_ERROR_INVALID_STATE;
137
173
} else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE;
175
kbuf->buf.n_blocks = i + 1;
176
sprintf(error, "Mistmatch in persistent modes of the re-used kmem blocks. Current buffer (use 0x%x, block: %zu) is %s, but prior ones %s",
177
use, i, ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?"persistent":"not persistent"), (persistent?"are":"are not"));
140
182
if (hardware < 0) {
141
183
/*if (((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE;
142
184
else*/ hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0;
143
185
} else if ((kh.flags&KMEM_FLAG_REUSED_HW) == 0) err = PCILIB_ERROR_INVALID_STATE;
144
186
} else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE;
188
kbuf->buf.n_blocks = i + 1;
189
sprintf(error, "Mistmatch in hardware modes of the re-used kmem blocks. Current buffer (use 0x%x, block: %zu) is %s, but prior ones %s",
190
use, i, ((kh.flags&KMEM_FLAG_REUSED_HW)?"hardware-locked":"not hardware-locked"), (hardware?"are":"are not"));
147
194
if (!i) reused = PCILIB_TRISTATE_NO;
148
195
else if (reused) reused = PCILIB_TRISTATE_PARTIAL;
150
if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) err = PCILIB_ERROR_INVALID_STATE;
151
if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) err = PCILIB_ERROR_INVALID_STATE;
197
if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) {
198
err = PCILIB_ERROR_INVALID_STATE;
199
sprintf(error, "Expecting to re-use persistent blocks, but buffer (use 0x%x, block: %zu) is not", use, i);
201
else if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) {
202
err = PCILIB_ERROR_INVALID_STATE;
203
sprintf(error, "Expecting to re-use hardware-locked blocks, but buffer (use 0x%x, block: %zu) is not", use, i);
206
kbuf->buf.n_blocks = i + 1;
155
kbuf->buf.n_blocks = i + 1;
159
212
if ((kh.align)&&((kh.type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE)) {
160
213
if (kh.pa % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.pa % kh.align;
161
214
kbuf->buf.blocks[i].size -= kh.align;
164
217
addr = mmap( 0, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
165
218
if ((!addr)||(addr == MAP_FAILED)) {
166
219
kbuf->buf.n_blocks = i + 1;
167
error = "Failed to mmap allocated kernel memory";
220
err = PCILIB_ERROR_FAILED;
221
sprintf(error, "Driver prevents us from mmaping buffer (use 0x%x, block: %zu), mmap have failed with errno %i", use, i, errno);
171
225
kbuf->buf.blocks[i].ua = addr;
172
// if (use == PCILIB_KMEM_USE_DMA_PAGES) {
173
// memset(addr, 10, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset);
176
226
kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask;
229
if (err) kbuf->buf.n_blocks = i + 1;
230
else kbuf->buf.n_blocks = i;
233
// Check if there are more unpicked buffers
234
if ((!err)&&((flags&PCILIB_KMEM_FLAG_MASS) == 0)&&(reused == PCILIB_TRISTATE_YES)&&((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_REGION)) {
235
kh.item = kbuf->buf.n_blocks;
236
kh.flags = KMEM_FLAG_REUSE|KMEM_FLAG_TRY;
238
ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
240
kh.flags = KMEM_FLAG_REUSE;
241
ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh);
242
reused = PCILIB_TRISTATE_PARTIAL;
243
} else if (errno != ENOENT) {
244
reused = PCILIB_TRISTATE_PARTIAL;
179
248
pcilib_unlock_global(ctx);
183
252
if (persistent < 0) persistent = 0;
184
253
if (hardware < 0) hardware = 0;
187
pcilib_kmem_flags_t free_flags = 0;
189
// for the sake of simplicity always clean partialy reused buffers
190
if ((persistent == PCILIB_TRISTATE_PARTIAL)||((persistent <= 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT))) {
191
free_flags |= PCILIB_KMEM_FLAG_PERSISTENT;
194
if ((hardware <= 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE)) {
195
free_flags |= PCILIB_KMEM_FLAG_HARDWARE;
198
// do not clean if we have reused peresistent buffers
199
// we don't care about -1, because it will be the value only if no buffers actually allocated
200
if ((!persistent)||(reused != PCILIB_TRISTATE_YES)) {
201
pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, err?kh.flags:0);
204
if (!error) error = "Reused buffers are inconsistent";
256
// do not clean if we have reused (even partially) persistent/hardware-locked buffers
257
if (((persistent)||(hardware))&&(reused != PCILIB_TRISTATE_NO)) {
258
pcilib_cancel_kernel_memory(ctx, kbuf, KMEM_FLAG_REUSE, 0);
260
pcilib_kmem_flags_t free_flags = 0;
261
if (flags&PCILIB_KMEM_FLAG_PERSISTENT) {
262
free_flags |= PCILIB_KMEM_FLAG_PERSISTENT;
264
if (flags&PCILIB_KMEM_FLAG_HARDWARE) {
265
free_flags |= PCILIB_KMEM_FLAG_HARDWARE;
267
// err indicates consistensy error. The last ioctl have succeeded and we need to clean it in a special way
268
pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, (err == PCILIB_ERROR_INVALID_STATE)?kh.flags:0);
271
pcilib_warning("Error %i: %s", err, error);
210
275
if (nmemb == 1) {
211
276
memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t));
214
279
kbuf->buf.reused = reused|(persistent?PCILIB_KMEM_REUSE_PERSISTENT:0)|(hardware?PCILIB_KMEM_REUSE_HARDWARE:0);
215
kbuf->buf.n_blocks = nmemb;
217
281
kbuf->prev = NULL;
218
282
kbuf->next = ctx->kmem_list;
219
283
if (ctx->kmem_list) ctx->kmem_list->prev = kbuf;