/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/ipe.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-11-20 13:24:17 UTC
  • Revision ID: csa@suren.me-20151120132417-fzm9hulvh7rs47gb
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using

Show diffs side-by-side

added added

removed removed

Lines of Context:
110
110
}
111
111
 
112
112
 
 
113
static void dma_ipe_disable(ipe_dma_t *ctx) {
 
114
            // Disable DMA
 
115
    WR(IPEDMA_REG_CONTROL, 0x0);
 
116
    usleep(IPEDMA_RESET_DELAY);
 
117
        
 
118
            // Reset DMA engine
 
119
    WR(IPEDMA_REG_RESET, 0x1);
 
120
    usleep(IPEDMA_RESET_DELAY);
 
121
    WR(IPEDMA_REG_RESET, 0x0);
 
122
    usleep(IPEDMA_RESET_DELAY);
 
123
 
 
124
        // Reseting configured DMA pages
 
125
    if (ctx->version < 3) {
 
126
        WR(IPEDMA_REG2_PAGE_COUNT, 0);
 
127
    }
 
128
    usleep(IPEDMA_RESET_DELAY);
 
129
}
 
130
 
113
131
int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
114
132
    int err;
115
133
    int mask = 32;
169
187
    } else
170
188
        ctx->page_size = IPEDMA_PAGE_SIZE;
171
189
 
172
 
    if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_pages", &value))
173
 
        ctx->dma_pages = value;
 
190
    if ((!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_pages", &value))&&(value > 0))
 
191
        ctx->ring_size = value;
174
192
    else
175
 
        ctx->dma_pages = IPEDMA_DMA_PAGES;
 
193
        ctx->ring_size = IPEDMA_DMA_PAGES;
176
194
 
177
195
    if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "ipedma_flags", &value))
178
196
        ctx->dma_flags = value;
191
209
 
192
210
    kflags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(ctx->preserve?PCILIB_KMEM_FLAG_PERSISTENT:0);
193
211
    pcilib_kmem_handle_t *desc = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags);
194
 
    pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, IPEDMA_DMA_PAGES, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags);
 
212
    pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, ctx->ring_size, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags);
195
213
 
196
214
    if (!desc||!pages) {
197
 
        if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, 0);
198
 
        if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, 0);
 
215
        if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE);
 
216
        if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE);
 
217
        printf("%lu\n", IPEDMA_DESCRIPTOR_SIZE);
 
218
        pcilib_error("Can't allocate required kernel memory for IPEDMA engine (%lu pages of %lu bytes + %lu byte descriptor)", ctx->ring_size, ctx->page_size, (unsigned long)IPEDMA_DESCRIPTOR_SIZE);
199
219
        return PCILIB_ERROR_MEMORY;
200
220
    }
201
221
    reuse_desc = pcilib_kmem_is_reused(ctx->dmactx.pcilib, desc);
202
222
    reuse_pages = pcilib_kmem_is_reused(ctx->dmactx.pcilib, pages);
203
223
 
204
 
    if (reuse_desc == reuse_pages) {
205
 
        if (reuse_desc & PCILIB_KMEM_REUSE_PARTIAL) pcilib_warning("Inconsistent DMA buffers are found (only part of required buffers is available), reinitializing...");
206
 
        else if (reuse_desc & PCILIB_KMEM_REUSE_REUSED) {
207
 
            if ((reuse_desc & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing...");
208
 
            else if ((reuse_desc & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing...");
 
224
    if ((reuse_pages & PCILIB_KMEM_REUSE_PARTIAL)||(reuse_desc & PCILIB_KMEM_REUSE_PARTIAL)) {
 
225
        dma_ipe_disable(ctx);
 
226
 
 
227
        pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE);
 
228
        pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE);
 
229
 
 
230
        if ((flags&PCILIB_DMA_FLAG_STOP) == 0) {
 
231
            pcilib_error("Inconsistent DMA buffers are found (buffers are only partially re-used). This is very wrong, please stop DMA engine and correct configuration...");
 
232
            return PCILIB_ERROR_INVALID_STATE;
 
233
        }
 
234
        
 
235
        pcilib_warning("Inconsistent DMA buffers are found (buffers are only partially re-used), reinitializing...");
 
236
        desc = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags|PCILIB_KMEM_FLAG_MASS);
 
237
        pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, ctx->ring_size, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags|PCILIB_KMEM_FLAG_MASS);
 
238
 
 
239
        if (!desc||!pages) {
 
240
            if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE);
 
241
            if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE);
 
242
            return PCILIB_ERROR_MEMORY;
 
243
        }
 
244
    } else if (reuse_desc != reuse_pages) {
 
245
         pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing....");
 
246
    } else if (reuse_desc & PCILIB_KMEM_REUSE_REUSED) {
 
247
        if ((reuse_desc & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing...");
 
248
        else if ((reuse_desc & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing...");
 
249
        else {
 
250
            if (ctx->streaming)
 
251
                preserve = 1;
209
252
            else {
210
 
                if (ctx->streaming)
 
253
                RD(IPEDMA_REG2_PAGE_COUNT, value);
 
254
 
 
255
                if (value != ctx->ring_size) 
 
256
                    pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers (%lu) does not match current request (%lu)), reinitializing...", value + 1, IPEDMA_DMA_PAGES);
 
257
                else 
211
258
                    preserve = 1;
212
 
                else {
213
 
                    RD(IPEDMA_REG2_PAGE_COUNT, value);
214
 
 
215
 
                    if (value != IPEDMA_DMA_PAGES) 
216
 
                        pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers (%lu) does not match current request (%lu)), reinitializing...", value + 1, IPEDMA_DMA_PAGES);
217
 
                    else 
218
 
                        preserve = 1;
219
 
                } 
220
 
            }
 
259
            } 
221
260
        }
222
 
    } else pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing....");
 
261
    }
