/alps/pcitool

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

« back to all changes in this revision

Viewing changes to dma/nwl_engine.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-04-20 20:01:04 UTC
  • Revision ID: csa@suren.me-20150420200104-b5xny65io8lvoz3w
Big redign of model structures

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
#include "pcilib.h"
11
11
#include "error.h"
12
12
#include "tools.h"
 
13
 
13
14
#include "nwl_private.h"
14
 
 
15
15
#include "nwl_defines.h"
16
 
 
17
16
#include "nwl_engine_buffers.h"
18
17
 
19
 
int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) {
 
18
int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_dma_engine_description_t *info, const char *base) {
20
19
    uint32_t val;
21
20
    
22
 
    info->base_addr = base;
23
 
    
24
21
    nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP);
25
22
 
26
23
    if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE;
27
24
    
28
 
    info->desc.addr = (val & DMA_ENG_NUMBER) >> DMA_ENG_NUMBER_SHIFT;
29
 
    if ((info->desc.addr > PCILIB_MAX_DMA_ENGINES)||(info->desc.addr < 0)) return PCILIB_ERROR_INVALID_DATA;
 
25
    info->addr = (val & DMA_ENG_NUMBER) >> DMA_ENG_NUMBER_SHIFT;
 
26
    if ((info->addr > PCILIB_MAX_DMA_ENGINES)||(info->addr < 0)) return PCILIB_ERROR_INVALID_DATA;
30
27
    
31
28
    switch (val & DMA_ENG_DIRECTION_MASK) {
32
29
        case  DMA_ENG_C2S:
33
 
            info->desc.direction = PCILIB_DMA_FROM_DEVICE;
 
30
            info->direction = PCILIB_DMA_FROM_DEVICE;
34
31
        break;
35
32
        default:
36
 
            info->desc.direction = PCILIB_DMA_TO_DEVICE;
 
33
            info->direction = PCILIB_DMA_TO_DEVICE;
37
34
    }
38
35
    
39
36
    switch (val & DMA_ENG_TYPE_MASK) {
40
37
        case DMA_ENG_BLOCK:
41
 
            info->desc.type = PCILIB_DMA_TYPE_BLOCK;
 
38
            info->type = PCILIB_DMA_TYPE_BLOCK;
42
39
        break;
43
40
        case DMA_ENG_PACKET:
44
 
            info->desc.type = PCILIB_DMA_TYPE_PACKET;
 
41
            info->type = PCILIB_DMA_TYPE_PACKET;
45
42
        break;
46
43
        default:
47
 
            info->desc.type = PCILIB_DMA_TYPE_UNKNOWN;
 
44
            info->type = PCILIB_DMA_TYPE_UNKNOWN;
48
45
    }
49
46
    
50
 
    info->desc.addr_bits = (val & DMA_ENG_BD_MAX_BC) >> DMA_ENG_BD_MAX_BC_SHIFT;
51
 
 
52
 
    info->base_addr = base;
 
47
    info->addr_bits = (val & DMA_ENG_BD_MAX_BC) >> DMA_ENG_BD_MAX_BC_SHIFT;
53
48
    
54
49
    return 0;
55
50
}
60
55
    uint32_t ring_pa;
61
56
    struct timeval start, cur;
62
57
 
63
 
    pcilib_nwl_engine_description_t *info = ctx->engines + dma;
 
58
    pcilib_nwl_engine_context_t *ectx = ctx->engines + dma;
64
59
    char *base = ctx->engines[dma].base_addr;
65
60
    
66
 
    if (info->started) return 0;
67
 
 
 
61
    if (ectx->started) return 0;
68
62
 
69
63
        // This will only successed if there are no parallel access to DMA engine
70
 
    err = dma_nwl_allocate_engine_buffers(ctx, info);
 
64
    err = dma_nwl_allocate_engine_buffers(ctx, ectx);
