/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>
69 by Suren A. Chilingaryan
Add timeout to pcilib_skip_dma
12
#include <sys/time.h>
45 by root
North West Logick DMA implementation
13
#include <errno.h>
14
#include <assert.h>
15
16
#include "error.h"
17
#include "pcilib.h"
18
#include "pci.h"
19
#include "dma.h"
20
21
const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) {
22
    if (!ctx->dma_ctx) {
70 by Suren A. Chilingaryan
Support modifications of DMA engine and allow DMA customizations by Event engine
23
        pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
24
25
	if ((ctx->event_ctx)&&(model_info->event_api->init_dma)) {
26
	    pcilib_map_register_space(ctx);
27
	    ctx->dma_ctx = model_info->event_api->init_dma(ctx->event_ctx);
28
	} else if ((model_info->dma_api)&&(model_info->dma_api->init)) {
29
	    pcilib_map_register_space(ctx);
30
	    ctx->dma_ctx = model_info->dma_api->init(ctx, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
45 by root
North West Logick DMA implementation
31
	}
32
	
33
	if (!ctx->dma_ctx) return NULL;
34
    }
35
    
36
    return &ctx->dma_info;
37
}
38
49 by Suren A. Chilingaryan
A bit of renaming
39
pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) {
40
    pcilib_dma_engine_t i;
45 by root
North West Logick DMA implementation
41
42
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
43
    if (!info) {
44
	pcilib_error("DMA Engine is not configured in the current model");
45
	return PCILIB_ERROR_NOTSUPPORTED;
46
    }
47
    
48
    for (i = 0; info->engines[i]; i++) {
49
	if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break;
50
    }
51
    
52
    if (info->engines[i]) return i;
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
53
    return PCILIB_DMA_ENGINE_INVALID;
45 by root
North West Logick DMA implementation
54
}
55
49 by Suren A. Chilingaryan
A bit of renaming
56
int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) {
45 by root
North West Logick DMA implementation
57
    ctx->dma_info.engines[engine] = desc;
58
}
59
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
60
int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
65 by Suren A. Chilingaryan
Separate NWL loopback code, provide DMA start/stop interfaces
61
    int err; 
62
63
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
64
    if (!info) {
65
	pcilib_error("DMA is not supported by the device");
66
	return PCILIB_ERROR_NOTSUPPORTED;
67
    }
68
69
    if (!ctx->model_info.dma_api) {
70
	pcilib_error("DMA Engine is not configured in the current model");
71
	return PCILIB_ERROR_NOTAVAILABLE;
72
    }
73
    
74
    if (!ctx->model_info.dma_api->start_dma) {
75
	return 0;
76
    }
77
    
78
    return ctx->model_info.dma_api->start_dma(ctx->dma_ctx, dma, flags);
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
79
}
80
81
int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
65 by Suren A. Chilingaryan
Separate NWL loopback code, provide DMA start/stop interfaces
82
    int err; 
83
84
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
85
    if (!info) {
86
	pcilib_error("DMA is not supported by the device");
87
	return PCILIB_ERROR_NOTSUPPORTED;
88
    }
89
90
    if (!ctx->model_info.dma_api) {
91
	pcilib_error("DMA Engine is not configured in the current model");
92
	return PCILIB_ERROR_NOTAVAILABLE;
93
    }
94
    
95
    if (!ctx->model_info.dma_api->stop_dma) {
96
	return 0;
97
    }
