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>
This commit is contained in:
		
							parent
							
								
									b8e439f48a
								
							
						
					
					
						commit
						d4ef098e4c
					
				| @ -19,7 +19,7 @@ comment "Intel MIC Host Driver" | ||||
| 
 | ||||
| config INTEL_MIC_HOST | ||||
| 	tristate "Intel MIC Host Driver" | ||||
| 	depends on 64BIT && PCI && X86 | ||||
| 	depends on 64BIT && PCI && X86 && INTEL_MIC_BUS | ||||
| 	select VHOST_RING | ||||
| 	help | ||||
| 	  This enables Host Driver support for the Intel Many Integrated | ||||
|  | ||||
| @ -23,11 +23,70 @@ | ||||
| #include <linux/pci.h> | ||||
| 
 | ||||
| #include <linux/mic_common.h> | ||||
| #include <linux/mic_bus.h> | ||||
| #include "../common/mic_dev.h" | ||||
| #include "mic_device.h" | ||||
| #include "mic_smpt.h" | ||||
| #include "mic_virtio.h" | ||||
| 
 | ||||
| static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev) | ||||
| { | ||||
| 	return dev_get_drvdata(mbdev->dev.parent); | ||||
| } | ||||
| 
 | ||||
| static dma_addr_t | ||||
| mic_dma_map_page(struct device *dev, struct page *page, | ||||
| 		 unsigned long offset, size_t size, enum dma_data_direction dir, | ||||
| 		 struct dma_attrs *attrs) | ||||
| { | ||||
| 	void *va = phys_to_virt(page_to_phys(page)) + offset; | ||||
| 	struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	return mic_map_single(mdev, va, size); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | ||||
| 		   size_t size, enum dma_data_direction dir, | ||||
| 		   struct dma_attrs *attrs) | ||||
| { | ||||
| 	struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||||
| 	mic_unmap_single(mdev, dma_addr, size); | ||||
| } | ||||
| 
 | ||||
| static struct dma_map_ops mic_dma_ops = { | ||||
| 	.map_page = mic_dma_map_page, | ||||
| 	.unmap_page = mic_dma_unmap_page, | ||||
| }; | ||||
| 
 | ||||
| static struct mic_irq * | ||||
| _mic_request_threaded_irq(struct mbus_device *mbdev, | ||||
| 			  irq_handler_t handler, irq_handler_t thread_fn, | ||||
| 			  const char *name, void *data, int intr_src) | ||||
| { | ||||
| 	return mic_request_threaded_irq(mbdev_to_mdev(mbdev), handler, | ||||
| 					thread_fn, name, data, | ||||
| 					intr_src, MIC_INTR_DMA); | ||||
| } | ||||
| 
 | ||||
| static void _mic_free_irq(struct mbus_device *mbdev, | ||||
| 			  struct mic_irq *cookie, void *data) | ||||
| { | ||||
| 	return mic_free_irq(mbdev_to_mdev(mbdev), cookie, data); | ||||
| } | ||||
| 
 | ||||
| static void _mic_ack_interrupt(struct mbus_device *mbdev, int num) | ||||
| { | ||||
| 	struct mic_device *mdev = mbdev_to_mdev(mbdev); | ||||
| 	mdev->ops->intr_workarounds(mdev); | ||||
| } | ||||
| 
 | ||||
