/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
1
#define NWL_RING_GET(data, offset)  *(uint32_t*)(((char*)(data)) + (offset))
2
#define NWL_RING_SET(data, offset, val)  *(uint32_t*)(((char*)(data)) + (offset)) = (val)
3
#define NWL_RING_UPDATE(data, offset, mask, val) *(uint32_t*)(((char*)(data)) + (offset)) = ((*(uint32_t*)(((char*)(data)) + (offset)))&(mask))|(val)
4
236 by Suren A. Chilingaryan
Big redign of model structures
5
static int dma_nwl_compute_read_s2c_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx, unsigned char *ring, uint32_t ring_pa) {
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
6
    uint32_t val;
7
236 by Suren A. Chilingaryan
Big redign of model structures
8
    const char *base = ectx->base_addr;
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
9
    
10
    nwl_read_register(val, ctx, base, REG_SW_NEXT_BD);
11
    if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
76 by Suren A. Chilingaryan
Handle correctly reference counting in the driver
12
	if (val < ring_pa) pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_SW_NEXT_BD register value (%lx) is below start of ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
13
	else pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
14
	return PCILIB_ERROR_INVALID_STATE;
15
    }
16
236 by Suren A. Chilingaryan
Big redign of model structures
17
    ectx->head = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
18
    if (ectx->head >= PCILIB_NWL_DMA_PAGES) {
19
	pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu) out of range)", ectx->head);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
20
	return PCILIB_ERROR_INVALID_STATE;
21
    }
22
23
    nwl_read_register(val, ctx, base, REG_DMA_ENG_NEXT_BD);
24
    if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
76 by Suren A. Chilingaryan
Handle correctly reference counting in the driver
25
	if (val < ring_pa) pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register value (%lx) is below start of ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
26
	else pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
27
	return PCILIB_ERROR_INVALID_STATE;
28
    }
29
236 by Suren A. Chilingaryan
Big redign of model structures
30
    ectx->tail = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
31
    if (ectx->tail >= PCILIB_NWL_DMA_PAGES) {
32
	pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register value (%zu) out of range)", ectx->tail);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
33
	return PCILIB_ERROR_INVALID_STATE;
34
    }
78 by Suren A. Chilingaryan
Correctly detect the tail pointer of C2S ring
35
250 by Suren A. Chilingaryan
Provide an interface for logging debug messages
36
    pcilib_debug(DMA, "S2C: %lu %lu\n", ectx->tail, ectx->head);
78 by Suren A. Chilingaryan
Correctly detect the tail pointer of C2S ring
37
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
38
    return 0;
39
}
40
236 by Suren A. Chilingaryan
Big redign of model structures
41
static int dma_nwl_compute_read_c2s_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx, unsigned char *ring, uint32_t ring_pa) {
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
42
    uint32_t val;
43
236 by Suren A. Chilingaryan
Big redign of model structures
44
    const char *base = ectx->base_addr;
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
45
46
    nwl_read_register(val, ctx, base, REG_SW_NEXT_BD);
47
    if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
76 by Suren A. Chilingaryan
Handle correctly reference counting in the driver
48
	if (val < ring_pa) pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%lx) is below start of the ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
49
	else pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
50
	return PCILIB_ERROR_INVALID_STATE;
51
    }
52
236 by Suren A. Chilingaryan
Big redign of model structures
53
    ectx->head = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
54
    if (ectx->head >= PCILIB_NWL_DMA_PAGES) {
55
	pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu) out of range)", ectx->head);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
56
	return PCILIB_ERROR_INVALID_STATE;
57
    }
58
    
236 by Suren A. Chilingaryan
Big redign of model structures
59
    ectx->tail = ectx->head + 1;
60
    if (ectx->tail == PCILIB_NWL_DMA_PAGES) ectx->tail = 0;