75 by Suren A. Chilingaryan
Few fixes
98
65 by Suren A. Chilingaryan
Separate NWL loopback code, provide DMA start/stop interfaces
99
    return ctx->model_info.dma_api->stop_dma(ctx->dma_ctx, dma, flags);
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
100
}
101
63 by Suren A. Chilingaryan
Provide IRQ enable/disable call
102
int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) {
103
    int err; 
104
105
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
106
    if (!info) {
107
	pcilib_error("DMA is not supported by the device");
108
	return PCILIB_ERROR_NOTSUPPORTED;
109
    }
110
111
    if (!ctx->model_info.dma_api) {
112
	pcilib_error("DMA Engine is not configured in the current model");
113
	return PCILIB_ERROR_NOTAVAILABLE;
114
    }
115
    
116
    if (!ctx->model_info.dma_api->enable_irq) {
65 by Suren A. Chilingaryan
Separate NWL loopback code, provide DMA start/stop interfaces
117
	return 0;
63 by Suren A. Chilingaryan
Provide IRQ enable/disable call
118
    }
75 by Suren A. Chilingaryan
Few fixes
119
63 by Suren A. Chilingaryan
Provide IRQ enable/disable call
120
    return ctx->model_info.dma_api->enable_irq(ctx->dma_ctx, irq_type, flags);
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
121
}
122
123
int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
63 by Suren A. Chilingaryan
Provide IRQ enable/disable call
124
    int err; 
125
126
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
127
    if (!info) {
128
	pcilib_error("DMA is not supported by the device");
129
	return PCILIB_ERROR_NOTSUPPORTED;
130
    }
131
132
    if (!ctx->model_info.dma_api) {
133
	pcilib_error("DMA Engine is not configured in the current model");
134
	return PCILIB_ERROR_NOTAVAILABLE;
135
    }
136
    
137
    if (!ctx->model_info.dma_api->disable_irq) {
65 by Suren A. Chilingaryan
Separate NWL loopback code, provide DMA start/stop interfaces
138
	return 0;
63 by Suren A. Chilingaryan
Provide IRQ enable/disable call
139
    }
140
    
141
    return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags);
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
142
}
143
88 by Suren A. Chilingaryan
IRQ acknowledgement support in the engine API
144
int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) {
145
    int err; 
146
147
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
148
    if (!info) {
149
	pcilib_error("DMA is not supported by the device");
150
	return PCILIB_ERROR_NOTSUPPORTED;
151
    }
152
153
    if (!ctx->model_info.dma_api) {
154
	pcilib_error("DMA Engine is not configured in the current model");
155
	return PCILIB_ERROR_NOTAVAILABLE;
156
    }
157
    
158
    if (!ctx->model_info.dma_api->acknowledge_irq) {
159
	return 0;
160
    }
161
162
    return ctx->model_info.dma_api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source);
163
}
164
165
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
166
45 by root
North West Logick DMA implementation
167
typedef struct {
168
    size_t size;
169
    void *data;
170
    size_t pos;
109 by Suren A. Chilingaryan
Improvements of DMA engine
171
    
172
    pcilib_dma_flags_t flags;
45 by root
North West Logick DMA implementation
173
} pcilib_dma_read_callback_context_t;
174
175
static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
176
    pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg;
177
    
178
    if (ctx->pos + bufsize > ctx->size) {
109 by Suren A. Chilingaryan
Improvements of DMA engine
179
	if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0)
180
	    pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize); 
181
	return -PCILIB_ERROR_TOOBIG;
45 by root
North West Logick DMA implementation
182
    }
183
    
184
    memcpy(ctx->data + ctx->pos, buf, bufsize);
185
    ctx->pos += bufsize;
186
109 by Suren A. Chilingaryan
Improvements of DMA engine
187
    if (flags & PCILIB_DMA_FLAG_EOP) {
188
	if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) {
117 by Suren A. Chilingaryan
new event architecture, first trial
189
	    if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT;
190
	    else return PCILIB_STREAMING_CONTINUE;
109 by Suren A. Chilingaryan
Improvements of DMA engine
191
	}
117 by Suren A. Chilingaryan
new event architecture, first trial
192
	return PCILIB_STREAMING_STOP;
109 by Suren A. Chilingaryan
Improvements of DMA engine
193
    }
117 by Suren A. Chilingaryan
new event architecture, first trial
194
    
195
    return PCILIB_STREAMING_REQ_FRAGMENT;
45 by root
North West Logick DMA implementation
196
}
197
198
static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
69 by Suren A. Chilingaryan
Add timeout to pcilib_skip_dma
199
    struct timeval *tv = (struct timeval*)arg;
