/alps/ipecamera

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/ipecamera

« back to all changes in this revision

Viewing changes to dma/ipe.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-04-27 00:28:57 UTC
  • Revision ID: csa@suren.me-20150427002857-82fk6r3e8rfgy4wr
First stand-alone ipecamera implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define _PCILIB_DMA_IPE_C
2
 
#define _BSD_SOURCE
3
 
 
4
 
#include <stdio.h>
5
 
#include <stdlib.h>
6
 
#include <string.h>
7
 
#include <unistd.h>
8
 
#include <sys/time.h>
9
 
#include <arpa/inet.h>
10
 
 
11
 
#include "pci.h"
12
 
#include "pcilib.h"
13
 
#include "error.h"
14
 
#include "tools.h"
15
 
 
16
 
#include "ipe.h"
17
 
#include "ipe_private.h"
18
 
#include "ipe_registers.h"
19
 
 
20
 
 
21
 
#define WR(addr, value) { *(uint32_t*)(ctx->base_addr + addr) = value; }
22
 
#define RD(addr, value) { value = *(uint32_t*)(ctx->base_addr + addr); }
23
 
 
24
 
 
25
 
pcilib_dma_context_t *dma_ipe_init(pcilib_t *pcilib, pcilib_dma_modification_t type, void *arg) {
26
 
    int err = 0;
27
 
    
28
 
    pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib);
29
 
 
30
 
    ipe_dma_t *ctx = malloc(sizeof(ipe_dma_t));
31
 
 
32
 
    if (ctx) {
33
 
        memset(ctx, 0, sizeof(ipe_dma_t));
34
 
        ctx->pcilib = pcilib;
35
 
//      ctx->mode64 = 1;
36
 
        
37
 
        memset(ctx->engine, 0, 2 * sizeof(pcilib_dma_engine_description_t));
38
 
        ctx->engine[0].addr = 0;
39
 
        ctx->engine[0].type = PCILIB_DMA_TYPE_PACKET;
40
 
        ctx->engine[0].direction = PCILIB_DMA_FROM_DEVICE;
41
 
        ctx->engine[0].addr_bits = 32;
42
 
        pcilib_set_dma_engine_description(pcilib, 0, &ctx->engine[0]);
43
 
        pcilib_set_dma_engine_description(pcilib, 1, NULL);
44
 
 
45
 
        pcilib_register_bank_t dma_bank = pcilib_find_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA);
46
 
        if (dma_bank == PCILIB_REGISTER_BANK_INVALID) {
47
 
            free(ctx);
48
 
            pcilib_error("DMA Register Bank could not be found");
49
 
            return NULL;
50
 
        }
51
 
 
52
 
        ctx->dma_bank = model_info->banks + dma_bank;
53
 
        ctx->base_addr = pcilib_resolve_register_address(pcilib, ctx->dma_bank->bar, ctx->dma_bank->read_addr);
54
 
 
55
 
        err = pcilib_add_registers(ctx->pcilib, 0, ipe_dma_registers);
56
 
        if (err) {
57
 
            free(ctx);
58
 
            pcilib_error("Error adding DMA registers");
59
 
            return NULL;
60
 
        }
61
 
    }
62
 
 
63
 
    return (pcilib_dma_context_t*)ctx;
64
 
}
65
 
 
66
 
void  dma_ipe_free(pcilib_dma_context_t *vctx) {
67
 
    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
68
 
 
69
 
    if (ctx) {
70
 
        dma_ipe_stop(vctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT);
71
 
        free(ctx);
72
 
    }
73
 
}
74
 
 
75
 
 
76
 
int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
77
 
    size_t i;
78
 
 
79
 
    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
80
 
 
81
 
    int preserve = 0;
82
 
    pcilib_kmem_flags_t kflags;
83
 
    pcilib_kmem_reuse_state_t reuse_desc, reuse_pages;
84
 
 
85
 
    volatile void *desc_va;
86
 
    volatile uint32_t *last_written_addr_ptr;
87
 
 
88
 
    pcilib_register_value_t value;
89
 
    
90
 
    uint32_t address64;
91
 
    
92
 
 
93
 
    if (dma == PCILIB_DMA_ENGINE_INVALID) return 0;
94
 
    else if (dma > 1) return PCILIB_ERROR_INVALID_BANK;
95
 
 
96
 
    if (!ctx->started) ctx->started = 1;