223
262
 
224
263
    desc_va = pcilib_kmem_get_ua(ctx->dmactx.pcilib, desc);
225
264
    if (ctx->version < 3) {
242
281
        RD(ctx->reg_last_read, value);
243
282
            // Numbered from 1 in FPGA
244
283
# ifdef IPEDMA_BUG_LAST_READ
245
 
        if (value == IPEDMA_DMA_PAGES)
 
284
        if (value == ctx->ring_size)
246
285
            value = 0;
247
286
# else /* IPEDMA_BUG_LAST_READ */
248
287
        value--;
251
290
        ctx->last_read = value;
252
291
    } else {
253
292
        ctx->reused = 0;
254
 
 
255
 
            // Disable DMA
256
 
        WR(IPEDMA_REG_CONTROL, 0x0);
257
 
        usleep(IPEDMA_RESET_DELAY);
258
293
        
259
 
            // Reset DMA engine
260
 
        WR(IPEDMA_REG_RESET, 0x1);
261
 
        usleep(IPEDMA_RESET_DELAY);
262
 
        WR(IPEDMA_REG_RESET, 0x0);
263
 
        usleep(IPEDMA_RESET_DELAY);
 
294
        dma_ipe_disable(ctx);
264
295
 
265
296
            // Verify PCIe link status
266
297
        RD(IPEDMA_REG_RESET, value);
284
315
 
285
316
            // Setting current read position and configuring progress register
286
317
#ifdef IPEDMA_BUG_LAST_READ
287
 
        WR(ctx->reg_last_read, IPEDMA_DMA_PAGES - 1);
 
318
        WR(ctx->reg_last_read, ctx->ring_size - 1);
288
319
#else /* IPEDMA_BUG_LAST_READ */
289
 
        WR(ctx->reg_last_read, IPEDMA_DMA_PAGES);
 
320
        WR(ctx->reg_last_read, ctx->ring_size);
290
321
#endif /* IPEDMA_BUG_LAST_READ */
291
322
 
292
323
        if (ctx->version < 3) {
304
335
            // In ring buffer mode, the hardware taking care to preserve an empty buffer to help distinguish between
305
336
            // completely empty and completely full cases. In streaming mode, it is our responsibility to track this
306
337
            // information. Therefore, we always keep the last buffer free
307
 
        num_pages = IPEDMA_DMA_PAGES;
 
338
        num_pages = ctx->ring_size;
308
339
        if (ctx->streaming) num_pages--;
309
340
        
310
341
        for (i = 0; i < num_pages; i++) {
330
361
            // Enable DMA
331
362
        WR(IPEDMA_REG_CONTROL, 0x1);
332
363
        
333
 
        ctx->last_read = IPEDMA_DMA_PAGES - 1;
 
364
        ctx->last_read = ctx->ring_size - 1;
334
365
    }
335
366
 
336
367
    ctx->last_read_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, pages, ctx->last_read);
338
369
    ctx->desc = desc;
339
370
    ctx->pages = pages;
340
371
 
341
 
    ctx->ring_size = IPEDMA_DMA_PAGES;
342
 
 
343
372
    return 0;
344
373
}
345
374
 
364
393
 
365
394
        ctx->started  = 0;
366
395
 
367
 
            // Disable DMA
368
 
        WR(IPEDMA_REG_CONTROL, 0);
369
 
        usleep(IPEDMA_RESET_DELAY);
370
 
        
371
 
            // Reset DMA engine
372
 
        WR(IPEDMA_REG_RESET, 0x1);
373
 
        usleep(IPEDMA_RESET_DELAY);
374
 
        WR(IPEDMA_REG_RESET, 0x0);
375
 
        usleep(IPEDMA_RESET_DELAY);
376
 
 
377
 
            // Reseting configured DMA pages
378
 
        if (ctx->version < 3) {
379
 
            WR(IPEDMA_REG2_PAGE_COUNT, 0);
380
 
        }
381
 
 
382
 
        usleep(IPEDMA_RESET_DELAY);
 
396
        dma_ipe_disable(ctx);
383
397
    }
384
398
 
385
399
        // Clean buffers
633
647
            size_t last_free;
634
648
                // We always keep 1 buffer free to distinguish between completely full and empty cases
635
649
            if (cur_read) last_free = cur_read - 1;
636
 
            else last_free = IPEDMA_DMA_PAGES - 1;
 
650
            else last_free = ctx->ring_size - 1;
637
651
 
638
652
            uintptr_t buf_ba = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, last_free);
639
653
            if (ctx->version < 3) {
651
665
 
652
666
            // Numbered from 1
653
667
#ifdef IPEDMA_BUG_LAST_READ
654
 
        WR(ctx->reg_last_read, cur_read?cur_read:IPEDMA_DMA_PAGES);
 
668
        WR(ctx->reg_last_read, cur_read?cur_read:ctx->ring_size);
655
669
#else /* IPEDMA_BUG_LAST_READ */
656
670
        WR(ctx->reg_last_read, cur_read + 1);
657
671
#endif /* IPEDMA_BUG_LAST_READ */