78 by Suren A. Chilingaryan
Correctly detect the tail pointer of C2S ring
61
250 by Suren A. Chilingaryan
Provide an interface for logging debug messages
62
    pcilib_debug(DMA, "C2S: %lu %lu\n", ectx->tail, ectx->head);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
63
64
    return 0;
65
}
66
67
236 by Suren A. Chilingaryan
Big redign of model structures
68
static int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx) {
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
69
    int err = 0;
70
71
    int i;
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
72
    int preserve = 0;
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
73
    uint16_t sub_use;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
74
    uint32_t val;
75
    uint32_t buf_sz;
76
    uint64_t buf_pa;
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
77
    pcilib_kmem_reuse_state_t reuse_ring, reuse_pages;
73 by Suren A. Chilingaryan
Implement DMA access synchronization in the driver
78
    pcilib_kmem_flags_t flags;
105 by Suren A. Chilingaryan
Properly perform synchronization of DMA buffers
79
    pcilib_kmem_type_t type;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
80
236 by Suren A. Chilingaryan
Big redign of model structures
81
    char *base = ectx->base_addr;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
82
    
236 by Suren A. Chilingaryan
Big redign of model structures
83
    if (ectx->pages) return 0;
75 by Suren A. Chilingaryan
Few fixes
84
    
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
85
	// Or bidirectional specified by 0x0|addr, or read 0x0|addr and write 0x80|addr
236 by Suren A. Chilingaryan
Big redign of model structures
86
    type = (ectx->desc->direction == PCILIB_DMA_TO_DEVICE)?PCILIB_KMEM_TYPE_DMA_S2C_PAGE:PCILIB_KMEM_TYPE_DMA_C2S_PAGE;
87
    sub_use = ectx->desc->addr|((ectx->desc->direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00);
88
    flags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(ectx->preserve?PCILIB_KMEM_FLAG_PERSISTENT:0);
75 by Suren A. Chilingaryan
Few fixes
89
    
236 by Suren A. Chilingaryan
Big redign of model structures
90
    pcilib_kmem_handle_t *ring = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, PCILIB_NWL_DMA_PAGES * PCILIB_NWL_DMA_DESCRIPTOR_SIZE, PCILIB_NWL_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, sub_use), flags);
91
    pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, type, PCILIB_NWL_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, sub_use), flags);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
92
227 by Suren A. Chilingaryan
Initial implementation of IPEDMA, dummy driver for KAPTURE, start of API changes
93
    if (!ring||!pages) {
236 by Suren A. Chilingaryan
Big redign of model structures
94
	if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, 0);
95
	if (ring) pcilib_free_kernel_memory(ctx->dmactx.pcilib, ring, 0);
227 by Suren A. Chilingaryan
Initial implementation of IPEDMA, dummy driver for KAPTURE, start of API changes
96
	return PCILIB_ERROR_MEMORY;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
97
    }
71 by Suren A. Chilingaryan
First iteration of work to preserve DMA state between executions
98
236 by Suren A. Chilingaryan
Big redign of model structures
99
    reuse_ring = pcilib_kmem_is_reused(ctx->dmactx.pcilib, ring);
100
    reuse_pages = pcilib_kmem_is_reused(ctx->dmactx.pcilib, pages);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