97
 
 
98
 
    if (flags&PCILIB_DMA_FLAG_PERSISTENT) ctx->preserve = 1;
99
 
 
100
 
    if (ctx->pages) return 0;
101
 
    
102
 
    kflags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(ctx->preserve?PCILIB_KMEM_FLAG_PERSISTENT:0);
103
 
    pcilib_kmem_handle_t *desc = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags);
104
 
    pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, IPEDMA_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags);
105
 
 
106
 
    if (!desc||!pages) {
107
 
        if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages, 0);
108
 
        if (desc) pcilib_free_kernel_memory(ctx->pcilib, desc, 0);
109
 
        return PCILIB_ERROR_MEMORY;
110
 
    }
111
 
    reuse_desc = pcilib_kmem_is_reused(ctx->pcilib, desc);
112
 
    reuse_pages = pcilib_kmem_is_reused(ctx->pcilib, pages);
113
 
 
114
 
    if (reuse_desc == reuse_pages) {
115
 
        if (reuse_desc & PCILIB_KMEM_REUSE_PARTIAL) pcilib_warning("Inconsistent DMA buffers are found (only part of required buffers is available), reinitializing...");
116
 
        else if (reuse_desc & PCILIB_KMEM_REUSE_REUSED) {
117
 
            if ((reuse_desc & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing...");
118
 
            else if ((reuse_desc & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing...");
119
 
            else {
120
 
#ifndef IPEDMA_BUG_DMARD
121
 
                RD(IPEDMA_REG_PAGE_COUNT, value);
122
 
 
123
 
                if (value != IPEDMA_DMA_PAGES) pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers (%lu) does not match current request (%lu)), reinitializing...", value + 1, IPEDMA_DMA_PAGES);
124
 
                else
125
 
#endif /* IPEDMA_BUG_DMARD */
126
 
                    preserve = 1;
127
 
            }
128
 
        }
129
 
    } else pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing....");
130
 
 
131
 
    desc_va = pcilib_kmem_get_ua(ctx->pcilib, desc);
132
 
    if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
133
 
    else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
134
 
 
135
 
    if (preserve) {
136
 
        ctx->reused = 1;
137
 
        ctx->preserve = 1;
138
 
        
139
 
 
140
 
//      usleep(100000);
141
 
 
142
 
            // Detect the current state of DMA engine
143
 
#ifdef IPEDMA_BUG_DMARD
144
 
        FILE *f = fopen("/tmp/pcitool_lastread", "r");
145
 
        if (!f) pcilib_error("Can't read current status");
146
 
        fread(&value, 1, sizeof(pcilib_register_value_t), f);
147
 
        fclose(f);
148
 
#else /* IPEDMA_BUG_DMARD */
149
 
        RD(IPEDMA_REG_LAST_READ, value);
150
 
            // Numbered from 1 in FPGA
151
 
        value--;
152
 
#endif /* IPEDMA_BUG_DMARD */
153
 
 
154
 
        ctx->last_read = value;
155
 
    } else {
156
 
        ctx->reused = 0;
157
 
 
158
 
            // Disable DMA
159
 
        WR(IPEDMA_REG_CONTROL, 0x0);
160
 
        usleep(100000);
161
 
        
162
 
            // Reset DMA engine
163
 
        WR(IPEDMA_REG_RESET, 0x1);
164
 
        usleep(100000);
165
 
        WR(IPEDMA_REG_RESET, 0x0);
166
 
        usleep(100000);
167
 
 
168
 
#ifndef IPEDMA_BUG_DMARD
169
 
            // Verify PCIe link status
170
 
        RD(IPEDMA_REG_RESET, value);
171
 
        if (value != 0x14031700) pcilib_warning("PCIe is not ready, code is %lx", value);
172
 
#endif /* IPEDMA_BUG_DMARD */
173
 
 
174
 
            // Enable 64 bit addressing and configure TLP and PACKET sizes (40 bit mode can be used with big pre-allocated buffers later)
175
 
        if (ctx->mode64) address64 = 0x8000 | (0<<24);
176
 
        else address64 = 0;
177
 
        
178
 
        WR(IPEDMA_REG_TLP_SIZE,  address64 | IPEDMA_TLP_SIZE);
179
 
        WR(IPEDMA_REG_TLP_COUNT, IPEDMA_PAGE_SIZE / (4 * IPEDMA_TLP_SIZE * IPEDMA_CORES));
180
 
 
181
 
            // Setting progress register threshold
182
 
        WR(IPEDMA_REG_UPDATE_THRESHOLD, IPEDMA_DMA_PROGRESS_THRESHOLD);
183
 
        
184
 
            // Reseting configured DMA pages
185
 
        WR(IPEDMA_REG_PAGE_COUNT, 0);
186
 
        
187
 
            // Setting current read position and configuring progress register
188
 
        WR(IPEDMA_REG_LAST_READ, IPEDMA_DMA_PAGES);
189
 
        WR(IPEDMA_REG_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->pcilib, desc, 0));
190
 
 
191
 
            // Instructing DMA engine that writting should start from the first DMA page
192
 
        *last_written_addr_ptr = 0;//htonl(pcilib_kmem_get_block_ba(ctx->pcilib, pages, IPEDMA_DMA_PAGES - 1));
193
 
 
194
 
        
195
 
        for (i = 0; i < IPEDMA_DMA_PAGES; i++) {
196
 
            uintptr_t bus_addr_check, bus_addr = pcilib_kmem_get_block_ba(ctx->pcilib, pages, i);
197
 
            WR(IPEDMA_REG_PAGE_ADDR, bus_addr);
198
 
            if (bus_addr%4096) printf("Bad address %lu: %lx\n", i, bus_addr);
199
 
            
200
 
            RD(IPEDMA_REG_PAGE_ADDR, bus_addr_check);
201
 
            if (bus_addr_check != bus_addr) {
202
 
                pcilib_error("Written (%x) and read (%x) bus addresses does not match\n", bus_addr, bus_addr_check);
203
 
            }
204
 
            
205
 
            usleep(1000);
206
 
        }
207
 
        
208
 
            // Enable DMA
209
 
        WR(IPEDMA_REG_CONTROL, 0x1);
210
 
        
211
 
        ctx->last_read = IPEDMA_DMA_PAGES - 1;
212
 
 
213
 
#ifdef IPEDMA_BUG_DMARD
214
 
        FILE *f = fopen("/tmp/pcitool_lastread", "w");
215
 
        if (!f) pcilib_error("Can't write current status");
216
 
        value = ctx->last_read;
217
 
        fwrite(&value, 1, sizeof(pcilib_register_value_t), f);
218
 
        fclose(f);
219
 
#endif /* IPEDMA_BUG_DMARD */
220
 
    }
221
 
 
222
 
//    ctx->last_read_addr = htonl(pcilib_kmem_get_block_ba(ctx->pcilib, pages, ctx->last_read));
223
 
    ctx->last_read_addr = pcilib_kmem_get_block_ba(ctx->pcilib, pages, ctx->last_read);
224
 
 
225
 
 
226
 
    ctx->desc = desc;
227
 
    ctx->pages = pages;
228
 
    ctx->page_size = pcilib_kmem_get_block_size(ctx->pcilib, pages, 0);;
229
 
    ctx->ring_size = IPEDMA_DMA_PAGES;
230
 
 
231
 
    return 0;
232
 
}
233
 
 
234
 
int dma_ipe_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
235
 
    pcilib_kmem_flags_t kflags;
236
 
 
237
 
    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
238
 
 
239
 
    if (!ctx->started) return 0;
240
 
 
241
 
    if ((dma != PCILIB_DMA_ENGINE_INVALID)&&(dma > 1)) return PCILIB_ERROR_INVALID_BANK;
242
 
 
243
 
            // ignoring previous setting if flag specified
244
 
    if (flags&PCILIB_DMA_FLAG_PERSISTENT) {
245
 
        ctx->preserve = 0;
246
 
    }
247
 
 
248
 
    if (ctx->preserve) {
249
 
        kflags = PCILIB_KMEM_FLAG_REUSE;
250
 
    } else {
251
 
        kflags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT;
252
 
 
253
 
        ctx->started  = 0;
254
 
 
255
 
            // Disable DMA
256
 
        WR(IPEDMA_REG_CONTROL, 0);
257
 
        usleep(100000);
258
 
        
259
 
            // Reset DMA engine
260
 
        WR(IPEDMA_REG_RESET, 0x1);
261
 
        usleep(100000);
262
 
        WR(IPEDMA_REG_RESET, 0x0);
263
 
        usleep(100000);
264
 
 
265
 
            // Reseting configured DMA pages
266
 
        WR(IPEDMA_REG_PAGE_COUNT, 0);
267
 
        usleep(100000);
268
 
    }
269
 
 
270
 
        // Clean buffers
271
 
    if (ctx->desc) {
272
 
        pcilib_free_kernel_memory(ctx->pcilib, ctx->desc, kflags);
273
 
        ctx->desc = NULL;
274
 
    }
275
 
 
276
 
    if (ctx->pages) {
277
 
        pcilib_free_kernel_memory(ctx->pcilib, ctx->pages, kflags);
278
 
        ctx->pages = NULL;
279
 
    }
280
 
 
281
 
    return 0;
282
 
}
283
 
 
284
 
 
285
 
