diff options
author | Siva Yerramreddy <yshivakrishna@gmail.com> | 2014-07-11 17:04:23 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-11 21:31:12 -0400 |
commit | d4ef098e4cd836b3726781eabe064d7010b6eaa8 (patch) | |
tree | 6d5eab0949f4cbc3552847a4ce874cb92a117379 | |
parent | b8e439f48a19e5832c08b4656a3a8ebb1f4b05f8 (diff) |
misc: mic: add dma support in host driver
This patch adds a dma device on the mic virtual bus and uses this dmaengine
to transfer data for virtio devices
Reviewed-by: Nikhil Rao <nikhil.rao@intel.com>
Signed-off-by: Sudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: Siva Yerramreddy <yshivakrishna@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/mic/Kconfig | 2 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_boot.c | 83 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_device.h | 24 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_intr.h | 3 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_virtio.c | 181 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_virtio.h | 21 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_x100.c | 8 |
7 files changed, 281 insertions, 41 deletions
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig index ee1d2ac3cd09..bf76313dab16 100644 --- a/drivers/misc/mic/Kconfig +++ b/drivers/misc/mic/Kconfig | |||
@@ -19,7 +19,7 @@ comment "Intel MIC Host Driver" | |||
19 | 19 | ||
20 | config INTEL_MIC_HOST | 20 | config INTEL_MIC_HOST |
21 | tristate "Intel MIC Host Driver" | 21 | tristate "Intel MIC Host Driver" |
22 | depends on 64BIT && PCI && X86 | 22 | depends on 64BIT && PCI && X86 && INTEL_MIC_BUS |
23 | select VHOST_RING | 23 | select VHOST_RING |
24 | help | 24 | help |
25 | This enables Host Driver support for the Intel Many Integrated | 25 | This enables Host Driver support for the Intel Many Integrated |
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c index b75c6b5cc20f..ff2b0fb1a6be 100644 --- a/drivers/misc/mic/host/mic_boot.c +++ b/drivers/misc/mic/host/mic_boot.c | |||
@@ -23,11 +23,70 @@ | |||
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | 24 | ||
25 | #include <linux/mic_common.h> | 25 | #include <linux/mic_common.h> |
26 | #include <linux/mic_bus.h> | ||
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 | ||
32 | static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev) | ||
33 | { | ||
34 | return dev_get_drvdata(mbdev->dev.parent); | ||
35 | } | ||
36 | |||
37 | static dma_addr_t | ||
38 | mic_dma_map_page(struct device *dev, struct page *page, | ||
39 | unsigned long offset, size_t size, enum dma_data_direction dir, | ||
40 | struct dma_attrs *attrs) | ||
41 | { | ||
42 | void *va = phys_to_virt(page_to_phys(page)) + offset; | ||
43 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
44 | |||
45 | return mic_map_single(mdev, va, size); | ||
46 | } | ||
47 | |||
48 | static void | ||
49 | mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | ||
50 | size_t size, enum dma_data_direction dir, | ||
51 | struct dma_attrs *attrs) | ||
52 | { | ||
53 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
54 | mic_unmap_single(mdev, dma_addr, size); | ||
55 | } | ||
56 | |||
57 | static struct dma_map_ops mic_dma_ops = { | ||
58 | .map_page = mic_dma_map_page, | ||
59 | .unmap_page = mic_dma_unmap_page, | ||
60 | }; | ||
61 | |||
62 | static struct mic_irq * | ||
63 | _mic_request_threaded_irq(struct mbus_device *mbdev, | ||
64 | irq_handler_t handler, irq_handler_t thread_fn, | ||
65 | const char *name, void *data, int intr_src) | ||
66 | { | ||
67 | return mic_request_threaded_irq(mbdev_to_mdev(mbdev), handler, | ||
68 | thread_fn, name, data, | ||
69 | intr_src, MIC_INTR_DMA); | ||
70 | } | ||
71 | |||
72 | static void _mic_free_irq(struct mbus_device *mbdev, | ||
73 | struct mic_irq *cookie, void *data) | ||
74 | { | ||
75 | return mic_free_irq(mbdev_to_mdev(mbdev), cookie, data); | ||
76 | } | ||
77 | |||
78 | static void _mic_ack_interrupt(struct mbus_device *mbdev, int num) | ||
79 | { | ||
80 | struct mic_device *mdev = mbdev_to_mdev(mbdev); | ||
81 | mdev->ops->intr_workarounds(mdev); | ||
82 | } | ||
83 | |||
84 | static struct mbus_hw_ops mbus_hw_ops = { | ||
85 | .request_threaded_irq = _mic_request_threaded_irq, | ||
86 | .free_irq = _mic_free_irq, | ||
87 | .ack_interrupt = _mic_ack_interrupt, | ||
88 | }; | ||
89 | |||
31 | /** | 90 | /** |
32 | * mic_reset - Reset the MIC device. | 91 | * mic_reset - Reset the MIC device. |
33 | * @mdev: pointer to mic_device instance | 92 | * @mdev: pointer to mic_device instance |
@@ -95,9 +154,21 @@ retry: | |||
95 | */ | 154 | */ |
96 | goto retry; | 155 | goto retry; |
97 | } | 156 | } |
157 | mdev->dma_mbdev = mbus_register_device(mdev->sdev->parent, | ||
158 | MBUS_DEV_DMA_HOST, &mic_dma_ops, | ||
159 | &mbus_hw_ops, mdev->mmio.va); | ||
160 | if (IS_ERR(mdev->dma_mbdev)) { | ||
161 | rc = PTR_ERR(mdev->dma_mbdev); | ||
162 | goto unlock_ret; | ||
163 | } | ||
164 | mdev->dma_ch = mic_request_dma_chan(mdev); | ||
165 | if (!mdev->dma_ch) { | ||
166 | rc = -ENXIO; | ||
167 | goto dma_remove; | ||
168 | } | ||
98 | rc = mdev->ops->load_mic_fw(mdev, buf); | 169 | rc = mdev->ops->load_mic_fw(mdev, buf); |
99 | if (rc) | 170 | if (rc) |
100 | goto unlock_ret; | 171 | goto dma_release; |
101 | mic_smpt_restore(mdev); | 172 | mic_smpt_restore(mdev); |
102 | mic_intr_restore(mdev); | 173 | mic_intr_restore(mdev); |
103 | mdev->intr_ops->enable_interrupts(mdev); | 174 | mdev->intr_ops->enable_interrupts(mdev); |
@@ -105,6 +176,11 @@ retry: | |||
105 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | 176 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); |
106 | mdev->ops->send_firmware_intr(mdev); | 177 | mdev->ops->send_firmware_intr(mdev); |
107 | mic_set_state(mdev, MIC_ONLINE); | 178 | mic_set_state(mdev, MIC_ONLINE); |
179 | goto unlock_ret; | ||
180 | dma_release: | ||
181 | dma_release_channel(mdev->dma_ch); | ||
182 | dma_remove: | ||
183 | mbus_unregister_device(mdev->dma_mbdev); | ||
108 | unlock_ret: | 184 | unlock_ret: |
109 | mutex_unlock(&mdev->mic_mutex); | 185 | mutex_unlock(&mdev->mic_mutex); |
110 | return rc; | 186 | return rc; |
@@ -122,6 +198,11 @@ void mic_stop(struct mic_device *mdev, bool force) | |||
122 | mutex_lock(&mdev->mic_mutex); | 198 | mutex_lock(&mdev->mic_mutex); |
123 | if (MIC_OFFLINE != mdev->state || force) { | 199 | if (MIC_OFFLINE != mdev->state || force) { |
124 | mic_virtio_reset_devices(mdev); | 200 | mic_virtio_reset_devices(mdev); |
201 | if (mdev->dma_ch) { | ||
202 | dma_release_channel(mdev->dma_ch); | ||
203 | mdev->dma_ch = NULL; | ||
204 | } | ||
205 | mbus_unregister_device(mdev->dma_mbdev); | ||
125 | mic_bootparam_init(mdev); | 206 | mic_bootparam_init(mdev); |
126 | mic_reset(mdev); | 207 | mic_reset(mdev); |
127 | if (MIC_RESET_FAILED == mdev->state) | 208 | if (MIC_RESET_FAILED == mdev->state) |
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h index 0398c696d257..016bd15a7bd1 100644 --- a/drivers/misc/mic/host/mic_device.h +++ b/drivers/misc/mic/host/mic_device.h | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <linux/idr.h> | 25 | #include <linux/idr.h> |
26 | #include <linux/notifier.h> | 26 | #include <linux/notifier.h> |
27 | #include <linux/irqreturn.h> | 27 | #include <linux/irqreturn.h> |
28 | #include <linux/dmaengine.h> | ||
29 | #include <linux/mic_bus.h> | ||
28 | 30 | ||
29 | #include "mic_intr.h" | 31 | #include "mic_intr.h" |
30 | 32 | ||
@@ -87,6 +89,8 @@ enum mic_stepping { | |||
87 | * @cdev: Character device for MIC. | 89 | * @cdev: Character device for MIC. |
88 | * @vdev_list: list of virtio devices. | 90 | * @vdev_list: list of virtio devices. |
89 | * @pm_notifier: Handles PM notifications from the OS. | 91 | * @pm_notifier: Handles PM notifications from the OS. |
92 | * @dma_mbdev: MIC BUS DMA device. | ||
93 | * @dma_ch: DMA channel reserved by this driver for use by virtio devices. | ||
90 | */ | 94 | */ |
91 | struct mic_device { | 95 | struct mic_device { |
92 | struct mic_mw mmio; | 96 | struct mic_mw mmio; |
@@ -124,6 +128,8 @@ struct mic_device { | |||
124 | struct cdev cdev; | 128 | struct cdev cdev; |
125 | struct list_head vdev_list; | 129 | struct list_head vdev_list; |
126 | struct notifier_block pm_notifier; | 130 | struct notifier_block pm_notifier; |
131 | struct mbus_device *dma_mbdev; | ||
132 | struct dma_chan *dma_ch; | ||
127 | }; | 133 | }; |
128 | 134 | ||
129 | /** | 135 | /** |
@@ -144,6 +150,7 @@ struct mic_device { | |||
144 | * @load_mic_fw: Load firmware segments required to boot the card | 150 | * @load_mic_fw: Load firmware segments required to boot the card |
145 | * into card memory. This includes the kernel, command line, ramdisk etc. | 151 | * into card memory. This includes the kernel, command line, ramdisk etc. |
146 | * @get_postcode: Get post code status from firmware. | 152 | * @get_postcode: Get post code status from firmware. |
153 | * @dma_filter: DMA filter function to be used. | ||
147 | */ | 154 | */ |
148 | struct mic_hw_ops { | 155 | struct mic_hw_ops { |
149 | u8 aper_bar; | 156 | u8 aper_bar; |
@@ -159,6 +166,7 @@ struct mic_hw_ops { | |||
159 | void (*send_firmware_intr)(struct mic_device *mdev); | 166 | void (*send_firmware_intr)(struct mic_device *mdev); |
160 | int (*load_mic_fw)(struct mic_device *mdev, const char *buf); | 167 | int (*load_mic_fw)(struct mic_device *mdev, const char *buf); |
161 | u32 (*get_postcode)(struct mic_device *mdev); | 168 | u32 (*get_postcode)(struct mic_device *mdev); |
169 | bool (*dma_filter)(struct dma_chan *chan, void *param); | ||
162 | }; | 170 | }; |
163 | 171 | ||
164 | /** | 172 | /** |
@@ -187,6 +195,22 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | |||
187 | iowrite32(val, mw->va + offset); | 195 | iowrite32(val, mw->va + offset); |
188 | } | 196 | } |
189 | 197 | ||
198 | static inline struct dma_chan *mic_request_dma_chan(struct mic_device *mdev) | ||
199 | { | ||
200 | dma_cap_mask_t mask; | ||
201 | struct dma_chan *chan; | ||
202 | |||
203 | dma_cap_zero(mask); | ||
204 | dma_cap_set(DMA_MEMCPY, mask); | ||
205 | chan = dma_request_channel(mask, mdev->ops->dma_filter, | ||
206 | mdev->sdev->parent); | ||
207 | if (chan) | ||
208 | return chan; | ||
209 | dev_err(mdev->sdev->parent, "%s %d unable to acquire channel\n", | ||
210 | __func__, __LINE__); | ||
211 | return NULL; | ||
212 | } | ||
213 | |||
190 | void mic_sysfs_init(struct mic_device *mdev); | 214 | void mic_sysfs_init(struct mic_device *mdev); |
191 | int mic_start(struct mic_device *mdev, const char *buf); | 215 | int mic_start(struct mic_device *mdev, const char *buf); |
192 | void mic_stop(struct mic_device *mdev, bool force); | 216 | void mic_stop(struct mic_device *mdev, bool force); |
diff --git a/drivers/misc/mic/host/mic_intr.h b/drivers/misc/mic/host/mic_intr.h index b1334dd9a0a1..9f783d4ad7f1 100644 --- a/drivers/misc/mic/host/mic_intr.h +++ b/drivers/misc/mic/host/mic_intr.h | |||
@@ -27,8 +27,9 @@ | |||
27 | * The minimum number of msix vectors required for normal operation. | 27 | * The minimum number of msix vectors required for normal operation. |
28 | * 3 for virtio network, console and block devices. | 28 | * 3 for virtio network, console and block devices. |
29 | * 1 for card shutdown notifications. | 29 | * 1 for card shutdown notifications. |
30 | * 4 for host owned DMA channels. | ||
30 | */ | 31 | */ |
31 | #define MIC_MIN_MSIX 4 | 32 | #define MIC_MIN_MSIX 8 |
32 | #define MIC_NUM_OFFSETS 32 | 33 | #define MIC_NUM_OFFSETS 32 |
33 | 34 | ||
34 | /** | 35 | /** |
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c index aba3e8324b82..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 | */ |
35 | static 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 | |
38 | static 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 | } | ||
63 | error: | ||
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 | */ | ||
76 | static 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; | ||
52 | err: | 114 | err: |
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 | */ |
60 | static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, | 125 | static 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 | } | ||
162 | memcpy: | ||
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; |
77 | err: | 173 | err: |
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 | */ |
112 | static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, | 209 | static 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,6 +689,10 @@ 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, |
@@ -673,6 +777,11 @@ skip_hot_remove: | |||
673 | vqconfig = mic_vq_config(mvdev->dd); | 777 | vqconfig = mic_vq_config(mvdev->dd); |
674 | for (i = 0; i < mvdev->dd->num_vq; i++) { | 778 | for (i = 0; i < mvdev->dd->num_vq; i++) { |
675 | 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)); | ||
676 | vringh_kiov_cleanup(&mvr->riov); | 785 | vringh_kiov_cleanup(&mvr->riov); |
677 | vringh_kiov_cleanup(&mvr->wiov); | 786 | vringh_kiov_cleanup(&mvr->wiov); |
678 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), | 787 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), |
diff --git a/drivers/misc/mic/host/mic_virtio.h b/drivers/misc/mic/host/mic_virtio.h index 184f3c84805b..d574efb853d9 100644 --- a/drivers/misc/mic/host/mic_virtio.h +++ b/drivers/misc/mic/host/mic_virtio.h | |||
@@ -46,18 +46,23 @@ | |||
46 | * @vrh: The host VRINGH used for accessing the card vrings. | 46 | * @vrh: The host VRINGH used for accessing the card vrings. |
47 | * @riov: The VRINGH read kernel IOV. | 47 | * @riov: The VRINGH read kernel IOV. |
48 | * @wiov: The VRINGH write kernel IOV. | 48 | * @wiov: The VRINGH write kernel IOV. |
49 | * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||
50 | * @vr_mutex: Mutex for synchronizing access to the VRING. | 49 | * @vr_mutex: Mutex for synchronizing access to the VRING. |
50 | * @buf: Temporary kernel buffer used to copy in/out data | ||
51 | * from/to the card via DMA. | ||
52 | * @buf_da: dma address of buf. | ||
51 | * @mvdev: Back pointer to MIC virtio device for vringh_notify(..). | 53 | * @mvdev: Back pointer to MIC virtio device for vringh_notify(..). |
54 | * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||
52 | */ | 55 | */ |
53 | struct mic_vringh { | 56 | struct mic_vringh { |
54 | struct mic_vring vring; | 57 | struct mic_vring vring; |
55 | struct vringh vrh; | 58 | struct vringh vrh; |
56 | struct vringh_kiov riov; | 59 | struct vringh_kiov riov; |
57 | struct vringh_kiov wiov; | 60 | struct vringh_kiov wiov; |
58 | u16 head; | ||
59 | struct mutex vr_mutex; | 61 | struct mutex vr_mutex; |
62 | void *buf; | ||
63 | dma_addr_t buf_da; | ||
60 | struct mic_vdev *mvdev; | 64 | struct mic_vdev *mvdev; |
65 | u16 head; | ||
61 | }; | 66 | }; |
62 | 67 | ||
63 | /** | 68 | /** |
@@ -69,6 +74,14 @@ struct mic_vringh { | |||
69 | * @poll_wake - Used for waking up threads blocked in poll. | 74 | * @poll_wake - Used for waking up threads blocked in poll. |
70 | * @out_bytes - Debug stats for number of bytes copied from host to card. | 75 | * @out_bytes - Debug stats for number of bytes copied from host to card. |
71 | * @in_bytes - Debug stats for number of bytes copied from card to host. | 76 | * @in_bytes - Debug stats for number of bytes copied from card to host. |
77 | * @out_bytes_dma - Debug stats for number of bytes copied from host to card | ||
78 | * using DMA. | ||
79 | * @in_bytes_dma - Debug stats for number of bytes copied from card to host | ||
80 | * using DMA. | ||
81 | * @tx_len_unaligned - Debug stats for number of bytes copied to the card where | ||
82 | * the transfer length did not have the required DMA alignment. | ||
83 | * @tx_dst_unaligned - Debug stats for number of bytes copied where the | ||
84 | * destination address on the card did not have the required DMA alignment. | ||
72 | * @mvr - Store per VRING data structures. | 85 | * @mvr - Store per VRING data structures. |
73 | * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. | 86 | * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. |
74 | * @dd - Virtio device descriptor. | 87 | * @dd - Virtio device descriptor. |
@@ -84,6 +97,10 @@ struct mic_vdev { | |||
84 | int poll_wake; | 97 | int poll_wake; |
85 | unsigned long out_bytes; | 98 | unsigned long out_bytes; |
86 | unsigned long in_bytes; | 99 | unsigned long in_bytes; |
100 | unsigned long out_bytes_dma; | ||
101 | unsigned long in_bytes_dma; | ||
102 | unsigned long tx_len_unaligned; | ||
103 | unsigned long tx_dst_unaligned; | ||
87 | struct mic_vringh mvr[MIC_MAX_VRINGS]; | 104 | struct mic_vringh mvr[MIC_MAX_VRINGS]; |
88 | struct work_struct virtio_bh_work; | 105 | struct work_struct virtio_bh_work; |
89 | struct mic_device_desc *dd; | 106 | struct mic_device_desc *dd; |
diff --git a/drivers/misc/mic/host/mic_x100.c b/drivers/misc/mic/host/mic_x100.c index 5562fdd3ef4e..b7a21e11dcdf 100644 --- a/drivers/misc/mic/host/mic_x100.c +++ b/drivers/misc/mic/host/mic_x100.c | |||
@@ -549,6 +549,13 @@ struct mic_smpt_ops mic_x100_smpt_ops = { | |||
549 | .set = mic_x100_smpt_set, | 549 | .set = mic_x100_smpt_set, |
550 | }; | 550 | }; |
551 | 551 | ||
552 | static bool mic_x100_dma_filter(struct dma_chan *chan, void *param) | ||
553 | { | ||
554 | if (chan->device->dev->parent == (struct device *)param) | ||
555 | return true; | ||
556 | return false; | ||
557 | } | ||
558 | |||
552 | struct mic_hw_ops mic_x100_ops = { | 559 | struct mic_hw_ops mic_x100_ops = { |
553 | .aper_bar = MIC_X100_APER_BAR, | 560 | .aper_bar = MIC_X100_APER_BAR, |
554 | .mmio_bar = MIC_X100_MMIO_BAR, | 561 | .mmio_bar = MIC_X100_MMIO_BAR, |
@@ -563,6 +570,7 @@ struct mic_hw_ops mic_x100_ops = { | |||
563 | .send_firmware_intr = mic_x100_send_firmware_intr, | 570 | .send_firmware_intr = mic_x100_send_firmware_intr, |
564 | .load_mic_fw = mic_x100_load_firmware, | 571 | .load_mic_fw = mic_x100_load_firmware, |
565 | .get_postcode = mic_x100_get_postcode, | 572 | .get_postcode = mic_x100_get_postcode, |
573 | .dma_filter = mic_x100_dma_filter, | ||
566 | }; | 574 | }; |
567 | 575 | ||
568 | struct mic_hw_intr_ops mic_x100_intr_ops = { | 576 | struct mic_hw_intr_ops mic_x100_intr_ops = { |