101
181 by Suren A. Chilingaryan
Fixes 2 bugs in NWL DMA initalization: DMA engine was not restarted in case of incosistency leading to possibility of data loss on DMA; Persistent mode was not respected after re-initalization (stop/start dma)
102
//	I guess idea here was that we not need to check all that stuff during the second iteration
103
//	which is basicaly true (shall we expect any driver-triggered changes or parallel accesses?)
104
//	but still we need to set preserve flag (and that if we enforcing preservation --start-dma). 
105
//	Probably having checks anyway is not harming...
236 by Suren A. Chilingaryan
Big redign of model structures
106
//    if (!ectx->preserve) {
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
107
	if (reuse_ring == reuse_pages) {
108
	    if (reuse_ring & PCILIB_KMEM_REUSE_PARTIAL) pcilib_warning("Inconsistent DMA buffers are found (only part of required buffers is available), reinitializing...");
109
	    else if (reuse_ring & PCILIB_KMEM_REUSE_REUSED) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
110
		if ((reuse_ring & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing...");
111
		else if ((reuse_ring & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing...");
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
112
		else {
236 by Suren A. Chilingaryan
Big redign of model structures
113
		    nwl_read_register(val, ctx, ectx->base_addr, REG_DMA_ENG_CTRL_STATUS);
79 by Suren A. Chilingaryan
Few more fixes
114
83 by Suren A. Chilingaryan
Correctly check if DMA is already enabled
115
		    if ((val&DMA_ENG_RUNNING) == 0) pcilib_warning("Lost DMA buffers are found (DMA engine is stopped), reinitializing...");
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
116
		    else preserve = 1;
117
		}
118
	    } 	
119
	} else pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing....");
181 by Suren A. Chilingaryan
Fixes 2 bugs in NWL DMA initalization: DMA engine was not restarted in case of incosistency leading to possibility of data loss on DMA; Persistent mode was not respected after re-initalization (stop/start dma)
120
//    }
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
121
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
122
    
236 by Suren A. Chilingaryan
Big redign of model structures
123
    unsigned char *data = (unsigned char*)pcilib_kmem_get_ua(ctx->dmactx.pcilib, ring);
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
124
    uint32_t ring_pa = pcilib_kmem_get_ba(ctx->dmactx.pcilib, ring);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
125
126
    if (preserve) {
236 by Suren A. Chilingaryan
Big redign of model structures
127
	if (ectx->desc->direction == PCILIB_DMA_FROM_DEVICE) err = dma_nwl_compute_read_c2s_pointers(ctx, ectx, data, ring_pa);
128
	else err = dma_nwl_compute_read_s2c_pointers(ctx, ectx, data, ring_pa);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
129
130
	if (err) preserve = 0;
131
    }
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
132
    
79 by Suren A. Chilingaryan
Few more fixes
133
    if (preserve) {
236 by Suren A. Chilingaryan
Big redign of model structures
134
	ectx->reused = 1;
135
        buf_sz = pcilib_kmem_get_block_size(ctx->dmactx.pcilib, pages, 0);
79 by Suren A. Chilingaryan
Few more fixes
136
    } else {
236 by Suren A. Chilingaryan
Big redign of model structures
137
	ectx->reused = 0;
181 by Suren A. Chilingaryan
Fixes 2 bugs in NWL DMA initalization: DMA engine was not restarted in case of incosistency leading to possibility of data loss on DMA; Persistent mode was not respected after re-initalization (stop/start dma)
138
	
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
139
	memset(data, 0, PCILIB_NWL_DMA_PAGES * PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
140
141
	for (i = 0; i < PCILIB_NWL_DMA_PAGES; i++, data += PCILIB_NWL_DMA_DESCRIPTOR_SIZE) {
236 by Suren A. Chilingaryan
Big redign of model structures
142
	    buf_pa = pcilib_kmem_get_block_pa(ctx->dmactx.pcilib, pages, i);
143
	    buf_sz = pcilib_kmem_get_block_size(ctx->dmactx.pcilib, pages, i);
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
144
145
	    NWL_RING_SET(data, DMA_BD_NDESC_OFFSET, ring_pa + ((i + 1) % PCILIB_NWL_DMA_PAGES) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
146
	    NWL_RING_SET(data, DMA_BD_BUFAL_OFFSET, buf_pa&0xFFFFFFFF);
147
	    NWL_RING_SET(data, DMA_BD_BUFAH_OFFSET, buf_pa>>32);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
148
#ifdef NWL_GENERATE_DMA_IRQ
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
149
    	    NWL_RING_SET(data, DMA_BD_BUFL_CTRL_OFFSET, buf_sz | DMA_BD_INT_ERROR_MASK | DMA_BD_INT_COMP_MASK);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
150
#else /* NWL_GENERATE_DMA_IRQ */
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
151
    	    NWL_RING_SET(data, DMA_BD_BUFL_CTRL_OFFSET, buf_sz);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
152
#endif /* NWL_GENERATE_DMA_IRQ */
74 by Suren A. Chilingaryan
Implement DMA access synchronization for NWL implementation
153
	}
154
155
	val = ring_pa;
156
	nwl_write_register(val, ctx, base, REG_DMA_ENG_NEXT_BD);
157
	nwl_write_register(val, ctx, base, REG_SW_NEXT_BD);
158
236 by Suren A. Chilingaryan
Big redign of model structures
159
        ectx->head = 0;
160
	ectx->tail = 0;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
161
    }
162
    
236 by Suren A. Chilingaryan
Big redign of model structures
163
    ectx->ring = ring;
164
    ectx->pages = pages;
165
    ectx->page_size = buf_sz;
166
    ectx->ring_size = PCILIB_NWL_DMA_PAGES;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
167
    
168
    return 0;
169
}
170
171
236 by Suren A. Chilingaryan
Big redign of model structures
172
static size_t dma_nwl_clean_buffers(nwl_dma_t * ctx, pcilib_nwl_engine_context_t *ectx) {
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
173
    size_t res = 0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
174
    uint32_t status;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
175
370 by Suren A. Chilingaryan
RPM generation
176
    volatile unsigned char *ring = pcilib_kmem_get_ua(ctx->dmactx.pcilib, ectx->ring);
236 by Suren A. Chilingaryan
Big redign of model structures
177
    ring += ectx->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
178
179
next_buffer:
180
    status = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET)&DMA_BD_STATUS_MASK;
181
//  control = NWL_RING_GET(ring, DMA_BD_BUFL_CTRL_OFFSET)&DMA_BD_CTRL_MASK;
182
    
183
    if (status & DMA_BD_ERROR_MASK) {
184
        pcilib_error("NWL DMA Engine reported error in ring descriptor");
185
        return (size_t)-1;
186
    }
187
	
188
    if (status & DMA_BD_SHORT_MASK) {
189
        pcilib_error("NWL DMA Engine reported short error");
190
        return (size_t)-1;
191
    }
192
	
193
    if (status & DMA_BD_COMP_MASK) {
236 by Suren A. Chilingaryan
Big redign of model structures
194
	ectx->tail++;
195
	if (ectx->tail == ectx->ring_size) {
196
	    ring -= (ectx->tail - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
197
	    ectx->tail = 0;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
198
	} else {
199
	    ring += PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
200
	}
201
	
202
	res++;
203
236 by Suren A. Chilingaryan
Big redign of model structures
204
	if (ectx->tail != ectx->head) goto next_buffer;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
205
    }
206
    
207
//    printf("====> Cleaned: %i\n", res);
208
    return res;
209
}
210
211
236 by Suren A. Chilingaryan
Big redign of model structures
212
static size_t dma_nwl_get_next_buffer(nwl_dma_t * ctx, pcilib_nwl_engine_context_t *ectx, size_t n_buffers, pcilib_timeout_t timeout) {
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
213
    struct timeval start, cur;
214
215
    size_t res, n = 0;
216
    size_t head;
217
236 by Suren A. Chilingaryan
Big redign of model structures
218
    for (head = ectx->head; (((head + 1)%ectx->ring_size) != ectx->tail)&&(n < n_buffers); head++, n++);
219
    if (n == n_buffers) return ectx->head;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
220
221
    gettimeofday(&start, NULL);
222
236 by Suren A. Chilingaryan
Big redign of model structures
223
    res = dma_nwl_clean_buffers(ctx, ectx);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
224
    if (res == (size_t)-1) return PCILIB_DMA_BUFFER_INVALID;
225
    else n += res;
226
227
    
228
    while (n < n_buffers) {
229
	if (timeout != PCILIB_TIMEOUT_INFINITE) {
230
	    gettimeofday(&cur, NULL);
231
	    if  (((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) > timeout) break;
232
	}
233
	
234
	usleep (10);	
235
236 by Suren A. Chilingaryan
Big redign of model structures
236
        res = dma_nwl_clean_buffers(ctx, ectx);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
237
        if (res == (size_t)-1) return PCILIB_DMA_BUFFER_INVALID;
238
	else if (res > 0) {
239
	    gettimeofday(&start, NULL);
240
	    n += res;
241
	}
242
    }
79 by Suren A. Chilingaryan
Few more fixes
243
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
244
    if (n < n_buffers) return PCILIB_DMA_BUFFER_INVALID;
245
    
236 by Suren A. Chilingaryan
Big redign of model structures
246
    return ectx->head;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
247
}
248
236 by Suren A. Chilingaryan
Big redign of model structures
249
static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx, size_t size, int eop, pcilib_timeout_t timeout) {
66 by Suren A. Chilingaryan
Few fixes
250
    int flags = 0;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
251
    
252
    uint32_t val;
370 by Suren A. Chilingaryan
RPM generation
253
    volatile unsigned char *ring = pcilib_kmem_get_ua(ctx->dmactx.pcilib, ectx->ring);
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
254
    uint32_t ring_pa = pcilib_kmem_get_ba(ctx->dmactx.pcilib, ectx->ring);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
255
236 by Suren A. Chilingaryan
Big redign of model structures
256
    ring += ectx->head * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
257
258
    
236 by Suren A. Chilingaryan
Big redign of model structures
259
    if (!ectx->writting) {
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
260
	flags |= DMA_BD_SOP_MASK;
236 by Suren A. Chilingaryan
Big redign of model structures
261
	ectx->writting = 1;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
262
    }
263
    if (eop) {
264
	flags |= DMA_BD_EOP_MASK;
236 by Suren A. Chilingaryan
Big redign of model structures
265
	ectx->writting = 0;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
266
    }
79 by Suren A. Chilingaryan
Few more fixes
267
    
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
268
    NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, size|flags);
269
    NWL_RING_SET(ring, DMA_BD_BUFL_STATUS_OFFSET, size);
270
236 by Suren A. Chilingaryan
Big redign of model structures
271
    ectx->head++;
272
    if (ectx->head == ectx->ring_size) ectx->head = 0;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
273
    
236 by Suren A. Chilingaryan
Big redign of model structures
274
    val = ring_pa + ectx->head * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
275
    nwl_write_register(val, ctx, ectx->base_addr, REG_SW_NEXT_BD);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
276
    
277
    return 0;
278
}
279
280
236 by Suren A. Chilingaryan
Big redign of model structures
281
static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx, size_t *size, int *eop, pcilib_timeout_t timeout) {
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
282
    struct timeval start, cur;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
283
    uint32_t status_size, status;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
284
370 by Suren A. Chilingaryan
RPM generation
285
    volatile unsigned char *ring = pcilib_kmem_get_ua(ctx->dmactx.pcilib, ectx->ring);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
286
    
236 by Suren A. Chilingaryan
Big redign of model structures
287
    ring += ectx->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
288
289
    gettimeofday(&start, NULL);
290
    
291
    do {
292
	status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
293
	status = status_size & DMA_BD_STATUS_MASK;
294
	
295
	if (status & DMA_BD_ERROR_MASK) {
296
    	    pcilib_error("NWL DMA Engine reported error in ring descriptor");
297
    	    return (size_t)-1;
298
	}	
299
	
300
	if (status & DMA_BD_COMP_MASK) {
301
	    if (status & DMA_BD_EOP_MASK) *eop = 1;
302
	    else *eop = 0;
109 by Suren A. Chilingaryan
Improvements of DMA engine
303
	            
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
304
	    *size = status_size & DMA_BD_BUFL_MASK;
109 by Suren A. Chilingaryan
Improvements of DMA engine
305
306
/*	    
307
	    if (mrd) {
236 by Suren A. Chilingaryan
Big redign of model structures
308
		if ((ectx->tail + 1) == ectx->ring_size) ring -= ectx->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
109 by Suren A. Chilingaryan
Improvements of DMA engine
309
		else ring += PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
310
		*mrd = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET)&DMA_BD_COMP_MASK;
311
	    }
312
*/
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
313
	
236 by Suren A. Chilingaryan
Big redign of model structures
314
	    return ectx->tail;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
315
	}
316
	
317
	usleep(10);
318
        gettimeofday(&cur, NULL);
319
    } while ((timeout == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < timeout));
320
321
    return (size_t)-1;
322
}
323
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
324
/*
325
    // This function is not used now, but we may need it in the future
236 by Suren A. Chilingaryan
Big redign of model structures
326
static int dma_nwl_is_overflown(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx) {
109 by Suren A. Chilingaryan
Improvements of DMA engine
327
    uint32_t status;
236 by Suren A. Chilingaryan
Big redign of model structures
328
    unsigned char *ring = pcilib_kmem_get_ua(ctx->dmactx.pcilib, ectx->ring);
329
    if (ectx->tail > 0) ring += (ectx->tail - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
330
    else ring += (ectx->ring_size - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
109 by Suren A. Chilingaryan
Improvements of DMA engine
331
332
    status = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
333
    return status&DMA_BD_COMP_MASK?1:0;
334
}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
335
*/
109 by Suren A. Chilingaryan
Improvements of DMA engine
336
236 by Suren A. Chilingaryan
Big redign of model structures
337
static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_context_t *ectx) {
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
338
    uint32_t val;
339
370 by Suren A. Chilingaryan
RPM generation
340
    volatile unsigned char *ring = pcilib_kmem_get_ua(ctx->dmactx.pcilib, ectx->ring);
352.1.4 by Suren A. Chilingaryan
Distinguish between hardware and bus addresses in pcilib
341
    uint32_t ring_pa = pcilib_kmem_get_ba(ctx->dmactx.pcilib, ectx->ring);
236 by Suren A. Chilingaryan
Big redign of model structures
342
    size_t bufsz = pcilib_kmem_get_block_size(ctx->dmactx.pcilib, ectx->pages, ectx->tail);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
343
236 by Suren A. Chilingaryan
Big redign of model structures
344
    ring += ectx->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
345
346
#ifdef NWL_GENERATE_DMA_IRQ    
347
    NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, bufsz | DMA_BD_INT_ERROR_MASK | DMA_BD_INT_COMP_MASK);
348
#else /* NWL_GENERATE_DMA_IRQ */
349
    NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, bufsz);