int dma_ipe_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
286
 
    size_t i;
287
 
    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
288
 
 
289
 
    void *desc_va = (void*)pcilib_kmem_get_ua(ctx->pcilib, ctx->desc);
290
 
    uint32_t *last_written_addr_ptr;
291
 
    uint32_t last_written_addr;
292
 
 
293
 
    if (!status) return -1;
294
 
 
295
 
    if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
296
 
    else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
297
 
 
298
 
    last_written_addr = *last_written_addr_ptr;
299
 
 
300
 
    status->started = ctx->started;
301
 
    status->ring_size = ctx->ring_size;
302
 
    status->buffer_size = ctx->page_size;
303
 
 
304
 
        // For simplicity, we keep last_read here, and fix in the end
305
 
    status->ring_tail = ctx->last_read;
306
 
 
307
 
        // Find where the ring head is actually are
308
 
    for (i = 0; i < ctx->ring_size; i++) {
309
 
        uintptr_t bus_addr = pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, i);
310
 
 
311
 
        if (bus_addr == last_written_addr) {
312
 
            status->ring_head = i;
313
 
            break;
314
 
        }
315
 
    }
316
 
 
317
 
    if (i == ctx->ring_size) {
318
 
        if (last_written_addr) {
319
 
            pcilib_warning("DMA is in unknown state, last_written_addr does not correspond any of available buffers");
320
 
            return -1;
321
 
        }
322
 
        status->ring_head = 0;
323
 
        status->ring_tail = 0;
324
 
    }