71
65
    if (err) {
72
 
        info->started = 1;
 
66
        ectx->started = 1;
73
67
        dma_nwl_stop_engine(ctx, dma);
74
68
        return err;
75
69
    }
76
70
    
77
 
    if (info->reused) {
78
 
        info->preserve = 1;
 
71
    if (ectx->reused) {
 
72
        ectx->preserve = 1;
79
73
 
80
74
        dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma);
81
75
 
86
80
        // Disable IRQs
87
81
        err = dma_nwl_disable_engine_irq(ctx, dma);
88
82
        if (err) {
89
 
            info->started = 1;
 
83
            ectx->started = 1;
90
84
            dma_nwl_stop_engine(ctx, dma);
91
85
            return err;
92
86
        }
102
96
        } while ((val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET))&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
103
97
    
104
98
        if (val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET)) {
105
 
            pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr);
 
99
            pcilib_error("Timeout during reset of DMA engine %i", ectx->desc->addr);
106
100
 
107
 
            info->started = 1;
 
101
            ectx->started = 1;
108
102
            dma_nwl_stop_engine(ctx, dma);
109
103
            return PCILIB_ERROR_TIMEOUT;
110
104
        }
119
113
        } while ((val & DMA_ENG_RESET)&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
120
114
    
121
115
        if (val & DMA_ENG_RESET) {
122
 
            pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr);
 
116
            pcilib_error("Timeout during reset of DMA engine %i", ectx->desc->addr);
123
117
 
124
 
            info->started = 1;
 
118
            ectx->started = 1;
125
119
            dma_nwl_stop_engine(ctx, dma);
126
120
            return PCILIB_ERROR_TIMEOUT;
127
121
        }
128
122
    
129
123
        dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma);
130
124
 
131
 
        ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring);
132
 
        nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD);
133
 
        nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD);
 
125
        ring_pa = pcilib_kmem_get_pa(ctx->dmactx.pcilib, ectx->ring);
 
126
        nwl_write_register(ring_pa, ctx, ectx->base_addr, REG_DMA_ENG_NEXT_BD);
 
127
        nwl_write_register(ring_pa, ctx, ectx->base_addr, REG_SW_NEXT_BD);
134
128
 
135
129
        __sync_synchronize();
136
130
 
137
 
        nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
 
131
        nwl_read_register(val, ctx, ectx->base_addr, REG_DMA_ENG_CTRL_STATUS);
138
132
        val |= (DMA_ENG_ENABLE);
139
 
        nwl_write_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
 
133
        nwl_write_register(val, ctx, ectx->base_addr, REG_DMA_ENG_CTRL_STATUS);
140
134
 
141
135
        __sync_synchronize();
142
136
 
144
138
        dma_nwl_enable_engine_irq(ctx, dma);
145
139
#endif /* NWL_GENERATE_DMA_IRQ */
146
140
 
147
 
        if (info->desc.direction == PCILIB_DMA_FROM_DEVICE) {
148
 
            ring_pa += (info->ring_size - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
149
 
            nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD);
 
141
        if (ectx->desc->direction == PCILIB_DMA_FROM_DEVICE) {
 
142
            ring_pa += (ectx->ring_size - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
 
143
            nwl_write_register(ring_pa, ctx, ectx->base_addr, REG_SW_NEXT_BD);
150
144
 
151
 
            info->tail = 0;
152
 
            info->head = (info->ring_size - 1);
 
145
            ectx->tail = 0;
 
146
            ectx->head = (ectx->ring_size - 1);
153
147
        } else {
154
 
            info->tail = 0;
155
 
            info->head = 0;
 
148
            ectx->tail = 0;
 
149
            ectx->head = 0;
156
150
        }
157
151
    }
158
152
    
159
 
    info->started = 1;
 
153
    ectx->started = 1;
160
154
    
161
155
    return 0;
162
156
}
170
164
    pcilib_kmem_flags_t flags;
171
165
    