350
#endif /* NWL_GENERATE_DMA_IRQ */
351
352
    NWL_RING_SET(ring, DMA_BD_BUFL_STATUS_OFFSET, 0);
353
236 by Suren A. Chilingaryan
Big redign of model structures
354
    val = ring_pa + ectx->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
355
    nwl_write_register(val, ctx, ectx->base_addr, REG_SW_NEXT_BD);
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
356
    
236 by Suren A. Chilingaryan
Big redign of model structures
357
    ectx->tail++;
358
    if (ectx->tail == ectx->ring_size) ectx->tail = 0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
359
    
360
    return 0;
58 by Suren A. Chilingaryan
Wait for the completion of DMA operations during writes
361
}
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
362
109 by Suren A. Chilingaryan
Improvements of DMA engine
363
int dma_nwl_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) {
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
364
    size_t i;
104 by Suren A. Chilingaryan
Precisely estimate used buffers for C2S engines
365
    uint32_t bstatus;
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
366
    nwl_dma_t *ctx = (nwl_dma_t*)vctx;
236 by Suren A. Chilingaryan
Big redign of model structures
367
    pcilib_nwl_engine_context_t *ectx = ctx->engines + dma;
368
    unsigned char *ring = (unsigned char*)pcilib_kmem_get_ua(ctx->dmactx.pcilib, ectx->ring);
104 by Suren A. Chilingaryan
Precisely estimate used buffers for C2S engines
369
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
370
371
    if (!status) return -1;
372
    
236 by Suren A. Chilingaryan
Big redign of model structures
373
    status->started = ectx->started;
374
    status->ring_size = ectx->ring_size;
375
    status->buffer_size = ectx->page_size;
376
    status->ring_tail = ectx->tail;
265 by Suren A. Chilingaryan
Add fields reporting consumed buffers and space to the dma_engine_status and provide better ipedma benchmarking
377
    status->written_buffers = 0;
378
    status->written_bytes = 0;
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
379
    
236 by Suren A. Chilingaryan
Big redign of model structures
380
    if (ectx->desc->direction == PCILIB_DMA_FROM_DEVICE) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
381
	size_t pos = 0;
236 by Suren A. Chilingaryan
Big redign of model structures
382
	for (i = 0; i < ectx->ring_size; i++) {
104 by Suren A. Chilingaryan
Precisely estimate used buffers for C2S engines
383
	    pos = status->ring_tail + i;
236 by Suren A. Chilingaryan
Big redign of model structures
384
	    if (pos >= ectx->ring_size) pos -= ectx->ring_size;
104 by Suren A. Chilingaryan
Precisely estimate used buffers for C2S engines
385
386
	    bstatus = NWL_RING_GET(ring + pos * PCILIB_NWL_DMA_DESCRIPTOR_SIZE, DMA_BD_BUFL_STATUS_OFFSET);
387
	    if ((bstatus&(DMA_BD_ERROR_MASK|DMA_BD_COMP_MASK)) == 0) break;
388
	}
389
        status->ring_head = pos;
390
    } else {
236 by Suren A. Chilingaryan
Big redign of model structures
391
        status->ring_head = ectx->head;
104 by Suren A. Chilingaryan
Precisely estimate used buffers for C2S engines
392
    }