325
 
 
326
 
    if (n_buffers > ctx->ring_size) n_buffers = ctx->ring_size;
327
 
 
328
 
    if (buffers) {
329
 
        memset(buffers, 0, n_buffers * sizeof(pcilib_dma_buffer_status_t));
330
 
        if (status->ring_head >= status->ring_tail) {
331
 
            for (i = status->ring_tail + 1; (i <= status->ring_head)&&(i < n_buffers); i++) {
332
 
                buffers[i].used = 1;
333
 
                buffers[i].size = ctx->page_size;
334
 
                buffers[i].first = 1;
335
 
                buffers[i].last = 1;
336
 
            }
337
 
        } else {
338
 
            for (i = 0; (i <= status->ring_head)&&(i < n_buffers); i++) {
339
 
                buffers[i].used = 1;
340
 
                buffers[i].size = ctx->page_size;
341
 
                buffers[i].first = 1;
342
 
                buffers[i].last = 1;
343
 
            } 
344
 
 
345
 
            for (i = status->ring_tail + 1; (i < status->ring_size)&&(i < n_buffers); i++) {
346
 
                buffers[i].used = 1;
347
 
                buffers[i].size = ctx->page_size;
348
 
                buffers[i].first = 1;
349
 
                buffers[i].last = 1;
350
 
            }
351
 
        }
352
 
    }
353
 
 
354
 
        // We actually keep last_read in the ring_tail, so need to increase
355
 
    if (status->ring_tail != status->ring_head) {
356
 
        status->ring_tail++;
357
 
        if (status->ring_tail == status->ring_size) status->ring_tail = 0;
358
 
    }
359
 
 
360
 
    return 0;
361
 
}
362
 
 
363
 
