diff options
| -rw-r--r-- | drivers/dma/fsldma.c | 128 |
1 files changed, 125 insertions, 3 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index cea08bed9cf..1ed29d10a5f 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
| @@ -38,6 +38,8 @@ | |||
| 38 | #include <asm/fsldma.h> | 38 | #include <asm/fsldma.h> |
| 39 | #include "fsldma.h" | 39 | #include "fsldma.h" |
| 40 | 40 | ||
| 41 | static const char msg_ld_oom[] = "No free memory for link descriptor\n"; | ||
| 42 | |||
| 41 | static void dma_init(struct fsldma_chan *chan) | 43 | static void dma_init(struct fsldma_chan *chan) |
| 42 | { | 44 | { |
| 43 | /* Reset the channel */ | 45 | /* Reset the channel */ |
| @@ -499,7 +501,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags) | |||
| 499 | 501 | ||
| 500 | new = fsl_dma_alloc_descriptor(chan); | 502 | new = fsl_dma_alloc_descriptor(chan); |
| 501 | if (!new) { | 503 | if (!new) { |
| 502 | dev_err(chan->dev, "No free memory for link descriptor\n"); | 504 | dev_err(chan->dev, msg_ld_oom); |
| 503 | return NULL; | 505 | return NULL; |
| 504 | } | 506 | } |
| 505 | 507 | ||
| @@ -536,8 +538,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( | |||
| 536 | /* Allocate the link descriptor from DMA pool */ | 538 | /* Allocate the link descriptor from DMA pool */ |
| 537 | new = fsl_dma_alloc_descriptor(chan); | 539 | new = fsl_dma_alloc_descriptor(chan); |
| 538 | if (!new) { | 540 | if (!new) { |
| 539 | dev_err(chan->dev, | 541 | dev_err(chan->dev, msg_ld_oom); |
| 540 | "No free memory for link descriptor\n"); | ||
| 541 | goto fail; | 542 | goto fail; |
| 542 | } | 543 | } |
| 543 | #ifdef FSL_DMA_LD_DEBUG | 544 | #ifdef FSL_DMA_LD_DEBUG |
| @@ -583,6 +584,125 @@ fail: | |||
| 583 | return NULL; | 584 | return NULL; |
| 584 | } | 585 | } |
| 585 | 586 | ||
| 587 | static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan, | ||
| 588 | struct scatterlist *dst_sg, unsigned int dst_nents, | ||
| 589 | struct scatterlist *src_sg, unsigned int src_nents, | ||
| 590 | unsigned long flags) | ||
| 591 | { | ||
| 592 | struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL; | ||
| 593 | struct fsldma_chan *chan = to_fsl_chan(dchan); | ||
| 594 | size_t dst_avail, src_avail; | ||
| 595 | dma_addr_t dst, src; | ||
| 596 | size_t len; | ||
| 597 | |||
| 598 | /* basic sanity checks */ | ||
| 599 | if (dst_nents == 0 || src_nents == 0) | ||
| 600 | return NULL; | ||
| 601 | |||
| 602 | if (dst_sg == NULL || src_sg == NULL) | ||
| 603 | return NULL; | ||
| 604 | |||
| 605 | /* | ||
| 606 | * TODO: should we check that both scatterlists have the same | ||
| 607 | * TODO: number of bytes in total? Is that really an error? | ||
| 608 | */ | ||
| 609 | |||
| 610 | /* get prepared for the loop */ | ||
| 611 | dst_avail = sg_dma_len(dst_sg); | ||
| 612 | src_avail = sg_dma_len(src_sg); | ||
| 613 | |||
| 614 | /* run until we are out of scatterlist entries */ | ||
| 615 | while (true) { | ||
| 616 | |||
| 617 | /* create the largest transaction possible */ | ||
| 618 | len = min_t(size_t, src_avail, dst_avail); | ||
| 619 | len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT); | ||
| 620 | if (len == 0) | ||
| 621 | goto fetch; | ||
| 622 | |||
| 623 | dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail; | ||
| 624 | src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail; | ||
| 625 | |||
| 626 | /* allocate and populate the descriptor */ | ||
| 627 | new = fsl_dma_alloc_descriptor(chan); | ||
| 628 | if (!new) { | ||
| 629 | dev_err(chan->dev, msg_ld_oom); | ||
| 630 | goto fail; | ||
| 631 | } | ||
| 632 | #ifdef FSL_DMA_LD_DEBUG | ||
| 633 | dev_dbg(chan->dev, "new link desc alloc %p\n", new); | ||
| 634 | #endif | ||
| 635 | |||
| 636 | set_desc_cnt(chan, &new->hw, len); | ||
| 637 | set_desc_src(chan, &new->hw, src); | ||
| 638 | set_desc_dst(chan, &new->hw, dst); | ||
| 639 | |||
| 640 | if (!first) | ||
| 641 | first = new; | ||
| 642 | else | ||
| 643 | set_desc_next(chan, &prev->hw, new->async_tx.phys); | ||
| 644 | |||
| 645 | new->async_tx.cookie = 0; | ||
| 646 | async_tx_ack(&new->async_tx); | ||
| 647 | prev = new; | ||
| 648 | |||
| 649 | /* Insert the link descriptor to the LD ring */ | ||
| 650 | list_add_tail(&new->node, &first->tx_list); | ||
| 651 | |||
| 652 | /* update metadata */ | ||
| 653 | dst_avail -= len; | ||
| 654 | src_avail -= len; | ||
| 655 | |||
| 656 | fetch: | ||
| 657 | /* fetch the next dst scatterlist entry */ | ||
| 658 | if (dst_avail == 0) { | ||
| 659 | |||
| 660 | /* no more entries: we're done */ | ||
| 661 | if (dst_nents == 0) | ||
| 662 | break; | ||
| 663 | |||
| 664 | /* fetch the next entry: if there are no more: done */ | ||
| 665 | dst_sg = sg_next(dst_sg); | ||
| 666 | if (dst_sg == NULL) | ||
| 667 | break; | ||
| 668 | |||
| 669 | dst_nents--; | ||
| 670 | dst_avail = sg_dma_len(dst_sg); | ||
| 671 | } | ||
| 672 | |||
| 673 | /* fetch the next src scatterlist entry */ | ||
| 674 | if (src_avail == 0) { | ||
| 675 | |||
| 676 | /* no more entries: we're done */ | ||
| 677 | if (src_nents == 0) | ||
| 678 | break; | ||
| 679 | |||
| 680 | /* fetch the next entry: if there are no more: done */ | ||
| 681 | src_sg = sg_next(src_sg); | ||
| 682 | if (src_sg == NULL) | ||
| 683 | break; | ||
| 684 | |||
| 685 | src_nents--; | ||
| 686 | src_avail = sg_dma_len(src_sg); | ||
| 687 | } | ||
| 688 | } | ||
| 689 | |||
| 690 | new->async_tx.flags = flags; /* client is in control of this ack */ | ||
| 691 | new->async_tx.cookie = -EBUSY; | ||
| 692 | |||
| 693 | /* Set End-of-link to the last link descriptor of new list */ | ||
| 694 | set_ld_eol(chan, new); | ||
| 695 | |||
| 696 | return &first->async_tx; | ||
| 697 | |||
| 698 | fail: | ||
| 699 | if (!first) | ||
| 700 | return NULL; | ||
| 701 | |||
| 702 | fsldma_free_desc_list_reverse(chan, &first->tx_list); | ||
| 703 | return NULL; | ||
| 704 | } | ||
| 705 | |||
| 586 | /** | 706 | /** |
| 587 | * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction | 707 | * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction |
| 588 | * @chan: DMA channel | 708 | * @chan: DMA channel |
| @@ -1327,11 +1447,13 @@ static int __devinit fsldma_of_probe(struct platform_device *op, | |||
| 1327 | 1447 | ||
| 1328 | dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); | 1448 | dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); |
| 1329 | dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); | 1449 | dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); |
| 1450 | dma_cap_set(DMA_SG, fdev->common.cap_mask); | ||
| 1330 | dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); | 1451 | dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); |
| 1331 | fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; | 1452 | fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; |
| 1332 | fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; | 1453 | fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; |
| 1333 | fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; | 1454 | fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; |
| 1334 | fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; | 1455 | fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; |
| 1456 | fdev->common.device_prep_dma_sg = fsl_dma_prep_sg; | ||
| 1335 | fdev->common.device_tx_status = fsl_tx_status; | 1457 | fdev->common.device_tx_status = fsl_tx_status; |
| 1336 | fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; | 1458 | fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; |
| 1337 | fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; | 1459 | fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; |