172
166
    
173
 
    pcilib_nwl_engine_description_t *info = ctx->engines + dma;
 
167
    pcilib_nwl_engine_context_t *ectx = ctx->engines + dma;
174
168
    char *base = ctx->engines[dma].base_addr;
175
169
 
176
 
    if (!info->started) return 0;
 
170
    if (!ectx->started) return 0;
177
171
    
178
 
    info->started = 0;
 
172
    ectx->started = 0;
179
173
 
180
174
    err = dma_nwl_disable_engine_irq(ctx, dma);
181
175
    if (err) return err;
182
176
 
183
 
    if (!info->preserve) {
 
177
    if (!ectx->preserve) {
184
178
            // Stopping DMA is not enough reset is required
185
179
        val = DMA_ENG_DISABLE|DMA_ENG_USER_RESET|DMA_ENG_RESET;
186
180
        nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
191
185
            gettimeofday(&cur, NULL);
192
186
        } while ((val & (DMA_ENG_RUNNING))&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
193
187
 
194
 
        if (info->ring) {
195
 
            ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring);
196
 
            nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD);
197
 
            nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD);
 
188
        if (ectx->ring) {
 
189
            ring_pa = pcilib_kmem_get_pa(ctx->dmactx.pcilib, ectx->ring);
 
190
            nwl_write_register(ring_pa, ctx, ectx->base_addr, REG_DMA_ENG_NEXT_BD);
 
191
            nwl_write_register(ring_pa, ctx, ectx->base_addr, REG_SW_NEXT_BD);
198
192
        }
199
193
    }
200
194
    
201
195
    dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma);
202
196
 
