10
10
#include "pcilib.h"
13
14
#include "nwl_private.h"
15
15
#include "nwl_defines.h"
17
16
#include "nwl_engine_buffers.h"
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) {
22
info->base_addr = base;
24
21
nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP);
26
23
if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE;
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;
31
28
switch (val & DMA_ENG_DIRECTION_MASK) {
33
info->desc.direction = PCILIB_DMA_FROM_DEVICE;
30
info->direction = PCILIB_DMA_FROM_DEVICE;
36
info->desc.direction = PCILIB_DMA_TO_DEVICE;
33
info->direction = PCILIB_DMA_TO_DEVICE;
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;
43
40
case DMA_ENG_PACKET:
44
info->desc.type = PCILIB_DMA_TYPE_PACKET;
41
info->type = PCILIB_DMA_TYPE_PACKET;
47
info->desc.type = PCILIB_DMA_TYPE_UNKNOWN;
44
info->type = PCILIB_DMA_TYPE_UNKNOWN;
50
info->desc.addr_bits = (val & DMA_ENG_BD_MAX_BC) >> DMA_ENG_BD_MAX_BC_SHIFT;
52
info->base_addr = base;
47
info->addr_bits = (val & DMA_ENG_BD_MAX_BC) >> DMA_ENG_BD_MAX_BC_SHIFT;
61
56
struct timeval start, cur;
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;
66
if (info->started) return 0;
61
if (ectx->started) return 0;
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);
73
67
dma_nwl_stop_engine(ctx, dma);
80
74
dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma);
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));
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);
108
102
dma_nwl_stop_engine(ctx, dma);
109
103
return PCILIB_ERROR_TIMEOUT;
119
113
} while ((val & DMA_ENG_RESET)&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
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);
125
119
dma_nwl_stop_engine(ctx, dma);
126
120
return PCILIB_ERROR_TIMEOUT;
129
123
dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma);
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);
135
129
__sync_synchronize();
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);
141
135
__sync_synchronize();
144
138
dma_nwl_enable_engine_irq(ctx, dma);
145
139
#endif /* NWL_GENERATE_DMA_IRQ */
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);
152
info->head = (info->ring_size - 1);
146
ectx->head = (ectx->ring_size - 1);
170
164
pcilib_kmem_flags_t flags;
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;
176
if (!info->started) return 0;
170
if (!ectx->started) return 0;
180
174
err = dma_nwl_disable_engine_irq(ctx, dma);
181
175
if (err) return err;
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));
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);
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);
201
195
dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma);
203
if (info->preserve) {
197
if (ectx->preserve) {
204
198
flags = PCILIB_KMEM_FLAG_REUSE;
206
200
flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT;
211
pcilib_free_kernel_memory(ctx->pcilib, info->ring, flags);
205
pcilib_free_kernel_memory(ctx->dmactx.pcilib, ectx->ring, flags);
216
pcilib_free_kernel_memory(ctx->pcilib, info->pages, flags);
210
pcilib_free_kernel_memory(ctx->dmactx.pcilib, ectx->pages, flags);
227
221
nwl_dma_t *ctx = (nwl_dma_t*)vctx;
229
pcilib_nwl_engine_description_t *info = ctx->engines + dma;
223
pcilib_nwl_engine_context_t *ectx = ctx->engines + dma;
231
225
err = dma_nwl_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
232
226
if (err) return err;
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);
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;
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);
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);
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);
252
246
if (written) *written = pos;
258
252
if (written) *written = size;
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;
288
282
// case PCILIB_STREAMING_CHECK: wait = 0; break;
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;
296
290
// EOP is not respected in IPE Camera
297
if (ctx->dmactx.ignore_eop) eop = 1;
291
if (ctx->ignore_eop) eop = 1;
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);