aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSiva Yerramreddy <yshivakrishna@gmail.com>2014-07-11 17:04:21 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-12 12:57:42 -0400
commit95b4ecbf759ae8ecf40462ed5e6a08023166a05c (patch)
tree2f479b7ba4a4678826a85d78f4e90d1baa4f870f
parenta8438814d3b899e04e808e45585b40931517244f (diff)
dma: MIC X100 DMA Driver
This patch implements DMA Engine API for DMA controller on MIC X100 Coprocessors. DMA h/w is shared between host and card s/w. Channels 0 to 3 are used by host and 4 to 7 are used by card. Since the DMA device doesn't show up as PCIe device, a virtual bus called mic bus is created and virtual devices are added on that bus to follow device model. Allowed dma transfer directions are host to card, card to host and card to card. Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com> Reviewed-by: Nikhil Rao <nikhil.rao@intel.com> Reviewed-by: Sudeep Dutt <sudeep.dutt@intel.com> Signed-off-by: Siva Yerramreddy <yshivakrishna@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/dma/Kconfig19
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/mic_x100_dma.c774
-rw-r--r--drivers/dma/mic_x100_dma.h286
4 files changed, 1080 insertions, 0 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1eca7b9760e6..7c8b8c41f4f4 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -33,6 +33,25 @@ if DMADEVICES
33 33
34comment "DMA Devices" 34comment "DMA Devices"
35 35
36config INTEL_MIC_X100_DMA
37 tristate "Intel MIC X100 DMA Driver"
38 depends on 64BIT && X86 && INTEL_MIC_BUS
39 select DMAENGINE
40 default N
41 help
42 This enables DMA support for the Intel Many Integrated Core
43 (MIC) family of PCIe form factor coprocessor X100 devices that
44 run a 64 bit Linux OS. This driver will be used by both MIC
45 host and card drivers.
46
47 If you are building host kernel with a MIC device or a card
48 kernel for a MIC device, then say M (recommended) or Y, else
49 say N. If unsure say N.
50
51 More information about the Intel MIC family as well as the Linux
52 OS and tools for MIC to use with this driver are available from
53 <http://software.intel.com/en-us/mic-developer>.
54
36config INTEL_MID_DMAC 55config INTEL_MID_DMAC
37 tristate "Intel MID DMA support for Peripheral DMA controllers" 56 tristate "Intel MID DMA support for Peripheral DMA controllers"
38 depends on PCI && X86 57 depends on PCI && X86
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index c779e1eb2db2..bd9e7fa928bd 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -47,3 +47,4 @@ obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
47obj-$(CONFIG_FSL_EDMA) += fsl-edma.o 47obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
48obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o 48obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o
49obj-y += xilinx/ 49obj-y += xilinx/
50obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
new file mode 100644
index 000000000000..6de2e677be04
--- /dev/null
+++ b/drivers/dma/mic_x100_dma.c
@@ -0,0 +1,774 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2014 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC X100 DMA Driver.
19 *
20 * Adapted from IOAT dma driver.
21 */
22#include <linux/module.h>
23#include <linux/io.h>
24#include <linux/seq_file.h>
25
26#include "mic_x100_dma.h"
27
28#define MIC_DMA_MAX_XFER_SIZE_CARD (1 * 1024 * 1024 -\
29 MIC_DMA_ALIGN_BYTES)
30#define MIC_DMA_MAX_XFER_SIZE_HOST (1 * 1024 * 1024 >> 1)
31#define MIC_DMA_DESC_TYPE_SHIFT 60
32#define MIC_DMA_MEMCPY_LEN_SHIFT 46
33#define MIC_DMA_STAT_INTR_SHIFT 59
34
35/* high-water mark for pushing dma descriptors */
36static int mic_dma_pending_level = 4;
37
38/* Status descriptor is used to write a 64 bit value to a memory location */
39enum mic_dma_desc_format_type {
40 MIC_DMA_MEMCPY = 1,
41 MIC_DMA_STATUS,
42};
43
44static inline u32 mic_dma_hw_ring_inc(u32 val)
45{
46 return (val + 1) % MIC_DMA_DESC_RX_SIZE;
47}
48
49static inline u32 mic_dma_hw_ring_dec(u32 val)
50{
51 return val ? val - 1 : MIC_DMA_DESC_RX_SIZE - 1;
52}
53
54static inline void mic_dma_hw_ring_inc_head(struct mic_dma_chan *ch)
55{
56 ch->head = mic_dma_hw_ring_inc(ch->head);
57}
58
59/* Prepare a memcpy desc */
60static inline void mic_dma_memcpy_desc(struct mic_dma_desc *desc,
61 dma_addr_t src_phys, dma_addr_t dst_phys, u64 size)
62{
63 u64 qw0, qw1;
64
65 qw0 = src_phys;
66 qw0 |= (size >> MIC_DMA_ALIGN_SHIFT) << MIC_DMA_MEMCPY_LEN_SHIFT;
67 qw1 = MIC_DMA_MEMCPY;
68 qw1 <<= MIC_DMA_DESC_TYPE_SHIFT;
69 qw1 |= dst_phys;
70 desc->qw0 = qw0;
71 desc->qw1 = qw1;
72}
73
74/* Prepare a status desc. with @data to be written at @dst_phys */
75static inline void mic_dma_prep_status_desc(struct mic_dma_desc *desc, u64 data,
76 dma_addr_t dst_phys, bool generate_intr)
77{
78 u64 qw0, qw1;
79
80 qw0 = data;
81 qw1 = (u64) MIC_DMA_STATUS << MIC_DMA_DESC_TYPE_SHIFT | dst_phys;
82 if (generate_intr)
83 qw1 |= (1ULL << MIC_DMA_STAT_INTR_SHIFT);
84 desc->qw0 = qw0;
85 desc->qw1 = qw1;
86}
87
88static void mic_dma_cleanup(struct mic_dma_chan *ch)
89{
90 struct dma_async_tx_descriptor *tx;
91 u32 tail;
92 u32 last_tail;
93
94 spin_lock(&ch->cleanup_lock);
95 tail = mic_dma_read_cmp_cnt(ch);
96 /*
97 * This is the barrier pair for smp_wmb() in fn.
98 * mic_dma_tx_submit_unlock. It's required so that we read the
99 * updated cookie value from tx->cookie.
100 */
101 smp_rmb();
102 for (last_tail = ch->last_tail; tail != last_tail;) {
103 tx = &ch->tx_array[last_tail];
104 if (tx->cookie) {
105 dma_cookie_complete(tx);
106 if (tx->callback) {
107 tx->callback(tx->callback_param);
108 tx->callback = NULL;
109 }
110 }
111 last_tail = mic_dma_hw_ring_inc(last_tail);
112 }
113 /* finish all completion callbacks before incrementing tail */
114 smp_mb();
115 ch->last_tail = last_tail;
116 spin_unlock(&ch->cleanup_lock);
117}
118
119static u32 mic_dma_ring_count(u32 head, u32 tail)
120{
121 u32 count;
122
123 if (head >= tail)
124 count = (tail - 0) + (MIC_DMA_DESC_RX_SIZE - head);
125 else
126 count = tail - head;
127 return count - 1;
128}
129
130/* Returns the num. of free descriptors on success, -ENOMEM on failure */
131static int mic_dma_avail_desc_ring_space(struct mic_dma_chan *ch, int required)
132{
133 struct device *dev = mic_dma_ch_to_device(ch);
134 u32 count;
135
136 count = mic_dma_ring_count(ch->head, ch->last_tail);
137 if (count < required) {
138 mic_dma_cleanup(ch);
139 count = mic_dma_ring_count(ch->head, ch->last_tail);
140 }
141
142 if (count < required) {
143 dev_dbg(dev, "Not enough desc space");
144 dev_dbg(dev, "%s %d required=%u, avail=%u\n",
145 __func__, __LINE__, required, count);
146 return -ENOMEM;
147 } else {
148 return count;
149 }
150}
151
152/* Program memcpy descriptors into the descriptor ring and update s/w head ptr*/
153static int mic_dma_prog_memcpy_desc(struct mic_dma_chan *ch, dma_addr_t src,
154 dma_addr_t dst, size_t len)
155