200
    struct timeval cur;
201
    
202
    if (tv) {
203
	gettimeofday(&cur, NULL);
117 by Suren A. Chilingaryan
new event architecture, first trial
204
	if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP;
69 by Suren A. Chilingaryan
Add timeout to pcilib_skip_dma
205
    }
206
    
117 by Suren A. Chilingaryan
new event architecture, first trial
207
    return PCILIB_STREAMING_REQ_PACKET;
45 by root
North West Logick DMA implementation
208
}
209
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
210
int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
45 by root
North West Logick DMA implementation
211
    int err; 
212
213
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
214
    if (!info) {
215
	pcilib_error("DMA is not supported by the device");
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
216
	return PCILIB_ERROR_NOTSUPPORTED;
45 by root
North West Logick DMA implementation
217
    }
218
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
219
    if (!ctx->model_info.dma_api) {
45 by root
North West Logick DMA implementation
220
	pcilib_error("DMA Engine is not configured in the current model");
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
221
	return PCILIB_ERROR_NOTAVAILABLE;
45 by root
North West Logick DMA implementation
222
    }
223
    
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
224
    if (!ctx->model_info.dma_api->stream) {
45 by root
North West Logick DMA implementation
225
	pcilib_error("The DMA read is not supported by configured DMA engine");
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
226
	return PCILIB_ERROR_NOTSUPPORTED;
45 by root
North West Logick DMA implementation
227
    }
228
    
229
    if (!info->engines[dma]) {
230
	pcilib_error("The DMA engine (%i) is not supported by device", dma);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
231
	return PCILIB_ERROR_NOTAVAILABLE;
45 by root
North West Logick DMA implementation
232
    }
233
234
    if (info->engines[dma]->direction&PCILIB_DMA_FROM_DEVICE == 0) {
235
	pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
236
	return PCILIB_ERROR_NOTSUPPORTED;
45 by root
North West Logick DMA implementation
237
    }
238
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
239
    return ctx->model_info.dma_api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr);
45 by root
North West Logick DMA implementation
240
}
241
109 by Suren A. Chilingaryan
Improvements of DMA engine
242
int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) {
243
    int err; 
244
245
    pcilib_dma_read_callback_context_t opts = {
246
	size, buf, 0, flags
247
    };
248
    
249
    err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts);
250
    if (read_bytes) *read_bytes = opts.pos;
251
    return err;
252
}
253
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
254
int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) {
45 by root
North West Logick DMA implementation
255
    int err; 
256
257
    pcilib_dma_read_callback_context_t opts = {
109 by Suren A. Chilingaryan
Improvements of DMA engine
258
	size, buf, 0, 0
45 by root
North West Logick DMA implementation
259
    };
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
260
    
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
261
    err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts);
262
    if (read_bytes) *read_bytes = opts.pos;
263
    return err;
45 by root
North West Logick DMA implementation
264
}
265
109 by Suren A. Chilingaryan
Improvements of DMA engine
266
49 by Suren A. Chilingaryan
A bit of renaming
267
int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) {
61 by Suren A. Chilingaryan
Few fixes
268
    int err;
69 by Suren A. Chilingaryan
Add timeout to pcilib_skip_dma
269
    struct timeval tv, cur;
270
271
    gettimeofday(&tv, NULL);
272
    tv.tv_usec += PCILIB_DMA_SKIP_TIMEOUT;
273
    tv.tv_sec += tv.tv_usec / 1000000;
274
    tv.tv_usec += tv.tv_usec % 1000000;
275
    
45 by root
North West Logick DMA implementation
276
    do {
277
	    // IMMEDIATE timeout is not working properly, so default is set
69 by Suren A. Chilingaryan
Add timeout to pcilib_skip_dma
278
	err = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, &tv);
279
	gettimeofday(&cur, NULL);
280
    } while ((!err)&&((cur.tv_sec < tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec < tv.tv_usec))));
