/alps/pcitool

To get this branch, use:
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;
236 by Suren A. Chilingaryan
Big redign of model structures
23
    kh.flags = flags|PCILIB_KMEM_FLAG_MASS;
81 by Suren A. Chilingaryan
Support forceful clean-up of kernel memory
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
370 by Suren A. Chilingaryan
RPM generation
32
    if (kbuf->buf.blocks[i].ua) munmap((void*)kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
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
	
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
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;
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
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;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
63
    char error[256];
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
64
    
45 by root
North West Logick DMA implementation
65
    int ret;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
66
    size_t i, allocated = nmemb;
45 by root
North West Logick DMA implementation
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));
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
82
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
83
    err = pcilib_lock_global(ctx);
282 by Suren A. Chilingaryan
Fix error-checking typo in kmem
84
    if (err) {
85
	pcilib_error("Error (%i) acquiring mmap lock", err);
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
86
	return NULL;
87
    }
88
45 by root
North West Logick DMA implementation
89
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_KMEM );
90
    if (ret) {
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
91
	pcilib_unlock_global(ctx);
45 by root
North West Logick DMA implementation
92
	pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed");
93
	return NULL;
94
    }
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
95
45 by root
North West Logick DMA implementation
96
    kh.type = type;
97
    kh.size = size;
98
    kh.align = alignment;
99
    kh.use = use;
100
202.1.2 by Suren A. Chilingaryan
Support pre-allocated memory with memmap in KMem
101
    if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) {
102
	kh.align = 0;
103
    } else if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) {
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
104
	kh.size += alignment;
105
    }
202.1.2 by Suren A. Chilingaryan
Support pre-allocated memory with memmap in KMem
106
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
107
    for ( i = 0; (i < nmemb)||(flags&PCILIB_KMEM_FLAG_MASS); i++) {
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
108
	kh.item = i;
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
109
	kh.flags = flags;
202.1.2 by Suren A. Chilingaryan
Support pre-allocated memory with memmap in KMem
110
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
111
	if (i >= nmemb) 
112
	    kh.flags |= KMEM_FLAG_TRY;
113
202.1.2 by Suren A. Chilingaryan
Support pre-allocated memory with memmap in KMem
114
	if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) {
115
	    kh.pa = alignment + i * size;
116
	}
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
117
	
45 by root
North West Logick DMA implementation
118
        ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
119
	if (ret) {
120
	    kbuf->buf.n_blocks = i;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
121
	    if ((i < nmemb)||(errno != ENOENT)) {
122
		err = PCILIB_ERROR_FAILED;
123
		if (errno == EINVAL) {
124
		    if (kh.type != type)
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"));
132
		    else 
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);
138
		} else {
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);
140
		}
141
	    }
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
142
	    break;
45 by root
North West Logick DMA implementation
143
	}
127 by Suren A. Chilingaryan
Reverts r99 and fixes inheritance of kernel buffers properly
144
	
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
145
	if (i >= allocated) {
146
	    void *kbuf_new = realloc(kbuf, sizeof(pcilib_kmem_list_t) + 2 * allocated * sizeof(pcilib_kmem_addr_t));
147
	    if (!kbuf_new) {
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));
151
		break;
152
	    }
153
	    memset(kbuf_new + sizeof(pcilib_kmem_list_t) + allocated * sizeof(pcilib_kmem_addr_t) , 0, allocated * sizeof(pcilib_kmem_addr_t));
154
	    kbuf = kbuf_new;
155
	    allocated *= 2;
156
	}
157
	
45 by root
North West Logick DMA implementation
158
	kbuf->buf.blocks[i].handle_id = kh.handle_id;
159
	kbuf->buf.blocks[i].pa = kh.pa;
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
160
	kbuf->buf.blocks[i].ba = kh.ba;
45 by root
North West Logick DMA implementation
161
	kbuf->buf.blocks[i].size = kh.size;
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
162
	
