Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Siva Yerramreddy and committed by
Greg Kroah-Hartman
d4ef098e b8e439f4

+283 -43
+1 -1
drivers/misc/mic/Kconfig
··· 19 19 20 20 config INTEL_MIC_HOST 21 21 tristate "Intel MIC Host Driver" 22 - depends on 64BIT && PCI && X86 22 + depends on 64BIT && PCI && X86 && INTEL_MIC_BUS 23 23 select VHOST_RING 24 24 help 25 25 This enables Host Driver support for the Intel Many Integrated
+82 -1
drivers/misc/mic/host/mic_boot.c
··· 23 23 #include <linux/pci.h> 24 24 25 25 #include <linux/mic_common.h> 26 + #include <linux/mic_bus.h> 26 27 #include "../common/mic_dev.h" 27 28 #include "mic_device.h" 28 29 #include "mic_smpt.h" 29 30 #include "mic_virtio.h" 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 + }; 30 89 31 90 /** 32 91 * mic_reset - Reset the MIC device. ··· 154 95 */ 155 96 goto retry; 156 97 } 98 + mdev->dma_mbdev = mbus_register_device(mdev->sdev->parent, 99 + MBUS_DEV_DMA_HOST, &mic_dma_ops, 100 + &mbus_hw_ops, mdev->mmio.va); 101 + if (IS_ERR(mdev->dma_mbdev)) { 102 + rc = PTR_ERR(mdev->dma_mbdev); 103 + goto unlock_ret; 104 + } 105 + mdev->dma_ch = mic_request_dma_chan(mdev); 106 + if (!mdev->dma_ch) { 107 + rc = -ENXIO; 108 + goto dma_remove; 109 + } 157 110 rc = mdev->ops->load_mic_fw(mdev, buf); 158 111 if (rc) 159 - goto unlock_ret; 112 + goto dma_release; 160 113 mic_smpt_restore(mdev); 161 114 mic_intr_restore(mdev); 162 115 mdev->intr_ops->enable_interrupts(mdev); ··· 176 105 mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); 177 106 mdev->ops->send_firmware_intr(mdev); 178 107 mic_set_state(mdev, MIC_ONLINE); 108 + goto unlock_ret; 109 + dma_release: 110 + dma_release_channel(mdev->dma_ch); 111 + dma_remove: 112 + mbus_unregister_device(mdev->dma_mbdev); 179 113 unlock_ret: 180 114 mutex_unlock(&mdev->mic_mutex); 181 115 return rc; ··· 198 122 mutex_lock(&mdev->mic_mutex); 199 123 if (MIC_OFFLINE != mdev->state || force) { 200 124 mic_virtio_reset_devices(mdev); 125 + if (mdev->dma_ch) { 126 + dma_release_channel(mdev->dma_ch); 127 + mdev->dma_ch = NULL; 128 + } 129 + mbus_unregister_device(mdev->dma_mbdev); 201 130 mic_bootparam_init(mdev); 202 131 mic_reset(mdev); 203 132 if (MIC_RESET_FAILED == mdev->state)
+24
drivers/misc/mic/host/mic_device.h
··· 25 25 #include <linux/idr.h> 26 26 #include <linux/notifier.h> 27 27 #include <linux/irqreturn.h> 28 + #include <linux/dmaengine.h> 29 + #include <linux/mic_bus.h> 28 30 29 31 #include "mic_intr.h" 30 32 ··· 89 87 * @cdev: Character device for MIC. 90 88 * @vdev_list: list of virtio devices. 91 89 * @pm_notifier: Handles PM notifications from the OS. 90 + * @dma_mbdev: MIC BUS DMA device. 91 + * @dma_ch: DMA channel reserved by this driver for use by virtio devices. 92 92 */ 93 93 struct mic_device { 94 94 struct mic_mw mmio; ··· 128 124 struct cdev cdev; 129 125 struct list_head vdev_list; 130 126 struct notifier_block pm_notifier; 127 + struct mbus_device *dma_mbdev; 128 + struct dma_chan *dma_ch; 131 129 }; 132 130 133 131 /** ··· 150 144 * @load_mic_fw: Load firmware segments required to boot the card 151 145 * into card memory. This includes the kernel, command line, ramdisk etc. 152 146 * @get_postcode: Get post code status from firmware. 147 + * @dma_filter: DMA filter function to be used. 153 148 */ 154 149 struct mic_hw_ops { 155 150 u8 aper_bar; ··· 166 159 void (*send_firmware_intr)(struct mic_device *mdev); 167 160 int (*load_mic_fw)(struct mic_device *mdev, const char *buf); 168 161 u32 (*get_postcode)(struct mic_device *mdev); 162 + bool (*dma_filter)(struct dma_chan *chan, void *param); 169 163 }; 170 164 171 165 /** ··· 193 185 mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) 194 186 { 195 187 iowrite32(val, mw->va + offset); 188 + } 189 + 190 + static inline struct dma_chan *mic_request_dma_chan(struct mic_device *mdev) 191 + { 192 + dma_cap_mask_t mask; 193 + struct dma_chan *chan; 194 + 195 + dma_cap_zero(mask); 196 + dma_cap_set(DMA_MEMCPY, mask); 197 + chan = dma_request_channel(mask, mdev->ops->dma_filter, 198 + mdev->sdev->parent); 199 + if (chan) 200 + return chan; 201 + dev_err(mdev->sdev->parent, "%s %d unable to acquire channel\n", 202 + __func__, __LINE__); 203 + return NULL; 196 204 } 197 205 198 206 void mic_sysfs_init(struct mic_device *mdev);
+2 -1
drivers/misc/mic/host/mic_intr.h
··· 27 27 * The minimum number of msix vectors required for normal operation. 28 28 * 3 for virtio network, console and block devices. 29 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 33 #define MIC_NUM_OFFSETS 32 33 34 34 35 /**
+147 -38
drivers/misc/mic/host/mic_virtio.c
··· 21 21 #include <linux/pci.h> 22 22 #include <linux/sched.h> 23 23 #include <linux/uaccess.h> 24 - 24 + #include <linux/dmaengine.h> 25 25 #include <linux/mic_common.h> 26 + 26 27 #include "../common/mic_dev.h" 27 28 #include "mic_device.h" 28 29 #include "mic_smpt.h" 29 30 #include "mic_virtio.h" 30 31 31 32 /* 32 - * Initiates the copies across the PCIe bus from card memory to 33 - * a user space buffer. 33 + * Size of the internal buffer used during DMA's as an intermediate buffer 34 + * for copy to/from user. 34 35 */ 35 - static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, 36 - void __user *ubuf, size_t len, u64 addr) 36 + #define MIC_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL) 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; 39 - void __iomem *dbuf = mvdev->mdev->aper.va + addr; 40 - /* 41 - * We are copying from IO below an should ideally use something 42 - * like copy_to_user_fromio(..) if it existed. 43 - */ 44 - if (copy_to_user(ubuf, (void __force *)dbuf, len)) { 45 - err = -EFAULT; 46 - dev_err(mic_dev(mvdev), "%s %d err %d\n", 47 - __func__, __LINE__, err); 48 - goto err; 41 + int err = 0; 42 + struct dma_async_tx_descriptor *tx; 43 + struct dma_chan *mic_ch = mdev->dma_ch; 44 + 45 + if (!mic_ch) { 46 + err = -EBUSY; 47 + goto error; 49 48 } 50 - mvdev->in_bytes += len; 51 - err = 0; 52 - err: 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", 66 + __func__, __LINE__, err); 53 67 return err; 54 68 } 55 69 56 70 /* 57 - * Initiates copies across the PCIe bus from a user space 58 - * buffer to card memory. 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. 59 75 */ 60 - static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, 61 - void __user *ubuf, size_t len, u64 addr) 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) 62 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; 63 86 int err; 64 - void __iomem *dbuf = mvdev->mdev->aper.va + addr; 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; 112 + } 113 + return 0; 114 + err: 115 + dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); 116 + return err; 117 + } 118 + 119 + /* 120 + * Initiates copies across the PCIe bus from a user space buffer to card 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. 124 + */ 125 + static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, void __user *ubuf, 126 + size_t len, u64 daddr, size_t dlen, 127 + int vr_idx) 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; 134 + int err; 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 164 * We are copying to IO below and should ideally use something 67 165 * like copy_from_user_toio(..) if it existed. 68 166 */ 69 167 if (copy_from_user((void __force *)dbuf, ubuf, len)) { 70 168 err = -EFAULT; 71 - dev_err(mic_dev(mvdev), "%s %d err %d\n", 72 - __func__, __LINE__, err); 73 169 goto err; 74 170 } 75 171 mvdev->out_bytes += len; 76 - err = 0; 172 + return 0; 77 173 err: 174 + dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); 78 175 return err; 79 176 } 80 177 ··· 207 110 * way to override the VRINGH xfer(..) routines as of v3.10. 208 111 */ 209 112 static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, 210 - void __user *ubuf, size_t len, bool read, size_t *out_len) 113 + void __user *ubuf, size_t len, bool read, int vr_idx, 114 + size_t *out_len) 211 115 { 212 116 int ret = 0; 213 117 size_t partlen, tot_len = 0; ··· 216 118 while (len && iov->i < iov->used) { 217 119 partlen = min(iov->iov[iov->i].iov_len, len); 218 120 if (read) 219 - ret = mic_virtio_copy_to_user(mvdev, 220 - ubuf, partlen, 221 - (u64)iov->iov[iov->i].iov_base); 121 + ret = mic_virtio_copy_to_user(mvdev, ubuf, partlen, 122 + (u64)iov->iov[iov->i].iov_base, 123 + iov->iov[iov->i].iov_len, 124 + vr_idx); 222 125 else 223 - ret = mic_virtio_copy_from_user(mvdev, 224 - ubuf, partlen, 225 - (u64)iov->iov[iov->i].iov_base); 126 + ret = mic_virtio_copy_from_user(mvdev, ubuf, partlen, 127 + (u64)iov->iov[iov->i].iov_base, 128 + iov->iov[iov->i].iov_len, 129 + vr_idx); 226 130 if (ret) { 227 131 dev_err(mic_dev(mvdev), "%s %d err %d\n", 228 132 __func__, __LINE__, ret); ··· 292 192 ubuf = iov.iov_base; 293 193 } 294 194 /* Issue all the read descriptors first */ 295 - ret = mic_vringh_copy(mvdev, riov, ubuf, len, 296 - MIC_VRINGH_READ, &out_len); 195 + ret = mic_vringh_copy(mvdev, riov, ubuf, len, MIC_VRINGH_READ, 196 + copy->vr_idx, &out_len); 297 197 if (ret) { 298 198 dev_err(mic_dev(mvdev), "%s %d err %d\n", 299 199 __func__, __LINE__, ret); ··· 303 203 ubuf += out_len; 304 204 copy->out_len += out_len; 305 205 /* Issue the write descriptors next */ 306 - ret = mic_vringh_copy(mvdev, wiov, ubuf, len, 307 - !MIC_VRINGH_READ, &out_len); 206 + ret = mic_vringh_copy(mvdev, wiov, ubuf, len, !MIC_VRINGH_READ, 207 + copy->vr_idx, &out_len); 308 208 if (ret) { 309 209 dev_err(mic_dev(mvdev), "%s %d err %d\n", 310 210 __func__, __LINE__, ret); ··· 689 589 dev_dbg(mdev->sdev->parent, 690 590 "%s %d index %d va %p info %p vr_size 0x%x\n", 691 591 __func__, __LINE__, i, vr->va, vr->info, vr_size); 592 + mvr->buf = (void *)__get_free_pages(GFP_KERNEL, 593 + get_order(MIC_INT_DMA_BUF_SIZE)); 594 + mvr->buf_da = mic_map_single(mvdev->mdev, mvr->buf, 595 + MIC_INT_DMA_BUF_SIZE); 692 596 } 693 597 694 598 snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, ··· 777 673 vqconfig = mic_vq_config(mvdev->dd); 778 674 for (i = 0; i < mvdev->dd->num_vq; i++) { 779 675 struct mic_vringh *mvr = &mvdev->mvr[i]; 676 + 677 + mic_unmap_single(mvdev->mdev, mvr->buf_da, 678 + MIC_INT_DMA_BUF_SIZE); 679 + free_pages((unsigned long)mvr->buf, 680 + get_order(MIC_INT_DMA_BUF_SIZE)); 780 681 vringh_kiov_cleanup(&mvr->riov); 781 682 vringh_kiov_cleanup(&mvr->wiov); 782 683 mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address),
+19 -2
drivers/misc/mic/host/mic_virtio.h
··· 46 46 * @vrh: The host VRINGH used for accessing the card vrings. 47 47 * @riov: The VRINGH read kernel IOV. 48 48 * @wiov: The VRINGH write kernel IOV. 49 - * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). 50 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 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 56 struct mic_vringh { 54 57 struct mic_vring vring; 55 58 struct vringh vrh; 56 59 struct vringh_kiov riov; 57 60 struct vringh_kiov wiov; 58 - u16 head; 59 61 struct mutex vr_mutex; 62 + void *buf; 63 + dma_addr_t buf_da; 60 64 struct mic_vdev *mvdev; 65 + u16 head; 61 66 }; 62 67 63 68 /** ··· 74 69 * @poll_wake - Used for waking up threads blocked in poll. 75 70 * @out_bytes - Debug stats for number of bytes copied from host to card. 76 71 * @in_bytes - Debug stats for number of bytes copied from card to host. 72 + * @out_bytes_dma - Debug stats for number of bytes copied from host to card 73 + * using DMA. 74 + * @in_bytes_dma - Debug stats for number of bytes copied from card to host 75 + * using DMA. 76 + * @tx_len_unaligned - Debug stats for number of bytes copied to the card where 77 + * the transfer length did not have the required DMA alignment. 78 + * @tx_dst_unaligned - Debug stats for number of bytes copied where the 79 + * destination address on the card did not have the required DMA alignment. 77 80 * @mvr - Store per VRING data structures. 78 81 * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. 79 82 * @dd - Virtio device descriptor. ··· 97 84 int poll_wake; 98 85 unsigned long out_bytes; 99 86 unsigned long in_bytes; 87 + unsigned long out_bytes_dma; 88 + unsigned long in_bytes_dma; 89 + unsigned long tx_len_unaligned; 90 + unsigned long tx_dst_unaligned; 100 91 struct mic_vringh mvr[MIC_MAX_VRINGS]; 101 92 struct work_struct virtio_bh_work; 102 93 struct mic_device_desc *dd;
+8
drivers/misc/mic/host/mic_x100.c
··· 549 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 559 struct mic_hw_ops mic_x100_ops = { 553 560 .aper_bar = MIC_X100_APER_BAR, 554 561 .mmio_bar = MIC_X100_MMIO_BAR, ··· 570 563 .send_firmware_intr = mic_x100_send_firmware_intr, 571 564 .load_mic_fw = mic_x100_load_firmware, 572 565 .get_postcode = mic_x100_get_postcode, 566 + .dma_filter = mic_x100_dma_filter, 573 567 }; 574 568 575 569 struct mic_hw_intr_ops mic_x100_intr_ops = {