/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera

« back to all changes in this revision

Viewing changes to dma/nwl_loopback.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 _BSD_SOURCE
2
 
#include <stdio.h>
3
 
#include <stdlib.h>
4
 
#include <string.h>
5
 
#include <unistd.h>
6
 
#include <sys/time.h>
7
 
 
8
 
#include "pci.h"
9
 
#include "pcilib.h"
10
 
#include "error.h"
11
 
#include "tools.h"
12
 
#include "nwl_private.h"
13
 
 
14
 
#include "nwl_defines.h"
15
 
 
16
 
#define NWL_BUG_EXTRA_DATA
17
 
 
18
 
 
19
 
int dma_nwl_start_loopback(nwl_dma_t *ctx,  pcilib_dma_direction_t direction, size_t packet_size) {
20
 
    uint32_t val;
21
 
 
22
 
    ctx->loopback_started = 1;
23
 
    dma_nwl_stop_loopback(ctx);
24
 
    
25
 
    val = packet_size;
26
 
    nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS);
27
 
 
28
 
    if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) {
29
 
        switch (direction) {
30
 
          case PCILIB_DMA_BIDIRECTIONAL:
31
 
            val = LOOPBACK;
32
 
            nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
33
 
            break;
34
 
          case PCILIB_DMA_TO_DEVICE:
35
 
            return -1;
36
 
          case PCILIB_DMA_FROM_DEVICE:
37
 
            val = PKTGENR;
38
 
            nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
39
 
            break;
40
 
        }
41
 
    }
42
 
 
43
 
    ctx->loopback_started = 1;
44
 
        
45
 
    return 0;
46
 
}
47
 
 
48
 
int dma_nwl_stop_loopback(nwl_dma_t *ctx) {
49
 
    uint32_t val = 0;
50
 
    
51
 
    if (!ctx->loopback_started) return 0;
52
 
 
53
 
        /* Stop in any case, otherwise we can have problems in benchmark due to
54
 
        engine initialized in previous run, and benchmark is only actual usage.
55
 
        Otherwise, we should detect current loopback status during initialization */
56
 
 
57
 
    if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) {
58
 
        nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
59
 
        nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
60
 
    }
61
 
    
62
 
    ctx->loopback_started = 0;
63
 
    
64
 
    return 0;
65
 
}
66
 
 
67
 
double dma_nwl_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) {
68
 
    int iter, i;
69
 
    int err;
70
 
    size_t bytes, rbytes;
71
 
    uint32_t *buf, *cmp;
72
 
    const char *error = NULL;
73
 
    size_t packet_size, blocks;    
74
 
 
75
 
    size_t us = 0;
76
 
    struct timeval start, cur;
77
 
 
78
 
    nwl_dma_t *ctx = (nwl_dma_t*)vctx;
79
 
 
80
 
    pcilib_dma_engine_t readid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_FROM_DEVICE, dma);
81
 
    pcilib_dma_engine_t writeid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_TO_DEVICE, dma);
82
 
 
83
 
    if (size%sizeof(uint32_t)) size = 1 + size / sizeof(uint32_t);
84
 
    else size /= sizeof(uint32_t);
85
 
 
86
 
        // Not supported
87
 
    if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) {
88
 
        if (direction == PCILIB_DMA_TO_DEVICE) return -1.;
89
 
    }
90
 
//    else if ((direction == PCILIB_DMA_FROM_DEVICE)&&(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) return -1.;
91
 
 
92
 
        // Stop Generators and drain old data
93
 
    if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx);
94
 
//    dma_nwl_stop_engine(ctx, readid); // DS: replace with something better
95
 
 
96
 
    __sync_synchronize();
97
 
 
98
 
    err = pcilib_skip_dma(ctx->pcilib, readid);
99
 
    if (err) {
100
 
        pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine");
101
 
        return -1;
102
 
    }
103
 
 
104
 
#ifdef NWL_GENERATE_DMA_IRQ
105
 
    dma_nwl_enable_engine_irq(ctx, readid);
106
 
    dma_nwl_enable_engine_irq(ctx, writeid);
107
 
#endif /* NWL_GENERATE_DMA_IRQ */
108
 
 
109
 
    if (size * sizeof(uint32_t) > NWL_MAX_PACKET_SIZE) {
110
 
        packet_size = NWL_MAX_PACKET_SIZE;
111
 
        blocks = (size * sizeof(uint32_t)) / packet_size + (((size*sizeof(uint32_t))%packet_size)?1:0);
112
 
    } else {
113
 
        packet_size = size * sizeof(uint32_t);
114
 
        blocks = 1;
115
 
    }
116
 
 
117
 
    dma_nwl_start_loopback(ctx, direction, packet_size);
118
 
 
119
 
        // Allocate memory and prepare data
120
 
    buf = malloc(blocks * packet_size * sizeof(uint32_t));
121
 
    cmp = malloc(blocks * packet_size * sizeof(uint32_t));
122
 
    if ((!buf)||(!cmp)) {
123
 
        if (buf) free(buf);
124
 
        if (cmp) free(cmp);
125
 
        return -1;
126
 
    }
127
 
 
128
 
    if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) {
129
 
        pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e5);
130
 
        usleep(100000);
131
 
        pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1);
132
 
 
133
 
            // This way causes more problems with garbage
134
 
        //pcilib_write_register(ctx->pcilib, NULL, "control", 0x3e1);