163
	if (!i) reused = (kh.flags&KMEM_FLAG_REUSED)?PCILIB_TRISTATE_YES:PCILIB_TRISTATE_NO;
164
165
        if (kh.flags&KMEM_FLAG_REUSED) {
166
	    if (!i) reused = PCILIB_TRISTATE_YES;
167
	    else if (!reused) reused = PCILIB_TRISTATE_PARTIAL;
168
	
169
	    if (persistent) {
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
170
		if (persistent < 0) {
127 by Suren A. Chilingaryan
Reverts r99 and fixes inheritance of kernel buffers properly
171
		    /*if (((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)&&(kh.flags&KMEM_FLAG_REUSED_PERSISTENT)) err = PCILIB_ERROR_INVALID_STATE;
172
		    else*/ persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
173
		} 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
174
	    } else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
175
	    if (err) {
176
		kbuf->buf.n_blocks = i + 1;
177
		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", 
178
		    use, i, ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?"persistent":"not persistent"), (persistent?"are":"are not"));
179
		break;
180
	    }
181
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
182
	    if (hardware) {
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
183
		if (hardware < 0) {
127 by Suren A. Chilingaryan
Reverts r99 and fixes inheritance of kernel buffers properly
184
		    /*if (((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE;
185
		    else*/ hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
186
		} 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
187
	    } else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
188
	    if (err) {
189
		kbuf->buf.n_blocks = i + 1;
190
		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", 
191
		    use, i, ((kh.flags&KMEM_FLAG_REUSED_HW)?"hardware-locked":"not hardware-locked"), (hardware?"are":"are not"));
192
		break;
193
	    }
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
194
	} else {
195
	    if (!i) reused = PCILIB_TRISTATE_NO;
196
	    else if (reused) reused = PCILIB_TRISTATE_PARTIAL;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
197
198
	    if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) {
199
		err = PCILIB_ERROR_INVALID_STATE;
200
		sprintf(error, "Expecting to re-use persistent blocks, but buffer (use 0x%x, block: %zu) is not", use, i);
201
	    }
202
	    else if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) {
203
		err = PCILIB_ERROR_INVALID_STATE;
204
		sprintf(error, "Expecting to re-use hardware-locked blocks, but buffer (use 0x%x, block: %zu) is not", use, i);
205
	    }