int dma_ipe_stream_read(pcilib_dma_context_t *vctx, 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) {
364
 
    int err, ret = PCILIB_STREAMING_REQ_PACKET;
365
 
 
366
 
 
367
 
    pcilib_timeout_t wait = 0;
368
 
    struct timeval start, cur;
369
 
 
370
 
    volatile void *desc_va;
371
 
    volatile uint32_t *last_written_addr_ptr;
372
 
    volatile uint32_t *empty_detected_ptr;
373
 
 
374
 
    pcilib_dma_flags_t packet_flags = PCILIB_DMA_FLAG_EOP;
375
 
 
376
 
#ifdef IPEDMA_BUG_DMARD
377
 
    pcilib_register_value_t value;
378
 
#endif /* IPEDMA_BUG_DMARD */
379
 
 
380
 
    size_t cur_read;
381
 
 
382
 
    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
383
 
 
384
 
    err = dma_ipe_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
385
 
    if (err) return err;
386
 
 
387
 
    desc_va = (void*)pcilib_kmem_get_ua(ctx->pcilib, ctx->desc);
388
 
 
389
 
    if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
390
 
    else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
391
 
 
392
 
    empty_detected_ptr = last_written_addr_ptr - 2;
393
 
 
394
 
    do {
395
 
        switch (ret&PCILIB_STREAMING_TIMEOUT_MASK) {
396
 
            case PCILIB_STREAMING_CONTINUE: 
397
 
                    // Hardware indicates that there is no more data pending and we can safely stop if there is no data in the kernel buffers already
398
 
#ifdef IPEDMA_SUPPORT_EMPTY_DETECTED
399
 
                if (*empty_detected_ptr)
400
 
                    wait = 0;
401
 
                else
402
 
#endif /* IPEDMA_SUPPORT_EMPTY_DETECTED */
403
 
                    wait = IPEDMA_DMA_TIMEOUT; 
404
 
            break;
405
 
            case PCILIB_STREAMING_WAIT: 
406
 
                wait = (timeout > IPEDMA_DMA_TIMEOUT)?timeout:IPEDMA_DMA_TIMEOUT;
407
 
            break;
408
 
//          case PCILIB_STREAMING_CHECK: wait = 0; break;
409
 
        }
410
 
 
411
 
#ifdef IPEDMA_DEBUG
412
 
        printf("Waiting for data: %u (last read) 0x%x (last read addr) 0x%x (last_written)\n", ctx->last_read, ctx->last_read_addr, *last_written_addr_ptr);
413
 
#endif /* IPEDMA_DEBUG */
414
 
 
415
 
        gettimeofday(&start, NULL);
416
 
        memcpy(&cur, &start, sizeof(struct timeval));
417
 
        while (((*last_written_addr_ptr == 0)||(ctx->last_read_addr == (*last_written_addr_ptr)))&&((wait == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < wait))) {
418
 
            usleep(10);
419
 
#ifdef IPEDMA_SUPPORT_EMPTY_DETECTED
420
 
            if ((ret != PCILIB_STREAMING_REQ_PACKET)&&(*empty_detected_ptr)) break;
421
 
#endif /* IPEDMA_SUPPORT_EMPTY_DETECTED */
422
 
            gettimeofday(&cur, NULL);
423
 
        }
424
 
        
425
 
            // Failing out if we exited on timeout
426
 
        if ((ctx->last_read_addr == (*last_written_addr_ptr))||(*last_written_addr_ptr == 0)) {
427
 
#ifdef IPEDMA_SUPPORT_EMPTY_DETECTED
428
 
# ifdef IPEDMA_DEBUG
429
 
            if ((wait)&&(*last_written_addr_ptr)&&(!*empty_detected_ptr))
430
 
                pcilib_warning("The empty_detected flag is not set, but no data arrived within %lu us\n", wait);
431
 
# endif /* IPEDMA_DEBUG */
432
 
#endif /* IPEDMA_SUPPORT_EMPTY_DETECTED */
433
 
            return (ret&PCILIB_STREAMING_FAIL)?PCILIB_ERROR_TIMEOUT:0;
434
 
        }
435
 
 
436
 
            // Getting next page to read
437
 
        cur_read = ctx->last_read + 1;
438
 
        if (cur_read == ctx->ring_size) cur_read = 0;
439
 
 
440
 
#ifdef IPEDMA_DEBUG
441
 
        printf("Reading: %u (last read) 0x%x (last read addr) 0x%x (last_written)\n", cur_read, ctx->last_read_addr, *last_written_addr_ptr);
442
 
#endif /* IPEDMA_DEBUG */
443
 
 
444
 
#ifdef IPEDMA_DETECT_PACKETS
445
 
        if ((*empty_detected_ptr)&&(pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, cur_read) == (*last_written_addr_ptr))) packet_flags = PCILIB_DMA_FLAG_EOP;
446
 
        else packet_flags = 0;
447
 
#endif /* IPEDMA_DETECT_PACKETS */
448
 
        
449
 
        pcilib_kmem_sync_block(ctx->pcilib, ctx->pages, PCILIB_KMEM_SYNC_FROMDEVICE, cur_read);
450
 
        void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, ctx->pages, cur_read);