281
282
    if ((cur.tv_sec > tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec > tv.tv_usec))) return PCILIB_ERROR_TIMEOUT;
45 by root
North West Logick DMA implementation
283
    
284
    return 0;
285
}
286
287
62 by Suren A. Chilingaryan
Suppport DMA modes in console application (not functional yet)
288
int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) {
45 by root
North West Logick DMA implementation
289
    int err; 
290
291
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
292
    if (!info) {
293
	pcilib_error("DMA is not supported by the device");
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
294
	return PCILIB_ERROR_NOTSUPPORTED;
45 by root
North West Logick DMA implementation
295
    }
296
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
297
    if (!ctx->model_info.dma_api) {
45 by root
North West Logick DMA implementation
298
	pcilib_error("DMA Engine is not configured in the current model");
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
299
	return PCILIB_ERROR_NOTAVAILABLE;
45 by root
North West Logick DMA implementation
300
    }
301
    
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
302
    if (!ctx->model_info.dma_api->push) {
45 by root
North West Logick DMA implementation
303
	pcilib_error("The DMA write is not supported by configured DMA engine");
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
304
	return PCILIB_ERROR_NOTSUPPORTED;
45 by root
North West Logick DMA implementation
305
    }
306
    
307
    if (!info->engines[dma]) {
308
	pcilib_error("The DMA engine (%i) is not supported by device", dma);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
309
	return PCILIB_ERROR_NOTAVAILABLE;
45 by root
North West Logick DMA implementation
310
    }
311
312
    if (info->engines[dma]->direction&PCILIB_DMA_TO_DEVICE == 0) {
313
	pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
314
	return PCILIB_ERROR_NOTSUPPORTED;
45 by root
North West Logick DMA implementation
315
    }
316
    
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
317
    return ctx->model_info.dma_api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written);
45 by root
North West Logick DMA implementation
318
}
319
320
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
321
int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes) {
61 by Suren A. Chilingaryan
Few fixes
322
    return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP|PCILIB_DMA_FLAG_WAIT, PCILIB_DMA_TIMEOUT, buf, written_bytes);
45 by root
North West Logick DMA implementation
323
}
324
49 by Suren A. Chilingaryan
A bit of renaming
325
double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
45 by root
North West Logick DMA implementation
326
    int err; 
327
328
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
329
    if (!info) {
330
	pcilib_error("DMA is not supported by the device");
331
	return 0;
332
    }
333
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
334
    if (!ctx->model_info.dma_api) {
45 by root
North West Logick DMA implementation
335
	pcilib_error("DMA Engine is not configured in the current model");
336
	return -1;
337
    }
338
    
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
339
    if (!ctx->model_info.dma_api->benchmark) {
45 by root
North West Logick DMA implementation
340
	pcilib_error("The DMA benchmark is not supported by configured DMA engine");
341
	return -1;
342
   }
343
    
344
    if (!info->engines[dma]) {
345
	pcilib_error("The DMA engine (%i) is not supported by device", dma);
346
	return -1;
347
    }
348
54 by Suren A. Chilingaryan
Support dynamic registers, support register offsets and multiregisters (bitmasks), list NWL DMA registers
349
    return ctx->model_info.dma_api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction);
45 by root
North West Logick DMA implementation
350
}
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
351
352
int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
353
    int err; 
354
355
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
356
    if (!info) {
357
	pcilib_error("DMA is not supported by the device");
358
	return 0;
359
    }
360
361
    if (!ctx->model_info.dma_api) {
362
	pcilib_error("DMA Engine is not configured in the current model");
363
	return -1;
364
    }
365
    
366
    if (!ctx->model_info.dma_api->status) {
367
	memset(status, 0, sizeof(pcilib_dma_engine_status_t));
368
	return -1;
369
   }
370
    
371
    if (!info->engines[dma]) {
372
	pcilib_error("The DMA engine (%i) is not supported by device", dma);
373
	return -1;
374
    }
375
376
    return ctx->model_info.dma_api->status(ctx->dma_ctx, dma, status, n_buffers, buffers);
377
378
}