aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/fsldma.h137
-rw-r--r--drivers/dma/fsldma.c226
-rw-r--r--include/linux/dmaengine.h3
3 files changed, 47 insertions, 319 deletions
diff --git a/arch/powerpc/include/asm/fsldma.h b/arch/powerpc/include/asm/fsldma.h
deleted file mode 100644
index debc5ed96d6..00000000000
--- a/arch/powerpc/include/asm/fsldma.h
+++ /dev/null
@@ -1,137 +0,0 @@
1/*
2 * Freescale MPC83XX / MPC85XX DMA Controller
3 *
4 * Copyright (c) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 */
10
11#ifndef __ARCH_POWERPC_ASM_FSLDMA_H__
12#define __ARCH_POWERPC_ASM_FSLDMA_H__
13
14#include <linux/slab.h>
15#include <linux/dmaengine.h>
16
17/*
18 * Definitions for the Freescale DMA controller's DMA_SLAVE implemention
19 *
20 * The Freescale DMA_SLAVE implementation was designed to handle many-to-many
21 * transfers. An example usage would be an accelerated copy between two
22 * scatterlists. Another example use would be an accelerated copy from
23 * multiple non-contiguous device buffers into a single scatterlist.
24 *
25 * A DMA_SLAVE transaction is defined by a struct fsl_dma_slave. This
26 * structure contains a list of hardware addresses that should be copied
27 * to/from the scatterlist passed into device_prep_slave_sg(). The structure
28 * also has some fields to enable hardware-specific features.
29 */
30
31/**
32 * struct fsl_dma_hw_addr
33 * @entry: linked list entry
34 * @address: the hardware address
35 * @length: length to transfer
36 *
37 * Holds a single physical hardware address / length pair for use
38 * with the DMAEngine DMA_SLAVE API.
39 */
40struct fsl_dma_hw_addr {
41 struct list_head entry;
42
43 dma_addr_t address;
44 size_t length;
45};
46
47/**
48 * struct fsl_dma_slave
49 * @addresses: a linked list of struct fsl_dma_hw_addr structures
50 * @request_count: value for DMA request count
51 * @src_loop_size: setup and enable constant source-address DMA transfers
52 * @dst_loop_size: setup and enable constant destination address DMA transfers
53 * @external_start: enable externally started DMA transfers
54 * @external_pause: enable externally paused DMA transfers
55 *
56 * Holds a list of address / length pairs for use with the DMAEngine
57 * DMA_SLAVE API implementation for the Freescale DMA controller.
58 */
59struct fsl_dma_slave {
60
61 /* List of hardware address/length pairs */
62 struct list_head addresses;
63
64 /* Support for extra controller features */
65 unsigned int request_count;
66 unsigned int src_loop_size;
67 unsigned int dst_loop_size;
68 bool external_start;
69 bool external_pause;
70};
71
72/**
73 * fsl_dma_slave_append - add an address/length pair to a struct fsl_dma_slave
74 * @slave: the &struct fsl_dma_slave to add to
75 * @address: the hardware address to add
76 * @length: the length of bytes to transfer from @address
77 *
78 * Add a hardware address/length pair to a struct fsl_dma_slave. Returns 0 on
79 * success, -ERRNO otherwise.
80 */
81static inline int fsl_dma_slave_append(struct fsl_dma_slave *slave,
82 dma_addr_t address, size_t length)
83{
84 struct fsl_dma_hw_addr *addr;
85
86 addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
87 if (!addr)
88 return -ENOMEM;
89
90 INIT_LIST_HEAD(&addr->entry);
91 addr->address = address;
92 addr->length = length;
93
94 list_add_tail(&addr->entry, &slave->addresses);
95 return 0;
96}
97
98/**
99 * fsl_dma_slave_free - free a struct fsl_dma_slave
100 * @slave: the struct fsl_dma_slave to free
101 *
102 * Free a struct fsl_dma_slave and all associated address/length pairs
103 */
104static inline void fsl_dma_slave_free(struct fsl_dma_slave *slave)
105{
106 struct fsl_dma_hw_addr *addr, *tmp;
107
108 if (slave) {
109 list_for_each_entry_safe(addr, tmp, &slave->addresses, entry) {
110 list_del(&addr->entry);
111 kfree(addr);
112 }
113
114 kfree(slave);
115 }
116}
117
118/**
119 * fsl_dma_slave_alloc - allocate a struct fsl_dma_slave
120 * @gfp: the flags to pass to kmalloc when allocating this structure
121 *
122 * Allocate a struct fsl_dma_slave for use by the DMA_SLAVE API. Returns a new
123 * struct fsl_dma_slave on success, or NULL on failure.
124 */
125static inline struct fsl_dma_slave *fsl_dma_slave_alloc(gfp_t gfp)
126{
127 struct fsl_dma_slave *slave;
128
129 slave = kzalloc(sizeof(*slave), gfp);
130 if (!slave)
131 return NULL;
132
133 INIT_LIST_HEAD(&slave->addresses);
134 return slave;
135}
136
137#endif /* __ARCH_POWERPC_ASM_FSLDMA_H__ */
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 1ed29d10a5f..286c3ac6bdc 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
41static const char msg_ld_oom[] = "No free memory for link descriptor\n"; 40static 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
851finished:
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
881fail:
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
898static int fsl_dma_device_control(struct dma_chan *dchan, 730static 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}
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 2c9ee98f6c7..885f3521167 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -120,12 +120,15 @@ enum dma_ctrl_flags {
120 * configuration data in statically from the platform). An additional 120 * configuration data in statically from the platform). An additional
121 * argument of struct dma_slave_config must be passed in with this 121 * argument of struct dma_slave_config must be passed in with this
122 * command. 122 * command.
123 * @FSLDMA_EXTERNAL_START: this command will put the Freescale DMA controller
124 * into external start mode.
123 */ 125 */
124enum dma_ctrl_cmd { 126enum dma_ctrl_cmd {
125 DMA_TERMINATE_ALL, 127 DMA_TERMINATE_ALL,
126 DMA_PAUSE, 128 DMA_PAUSE,
127 DMA_RESUME, 129 DMA_RESUME,
128 DMA_SLAVE_CONFIG, 130 DMA_SLAVE_CONFIG,
131 FSLDMA_EXTERNAL_START,
129}; 132};
130 133
131/** 134/**