206
	    if (err) {
207
		kbuf->buf.n_blocks = i + 1;
208
		break;
209
	    }
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
210
	}
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
211
	
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
212
192 by Suren A. Chilingaryan
Kernel memory allocation
213
        if ((kh.align)&&((kh.type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE)) {
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
214
    		//  Physical or bus address here?
215
    	    if (kh.ba) {
216
	        if (kh.ba % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.ba % kh.align;
217
    	    } else {
218
	        if (kh.pa % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.pa % kh.align;
219
	    }
100 by root
Support exporting data from kernel buffers
220
	    kbuf->buf.blocks[i].size -= kh.align;
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
221
	}
192 by Suren A. Chilingaryan
Kernel memory allocation
222
76 by Suren A. Chilingaryan
Handle correctly reference counting in the driver
223
    	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
224
	if ((!addr)||(addr == MAP_FAILED)) {
225
	    kbuf->buf.n_blocks = i + 1;
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
226
	    err = PCILIB_ERROR_FAILED;
227
	    sprintf(error, "Driver prevents us from mmaping buffer (use 0x%x, block: %zu), mmap have failed with errno %i", use, i, errno);
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
228
	    break;
45 by root
North West Logick DMA implementation
229
	}
230
231
	kbuf->buf.blocks[i].ua = addr;
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
232
	kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask;
45 by root
North West Logick DMA implementation
233
    }
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
234
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
235
    if (err) kbuf->buf.n_blocks = i + 1;
236
    else kbuf->buf.n_blocks = i;
237
238
239
	// Check if there are more unpicked buffers
240
    if ((!err)&&((flags&PCILIB_KMEM_FLAG_MASS) == 0)&&(reused == PCILIB_TRISTATE_YES)&&((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_REGION)) {
241
	kh.item = kbuf->buf.n_blocks;
242
	kh.flags = KMEM_FLAG_REUSE|KMEM_FLAG_TRY;
243
244
        ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
245
	if (!ret) {
246
	    kh.flags = KMEM_FLAG_REUSE;
247
	    ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh);
248
	    reused = PCILIB_TRISTATE_PARTIAL;
249
	} else if (errno != ENOENT) {
250
	    reused = PCILIB_TRISTATE_PARTIAL;
251
	}
252
    }
253
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
254
    pcilib_unlock_global(ctx);
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
255
256
127 by Suren A. Chilingaryan
Reverts r99 and fixes inheritance of kernel buffers properly
257
	//This is possible in the case of error (nothing is allocated yet) or if buffers are not reused
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
258
    if (persistent < 0) persistent = 0;
259
    if (hardware < 0) hardware = 0;
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
260
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
261
    if (err) {
262
	    // do not clean if we have reused (even partially) persistent/hardware-locked buffers
263
	if (((persistent)||(hardware))&&(reused != PCILIB_TRISTATE_NO)) {
264
	    pcilib_cancel_kernel_memory(ctx, kbuf, KMEM_FLAG_REUSE, 0);
265
	} else {
266
	    pcilib_kmem_flags_t free_flags = 0;
267
	    if (flags&PCILIB_KMEM_FLAG_PERSISTENT) {
268
		free_flags |= PCILIB_KMEM_FLAG_PERSISTENT;
269
	    }
270
	    if (flags&PCILIB_KMEM_FLAG_HARDWARE) {
271
		free_flags |= PCILIB_KMEM_FLAG_HARDWARE;
272
	    }
273
		// err indicates consistensy error. The last ioctl have succeeded and we need to clean it in a special way
274
	    pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, (err == PCILIB_ERROR_INVALID_STATE)?kh.flags:0);
275
	}
276
277
	pcilib_warning("Error %i: %s", err, error);
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
278
	return NULL;
279
    }
280
    
45 by root
North West Logick DMA implementation
281
    if (nmemb == 1) {
282
	memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t));
283
    }
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
284
346 by Suren A. Chilingaryan
Fix reading non DMA-able kernel pages using pcitool
285
    kbuf->buf.type = type;
286
    kbuf->buf.use = use;
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
287
    kbuf->buf.reused = reused|(persistent?PCILIB_KMEM_REUSE_PERSISTENT:0)|(hardware?PCILIB_KMEM_REUSE_HARDWARE:0);
343 by Suren A. Chilingaryan
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using
288
45 by root
North West Logick DMA implementation
289
    kbuf->prev = NULL;
290
    kbuf->next = ctx->kmem_list;
291
    if (ctx->kmem_list) ctx->kmem_list->prev = kbuf;
292
    ctx->kmem_list = kbuf;
293
294
    return (pcilib_kmem_handle_t*)kbuf;
295
}
296
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
297
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
298
    int ret, err = 0; 
299
    int i;
300
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
301
302
	// if linked in to the list
303
    if (kbuf->next) kbuf->next->prev = kbuf->prev;
304
    if (kbuf->prev) kbuf->prev->next = kbuf->next;
305
    else if (ctx->kmem_list == kbuf) ctx->kmem_list = kbuf->next;
306
307
    for (i = 0; i < kbuf->buf.n_blocks; i++) {
75 by Suren A. Chilingaryan
Few fixes
308
        ret = pcilib_free_kernel_buffer(ctx, kbuf, i, flags);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
309
    	if ((ret)&&(!err)) err = ret;
45 by root
North West Logick DMA implementation
310
    }
311
    
312
    free(kbuf);
313
    
314
    if (err) {
315
	pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed");
316
    }
