diff options
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/fsldma.c | 226 |
1 files changed, 44 insertions, 182 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 1ed29d10a5fa..286c3ac6bdcc 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/dmapool.h> | 35 | #include <linux/dmapool.h> |
36 | #include <linux/of_platform.h> | 36 | #include <linux/of_platform.h> |
37 | 37 | ||
38 | #include <asm/fsldma.h> | ||
39 | #include "fsldma.h" | 38 | #include "fsldma.h" |
40 | 39 | ||
41 | static const char msg_ld_oom[] = "No free memory for link descriptor\n"; | 40 | static const char msg_ld_oom[] = "No free memory for link descriptor\n"; |
@@ -719,207 +718,70 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg( | |||
719 | struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, | 718 | struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, |
720 | enum dma_data_direction direction, unsigned long flags) | 719 | enum dma_data_direction direction, unsigned long flags) |
721 | { | 720 | { |
722 | struct fsldma_chan *chan; | ||
723 | struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL; | ||
724 | struct fsl_dma_slave *slave; | ||
725 | size_t copy; | ||
726 | |||
727 | int i; | ||
728 | struct scatterlist *sg; | ||
729 | size_t sg_used; | ||
730 | size_t hw_used; | ||
731 | struct fsl_dma_hw_addr *hw; | ||
732 | dma_addr_t dma_dst, dma_src; | ||
733 | |||
734 | if (!dchan) | ||
735 | return NULL; | ||
736 | |||
737 | if (!dchan->private) | ||
738 | return NULL; | ||
739 | |||
740 | chan = to_fsl_chan(dchan); | ||
741 | slave = dchan->private; | ||
742 | |||
743 | if (list_empty(&slave->addresses)) | ||
744 | return NULL; | ||
745 | |||
746 | hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry); | ||
747 | hw_used = 0; | ||
748 | |||
749 | /* | 721 | /* |
750 | * Build the hardware transaction to copy from the scatterlist to | 722 | * This operation is not supported on the Freescale DMA controller |
751 | * the hardware, or from the hardware to the scatterlist | ||
752 | * | 723 | * |
753 | * If you are copying from the hardware to the scatterlist and it | 724 | * However, we need to provide the function pointer to allow the |
754 | * takes two hardware entries to fill an entire page, then both | 725 | * device_control() method to work. |
755 | * hardware entries will be coalesced into the same page | ||
756 | * | ||
757 | * If you are copying from the scatterlist to the hardware and a | ||
758 | * single page can fill two hardware entries, then the data will | ||
759 | * be read out of the page into the first hardware entry, and so on | ||
760 | */ | 726 | */ |
761 | for_each_sg(sgl, sg, sg_len, i) { | ||
762 | sg_used = 0; | ||
763 | |||
764 | /* Loop until the entire scatterlist entry is used */ | ||
765 | while (sg_used < sg_dma_len(sg)) { | ||
766 | |||
767 | /* | ||
768 | * If we've used up the current hardware address/length | ||
769 | * pair, we need to load a new one | ||
770 | * | ||
771 | * This is done in a while loop so that descriptors with | ||
772 | * length == 0 will be skipped | ||
773 | */ | ||
774 | while (hw_used >= hw->length) { | ||
775 | |||
776 | /* | ||
777 | * If the current hardware entry is the last | ||
778 | * entry in the list, we're finished | ||
779 | */ | ||
780 | if (list_is_last(&hw->entry, &slave->addresses)) | ||
781 | goto finished; | ||
782 | |||
783 | /* Get the next hardware address/length pair */ | ||
784 | hw = list_entry(hw->entry.next, | ||
785 | struct fsl_dma_hw_addr, entry); | ||
786 | hw_used = 0; | ||
787 | } | ||
788 | |||
789 | /* Allocate the link descriptor from DMA pool */ | ||
790 | new = fsl_dma_alloc_descriptor(chan); | ||
791 | if (!new) { | ||
792 | dev_err(chan->dev, "No free memory for " | ||
793 | "link descriptor\n"); | ||
794 | goto fail; | ||
795 | } | ||
796 | #ifdef FSL_DMA_LD_DEBUG | ||
797 | dev_dbg(chan->dev, "new link desc alloc %p\n", new); | ||
798 | #endif | ||
799 | |||
800 | /* | ||
801 | * Calculate the maximum number of bytes to transfer, | ||
802 | * making sure it is less than the DMA controller limit | ||
803 | */ | ||
804 | copy = min_t(size_t, sg_dma_len(sg) - sg_used, | ||
805 | hw->length - hw_used); | ||
806 | copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT); | ||
807 | |||
808 | /* | ||
809 | * DMA_FROM_DEVICE | ||
810 | * from the hardware to the scatterlist | ||
811 | * | ||
812 | * DMA_TO_DEVICE | ||
813 | * from the scatterlist to the hardware | ||
814 | */ | ||
815 | if (direction == DMA_FROM_DEVICE) { | ||
816 | dma_src = hw->address + hw_used; | ||
817 | dma_dst = sg_dma_address(sg) + sg_used; | ||
818 | } else { | ||
819 | dma_src = sg_dma_address(sg) + sg_used; | ||
820 | dma_dst = hw->address + hw_used; | ||
821 | } | ||
822 | |||
823 | /* Fill in the descriptor */ | ||
824 | set_desc_cnt(chan, &new->hw, copy); | ||
825 | set_desc_src(chan, &new->hw, dma_src); | ||
826 | set_desc_dst(chan, &new->hw, dma_dst); | ||
827 | |||
828 | /* | ||
829 | * If this is not the first descriptor, chain the | ||
830 | * current descriptor after the previous descriptor | ||
831 | */ | ||
832 | if (!first) { | ||
833 | first = new; | ||
834 | } else { | ||
835 | set_desc_next(chan, &prev->hw, | ||
836 | new->async_tx.phys); | ||
837 | } | ||
838 | |||
839 | new->async_tx.cookie = 0; | ||
840 | async_tx_ack(&new->async_tx); | ||
841 | |||
842 | prev = new; | ||
843 | sg_used += copy; | ||
844 | hw_used += copy; | ||
845 | |||
846 | /* Insert the link descriptor into the LD ring */ | ||
847 | list_add_tail(&new->node, &first->tx_list); | ||
848 | } | ||
849 | } | ||
850 | |||
851 | finished: | ||
852 | |||
853 | /* All of the hardware address/length pairs had length == 0 */ | ||
854 | if (!first || !new) | ||
855 | return NULL; | ||
856 | |||
857 | new->async_tx.flags = flags; | ||
858 | new->async_tx.cookie = -EBUSY; | ||
859 | |||
860 | /* Set End-of-link to the last link descriptor of new list */ | ||
861 | set_ld_eol(chan, new); | ||
862 | |||
863 | /* Enable extra controller features */ | ||
864 | if (chan->set_src_loop_size) | ||
865 | chan->set_src_loop_size(chan, slave->src_loop_size); | ||
866 | |||
867 | if (chan->set_dst_loop_size) | ||
868 | chan->set_dst_loop_size(chan, slave->dst_loop_size); | ||
869 | |||
870 | if (chan->toggle_ext_start) | ||
871 | chan->toggle_ext_start(chan, slave->external_start); | ||
872 | |||
873 | if (chan->toggle_ext_pause) | ||
874 | chan->toggle_ext_pause(chan, slave->external_pause); | ||
875 | |||
876 | if (chan->set_request_count) | ||
877 | chan->set_request_count(chan, slave->request_count); | ||
878 | |||
879 | return &first->async_tx; | ||
880 | |||
881 | fail: | ||
882 | /* If first was not set, then we failed to allocate the very first | ||
883 | * descriptor, and we're done */ | ||
884 | if (!first) | ||
885 | return NULL; | ||
886 | |||
887 | /* | ||
888 | * First is set, so all of the descriptors we allocated have been added | ||
889 | * to first->tx_list, INCLUDING "first" itself. Therefore we | ||
890 | * must traverse the list backwards freeing each descriptor in turn | ||
891 | * | ||
892 | * We're re-using variables for the loop, oh well | ||
893 | */ | ||
894 | fsldma_free_desc_list_reverse(chan, &first->tx_list); | ||
895 | return NULL; | 727 | return NULL; |
896 | } | 728 | } |
897 | 729 | ||
898 | static int fsl_dma_device_control(struct dma_chan *dchan, | 730 | static int fsl_dma_device_control(struct dma_chan *dchan, |
899 | enum dma_ctrl_cmd cmd, unsigned long arg) | 731 | enum dma_ctrl_cmd cmd, unsigned long arg) |
900 | { | 732 | { |
733 | struct dma_slave_config *config; | ||
901 | struct fsldma_chan *chan; | 734 | struct fsldma_chan *chan; |
902 | unsigned long flags; | 735 | unsigned long flags; |
903 | 736 | int size; | |
904 | /* Only supports DMA_TERMINATE_ALL */ | ||
905 | if (cmd != DMA_TERMINATE_ALL) | ||
906 | return -ENXIO; | ||
907 | 737 | ||
908 | if (!dchan) | 738 | if (!dchan) |
909 | return -EINVAL; | 739 | return -EINVAL; |
910 | 740 | ||
911 | chan = to_fsl_chan(dchan); | 741 | chan = to_fsl_chan(dchan); |
912 | 742 | ||
913 | /* Halt the DMA engine */ | 743 | switch (cmd) { |
914 | dma_halt(chan); | 744 | case DMA_TERMINATE_ALL: |
745 | /* Halt the DMA engine */ | ||
746 | dma_halt(chan); | ||
915 | 747 | ||
916 | spin_lock_irqsave(&chan->desc_lock, flags); | 748 | spin_lock_irqsave(&chan->desc_lock, flags); |
917 | 749 | ||
918 | /* Remove and free all of the descriptors in the LD queue */ | 750 | /* Remove and free all of the descriptors in the LD queue */ |
919 | fsldma_free_desc_list(chan, &chan->ld_pending); | 751 | fsldma_free_desc_list(chan, &chan->ld_pending); |
920 | fsldma_free_desc_list(chan, &chan->ld_running); | 752 | fsldma_free_desc_list(chan, &chan->ld_running); |
921 | 753 | ||
922 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 754 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
755 | return 0; | ||
756 | |||
757 | case DMA_SLAVE_CONFIG: | ||
758 | config = (struct dma_slave_config *)arg; | ||
759 | |||
760 | /* make sure the channel supports setting burst size */ | ||
761 | if (!chan->set_request_count) | ||
762 | return -ENXIO; | ||
763 | |||
764 | /* we set the controller burst size depending on direction */ | ||
765 | if (config->direction == DMA_TO_DEVICE) | ||
766 | size = config->dst_addr_width * config->dst_maxburst; | ||
767 | else | ||
768 | size = config->src_addr_width * config->src_maxburst; | ||
769 | |||
770 | chan->set_request_count(chan, size); | ||
771 | return 0; | ||
772 | |||
773 | case FSLDMA_EXTERNAL_START: | ||
774 | |||
775 | /* make sure the channel supports external start */ | ||
776 | if (!chan->toggle_ext_start) | ||
777 | return -ENXIO; | ||
778 | |||
779 | chan->toggle_ext_start(chan, arg); | ||
780 | return 0; | ||
781 | |||
782 | default: | ||
783 | return -ENXIO; | ||
784 | } | ||
923 | 785 | ||
924 | return 0; | 786 | return 0; |
925 | } | 787 | } |