135
 
    }
136
 
 
137
 
        // Benchmark
138
 
    for (iter = 0; iter < iterations; iter++) {
139
 
        memset(cmp, 0x13 + iter, size * sizeof(uint32_t));
140
 
 
141
 
        if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) {
142
 
            pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1);
143
 
        }
144
 
 
145
 
        if ((direction&PCILIB_DMA_TO_DEVICE)||(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) {
146
 
            memcpy(buf, cmp, size * sizeof(uint32_t));
147
 
 
148
 
            if (direction&PCILIB_DMA_TO_DEVICE) {
149
 
                gettimeofday(&start, NULL);
150
 
            }
151
 
            
152
 
            err = pcilib_write_dma(ctx->pcilib, writeid, addr, size * sizeof(uint32_t), buf, &bytes);
153
 
            if ((err)||(bytes != size * sizeof(uint32_t))) {
154
 
                error = "Write failed";
155
 
                break;
156
 
            }
157
 
            
158
 
            if (direction&PCILIB_DMA_TO_DEVICE) {
159
 
                // wait written
160
 
                if (direction == PCILIB_DMA_TO_DEVICE) {
161
 
                    dma_nwl_wait_completion(ctx, writeid, PCILIB_DMA_TIMEOUT);
162
 
                }
163
 
                gettimeofday(&cur, NULL);
164
 
                us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec));    
165
 
            }
166
 
        }
167
 
 
168
 
        if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) {
169
 
            pcilib_write_register(ctx->pcilib, NULL, "control", 0x3e1);
170
 
        }
171
 
 
172
 
        memset(buf, 0, size * sizeof(uint32_t));
173
 
 
174
 
        if (direction&PCILIB_DMA_FROM_DEVICE) {
175
 
            gettimeofday(&start, NULL);
176
 
        }
177
 
 
178
 
        for (i = 0, bytes = 0; i < blocks; i++) {
179
 
#ifdef NWL_BUG_EXTRA_DATA
180
 
            retry:
181
 
#endif
182
 
    
183
 
            err = pcilib_read_dma(ctx->pcilib, readid, addr, packet_size * sizeof(uint32_t), buf + (bytes>>2), &rbytes);
184
 
            if ((err)||(rbytes%sizeof(uint32_t))) {
185
 
                break;
186
 
            } 
187
 
#ifdef NWL_BUG_EXTRA_DATA
188
 
            else if (rbytes == 8) {
189
 
                goto retry;     
190
 
            }
191
 
#endif
192
 
            bytes += rbytes;
193
 
        }
194
 
 
195
 
        if (direction&PCILIB_DMA_FROM_DEVICE) {
196
 
            gettimeofday(&cur, NULL);
197
 
            us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec));
198
 
        }
199
 
#ifdef NWL_BUG_EXTRA_DATA
200
 
        if ((err)||((bytes != size * sizeof(uint32_t))&&((bytes - 8) != size * sizeof(uint32_t)))) {
201
 
#else
202
 
        if ((err)||(bytes != size * sizeof(uint32_t))) {
203
 
#endif
204
 
            printf("Expected: %zu bytes, but %zu read, error: %i\n", size * sizeof(uint32_t), bytes, err);
205
 
            error = "Read failed";
206
 
            break;
207
 
        }
208
 
        
209
 
#ifndef NWL_BUG_EXTRA_DATA
210
 
        if (direction == PCILIB_DMA_BIDIRECTIONAL) {
211
 
            if (memcmp(buf, cmp, size * sizeof(uint32_t))) {
212
 
                for (i = 0; i < size; i++)
213
 
                    if (buf[i] != cmp[i]) break;
214
 
                
215
 
                bytes = i;
216
 
                printf("Expected: *0x%lx, Written at dword %lu:", 0x13 + iter, bytes);
217
 
                for (; (i < size)&&(i < (bytes + 16)); i++) {
218
 
                    if (((i - bytes)%8)==0) printf("\n");
219
 
                    printf("% 10lx", buf[i]);
220
 
                }
221
 
                printf("\n");
222
 
                
223
 
                error = "Written and read values does not match";
224
 
                break;
225
 
            }
226
 
        }
227
 
#endif
228
 
    }
229
 
 
230
 
    if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) {
231
 
        pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1);
232
 
    }
233
 
 
234
 
    if (error) {
235
 
        pcilib_warning("%s at iteration %i, error: %i, bytes: %zu", error, iter, err, bytes);
236
 
    }
237
 
    
238
 
#ifdef NWL_GENERATE_DMA_IRQ
239
 
    dma_nwl_disable_engine_irq(ctx, writeid);
240
 
    dma_nwl_disable_engine_irq(ctx, readid);
241
 
#endif /* NWL_GENERATE_DMA_IRQ */
242
 
 
243
 
    dma_nwl_stop_loopback(ctx);
244
 
 
245
 
    __sync_synchronize();
246
 
    
247
 
    if (direction == PCILIB_DMA_FROM_DEVICE) {
248
 
        pcilib_skip_dma(ctx->pcilib, readid);
249
 
    }
250
 
    
251
 
    free(cmp);
252
 
    free(buf);
253
 
 
254
 
    return /*error?-1:*/(1. * size * sizeof(uint32_t) * iterations * 1000000) / (1024. * 1024. * us);
255
 
}