aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mic/host/mic_virtio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mic/host/mic_virtio.c')
-rw-r--r--drivers/misc/mic/host/mic_virtio.c187
1 files changed, 149 insertions, 38 deletions
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c
index 7e1ef0ebbb80..a020e4eb435a 100644
--- a/drivers/misc/mic/host/mic_virtio.c
+++ b/drivers/misc/mic/host/mic_virtio.c
@@ -21,60 +21,157 @@
21#include <linux/pci.h> 21#include <linux/pci.h>
22#include <linux/sched.h> 22#include <linux/sched.h>
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24 24#include <linux/dmaengine.h>
25#include <linux/mic_common.h> 25#include <linux/mic_common.h>
26
26#include "../common/mic_dev.h" 27#include "../common/mic_dev.h"
27#include "mic_device.h" 28#include "mic_device.h"
28#include "mic_smpt.h" 29#include "mic_smpt.h"
29#include "mic_virtio.h" 30#include "mic_virtio.h"
30 31
31/* 32/*
32 * Initiates the copies across the PCIe bus from card memory to 33 * Size of the internal buffer used during DMA's as an intermediate buffer
33 * a user space buffer. 34 * for copy to/from user.
34 */ 35 */
35static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, 36#define MIC_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL)
36 void __user *ubuf, size_t len, u64 addr) 37
38static int mic_sync_dma(struct mic_device *mdev, dma_addr_t dst,
39 dma_addr_t src, size_t len)
37{ 40{
38 int err; 41 int err = 0;
39 void __iomem *dbuf = mvdev->mdev->aper.va + addr; 42 struct dma_async_tx_descriptor *tx;
40 /* 43 struct dma_chan *mic_ch = mdev->dma_ch;
41 * We are copying from IO below an should ideally use something 44
42 * like copy_to_user_fromio(..) if it existed. 45 if (!mic_ch) {
43 */ 46 err = -EBUSY;
44 if (copy_to_user(ubuf, (void __force *)dbuf, len)) { 47 goto error;
45 err = -EFAULT; 48 }
46 dev_err(mic_dev(mvdev), "%s %d err %d\n", 49
50 tx = mic_ch->device->device_prep_dma_memcpy(mic_ch, dst, src, len,
51 DMA_PREP_FENCE);
52 if (!tx) {
53 err = -ENOMEM;
54 goto error;
55 } else {
56 dma_cookie_t cookie = tx->tx_submit(tx);
57
58 err = dma_submit_error(cookie);
59 if (err)
60 goto error;
61 err = dma_sync_wait(mic_ch, cookie);
62 }
63error:
64 if (err)
65 dev_err(mdev->sdev->parent, "%s %d err %d\n",
47 __func__, __LINE__, err); 66 __func__, __LINE__, err);
48 goto err; 67 return err;
68}
69
70/*
71 * Initiates the copies across the PCIe bus from card memory to a user
72 * space buffer. When transfers are done using DMA, source/destination
73 * addresses and transfer length must follow the alignment requirements of
74 * the MIC DMA engine.
75 */
76static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, void __user *ubuf,
77 size_t len, u64 daddr, size_t dlen,
78 int vr_idx)
79{
80 struct mic_device *mdev = mvdev->mdev;
81 void __iomem *dbuf = mdev->aper.va + daddr;
82 struct mic_vringh *mvr = &mvdev->mvr[vr_idx];
83 size_t dma_alignment = 1 << mdev->dma_ch->device->copy_align;
84 size_t dma_offset;
85 size_t partlen;
86 int err;
87
88 dma_offset = daddr - round_down(daddr, dma_alignment);
89 daddr -= dma_offset;
90 len += dma_offset;
91
92 while (len) {
93 partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE);
94
95 err = mic_sync_dma(mdev, mvr->buf_da, daddr,
96 ALIGN(partlen, dma_alignment));
97 if (err)
98 goto err;
99
100 if (copy_to_user(ubuf, mvr->buf + dma_offset,
101 partlen - dma_offset)) {
102 err = -EFAULT;
103 goto err;
104 }
105 daddr += partlen;
106 ubuf += partlen;
107 dbuf += partlen;
108 mvdev->in_bytes_dma += partlen;
109 mvdev->in_bytes += partlen;
110 len -= partlen;
111 dma_offset = 0;
49 } 112 }
50 mvdev->in_bytes += len; 113 return 0;
51 err = 0;
52err: 114err:
115 dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err);
53 return err; 116 return err;
54} 117}
55 118
56/* 119/*
57 * Initiates copies across the PCIe bus from a user space 120 * Initiates copies across the PCIe bus from a user space buffer to card
58 * buffer to card memory. 121 * memory. When transfers are done using DMA, source/destination addresses
122 * and transfer length must follow the alignment requirements of the MIC
123 * DMA engine.
59 */ 124 */
60static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, 125static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, void __user *ubuf,
61 void __user *ubuf, size_t len, u64 addr) 126 size_t len, u64 daddr, size_t dlen,
127 int vr_idx)
62{ 128{
129 struct mic_device *mdev = mvdev->mdev;
130 void __iomem *dbuf = mdev->aper.va + daddr;
131 struct mic_vringh *mvr = &mvdev->mvr[vr_idx];
132 size_t dma_alignment = 1 << mdev->dma_ch->device->copy_align;
133 size_t partlen;
63 int err; 134 int err;
64 void __iomem *dbuf = mvdev->mdev->aper.va + addr; 135
136 if (daddr & (dma_alignment - 1)) {
137 mvdev->tx_dst_unaligned += len;
138 goto memcpy;
139 } else if (ALIGN(len, dma_alignment) > dlen) {
140 mvdev->tx_len_unaligned += len;
141 goto memcpy;
142 }
143
144 while (len) {
145 partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE);
146
147 if (copy_from_user(mvr->buf, ubuf, partlen)) {
148 err = -EFAULT;
149 goto err;
150 }
151 err = mic_sync_dma(mdev, daddr, mvr->buf_da,
152 ALIGN(partlen, dma_alignment));
153 if (err)
154 goto err;
155 daddr += partlen;
156 ubuf += partlen;
157 dbuf += partlen;
158 mvdev->out_bytes_dma += partlen;
159 mvdev->out_bytes += partlen;
160 len -= partlen;
161 }
162memcpy:
65 /* 163 /*
66 * We are copying to IO below and should ideally use something 164 * We are copying to IO below and should ideally use something
67 * like copy_from_user_toio(..) if it existed. 165 * like copy_from_user_toio(..) if it existed.
68 */ 166 */
69 if (copy_from_user((void __force *)dbuf, ubuf, len)) { 167 if (copy_from_user((void __force *)dbuf, ubuf, len)) {
70 err = -EFAULT; 168 err = -EFAULT;
71 dev_err(mic_dev(mvdev), "%s %d err %d\n",
72 __func__, __LINE__, err);
73 goto err; 169 goto err;
74 } 170 }
75 mvdev->out_bytes += len; 171 mvdev->out_bytes += len;
76 err = 0; 172 return 0;
77err: 173err:
174 dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err);
78 return err; 175 return err;
79} 176}
80 177
@@ -110,7 +207,8 @@ static inline u32 mic_vringh_iov_consumed(struct vringh_kiov *iov)
110 * way to override the VRINGH xfer(..) routines as of v3.10. 207 * way to override the VRINGH xfer(..) routines as of v3.10.
111 */ 208 */
112static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, 209static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov,
113 void __user *ubuf, size_t len, bool read, size_t *out_len) 210 void __user *ubuf, size_t len, bool read, int vr_idx,
211 size_t *out_len)
114{ 212{
115 int ret = 0; 213 int ret = 0;
116 size_t partlen, tot_len = 0; 214 size_t partlen, tot_len = 0;
@@ -118,13 +216,15 @@ static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov,
118 while (len && iov->i < iov->used) { 216 while (len && iov->i < iov->used) {
119 partlen = min(iov->iov[iov->i].iov_len, len); 217 partlen = min(iov->iov[iov->i].iov_len, len);
120 if (read) 218 if (read)
121 ret = mic_virtio_copy_to_user(mvdev, 219 ret = mic_virtio_copy_to_user(mvdev, ubuf, partlen,
122 ubuf, partlen, 220 (u64)iov->iov[iov->i].iov_base,
123 (u64)iov->iov[iov->i].iov_base); 221 iov->iov[iov->i].iov_len,
222 vr_idx);
124 else 223 else
125 ret = mic_virtio_copy_from_user(mvdev, 224 ret = mic_virtio_copy_from_user(mvdev, ubuf, partlen,
126 ubuf, partlen, 225 (u64)iov->iov[iov->i].iov_base,
127 (u64)iov->iov[iov->i].iov_base); 226 iov->iov[iov->i].iov_len,
227 vr_idx);
128 if (ret) { 228 if (ret) {
129 dev_err(mic_dev(mvdev), "%s %d err %d\n", 229 dev_err(mic_dev(mvdev), "%s %d err %d\n",
130 __func__, __LINE__, ret); 230 __func__, __LINE__, ret);
@@ -192,8 +292,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev,
192 ubuf = iov.iov_base; 292 ubuf = iov.iov_base;
193 } 293 }
194 /* Issue all the read descriptors first */ 294 /* Issue all the read descriptors first */
195 ret = mic_vringh_copy(mvdev, riov, ubuf, len, 295 ret = mic_vringh_copy(mvdev, riov, ubuf, len, MIC_VRINGH_READ,
196 MIC_VRINGH_READ, &out_len); 296 copy->vr_idx, &out_len);
197 if (ret) { 297 if (ret) {
198 dev_err(mic_dev(mvdev), "%s %d err %d\n", 298 dev_err(mic_dev(mvdev), "%s %d err %d\n",
199 __func__, __LINE__, ret); 299 __func__, __LINE__, ret);
@@ -203,8 +303,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev,
203 ubuf += out_len; 303 ubuf += out_len;
204 copy->out_len += out_len; 304 copy->out_len += out_len;
205 /* Issue the write descriptors next */ 305 /* Issue the write descriptors next */
206 ret = mic_vringh_copy(mvdev, wiov, ubuf, len, 306 ret = mic_vringh_copy(mvdev, wiov, ubuf, len, !MIC_VRINGH_READ,
207 !MIC_VRINGH_READ, &out_len); 307 copy->vr_idx, &out_len);
208 if (ret) { 308 if (ret) {
209 dev_err(mic_dev(mvdev), "%s %d err %d\n", 309 dev_err(mic_dev(mvdev), "%s %d err %d\n",
210 __func__, __LINE__, ret); 310 __func__, __LINE__, ret);
@@ -589,13 +689,19 @@ int mic_virtio_add_device(struct mic_vdev *mvdev,
589 dev_dbg(mdev->sdev->parent, 689 dev_dbg(mdev->sdev->parent,
590 "%s %d index %d va %p info %p vr_size 0x%x\n", 690 "%s %d index %d va %p info %p vr_size 0x%x\n",
591 __func__, __LINE__, i, vr->va, vr->info, vr_size); 691 __func__, __LINE__, i, vr->va, vr->info, vr_size);
692 mvr->buf = (void *)__get_free_pages(GFP_KERNEL,
693 get_order(MIC_INT_DMA_BUF_SIZE));
694 mvr->buf_da = mic_map_single(mvdev->mdev, mvr->buf,
695 MIC_INT_DMA_BUF_SIZE);
592 } 696 }
593 697
594 snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, 698 snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id,
595 mvdev->virtio_id); 699 mvdev->virtio_id);
596 mvdev->virtio_db = mic_next_db(mdev); 700 mvdev->virtio_db = mic_next_db(mdev);
597 mvdev->virtio_cookie = mic_request_irq(mdev, mic_virtio_intr_handler, 701 mvdev->virtio_cookie = mic_request_threaded_irq(mdev,
598 irqname, mvdev, mvdev->virtio_db, MIC_INTR_DB); 702 mic_virtio_intr_handler,
703 NULL, irqname, mvdev,
704 mvdev->virtio_db, MIC_INTR_DB);
599 if (IS_ERR(mvdev->virtio_cookie)) { 705 if (IS_ERR(mvdev->virtio_cookie)) {
600 ret = PTR_ERR(mvdev->virtio_cookie); 706 ret = PTR_ERR(mvdev->virtio_cookie);
601 dev_dbg(mdev->sdev->parent, "request irq failed\n"); 707 dev_dbg(mdev->sdev->parent, "request irq failed\n");
@@ -671,6 +777,11 @@ skip_hot_remove:
671 vqconfig = mic_vq_config(mvdev->dd); 777 vqconfig = mic_vq_config(mvdev->dd);
672 for (i = 0; i < mvdev->dd->num_vq; i++) { 778 for (i = 0; i < mvdev->dd->num_vq; i++) {
673 struct mic_vringh *mvr = &mvdev->mvr[i]; 779 struct mic_vringh *mvr = &mvdev->mvr[i];
780
781 mic_unmap_single(mvdev->mdev, mvr->buf_da,
782 MIC_INT_DMA_BUF_SIZE);
783 free_pages((unsigned long)mvr->buf,
784 get_order(MIC_INT_DMA_BUF_SIZE));
674 vringh_kiov_cleanup(&mvr->riov); 785 vringh_kiov_cleanup(&mvr->riov);
675 vringh_kiov_cleanup(&mvr->wiov); 786 vringh_kiov_cleanup(&mvr->wiov);
676 mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), 787 mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address),