317
}
318
106 by Suren A. Chilingaryan
Sync only required buffers
319
/*
148 by Suren A. Chilingaryan
Synchronize kernel buffers during the read-kernel-memory and while accessing via sysfs
320
int pcilib_kmem_sync(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir) {
45 by root
North West Logick DMA implementation
321
    int i;
322
    int ret;
323
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
324
    
325
    for (i = 0; i < kbuf->buf.n_blocks; i++) {
148 by Suren A. Chilingaryan
Synchronize kernel buffers during the read-kernel-memory and while accessing via sysfs
326
	ret = pcilib_kmem_sync_block(ctx, k, dir, i);
45 by root
North West Logick DMA implementation
327
	if (ret) {
328
	    pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed");
329
	    return PCILIB_ERROR_FAILED;
330
	}
331
    }
332
    
333
    return 0;    
334
}
106 by Suren A. Chilingaryan
Sync only required buffers
335
*/
336
337
int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir, size_t block) {
338
    int ret;
339
    kmem_sync_t ks;
340
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
341
346 by Suren A. Chilingaryan
Fix reading non DMA-able kernel pages using pcitool
342
    switch (kbuf->buf.type) {
343
      case PCILIB_KMEM_TYPE_DMA_S2C_PAGE:
344
      case PCILIB_KMEM_TYPE_DMA_C2S_PAGE:
345
      case PCILIB_KMEM_TYPE_REGION_S2C:
346
      case PCILIB_KMEM_TYPE_REGION_C2S:
347
        ks.dir = dir;
348
	ks.handle.handle_id = kbuf->buf.blocks[block].handle_id;
349
	ks.handle.pa = kbuf->buf.blocks[block].pa;
350
	
351
	ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_SYNC, &ks);
352
	if (ret) {
353
	    pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed");
354
	    return PCILIB_ERROR_FAILED;
355
	}
356
	break;
357
      default:
358
	;
106 by Suren A. Chilingaryan
Sync only required buffers
359
    }
346 by Suren A. Chilingaryan
Fix reading non DMA-able kernel pages using pcitool
360
106 by Suren A. Chilingaryan
Sync only required buffers
361
    return 0;
362
}
45 by root
North West Logick DMA implementation
363
370 by Suren A. Chilingaryan
RPM generation
364
volatile void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
45 by root
North West Logick DMA implementation
365
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
366
    return kbuf->buf.addr.ua + kbuf->buf.addr.alignment_offset + kbuf->buf.addr.mmap_offset;
45 by root
North West Logick DMA implementation
367
}
368
369
uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
370
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
371
    return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset;
45 by root
North West Logick DMA implementation
372
}
373
192 by Suren A. Chilingaryan
Kernel memory allocation
374
uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
375
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
376
377
    if (kbuf->buf.addr.ba)
378
	return kbuf->buf.addr.ba + kbuf->buf.addr.alignment_offset;
379
380
    return 0;
192 by Suren A. Chilingaryan
Kernel memory allocation
381
}
382
370 by Suren A. Chilingaryan
RPM generation
383
volatile void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
45 by root
North West Logick DMA implementation
384
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
385
    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
386
}
387
388
uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
389
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
52 by Suren A. Chilingaryan
Support alignments in kmem allocation
390
    return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset;
45 by root
North West Logick DMA implementation
391
}
392
192 by Suren A. Chilingaryan
Kernel memory allocation
393
uintptr_t pcilib_kmem_get_block_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
394
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
395
396
    if (kbuf->buf.blocks[block].ba)
397
	return kbuf->buf.blocks[block].ba + kbuf->buf.blocks[block].alignment_offset;
398
399
    return 0;
192 by Suren A. Chilingaryan
Kernel memory allocation
400
}
401
45 by root
North West Logick DMA implementation
402
size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
403
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
404
    return kbuf->buf.blocks[block].size;
405
}
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
406
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
407
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
408
    pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
409
    return kbuf->buf.reused;
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
410
}