393
394
395
    if (buffers) {	
236 by Suren A. Chilingaryan
Big redign of model structures
396
	for (i = 0; (i < ectx->ring_size)&&(i < n_buffers); i++) {
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
397
	    bstatus = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
398
399
	    buffers[i].error = bstatus & (DMA_BD_ERROR_MASK/*|DMA_BD_SHORT_MASK*/);
400
	    buffers[i].used = bstatus & DMA_BD_COMP_MASK;
401
	    buffers[i].size = bstatus & DMA_BD_BUFL_MASK;
402
	    buffers[i].first = bstatus & DMA_BD_SOP_MASK;
403
	    buffers[i].last = bstatus & DMA_BD_EOP_MASK;
404
405
	    ring += PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
406
	}
265 by Suren A. Chilingaryan
Add fields reporting consumed buffers and space to the dma_engine_status and provide better ipedma benchmarking
407
    } 
408
409
    for (i = 0; (i < ectx->ring_size)&&(i < n_buffers); i++) {
410
	bstatus = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
411
	if (bstatus & DMA_BD_COMP_MASK) {
412
	    status->written_buffers++;
413
	    if ((bstatus & (DMA_BD_ERROR_MASK)) == 0)
414
		status->written_bytes += bstatus & DMA_BD_BUFL_MASK;
415
	}
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
416
    }
265 by Suren A. Chilingaryan
Add fields reporting consumed buffers and space to the dma_engine_status and provide better ipedma benchmarking
417
103 by Suren A. Chilingaryan
Provide information about active DMA engines & buffers
418
    return 0;
419
}