| static struct mbus_hw_ops mbus_hw_ops = { | ||||
| 	.request_threaded_irq = _mic_request_threaded_irq, | ||||
| 	.free_irq = _mic_free_irq, | ||||
| 	.ack_interrupt = _mic_ack_interrupt, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * mic_reset - Reset the MIC device. | ||||
|  * @mdev: pointer to mic_device instance | ||||
| @ -95,9 +154,21 @@ retry: | ||||
| 		 */ | ||||
| 		goto retry; | ||||
| 	} | ||||
| 	mdev->dma_mbdev = mbus_register_device(mdev->sdev->parent, | ||||
| 					       MBUS_DEV_DMA_HOST, &mic_dma_ops, | ||||
| 					       &mbus_hw_ops, mdev->mmio.va); | ||||
| 	if (IS_ERR(mdev->dma_mbdev)) { | ||||
| 		rc = PTR_ERR(mdev->dma_mbdev); | ||||
| 		goto unlock_ret; | ||||
| 	} | ||||
| 	mdev->dma_ch = mic_request_dma_chan(mdev); | ||||
| 	if (!mdev->dma_ch) { | ||||
| 		rc = -ENXIO; | ||||
| 		goto dma_remove; | ||||
| 	} | ||||
| 	rc = mdev->ops->load_mic_fw(mdev, buf); | ||||
| 	if (rc) | ||||
| 		goto unlock_ret; | ||||
| 		goto dma_release; | ||||
| 	mic_smpt_restore(mdev); | ||||
| 	mic_intr_restore(mdev); | ||||
| 	mdev->intr_ops->enable_interrupts(mdev); | ||||
| @ -105,6 +176,11 @@ retry: | ||||
| 	mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | ||||
| 	mdev->ops->send_firmware_intr(mdev); | ||||
| 	mic_set_state(mdev, MIC_ONLINE); | ||||
| 	goto unlock_ret; | ||||
| dma_release: | ||||
| 	dma_release_channel(mdev->dma_ch); | ||||
| dma_remove: | ||||
| 	mbus_unregister_device(mdev->dma_mbdev); | ||||
| unlock_ret: | ||||
| 	mutex_unlock(&mdev->mic_mutex); | ||||
| 	return rc; | ||||
| @ -122,6 +198,11 @@ void mic_stop(struct mic_device *mdev, bool force) | ||||
| 	mutex_lock(&mdev->mic_mutex); | ||||
| 	if (MIC_OFFLINE != mdev->state || force) { | ||||
| 		mic_virtio_reset_devices(mdev); | ||||
| 		if (mdev->dma_ch) { | ||||
| 			dma_release_channel(mdev->dma_ch); | ||||
| 			mdev->dma_ch = NULL; | ||||
| 		} | ||||
| 		mbus_unregister_device(mdev->dma_mbdev); | ||||
| 		mic_bootparam_init(mdev); | ||||
| 		mic_reset(mdev); | ||||
| 		if (MIC_RESET_FAILED == mdev->state) | ||||
|  | ||||
| @ -25,6 +25,8 @@ | ||||
| #include <linux/idr.h> | ||||
| #include <linux/notifier.h> | ||||
| #include <linux/irqreturn.h> | ||||
| #include <linux/dmaengine.h> | ||||
| #include <linux/mic_bus.h> | ||||
| 
 | ||||
| #include "mic_intr.h" | ||||
| 
 | ||||
| @ -87,6 +89,8 @@ enum mic_stepping { | ||||
|  * @cdev: Character device for MIC. | ||||
|  * @vdev_list: list of virtio devices. | ||||
|  * @pm_notifier: Handles PM notifications from the OS. | ||||
|  * @dma_mbdev: MIC BUS DMA device. | ||||
|  * @dma_ch: DMA channel reserved by this driver for use by virtio devices. | ||||
|  */ | ||||
| struct mic_device { | ||||
| 	struct mic_mw mmio; | ||||
| @ -124,6 +128,8 @@ struct mic_device { | ||||
| 	struct cdev cdev; | ||||
| 	struct list_head vdev_list; | ||||
| 	struct notifier_block pm_notifier; | ||||
| 	struct mbus_device *dma_mbdev; | ||||
| 	struct dma_chan *dma_ch; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -144,6 +150,7 @@ struct mic_device { | ||||
|  * @load_mic_fw: Load firmware segments required to boot the card | ||||
|  * into card memory. This includes the kernel, command line, ramdisk etc. | ||||
|  * @get_postcode: Get post code status from firmware. | ||||
|  * @dma_filter: DMA filter function to be used. | ||||
|  */ | ||||
| struct mic_hw_ops { | ||||
| 	u8 aper_bar; | ||||
| @ -159,6 +166,7 @@ struct mic_hw_ops { | ||||
| 	void (*send_firmware_intr)(struct mic_device *mdev); | ||||
| 	int (*load_mic_fw)(struct mic_device *mdev, const char *buf); | ||||
| 	u32 (*get_postcode)(struct mic_device *mdev); | ||||
| 	bool (*dma_filter)(struct dma_chan *chan, void *param); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -187,6 +195,22 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | ||||
| 	iowrite32(val, mw->va + offset); | ||||
| } | ||||
| 
 | ||||
| static inline struct dma_chan *mic_request_dma_chan(struct mic_device *mdev) | ||||
| { | ||||
| 	dma_cap_mask_t mask; | ||||
| 	struct dma_chan *chan; | ||||
| 
 | ||||
| 	dma_cap_zero(mask); | ||||
| 	dma_cap_set(DMA_MEMCPY, mask); | ||||
| 	chan = dma_request_channel(mask, mdev->ops->dma_filter, | ||||
| 				   mdev->sdev->parent); | ||||
| 	if (chan) | ||||
| 		return chan; | ||||
| 	dev_err(mdev->sdev->parent, "%s %d unable to acquire channel\n", | ||||
| 		__func__, __LINE__); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| void mic_sysfs_init(struct mic_device *mdev); | ||||
| int mic_start(struct mic_device *mdev, const char *buf); | ||||
| void mic_stop(struct mic_device *mdev, bool force); | ||||
|  | ||||
| @ -27,8 +27,9 @@ | ||||
|  * The minimum number of msix vectors required for normal operation. | ||||
|  * 3 for virtio network, console and block devices. | ||||
|  * 1 for card shutdown notifications. | ||||
|  * 4 for host owned DMA channels. | ||||
|  */ | ||||
| #define MIC_MIN_MSIX 4 | ||||
| #define MIC_MIN_MSIX 8 | ||||
| #define MIC_NUM_OFFSETS 32 | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -21,60 +21,157 @@ | ||||
| #include <linux/pci.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/uaccess.h> | ||||
| 
 | ||||
| #include <linux/dmaengine.h> | ||||
| #include <linux/mic_common.h> | ||||
| 
 | ||||
| #include "../common/mic_dev.h" | ||||
| #include "mic_device.h" | ||||
| #include "mic_smpt.h" | ||||
| #include "mic_virtio.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Initiates the copies across the PCIe bus from card memory to | ||||
|  * a user space buffer. | ||||
|  * Size of the internal buffer used during DMA's as an intermediate buffer | ||||
|  * for copy to/from user. | ||||
|  */ | ||||
| static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, | ||||
| 		void __user *ubuf, size_t len, u64 addr) | ||||
| #define MIC_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL) | ||||
| 
 | ||||
| static int mic_sync_dma(struct mic_device *mdev, dma_addr_t dst, | ||||
| 			dma_addr_t src, size_t len) | ||||
| { | ||||
| 	int err; | ||||
| 	void __iomem *dbuf = mvdev->mdev->aper.va + addr; | ||||
| 	/*
 | ||||
| 	 * We are copying from IO below an should ideally use something | ||||
| 	 * like copy_to_user_fromio(..) if it existed. | ||||
| 	 */ | ||||
| 	if (copy_to_user(ubuf, (void __force *)dbuf, len)) { | ||||
| 		err = -EFAULT; | ||||
| 		dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||||
| 			__func__, __LINE__, err); | ||||
| 		goto err; | ||||
| 	int err = 0; | ||||
| 	struct dma_async_tx_descriptor *tx; | ||||
| 	struct dma_chan *mic_ch = mdev->dma_ch; | ||||
| 
 | ||||
| 	if (!mic_ch) { | ||||
| 		err = -EBUSY; | ||||
| 		goto error; | ||||
| 	} | ||||
| 	mvdev->in_bytes += len; | ||||
| 	err = 0; | ||||
| err: | ||||
| 
 | ||||
| 	tx = mic_ch->device->device_prep_dma_memcpy(mic_ch, dst, src, len, | ||||
| 						    DMA_PREP_FENCE); | ||||
| 	if (!tx) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto error; | ||||
| 	} else { | ||||
| 		dma_cookie_t cookie = tx->tx_submit(tx); | ||||
| 
 | ||||
| 		err = dma_submit_error(cookie); | ||||
| 		if (err) | ||||
| 			goto error; | ||||
| 		err = dma_sync_wait(mic_ch, cookie); | ||||
| 	} | ||||
| error: | ||||
| 	if (err) | ||||
| 		dev_err(mdev->sdev->parent, "%s %d err %d\n", | ||||
| 			__func__, __LINE__, err); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Initiates copies across the PCIe bus from a user space | ||||
|  * buffer to card memory. | ||||
|  * Initiates the copies across the PCIe bus from card memory to a user | ||||
|  * space buffer. When transfers are done using DMA, source/destination | ||||
|  * addresses and transfer length must follow the alignment requirements of | ||||
|  * the MIC DMA engine. | ||||
|  */ | ||||
| static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, | ||||
| 		void __user *ubuf, size_t len, u64 addr) | ||||
| static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, void __user *ubuf, | ||||
| 				   size_t len, u64 daddr, size_t dlen, | ||||
| 				   int vr_idx) | ||||
| { | ||||
| 	struct mic_device *mdev = mvdev->mdev; | ||||
| 	void __iomem *dbuf = mdev->aper.va + daddr; | ||||
| 	struct mic_vringh *mvr = &mvdev->mvr[vr_idx]; | ||||
| 	size_t dma_alignment = 1 << mdev->dma_ch->device->copy_align; | ||||
| 	size_t dma_offset; | ||||
| 	size_t partlen; | ||||
| 	int err; | ||||
| 	void __iomem *dbuf = mvdev->mdev->aper.va + addr; | ||||
| 
 | ||||
| 	dma_offset = daddr - round_down(daddr, dma_alignment); | ||||
| 	daddr -= dma_offset; | ||||
| 	len += dma_offset; | ||||
| 
 | ||||
| 	while (len) { | ||||
| 		partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE); | ||||
| 
 | ||||
| 		err = mic_sync_dma(mdev, mvr->buf_da, daddr, | ||||
| 				   ALIGN(partlen, dma_alignment)); | ||||
| 		if (err) | ||||
| 			goto err; | ||||
| 
 | ||||
| 		if (copy_to_user(ubuf, mvr->buf + dma_offset, | ||||
| 				 partlen - dma_offset)) { | ||||
| 			err = -EFAULT; | ||||
| 			goto err; | ||||
| 		} | ||||
| 		daddr += partlen; | ||||
| 		ubuf += partlen; | ||||
| 		dbuf += partlen; | ||||
| 		mvdev->in_bytes_dma += partlen; | ||||
| 		mvdev->in_bytes += partlen; | ||||
| 		len -= partlen; | ||||
| 		dma_offset = 0; | ||||
| 	} | ||||
| 	return 0; | ||||
| err: | ||||
| 	dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Initiates copies across the PCIe bus from a user space buffer to card | ||||
|  * memory. When transfers are done using DMA, source/destination addresses | ||||
|  * and transfer length must follow the alignment requirements of the MIC | ||||
|  * DMA engine. | ||||
|  */ | ||||
| static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, void __user *ubuf, | ||||
| 				     size_t len, u64 daddr, size_t dlen, | ||||
| 				     int vr_idx) | ||||
| { | ||||
| 	struct mic_device *mdev = mvdev->mdev; | ||||
| 	void __iomem *dbuf = mdev->aper.va + daddr; | ||||
| 	struct mic_vringh *mvr = &mvdev->mvr[vr_idx]; | ||||
| 	size_t dma_alignment = 1 << mdev->dma_ch->device->copy_align; | ||||
| 	size_t partlen; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (daddr & (dma_alignment - 1)) { | ||||
| 		mvdev->tx_dst_unaligned += len; | ||||
| 		goto memcpy; | ||||
| 	} else if (ALIGN(len, dma_alignment) > dlen) { | ||||
| 		mvdev->tx_len_unaligned += len; | ||||
| 		goto memcpy; | ||||
| 	} | ||||
| 
 | ||||
| 	while (len) { | ||||
| 		partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE); | ||||
| 
 | ||||
| 		if (copy_from_user(mvr->buf, ubuf, partlen)) { | ||||
| 			err = -EFAULT; | ||||
| 			goto err; | ||||
| 		} | ||||
| 		err = mic_sync_dma(mdev, daddr, mvr->buf_da, | ||||
| 				   ALIGN(partlen, dma_alignment)); | ||||
| 		if (err) | ||||
| 			goto err; | ||||
| 		daddr += partlen; | ||||
| 		ubuf += partlen; | ||||
| 		dbuf += partlen; | ||||
| 		mvdev->out_bytes_dma += partlen; | ||||
| 		mvdev->out_bytes += partlen; | ||||
| 		len -= partlen; | ||||
| 	} | ||||
| memcpy: | ||||
| 	/*
 | ||||
| 	 * We are copying to IO below and should ideally use something | ||||
| 	 * like copy_from_user_toio(..) if it existed. | ||||
| 	 */ | ||||
| 	if (copy_from_user((void __force *)dbuf, ubuf, len)) { | ||||
| 		err = -EFAULT; | ||||
| 		dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||||
| 			__func__, __LINE__, err); | ||||
| 		goto err; | ||||
| 	} | ||||
| 	mvdev->out_bytes += len; | ||||
| 	err = 0; | ||||
| 	return 0; | ||||
| err: | ||||
| 	dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| @ -110,7 +207,8 @@ static inline u32 mic_vringh_iov_consumed(struct vringh_kiov *iov) | ||||
|  * way to override the VRINGH xfer(..) routines as of v3.10. | ||||
|  */ | ||||
| static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, | ||||
| 	void __user *ubuf, size_t len, bool read, size_t *out_len) | ||||
| 			void __user *ubuf, size_t len, bool read, int vr_idx, | ||||
| 			size_t *out_len) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	size_t partlen, tot_len = 0; | ||||
| @ -118,13 +216,15 @@ static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, | ||||
| 	while (len && iov->i < iov->used) { | ||||
| 		partlen = min(iov->iov[iov->i].iov_len, len); | ||||
| 		if (read) | ||||
| 			ret = mic_virtio_copy_to_user(mvdev, | ||||
| 				ubuf, partlen, | ||||
| 				(u64)iov->iov[iov->i].iov_base); | ||||
| 			ret = mic_virtio_copy_to_user(mvdev, ubuf, partlen, | ||||
| 						(u64)iov->iov[iov->i].iov_base, | ||||
| 						iov->iov[iov->i].iov_len, | ||||
| 						vr_idx); | ||||
| 		else | ||||
| 			ret = mic_virtio_copy_from_user(mvdev, | ||||
| 				ubuf, partlen, | ||||
| 				(u64)iov->iov[iov->i].iov_base); | ||||
| 			ret = mic_virtio_copy_from_user(mvdev, ubuf, partlen, | ||||
| 						(u64)iov->iov[iov->i].iov_base, | ||||
| 						iov->iov[iov->i].iov_len, | ||||
| 						vr_idx); | ||||
| 		if (ret) { | ||||
| 			dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||||
| 				__func__, __LINE__, ret); | ||||
| @ -192,8 +292,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, | ||||
| 			ubuf = iov.iov_base; | ||||
| 		} | ||||
| 		/* Issue all the read descriptors first */ | ||||
| 		ret = mic_vringh_copy(mvdev, riov, ubuf, len, | ||||
| 			MIC_VRINGH_READ, &out_len); | ||||
| 		ret = mic_vringh_copy(mvdev, riov, ubuf, len, MIC_VRINGH_READ, | ||||
| 				      copy->vr_idx, &out_len); | ||||
| 		if (ret) { | ||||
| 			dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||||
| 				__func__, __LINE__, ret); | ||||
| @ -203,8 +303,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, | ||||
| 		ubuf += out_len; | ||||
| 		copy->out_len += out_len; | ||||
| 		/* Issue the write descriptors next */ | ||||
| 		ret = mic_vringh_copy(mvdev, wiov, ubuf, len, | ||||
| 			!MIC_VRINGH_READ, &out_len); | ||||
| 		ret = mic_vringh_copy(mvdev, wiov, ubuf, len, !MIC_VRINGH_READ, | ||||
| 				      copy->vr_idx, &out_len); | ||||
| 		if (ret) { | ||||
| 			dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||||
| 				__func__, __LINE__, ret); | ||||
| @ -589,6 +689,10 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, | ||||
| 		dev_dbg(mdev->sdev->parent, | ||||
| 			"%s %d index %d va %p info %p vr_size 0x%x\n", | ||||
| 			__func__, __LINE__, i, vr->va, vr->info, vr_size); | ||||
| 		mvr->buf = (void *)__get_free_pages(GFP_KERNEL, | ||||
| 					get_order(MIC_INT_DMA_BUF_SIZE)); | ||||
| 		mvr->buf_da = mic_map_single(mvdev->mdev, mvr->buf, | ||||
| 					  MIC_INT_DMA_BUF_SIZE); | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, | ||||
| @ -673,6 +777,11 @@ skip_hot_remove: | ||||
| 	vqconfig = mic_vq_config(mvdev->dd); | ||||
| 	for (i = 0; i < mvdev->dd->num_vq; i++) { | ||||
| 		struct mic_vringh *mvr = &mvdev->mvr[i]; | ||||
| 
 | ||||
| 		mic_unmap_single(mvdev->mdev, mvr->buf_da, | ||||
| 				 MIC_INT_DMA_BUF_SIZE); | ||||
| 		free_pages((unsigned long)mvr->buf, | ||||
| 			   get_order(MIC_INT_DMA_BUF_SIZE)); | ||||
| 		vringh_kiov_cleanup(&mvr->riov); | ||||
| 		vringh_kiov_cleanup(&mvr->wiov); | ||||
| 		mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), | ||||
|  | ||||
| @ -46,18 +46,23 @@ | ||||
|  * @vrh: The host VRINGH used for accessing the card vrings. | ||||
|  * @riov: The VRINGH read kernel IOV. | ||||
|  * @wiov: The VRINGH write kernel IOV. | ||||
|  * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||||
|  * @vr_mutex: Mutex for synchronizing access to the VRING. | ||||
|  * @buf: Temporary kernel buffer used to copy in/out data | ||||
|  * from/to the card via DMA. | ||||
|  * @buf_da: dma address of buf. | ||||
|  * @mvdev: Back pointer to MIC virtio device for vringh_notify(..). | ||||
|  * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||||
|  */ | ||||
| struct mic_vringh { | ||||
| 	struct mic_vring vring; | ||||
| 	struct vringh vrh; | ||||
| 	struct vringh_kiov riov; | ||||
| 	struct vringh_kiov wiov; | ||||
| 	u16 head; | ||||
| 	struct mutex vr_mutex; | ||||
| 	void *buf; | ||||
| 	dma_addr_t buf_da; | ||||
| 	struct mic_vdev *mvdev; | ||||
| 	u16 head; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -69,6 +74,14 @@ struct mic_vringh { | ||||
|  * @poll_wake - Used for waking up threads blocked in poll. | ||||
|  * @out_bytes - Debug stats for number of bytes copied from host to card. | ||||
|  * @in_bytes - Debug stats for number of bytes copied from card to host. | ||||
|  * @out_bytes_dma - Debug stats for number of bytes copied from host to card | ||||
|  * using DMA. | ||||
|  * @in_bytes_dma - Debug stats for number of bytes copied from card to host | ||||
|  * using DMA. | ||||
|  * @tx_len_unaligned - Debug stats for number of bytes copied to the card where | ||||
|  * the transfer length did not have the required DMA alignment. | ||||
|  * @tx_dst_unaligned - Debug stats for number of bytes copied where the | ||||
|  * destination address on the card did not have the required DMA alignment. | ||||
|  * @mvr - Store per VRING data structures. | ||||
|  * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. | ||||
|  * @dd - Virtio device descriptor. | ||||
| @ -84,6 +97,10 @@ struct mic_vdev { | ||||
| 	int poll_wake; | ||||
| 	unsigned long out_bytes; | ||||
| 	unsigned long in_bytes; | ||||
| 	unsigned long out_bytes_dma; | ||||
| 	unsigned long in_bytes_dma; | ||||
| 	unsigned long tx_len_unaligned; | ||||
| 	unsigned long tx_dst_unaligned; | ||||
| 	struct mic_vringh mvr[MIC_MAX_VRINGS]; | ||||
| 	struct work_struct virtio_bh_work; | ||||
| 	struct mic_device_desc *dd; | ||||
|  | ||||
| @ -549,6 +549,13 @@ struct mic_smpt_ops mic_x100_smpt_ops = { | ||||
| 	.set = mic_x100_smpt_set, | ||||
| }; | ||||
| 
 | ||||
| static bool mic_x100_dma_filter(struct dma_chan *chan, void *param) | ||||
| { | ||||
| 	if (chan->device->dev->parent == (struct device *)param) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| struct mic_hw_ops mic_x100_ops = { | ||||
| 	.aper_bar = MIC_X100_APER_BAR, | ||||
| 	.mmio_bar = MIC_X100_MMIO_BAR, | ||||
| @ -563,6 +570,7 @@ struct mic_hw_ops mic_x100_ops = { | ||||
| 	.send_firmware_intr = mic_x100_send_firmware_intr, | ||||
| 	.load_mic_fw = mic_x100_load_firmware, | ||||
| 	.get_postcode = mic_x100_get_postcode, | ||||
| 	.dma_filter = mic_x100_dma_filter, | ||||
| }; | ||||
| 
 | ||||
| struct mic_hw_intr_ops mic_x100_intr_ops = { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user