diff options
author | Jonas Aaberg <jonas.aberg@stericsson.com> | 2010-08-09 08:08:56 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2010-09-22 17:53:46 -0400 |
commit | 698e4732e7c9cf9f1f3eac2b8cdce8d4fe2b90bd (patch) | |
tree | 9716c813accd1f8f5f5fe6d4ad389fd64396c26d /drivers/dma/ste_dma40_ll.c | |
parent | 69f93faa57ed6c91b32aae1dcff7282fcb2872f5 (diff) |
DMAENGINE: ste_dma40: rewrote LCLA entries allocation code
LLI allocation is now done on job level instead of channel level.
Previously the maximum length of a linked job in hw on a logical
channel was 8, since the LLIs where evenly divided. Now only
executing jobs have allocated LLIs which increase the length to
a maximum of 64 links in HW.
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/ste_dma40_ll.c')
-rw-r--r-- | drivers/dma/ste_dma40_ll.c | 161 |
1 files changed, 55 insertions, 106 deletions
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 92a0960fba08..86a306dbe1b4 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c | |||
@@ -37,16 +37,13 @@ void d40_log_cfg(struct stedma40_chan_cfg *cfg, | |||
37 | cfg->dir == STEDMA40_PERIPH_TO_PERIPH) | 37 | cfg->dir == STEDMA40_PERIPH_TO_PERIPH) |
38 | l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS; | 38 | l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS; |
39 | 39 | ||
40 | l3 |= 1 << D40_MEM_LCSP3_DCFG_TIM_POS; | ||
41 | l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS; | 40 | l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS; |
42 | l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS; | 41 | l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS; |
43 | l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS; | 42 | l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS; |
44 | l3 |= 1 << D40_MEM_LCSP3_DTCP_POS; | ||
45 | 43 | ||
46 | l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS; | 44 | l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS; |
47 | l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS; | 45 | l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS; |
48 | l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS; | 46 | l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS; |
49 | l1 |= 1 << D40_MEM_LCSP1_STCP_POS; | ||
50 | 47 | ||
51 | *lcsp1 = l1; | 48 | *lcsp1 = l1; |
52 | *lcsp3 = l3; | 49 | *lcsp3 = l3; |
@@ -235,7 +232,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, | |||
235 | } | 232 | } |
236 | 233 | ||
237 | return total_size; | 234 | return total_size; |
238 | err: | 235 | err: |
239 | return err; | 236 | return err; |
240 | } | 237 | } |
241 | 238 | ||
@@ -268,11 +265,59 @@ void d40_phy_lli_write(void __iomem *virtbase, | |||
268 | 265 | ||
269 | /* DMA logical lli operations */ | 266 | /* DMA logical lli operations */ |
270 | 267 | ||
268 | static void d40_log_lli_link(struct d40_log_lli *lli_dst, | ||
269 | struct d40_log_lli *lli_src, | ||
270 | int next) | ||
271 | { | ||
272 | u32 slos = 0; | ||
273 | u32 dlos = 0; | ||
274 | |||
275 | if (next != -EINVAL) { | ||
276 | slos = next * 2; | ||
277 | dlos = next * 2 + 1; | ||
278 | } else { | ||
279 | lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; | ||
280 | lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; | ||
281 | } | ||
282 | |||
283 | lli_src->lcsp13 = (lli_src->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) | | ||
284 | (slos << D40_MEM_LCSP1_SLOS_POS); | ||
285 | |||
286 | lli_dst->lcsp13 = (lli_dst->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) | | ||
287 | (dlos << D40_MEM_LCSP1_SLOS_POS); | ||
288 | } | ||
289 | |||
290 | void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, | ||
291 | struct d40_log_lli *lli_dst, | ||
292 | struct d40_log_lli *lli_src, | ||
293 | int next) | ||
294 | { | ||
295 | d40_log_lli_link(lli_dst, lli_src, next); | ||
296 | |||
297 | writel(lli_src->lcsp02, &lcpa[0].lcsp0); | ||
298 | writel(lli_src->lcsp13, &lcpa[0].lcsp1); | ||
299 | writel(lli_dst->lcsp02, &lcpa[0].lcsp2); | ||
300 | writel(lli_dst->lcsp13, &lcpa[0].lcsp3); | ||
301 | } | ||
302 | |||
303 | void d40_log_lli_lcla_write(struct d40_log_lli *lcla, | ||
304 | struct d40_log_lli *lli_dst, | ||
305 | struct d40_log_lli *lli_src, | ||
306 | int next) | ||
307 | { | ||
308 | d40_log_lli_link(lli_dst, lli_src, next); | ||
309 | |||
310 | writel(lli_src->lcsp02, &lcla[0].lcsp02); | ||
311 | writel(lli_src->lcsp13, &lcla[0].lcsp13); | ||
312 | writel(lli_dst->lcsp02, &lcla[1].lcsp02); | ||
313 | writel(lli_dst->lcsp13, &lcla[1].lcsp13); | ||
314 | } | ||
315 | |||
271 | void d40_log_fill_lli(struct d40_log_lli *lli, | 316 | void d40_log_fill_lli(struct d40_log_lli *lli, |
272 | dma_addr_t data, u32 data_size, | 317 | dma_addr_t data, u32 data_size, |
273 | u32 lli_next_off, u32 reg_cfg, | 318 | u32 reg_cfg, |
274 | u32 data_width, | 319 | u32 data_width, |
275 | bool term_int, bool addr_inc) | 320 | bool addr_inc) |
276 | { | 321 | { |
277 | lli->lcsp13 = reg_cfg; | 322 | lli->lcsp13 = reg_cfg; |
278 | 323 | ||
@@ -287,165 +332,69 @@ void d40_log_fill_lli(struct d40_log_lli *lli, | |||
287 | if (addr_inc) | 332 | if (addr_inc) |
288 | lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK; | 333 | lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK; |
289 | 334 | ||
290 | lli->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; | ||
291 | /* If this scatter list entry is the last one, no next link */ | ||
292 | lli->lcsp13 |= (lli_next_off << D40_MEM_LCSP1_SLOS_POS) & | ||
293 | D40_MEM_LCSP1_SLOS_MASK; | ||
294 | |||
295 | if (term_int) | ||
296 | lli->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; | ||
297 | else | ||
298 | lli->lcsp13 &= ~D40_MEM_LCSP1_SCFG_TIM_MASK; | ||
299 | } | 335 | } |
300 | 336 | ||
301 | int d40_log_sg_to_dev(struct d40_lcla_elem *lcla, | 337 | int d40_log_sg_to_dev(struct scatterlist *sg, |
302 | struct scatterlist *sg, | ||
303 | int sg_len, | 338 | int sg_len, |
304 | struct d40_log_lli_bidir *lli, | 339 | struct d40_log_lli_bidir *lli, |
305 | struct d40_def_lcsp *lcsp, | 340 | struct d40_def_lcsp *lcsp, |
306 | u32 src_data_width, | 341 | u32 src_data_width, |
307 | u32 dst_data_width, | 342 | u32 dst_data_width, |
308 | enum dma_data_direction direction, | 343 | enum dma_data_direction direction, |
309 | dma_addr_t dev_addr, int max_len, | 344 | dma_addr_t dev_addr) |
310 | int llis_per_log) | ||
311 | { | 345 | { |
312 | int total_size = 0; | 346 | int total_size = 0; |
313 | struct scatterlist *current_sg = sg; | 347 | struct scatterlist *current_sg = sg; |
314 | int i; | 348 | int i; |
315 | u32 next_lli_off_dst = 0; | ||
316 | u32 next_lli_off_src = 0; | ||
317 | 349 | ||
318 | for_each_sg(sg, current_sg, sg_len, i) { | 350 | for_each_sg(sg, current_sg, sg_len, i) { |
319 | total_size += sg_dma_len(current_sg); | 351 | total_size += sg_dma_len(current_sg); |
320 | 352 | ||
321 | /* | ||
322 | * If this scatter list entry is the last one or | ||
323 | * max length, terminate link. | ||
324 | */ | ||
325 | if (sg_len - 1 == i || ((i+1) % max_len == 0)) { | ||
326 | next_lli_off_src = 0; | ||
327 | next_lli_off_dst = 0; | ||
328 | } else { | ||
329 | if (next_lli_off_dst == 0 && | ||
330 | next_lli_off_src == 0) { | ||
331 | /* The first lli will be at next_lli_off */ | ||
332 | next_lli_off_dst = (lcla->dst_id * | ||
333 | llis_per_log + 1); | ||
334 | next_lli_off_src = (lcla->src_id * | ||
335 | llis_per_log + 1); | ||
336 | } else { | ||
337 | next_lli_off_dst++; | ||
338 | next_lli_off_src++; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | if (direction == DMA_TO_DEVICE) { | 353 | if (direction == DMA_TO_DEVICE) { |
343 | d40_log_fill_lli(&lli->src[i], | 354 | d40_log_fill_lli(&lli->src[i], |
344 | sg_phys(current_sg), | 355 | sg_phys(current_sg), |
345 | sg_dma_len(current_sg), | 356 | sg_dma_len(current_sg), |
346 | next_lli_off_src, | ||
347 | lcsp->lcsp1, src_data_width, | 357 | lcsp->lcsp1, src_data_width, |
348 | false, | ||
349 | true); | 358 | true); |
350 | d40_log_fill_lli(&lli->dst[i], | 359 | d40_log_fill_lli(&lli->dst[i], |
351 | dev_addr, | 360 | dev_addr, |
352 | sg_dma_len(current_sg), | 361 | sg_dma_len(current_sg), |
353 | next_lli_off_dst, | ||
354 | lcsp->lcsp3, dst_data_width, | 362 | lcsp->lcsp3, dst_data_width, |
355 | /* No next == terminal interrupt */ | ||
356 | !next_lli_off_dst, | ||
357 | false); | 363 | false); |
358 | } else { | 364 | } else { |
359 | d40_log_fill_lli(&lli->dst[i], | 365 | d40_log_fill_lli(&lli->dst[i], |
360 | sg_phys(current_sg), | 366 | sg_phys(current_sg), |
361 | sg_dma_len(current_sg), | 367 | sg_dma_len(current_sg), |
362 | next_lli_off_dst, | ||
363 | lcsp->lcsp3, dst_data_width, | 368 | lcsp->lcsp3, dst_data_width, |
364 | /* No next == terminal interrupt */ | ||
365 | !next_lli_off_dst, | ||
366 | true); | 369 | true); |
367 | d40_log_fill_lli(&lli->src[i], | 370 | d40_log_fill_lli(&lli->src[i], |
368 | dev_addr, | 371 | dev_addr, |
369 | sg_dma_len(current_sg), | 372 | sg_dma_len(current_sg), |
370 | next_lli_off_src, | ||
371 | lcsp->lcsp1, src_data_width, | 373 | lcsp->lcsp1, src_data_width, |
372 | false, | ||
373 | false); | 374 | false); |
374 | } | 375 | } |
375 | } | 376 | } |
376 | return total_size; | 377 | return total_size; |
377 | } | 378 | } |
378 | 379 | ||
379 | int d40_log_sg_to_lli(int lcla_id, | 380 | int d40_log_sg_to_lli(struct scatterlist *sg, |
380 | struct scatterlist *sg, | ||
381 | int sg_len, | 381 | int sg_len, |
382 | struct d40_log_lli *lli_sg, | 382 | struct d40_log_lli *lli_sg, |
383 | u32 lcsp13, /* src or dst*/ | 383 | u32 lcsp13, /* src or dst*/ |
384 | u32 data_width, | 384 | u32 data_width) |
385 | int max_len, int llis_per_log) | ||
386 | { | 385 | { |
387 | int total_size = 0; | 386 | int total_size = 0; |
388 | struct scatterlist *current_sg = sg; | 387 | struct scatterlist *current_sg = sg; |
389 | int i; | 388 | int i; |
390 | u32 next_lli_off = 0; | ||
391 | 389 | ||
392 | for_each_sg(sg, current_sg, sg_len, i) { | 390 | for_each_sg(sg, current_sg, sg_len, i) { |
393 | total_size += sg_dma_len(current_sg); | 391 | total_size += sg_dma_len(current_sg); |
394 | 392 | ||
395 | /* | ||
396 | * If this scatter list entry is the last one or | ||
397 | * max length, terminate link. | ||
398 | */ | ||
399 | if (sg_len - 1 == i || ((i+1) % max_len == 0)) | ||
400 | next_lli_off = 0; | ||
401 | else { | ||
402 | if (next_lli_off == 0) | ||
403 | /* The first lli will be at next_lli_off */ | ||
404 | next_lli_off = lcla_id * llis_per_log + 1; | ||
405 | else | ||
406 | next_lli_off++; | ||
407 | } | ||
408 | |||
409 | d40_log_fill_lli(&lli_sg[i], | 393 | d40_log_fill_lli(&lli_sg[i], |
410 | sg_phys(current_sg), | 394 | sg_phys(current_sg), |
411 | sg_dma_len(current_sg), | 395 | sg_dma_len(current_sg), |
412 | next_lli_off, | ||
413 | lcsp13, data_width, | 396 | lcsp13, data_width, |
414 | !next_lli_off, | ||
415 | true); | 397 | true); |
416 | } | 398 | } |
417 | return total_size; | 399 | return total_size; |
418 | } | 400 | } |
419 | |||
420 | int d40_log_lli_write(struct d40_log_lli_full *lcpa, | ||
421 | struct d40_log_lli *lcla_src, | ||
422 | struct d40_log_lli *lcla_dst, | ||
423 | struct d40_log_lli *lli_dst, | ||
424 | struct d40_log_lli *lli_src, | ||
425 | int llis_per_log) | ||
426 | { | ||
427 | u32 slos; | ||
428 | u32 dlos; | ||
429 | int i; | ||
430 | |||
431 | writel(lli_src->lcsp02, &lcpa->lcsp0); | ||
432 | writel(lli_src->lcsp13, &lcpa->lcsp1); | ||
433 | writel(lli_dst->lcsp02, &lcpa->lcsp2); | ||
434 | writel(lli_dst->lcsp13, &lcpa->lcsp3); | ||
435 | |||
436 | slos = lli_src->lcsp13 & D40_MEM_LCSP1_SLOS_MASK; | ||
437 | dlos = lli_dst->lcsp13 & D40_MEM_LCSP3_DLOS_MASK; | ||
438 | |||
439 | for (i = 0; (i < llis_per_log) && slos && dlos; i++) { | ||
440 | writel(lli_src[i + 1].lcsp02, &lcla_src[i].lcsp02); | ||
441 | writel(lli_src[i + 1].lcsp13, &lcla_src[i].lcsp13); | ||
442 | writel(lli_dst[i + 1].lcsp02, &lcla_dst[i].lcsp02); | ||
443 | writel(lli_dst[i + 1].lcsp13, &lcla_dst[i].lcsp13); | ||
444 | |||
445 | slos = lli_src[i + 1].lcsp13 & D40_MEM_LCSP1_SLOS_MASK; | ||
446 | dlos = lli_dst[i + 1].lcsp13 & D40_MEM_LCSP3_DLOS_MASK; | ||
447 | } | ||
448 | |||
449 | return i; | ||
450 | |||
451 | } | ||