451
 
        ret = cb(cbattr, packet_flags, ctx->page_size, buf);
452
 
        if (ret < 0) return -ret;
453
 
        
454
 
//      DS: Fixme, it looks like we can avoid calling this for the sake of performance
455
 
//      pcilib_kmem_sync_block(ctx->pcilib, ctx->pages, PCILIB_KMEM_SYNC_TODEVICE, cur_read);
456
 
 
457
 
            // Numbered from 1
458
 
        WR(IPEDMA_REG_LAST_READ, cur_read + 1);
459
 
 
460
 
        ctx->last_read = cur_read;
461
 
//      ctx->last_read_addr = htonl(pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, cur_read));
462
 
        ctx->last_read_addr = pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, cur_read);
463
 
 
464
 
#ifdef IPEDMA_BUG_DMARD
465
 
        FILE *f = fopen("/tmp/pcitool_lastread", "w");
466
 
        if (!f) pcilib_error("Can't write current status");
467
 
        value = cur_read;
468
 
        fwrite(&value, 1, sizeof(pcilib_register_value_t), f);
469
 
        fclose(f);
470
 
#endif /* IPEDMA_BUG_DMARD */
471
 
 
472
 
    } while (ret);
473
 
 
474
 
    return 0;
475
 
}
476
 
 
477
 
double dma_ipe_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
478
 
    int err = 0;
479
 
 
480
 
    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
481
 
 
482
 
    int iter;
483
 
    size_t us = 0;
484
 
    struct timeval start, cur;
485
 
    
486
 
    void *buf;
487
 
    size_t bytes, rbytes;
488
 
 
489
 
    if ((direction == PCILIB_DMA_TO_DEVICE)||(direction == PCILIB_DMA_BIDIRECTIONAL)) return -1.;
490
 
 
491
 
    if ((dma != PCILIB_DMA_ENGINE_INVALID)&&(dma > 1)) return -1.;
492
 
 
493
 
    err = dma_ipe_start(vctx, 0, PCILIB_DMA_FLAGS_DEFAULT);
494
 
    if (err) return err;
495
 
 
496
 
    WR(IPEDMA_REG_CONTROL, 0x0);
497
 
 
498
 
    err = pcilib_skip_dma(ctx->pcilib, 0);
499
 
    if (err) {
500
 
        pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine");
501
 
        return -1;
502
 
    }
503
 
 
504
 
    if (size%IPEDMA_PAGE_SIZE) size = (1 + size / IPEDMA_PAGE_SIZE) * IPEDMA_PAGE_SIZE;
505
 
 
506
 
        // Allocate memory and prepare data
507
 
    buf = malloc(size);
508
 
    if (!buf) return -1;
509
 
 
510
 
    for (iter = 0; iter < iterations; iter++) {
511
 
        gettimeofday(&start, NULL);
512
 
 
513
 
            // Starting DMA
514
 
        WR(IPEDMA_REG_CONTROL, 0x1);
515
 
        
516
 
        for (bytes = 0; bytes < size; bytes += rbytes) {
517
 
            err = pcilib_read_dma(ctx->pcilib, 0, addr, size - bytes, buf + bytes, &rbytes);
518
 
            if (err) {
519
 
                pcilib_error("Can't read data from DMA, error %i", err);
520
 
                return -1;
521
 
            }
522
 
        }
523
 
 
524
 
            // Stopping DMA
525
 
        WR(IPEDMA_REG_CONTROL, 0x0);
526
 
        if (err) break;
527
 
        
528
 
        gettimeofday(&cur, NULL);
529
 
        us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec));
530
 
            
531
 
        err = pcilib_skip_dma(ctx->pcilib, 0);
532
 
        if (err) {
533
 
            pcilib_error("Can't start iteration, devices continuously writes unexpected data using DMA engine");
534
 
            break;
535
 
        }
536
 
    }
537
 
 
538
 
    free(buf);
539
 
 
540
 
    return err?-1:((1. * size * iterations * 1000000) / (1024. * 1024. * us));
541
 
}