203
 
    if (info->preserve) {
 
197
    if (ectx->preserve) {
204
198
        flags = PCILIB_KMEM_FLAG_REUSE;
205
199
    } else {
206
200
        flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT;
207
201
    }
208
202
    
209
203
        // Clean buffers
210
 
    if (info->ring) {
211
 
        pcilib_free_kernel_memory(ctx->pcilib, info->ring, flags);
212
 
        info->ring = NULL;
 
204
    if (ectx->ring) {
 
205
        pcilib_free_kernel_memory(ctx->dmactx.pcilib, ectx->ring, flags);
 
206
        ectx->ring = NULL;
213
207
    }
214
208
 
215
 
    if (info->pages) {
216
 
        pcilib_free_kernel_memory(ctx->pcilib, info->pages, flags);
217
 
        info->pages = NULL;
 
209
    if (ectx->pages) {
 
210
        pcilib_free_kernel_memory(ctx->dmactx.pcilib, ectx->pages, flags);
 
211
        ectx->pages = NULL;
218
212
    }
219
213
 
220
214
    return 0;
226
220
    size_t bufnum;
227
221
    nwl_dma_t *ctx = (nwl_dma_t*)vctx;
228
222
 
229
 
    pcilib_nwl_engine_description_t *info = ctx->engines + dma;
 
223
    pcilib_nwl_engine_context_t *ectx = ctx->engines + dma;
230
224
 
231
225
    err = dma_nwl_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
232
226
    if (err) return err;
233
227
 
234
228
    if (data) {
235
 
        for (pos = 0; pos < size; pos += info->page_size) {
236
 
            int block_size = min2(size - pos, info->page_size);
 
229
        for (pos = 0; pos < size; pos += ectx->page_size) {
 
230
            int block_size = min2(size - pos, ectx->page_size);
237
231
            
238
 
            bufnum = dma_nwl_get_next_buffer(ctx, info, 1, timeout);
 
232
            bufnum = dma_nwl_get_next_buffer(ctx, ectx, 1, timeout);
239
233
            if (bufnum == PCILIB_DMA_BUFFER_INVALID) {
240
234
                if (written) *written = pos;
241
235
                return PCILIB_ERROR_TIMEOUT;
242
236
            }
243
237
        
244
 
            void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, info->pages, bufnum);
 
238
            void *buf = pcilib_kmem_get_block_ua(ctx->dmactx.pcilib, ectx->pages, bufnum);
245
239
 
246
 
            pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_FROMDEVICE, bufnum);
 
240
            pcilib_kmem_sync_block(ctx->dmactx.pcilib, ectx->pages, PCILIB_KMEM_SYNC_FROMDEVICE, bufnum);
247
241
            memcpy(buf, data, block_size);
248
 
            pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_TODEVICE, bufnum);
 
242
            pcilib_kmem_sync_block(ctx->dmactx.pcilib, ectx->pages, PCILIB_KMEM_SYNC_TODEVICE, bufnum);
249
243
 
250
 
            err = dma_nwl_push_buffer(ctx, info, block_size, (flags&PCILIB_DMA_FLAG_EOP)&&((pos + block_size) == size), timeout);
 
244
            err = dma_nwl_push_buffer(ctx, ectx, block_size, (flags&PCILIB_DMA_FLAG_EOP)&&((pos + block_size) == size), timeout);
251
245
            if (err) {
252
246
                if (written) *written = pos;
253
247
                return err;
258
252
    if (written) *written = size;
259
253
    
260
254
    if (flags&PCILIB_DMA_FLAG_WAIT) {
261
 
        bufnum =  dma_nwl_get_next_buffer(ctx, info, PCILIB_NWL_DMA_PAGES - 1, timeout);
 
255
        bufnum =  dma_nwl_get_next_buffer(ctx, ectx, PCILIB_NWL_DMA_PAGES - 1, timeout);
262
256
        if (bufnum == PCILIB_DMA_BUFFER_INVALID) return PCILIB_ERROR_TIMEOUT;
263
257
    }
264
258
    
276
270
 
277
271
    int eop;
278
272
 
279
 
    pcilib_nwl_engine_description_t *info = ctx->engines + dma;
 
273
    pcilib_nwl_engine_context_t *ectx = ctx->engines + dma;
280
274
 
281
275
    err = dma_nwl_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
282
276
    if (err) return err;
288
282
//          case PCILIB_STREAMING_CHECK: wait = 0; break;
289
283
        }
290
284
    
291
 
        bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, wait);
 
285
        bufnum = dma_nwl_wait_buffer(ctx, ectx, &bufsize, &eop, wait);
292
286
        if (bufnum == PCILIB_DMA_BUFFER_INVALID) {
293
287
            return (ret&PCILIB_STREAMING_FAIL)?PCILIB_ERROR_TIMEOUT:0;
294
288
        }
295
289
 
296
290
            // EOP is not respected in IPE Camera
297
 
        if (ctx->dmactx.ignore_eop) eop = 1;
 
291
        if (ctx->ignore_eop) eop = 1;
298
292
        
299
 
        pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_FROMDEVICE, bufnum);
300
 
        void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, info->pages, bufnum);
 
293
        pcilib_kmem_sync_block(ctx->dmactx.pcilib, ectx->pages, PCILIB_KMEM_SYNC_FROMDEVICE, bufnum);
 
294
        void *buf = pcilib_kmem_get_block_ua(ctx->dmactx.pcilib, ectx->pages, bufnum);
301
295
        ret = cb(cbattr, (eop?PCILIB_DMA_FLAG_EOP:0), bufsize, buf);
302
296
        if (ret < 0) return -ret;
303
297
//      DS: Fixme, it looks like we can avoid calling this for the sake of performance
304
 
//      pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_TODEVICE, bufnum);
305
 
        dma_nwl_return_buffer(ctx, info);
 
298
//      pcilib_kmem_sync_block(ctx->dmactx.pcilib, ectx->pages, PCILIB_KMEM_SYNC_TODEVICE, bufnum);
 
299
        dma_nwl_return_buffer(ctx, ectx);
306
300
        
307
301
        res += bufsize;
308
302