diff options
Diffstat (limited to 'drivers/dma/fsldma.c')
-rw-r--r-- | drivers/dma/fsldma.c | 88 |
1 files changed, 74 insertions, 14 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index cc9a68158d99..72692309398a 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
@@ -57,12 +57,12 @@ static void dma_init(struct fsl_dma_chan *fsl_chan) | |||
57 | 57 | ||
58 | } | 58 | } |
59 | 59 | ||
60 | static void set_sr(struct fsl_dma_chan *fsl_chan, dma_addr_t val) | 60 | static void set_sr(struct fsl_dma_chan *fsl_chan, u32 val) |
61 | { | 61 | { |
62 | DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32); | 62 | DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32); |
63 | } | 63 | } |
64 | 64 | ||
65 | static dma_addr_t get_sr(struct fsl_dma_chan *fsl_chan) | 65 | static u32 get_sr(struct fsl_dma_chan *fsl_chan) |
66 | { | 66 | { |
67 | return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32); | 67 | return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32); |
68 | } | 68 | } |
@@ -123,6 +123,11 @@ static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan) | |||
123 | return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64); | 123 | return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64); |
124 | } | 124 | } |
125 | 125 | ||
126 | static u32 get_bcr(struct fsl_dma_chan *fsl_chan) | ||
127 | { | ||
128 | return DMA_IN(fsl_chan, &fsl_chan->reg_base->bcr, 32); | ||
129 | } | ||
130 | |||
126 | static int dma_is_idle(struct fsl_dma_chan *fsl_chan) | 131 | static int dma_is_idle(struct fsl_dma_chan *fsl_chan) |
127 | { | 132 | { |
128 | u32 sr = get_sr(fsl_chan); | 133 | u32 sr = get_sr(fsl_chan); |
@@ -406,6 +411,35 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan) | |||
406 | dma_pool_destroy(fsl_chan->desc_pool); | 411 | dma_pool_destroy(fsl_chan->desc_pool); |
407 | } | 412 | } |
408 | 413 | ||
414 | static struct dma_async_tx_descriptor * | ||
415 | fsl_dma_prep_interrupt(struct dma_chan *chan) | ||
416 | { | ||
417 | struct fsl_dma_chan *fsl_chan; | ||
418 | struct fsl_desc_sw *new; | ||
419 | |||
420 | if (!chan) | ||
421 | return NULL; | ||
422 | |||
423 | fsl_chan = to_fsl_chan(chan); | ||
424 | |||
425 | new = fsl_dma_alloc_descriptor(fsl_chan); | ||
426 | if (!new) { | ||
427 | dev_err(fsl_chan->dev, "No free memory for link descriptor\n"); | ||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | new->async_tx.cookie = -EBUSY; | ||
432 | new->async_tx.ack = 0; | ||
433 | |||
434 | /* Insert the link descriptor to the LD ring */ | ||
435 | list_add_tail(&new->node, &new->async_tx.tx_list); | ||
436 | |||
437 | /* Set End-of-link to the last link descriptor of new list*/ | ||
438 | set_ld_eol(fsl_chan, new); | ||
439 | |||
440 | return &new->async_tx; | ||
441 | } | ||
442 | |||
409 | static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( | 443 | static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( |
410 | struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src, | 444 | struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src, |
411 | size_t len, unsigned long flags) | 445 | size_t len, unsigned long flags) |
@@ -436,7 +470,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( | |||
436 | dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new); | 470 | dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new); |
437 | #endif | 471 | #endif |
438 | 472 | ||
439 | copy = min(len, FSL_DMA_BCR_MAX_CNT); | 473 | copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT); |
440 | 474 | ||
441 | set_desc_cnt(fsl_chan, &new->hw, copy); | 475 | set_desc_cnt(fsl_chan, &new->hw, copy); |
442 | set_desc_src(fsl_chan, &new->hw, dma_src); | 476 | set_desc_src(fsl_chan, &new->hw, dma_src); |
@@ -513,7 +547,6 @@ static void fsl_chan_ld_cleanup(struct fsl_dma_chan *fsl_chan) | |||
513 | 547 | ||
514 | spin_lock_irqsave(&fsl_chan->desc_lock, flags); | 548 | spin_lock_irqsave(&fsl_chan->desc_lock, flags); |
515 | 549 | ||
516 | fsl_dma_update_completed_cookie(fsl_chan); | ||
517 | dev_dbg(fsl_chan->dev, "chan completed_cookie = %d\n", | 550 | dev_dbg(fsl_chan->dev, "chan completed_cookie = %d\n", |
518 | fsl_chan->completed_cookie); | 551 | fsl_chan->completed_cookie); |
519 | list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) { | 552 | list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) { |
@@ -581,8 +614,8 @@ static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan) | |||
581 | if (ld_node != &fsl_chan->ld_queue) { | 614 | if (ld_node != &fsl_chan->ld_queue) { |
582 | /* Get the ld start address from ld_queue */ | 615 | /* Get the ld start address from ld_queue */ |
583 | next_dest_addr = to_fsl_desc(ld_node)->async_tx.phys; | 616 | next_dest_addr = to_fsl_desc(ld_node)->async_tx.phys; |
584 | dev_dbg(fsl_chan->dev, "xfer LDs staring from 0x%016llx\n", | 617 | dev_dbg(fsl_chan->dev, "xfer LDs staring from %p\n", |
585 | (u64)next_dest_addr); | 618 | (void *)next_dest_addr); |
586 | set_cdar(fsl_chan, next_dest_addr); | 619 | set_cdar(fsl_chan, next_dest_addr); |
587 | dma_start(fsl_chan); | 620 | dma_start(fsl_chan); |
588 | } else { | 621 | } else { |
@@ -662,7 +695,7 @@ static enum dma_status fsl_dma_is_complete(struct dma_chan *chan, | |||
662 | static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) | 695 | static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) |
663 | { | 696 | { |
664 | struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data; | 697 | struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data; |
665 | dma_addr_t stat; | 698 | u32 stat; |
666 | 699 | ||
667 | stat = get_sr(fsl_chan); | 700 | stat = get_sr(fsl_chan); |
668 | dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n", | 701 | dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n", |
@@ -676,15 +709,32 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) | |||
676 | if (stat & FSL_DMA_SR_TE) | 709 | if (stat & FSL_DMA_SR_TE) |
677 | dev_err(fsl_chan->dev, "Transfer Error!\n"); | 710 | dev_err(fsl_chan->dev, "Transfer Error!\n"); |
678 | 711 | ||
712 | /* Programming Error | ||
713 | * The DMA_INTERRUPT async_tx is a NULL transfer, which will | ||
714 | * triger a PE interrupt. | ||
715 | */ | ||
716 | if (stat & FSL_DMA_SR_PE) { | ||
717 | dev_dbg(fsl_chan->dev, "event: Programming Error INT\n"); | ||
718 | if (get_bcr(fsl_chan) == 0) { | ||
719 | /* BCR register is 0, this is a DMA_INTERRUPT async_tx. | ||
720 | * Now, update the completed cookie, and continue the | ||
721 | * next uncompleted transfer. | ||
722 | */ | ||
723 | fsl_dma_update_completed_cookie(fsl_chan); | ||
724 | fsl_chan_xfer_ld_queue(fsl_chan); | ||
725 | } | ||
726 | stat &= ~FSL_DMA_SR_PE; | ||
727 | } | ||
728 | |||
679 | /* If the link descriptor segment transfer finishes, | 729 | /* If the link descriptor segment transfer finishes, |
680 | * we will recycle the used descriptor. | 730 | * we will recycle the used descriptor. |
681 | */ | 731 | */ |
682 | if (stat & FSL_DMA_SR_EOSI) { | 732 | if (stat & FSL_DMA_SR_EOSI) { |
683 | dev_dbg(fsl_chan->dev, "event: End-of-segments INT\n"); | 733 | dev_dbg(fsl_chan->dev, "event: End-of-segments INT\n"); |
684 | dev_dbg(fsl_chan->dev, "event: clndar 0x%016llx, " | 734 | dev_dbg(fsl_chan->dev, "event: clndar %p, nlndar %p\n", |
685 | "nlndar 0x%016llx\n", (u64)get_cdar(fsl_chan), | 735 | (void *)get_cdar(fsl_chan), (void *)get_ndar(fsl_chan)); |
686 | (u64)get_ndar(fsl_chan)); | ||
687 | stat &= ~FSL_DMA_SR_EOSI; | 736 | stat &= ~FSL_DMA_SR_EOSI; |
737 | fsl_dma_update_completed_cookie(fsl_chan); | ||
688 | } | 738 | } |
689 | 739 | ||
690 | /* If it current transfer is the end-of-transfer, | 740 | /* If it current transfer is the end-of-transfer, |
@@ -726,12 +776,15 @@ static void dma_do_tasklet(unsigned long data) | |||
726 | fsl_chan_ld_cleanup(fsl_chan); | 776 | fsl_chan_ld_cleanup(fsl_chan); |
727 | } | 777 | } |
728 | 778 | ||
779 | #ifdef FSL_DMA_CALLBACKTEST | ||
729 | static void fsl_dma_callback_test(struct fsl_dma_chan *fsl_chan) | 780 | static void fsl_dma_callback_test(struct fsl_dma_chan *fsl_chan) |
730 | { | 781 | { |
731 | if (fsl_chan) | 782 | if (fsl_chan) |
732 | dev_info(fsl_chan->dev, "selftest: callback is ok!\n"); | 783 | dev_info(fsl_chan->dev, "selftest: callback is ok!\n"); |
733 | } | 784 | } |
785 | #endif | ||
734 | 786 | ||
787 | #ifdef CONFIG_FSL_DMA_SELFTEST | ||
735 | static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) | 788 | static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) |
736 | { | 789 | { |
737 | struct dma_chan *chan; | 790 | struct dma_chan *chan; |
@@ -813,6 +866,11 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) | |||
813 | tx3 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0); | 866 | tx3 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0); |
814 | async_tx_ack(tx3); | 867 | async_tx_ack(tx3); |
815 | 868 | ||
869 | /* Interrupt tx test */ | ||
870 | tx1 = fsl_dma_prep_interrupt(chan); | ||
871 | async_tx_ack(tx1); | ||
872 | cookie = fsl_dma_tx_submit(tx1); | ||
873 | |||
816 | /* Test exchanging the prepared tx sort */ | 874 | /* Test exchanging the prepared tx sort */ |
817 | cookie = fsl_dma_tx_submit(tx3); | 875 | cookie = fsl_dma_tx_submit(tx3); |
818 | cookie = fsl_dma_tx_submit(tx2); | 876 | cookie = fsl_dma_tx_submit(tx2); |
@@ -837,9 +895,9 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) | |||
837 | if (err) { | 895 | if (err) { |
838 | for (i = 0; (*(src + i) == *(dest + i)) && (i < test_size); | 896 | for (i = 0; (*(src + i) == *(dest + i)) && (i < test_size); |
839 | i++); | 897 | i++); |
840 | dev_err(fsl_chan->dev, "selftest: Test failed, data %d/%d is " | 898 | dev_err(fsl_chan->dev, "selftest: Test failed, data %d/%ld is " |
841 | "error! src 0x%x, dest 0x%x\n", | 899 | "error! src 0x%x, dest 0x%x\n", |
842 | i, test_size, *(src + i), *(dest + i)); | 900 | i, (long)test_size, *(src + i), *(dest + i)); |
843 | } | 901 | } |
844 | 902 | ||
845 | free_resources: | 903 | free_resources: |
@@ -848,6 +906,7 @@ out: | |||
848 | kfree(src); | 906 | kfree(src); |
849 | return err; | 907 | return err; |
850 | } | 908 | } |
909 | #endif | ||
851 | 910 | ||
852 | static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, | 911 | static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, |
853 | const struct of_device_id *match) | 912 | const struct of_device_id *match) |
@@ -1008,8 +1067,8 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, | |||
1008 | } | 1067 | } |
1009 | 1068 | ||
1010 | dev_info(&dev->dev, "Probe the Freescale DMA driver for %s " | 1069 | dev_info(&dev->dev, "Probe the Freescale DMA driver for %s " |
1011 | "controller at 0x%08x...\n", | 1070 | "controller at %p...\n", |
1012 | match->compatible, fdev->reg.start); | 1071 | match->compatible, (void *)fdev->reg.start); |
1013 | fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end | 1072 | fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end |
1014 | - fdev->reg.start + 1); | 1073 | - fdev->reg.start + 1); |
1015 | 1074 | ||
@@ -1017,6 +1076,7 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, | |||
1017 | dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); | 1076 | dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); |
1018 | fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; | 1077 | fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; |
1019 | fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; | 1078 | fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; |
1079 | fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; | ||
1020 | fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; | 1080 | fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; |
1021 | fdev->common.device_is_tx_complete = fsl_dma_is_complete; | 1081 | fdev->common.device_is_tx_complete = fsl_dma_is_complete; |
1022 | fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; | 1082 | fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; |