diff options
author | Sudeep Dutt <sudeep.dutt@intel.com> | 2016-02-08 15:48:11 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-02-09 17:32:37 -0800 |
commit | ef39830c35838696013a2f6c16f6728c4a9dcefd (patch) | |
tree | bd8a092e201d63149755d54bbbe3bfa7cf32597e | |
parent | 4ddbdbb90d2ec7d7db93c98936faf3dad75f479b (diff) |
misc: mic: Remove MIC X100 host virtio functionality
This patch deletes the virtio functionality from the MIC X100 host
driver. A subsequent patch will re-enable this functionality by
consolidating the hardware independent logic in a new Virtio over PCIe
(VOP) driver.
Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: Sudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/mic/host/Makefile | 2 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_boot.c | 2 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_debugfs.c | 190 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_device.h | 6 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_fops.c | 222 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_fops.h | 32 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_main.c | 48 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_virtio.c | 811 | ||||
-rw-r--r-- | drivers/misc/mic/host/mic_virtio.h | 155 |
9 files changed, 4 insertions, 1464 deletions
diff --git a/drivers/misc/mic/host/Makefile b/drivers/misc/mic/host/Makefile index 004d3db0f990..f3b502333ded 100644 --- a/drivers/misc/mic/host/Makefile +++ b/drivers/misc/mic/host/Makefile @@ -9,5 +9,3 @@ mic_host-objs += mic_smpt.o mic_host-objs += mic_intr.o mic_host-objs += mic_boot.o mic_host-objs += mic_debugfs.o -mic_host-objs += mic_fops.o -mic_host-objs += mic_virtio.o diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c index 7845564dff64..3df305f6282c 100644 --- a/drivers/misc/mic/host/mic_boot.c +++ b/drivers/misc/mic/host/mic_boot.c @@ -28,7 +28,6 @@ #include "../common/mic_dev.h" #include "mic_device.h" #include "mic_smpt.h" -#include "mic_virtio.h" static inline struct mic_device *scdev_to_mdev(struct scif_hw_dev *scdev) { @@ -423,7 +422,6 @@ static void _mic_stop(struct cosm_device *cdev, bool force) * will be the first to be registered and the last to be * unregistered. */ - mic_virtio_reset_devices(mdev); scif_unregister_device(mdev->scdev); mic_free_dma_chans(mdev); mbus_unregister_device(mdev->dma_mbdev); diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c index 10581600777a..0a9daba8bb5d 100644 --- a/drivers/misc/mic/host/mic_debugfs.c +++ b/drivers/misc/mic/host/mic_debugfs.c @@ -26,7 +26,6 @@ #include "../common/mic_dev.h" #include "mic_device.h" #include "mic_smpt.h" -#include "mic_virtio.h" /* Debugfs parent dir */ static struct dentry *mic_dbg; @@ -100,190 +99,6 @@ static const struct file_operations post_code_ops = { .release = mic_post_code_debug_release }; -static int mic_dp_show(struct seq_file *s, void *pos) -{ - struct mic_device *mdev = s->private; - struct mic_device_desc *d; - struct mic_device_ctrl *dc; - struct mic_vqconfig *vqconfig; - __u32 *features; - __u8 *config; - struct mic_bootparam *bootparam = mdev->dp; - int i, j; - - seq_printf(s, "Bootparam: magic 0x%x\n", - bootparam->magic); - seq_printf(s, "Bootparam: h2c_config_db %d\n", - bootparam->h2c_config_db); - seq_printf(s, "Bootparam: node_id %d\n", - bootparam->node_id); - seq_printf(s, "Bootparam: c2h_scif_db %d\n", - bootparam->c2h_scif_db); - seq_printf(s, "Bootparam: h2c_scif_db %d\n", - bootparam->h2c_scif_db); - seq_printf(s, "Bootparam: scif_host_dma_addr 0x%llx\n", - bootparam->scif_host_dma_addr); - seq_printf(s, "Bootparam: scif_card_dma_addr 0x%llx\n", - bootparam->scif_card_dma_addr); - - - for (i = sizeof(*bootparam); i < MIC_DP_SIZE; - i += mic_total_desc_size(d)) { - d = mdev->dp + i; - dc = (void *)d + mic_aligned_desc_size(d); - - /* end of list */ - if (d->type == 0) - break; - - if (d->type == -1) - continue; - - seq_printf(s, "Type %d ", d->type); - seq_printf(s, "Num VQ %d ", d->num_vq); - seq_printf(s, "Feature Len %d\n", d->feature_len); - seq_printf(s, "Config Len %d ", d->config_len); - seq_printf(s, "Shutdown Status %d\n", d->status); - - for (j = 0; j < d->num_vq; j++) { - vqconfig = mic_vq_config(d) + j; - seq_printf(s, "vqconfig[%d]: ", j); - seq_printf(s, "address 0x%llx ", vqconfig->address); - seq_printf(s, "num %d ", vqconfig->num); - seq_printf(s, "used address 0x%llx\n", - vqconfig->used_address); - } - - features = (__u32 *)mic_vq_features(d); - seq_printf(s, "Features: Host 0x%x ", features[0]); - seq_printf(s, "Guest 0x%x\n", features[1]); - - config = mic_vq_configspace(d); - for (j = 0; j < d->config_len; j++) - seq_printf(s, "config[%d]=%d\n", j, config[j]); - - seq_puts(s, "Device control:\n"); - seq_printf(s, "Config Change %d ", dc->config_change); - seq_printf(s, "Vdev reset %d\n", dc->vdev_reset); - seq_printf(s, "Guest Ack %d ", dc->guest_ack); - seq_printf(s, "Host ack %d\n", dc->host_ack); - seq_printf(s, "Used address updated %d ", - dc->used_address_updated); - seq_printf(s, "Vdev 0x%llx\n", dc->vdev); - seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db); - seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db); - } - - return 0; -} - -static int mic_dp_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, mic_dp_show, inode->i_private); -} - -static int mic_dp_debug_release(struct inode *inode, struct file *file) -{ - return single_release(inode, file); -} - -static const struct file_operations dp_ops = { - .owner = THIS_MODULE, - .open = mic_dp_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mic_dp_debug_release -}; - -static int mic_vdev_info_show(struct seq_file *s, void *unused) -{ - struct mic_device *mdev = s->private; - struct list_head *pos, *tmp; - struct mic_vdev *mvdev; - int i, j; - - mutex_lock(&mdev->mic_mutex); - list_for_each_safe(pos, tmp, &mdev->vdev_list) { - mvdev = list_entry(pos, struct mic_vdev, list); - seq_printf(s, "VDEV type %d state %s in %ld out %ld\n", - mvdev->virtio_id, - mic_vdevup(mvdev) ? "UP" : "DOWN", - mvdev->in_bytes, - mvdev->out_bytes); - for (i = 0; i < MIC_MAX_VRINGS; i++) { - struct vring_desc *desc; - struct vring_avail *avail; - struct vring_used *used; - struct mic_vringh *mvr = &mvdev->mvr[i]; - struct vringh *vrh = &mvr->vrh; - int num = vrh->vring.num; - if (!num) - continue; - desc = vrh->vring.desc; - seq_printf(s, "vring i %d avail_idx %d", - i, mvr->vring.info->avail_idx & (num - 1)); - seq_printf(s, " vring i %d avail_idx %d\n", - i, mvr->vring.info->avail_idx); - seq_printf(s, "vrh i %d weak_barriers %d", - i, vrh->weak_barriers); - seq_printf(s, " last_avail_idx %d last_used_idx %d", - vrh->last_avail_idx, vrh->last_used_idx); - seq_printf(s, " completed %d\n", vrh->completed); - for (j = 0; j < num; j++) { - seq_printf(s, "desc[%d] addr 0x%llx len %d", - j, desc->addr, desc->len); - seq_printf(s, " flags 0x%x next %d\n", - desc->flags, desc->next); - desc++; - } - avail = vrh->vring.avail; - seq_printf(s, "avail flags 0x%x idx %d\n", - vringh16_to_cpu(vrh, avail->flags), - vringh16_to_cpu(vrh, avail->idx) & (num - 1)); - seq_printf(s, "avail flags 0x%x idx %d\n", - vringh16_to_cpu(vrh, avail->flags), - vringh16_to_cpu(vrh, avail->idx)); - for (j = 0; j < num; j++) - seq_printf(s, "avail ring[%d] %d\n", - j, avail->ring[j]); - used = vrh->vring.used; - seq_printf(s, "used flags 0x%x idx %d\n", - vringh16_to_cpu(vrh, used->flags), - vringh16_to_cpu(vrh, used->idx) & (num - 1)); - seq_printf(s, "used flags 0x%x idx %d\n", - vringh16_to_cpu(vrh, used->flags), - vringh16_to_cpu(vrh, used->idx)); - for (j = 0; j < num; j++) - seq_printf(s, "used ring[%d] id %d len %d\n", - j, vringh32_to_cpu(vrh, - used->ring[j].id), - vringh32_to_cpu(vrh, - used->ring[j].len)); - } - } - mutex_unlock(&mdev->mic_mutex); - - return 0; -} - -static int mic_vdev_info_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, mic_vdev_info_show, inode->i_private); -} - -static int mic_vdev_info_debug_release(struct inode *inode, struct file *file) -{ - return single_release(inode, file); -} - -static const struct file_operations vdev_info_ops = { - .owner = THIS_MODULE, - .open = mic_vdev_info_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mic_vdev_info_debug_release -}; - static int mic_msi_irq_info_show(struct seq_file *s, void *pos) { struct mic_device *mdev = s->private; @@ -367,11 +182,6 @@ void mic_create_debug_dir(struct mic_device *mdev) debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev, &post_code_ops); - debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops); - - debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev, - &vdev_info_ops); - debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev, &msi_irq_info_ops); } diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h index 461184a12fbb..8460de122929 100644 --- a/drivers/misc/mic/host/mic_device.h +++ b/drivers/misc/mic/host/mic_device.h @@ -64,9 +64,6 @@ extern struct cosm_hw_ops cosm_hw_ops; * @bootaddr: MIC boot address. * @dp: virtio device page * @dp_dma_addr: virtio device page DMA address. - * @name: name for the misc char device - * @miscdev: registered misc char device - * @vdev_list: list of virtio devices. * @dma_mbdev: MIC BUS DMA device. * @dma_ch - Array of DMA channels * @num_dma_ch - Number of DMA channels available @@ -91,9 +88,6 @@ struct mic_device { u32 bootaddr; void *dp; dma_addr_t dp_dma_addr; - char name[16]; - struct miscdevice miscdev; - struct list_head vdev_list; struct mbus_device *dma_mbdev; struct dma_chan *dma_ch[MIC_MAX_DMA_CHAN]; int num_dma_ch; diff --git a/drivers/misc/mic/host/mic_fops.c b/drivers/misc/mic/host/mic_fops.c deleted file mode 100644 index 8cc1d90cd949..000000000000 --- a/drivers/misc/mic/host/mic_fops.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Intel MIC Platform Software Stack (MPSS) - * - * Copyright(c) 2013 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Intel MIC Host driver. - * - */ -#include <linux/poll.h> -#include <linux/pci.h> - -#include <linux/mic_common.h> -#include "../common/mic_dev.h" -#include "mic_device.h" -#include "mic_fops.h" -#include "mic_virtio.h" - -int mic_open(struct inode *inode, struct file *f) -{ - struct mic_vdev *mvdev; - struct mic_device *mdev = container_of(f->private_data, - struct mic_device, miscdev); - - mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL); - if (!mvdev) - return -ENOMEM; - - init_waitqueue_head(&mvdev->waitq); - INIT_LIST_HEAD(&mvdev->list); - mvdev->mdev = mdev; - mvdev->virtio_id = -1; - - f->private_data = mvdev; - return 0; -} - -int mic_release(struct inode *inode, struct file *f) -{ - struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; - - if (-1 != mvdev->virtio_id) - mic_virtio_del_device(mvdev); - f->private_data = NULL; - kfree(mvdev); - return 0; -} - -long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; - void __user *argp = (void __user *)arg; - int ret; - - switch (cmd) { - case MIC_VIRTIO_ADD_DEVICE: - { - ret = mic_virtio_add_device(mvdev, argp); - if (ret < 0) { - dev_err(mic_dev(mvdev), - "%s %d errno ret %d\n", - __func__, __LINE__, ret); - return ret; - } - break; - } - case MIC_VIRTIO_COPY_DESC: - { - struct mic_copy_desc copy; - - ret = mic_vdev_inited(mvdev); - if (ret) - return ret; - - if (copy_from_user(©, argp, sizeof(copy))) - return -EFAULT; - - dev_dbg(mic_dev(mvdev), - "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n", - __func__, __LINE__, copy.iovcnt, copy.vr_idx, - copy.update_used); - - ret = mic_virtio_copy_desc(mvdev, ©); - if (ret < 0) { - dev_err(mic_dev(mvdev), - "%s %d errno ret %d\n", - __func__, __LINE__, ret); - return ret; - } - if (copy_to_user( - &((struct mic_copy_desc __user *)argp)->out_len, - ©.out_len, sizeof(copy.out_len))) { - dev_err(mic_dev(mvdev), "%s %d errno ret %d\n", - __func__, __LINE__, -EFAULT); - return -EFAULT; - } - break; - } - case MIC_VIRTIO_CONFIG_CHANGE: - { - ret = mic_vdev_inited(mvdev); - if (ret) - return ret; - - ret = mic_virtio_config_change(mvdev, argp); - if (ret < 0) { - dev_err(mic_dev(mvdev), - "%s %d errno ret %d\n", - __func__, __LINE__, ret); - return ret; - } - break; - } - default: - return -ENOIOCTLCMD; - }; - return 0; -} - -/* - * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and - * not when previously enqueued buffers may be available. This means that - * in the card->host (TX) path, when userspace is unblocked by poll it - * must drain all available descriptors or it can stall. - */ -unsigned int mic_poll(struct file *f, poll_table *wait) -{ - struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; - int mask = 0; - - poll_wait(f, &mvdev->waitq, wait); - - if (mic_vdev_inited(mvdev)) { - mask = POLLERR; - } else if (mvdev->poll_wake) { - mvdev->poll_wake = 0; - mask = POLLIN | POLLOUT; - } - - return mask; -} - -static inline int -mic_query_offset(struct mic_vdev *mvdev, unsigned long offset, - unsigned long *size, unsigned long *pa) -{ - struct mic_device *mdev = mvdev->mdev; - unsigned long start = MIC_DP_SIZE; - int i; - - /* - * MMAP interface is as follows: - * offset region - * 0x0 virtio device_page - * 0x1000 first vring - * 0x1000 + size of 1st vring second vring - * .... - */ - if (!offset) { - *pa = virt_to_phys(mdev->dp); - *size = MIC_DP_SIZE; - return 0; - } - - for (i = 0; i < mvdev->dd->num_vq; i++) { - struct mic_vringh *mvr = &mvdev->mvr[i]; - if (offset == start) { - *pa = virt_to_phys(mvr->vring.va); - *size = mvr->vring.len; - return 0; - } - start += mvr->vring.len; - } - return -1; -} - -/* - * Maps the device page and virtio rings to user space for readonly access. - */ -int -mic_mmap(struct file *f, struct vm_area_struct *vma) -{ - struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size; - int i, err; - - err = mic_vdev_inited(mvdev); - if (err) - return err; - - if (vma->vm_flags & VM_WRITE) - return -EACCES; - - while (size_rem) { - i = mic_query_offset(mvdev, offset, &size, &pa); - if (i < 0) - return -EINVAL; - err = remap_pfn_range(vma, vma->vm_start + offset, - pa >> PAGE_SHIFT, size, vma->vm_page_prot); - if (err) - return err; - dev_dbg(mic_dev(mvdev), - "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n", - __func__, __LINE__, mvdev->virtio_id, size, offset, - pa, vma->vm_start + offset); - size_rem -= size; - offset += size; - } - return 0; -} diff --git a/drivers/misc/mic/host/mic_fops.h b/drivers/misc/mic/host/mic_fops.h deleted file mode 100644 index dc3893dff667..000000000000 --- a/drivers/misc/mic/host/mic_fops.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Intel MIC Platform Software Stack (MPSS) - * - * Copyright(c) 2013 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Intel MIC Host driver. - * - */ -#ifndef _MIC_FOPS_H_ -#define _MIC_FOPS_H_ - -int mic_open(struct inode *inode, struct file *filp); -int mic_release(struct inode *inode, struct file *filp); -ssize_t mic_read(struct file *filp, char __user *buf, - size_t count, loff_t *pos); -long mic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -int mic_mmap(struct file *f, struct vm_area_struct *vma); -unsigned int mic_poll(struct file *f, poll_table *wait); - -#endif diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c index 153894e7ed5b..400def2106e7 100644 --- a/drivers/misc/mic/host/mic_main.c +++ b/drivers/misc/mic/host/mic_main.c @@ -27,8 +27,6 @@ #include "mic_device.h" #include "mic_x100.h" #include "mic_smpt.h" -#include "mic_fops.h" -#include "mic_virtio.h" static const char mic_driver_name[] = "mic"; @@ -57,17 +55,6 @@ MODULE_DEVICE_TABLE(pci, mic_pci_tbl); /* ID allocator for MIC devices */ static struct ida g_mic_ida; -/* Base device node number for MIC devices */ -static dev_t g_mic_devno; - -static const struct file_operations mic_fops = { - .open = mic_open, - .release = mic_release, - .unlocked_ioctl = mic_ioctl, - .poll = mic_poll, - .mmap = mic_mmap, - .owner = THIS_MODULE, -}; /* Initialize the device page */ static int mic_dp_init(struct mic_device *mdev) @@ -169,7 +156,6 @@ mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) mic_ops_init(mdev); mutex_init(&mdev->mic_mutex); mdev->irq_info.next_avail_src = 0; - INIT_LIST_HEAD(&mdev->vdev_list); } /** @@ -259,30 +245,15 @@ static int mic_probe(struct pci_dev *pdev, goto smpt_uninit; } mic_bootparam_init(mdev); - mic_create_debug_dir(mdev); - mdev->miscdev.minor = MISC_DYNAMIC_MINOR; - snprintf(mdev->name, sizeof(mdev->name), "mic%d", mdev->id); - mdev->miscdev.name = mdev->name; - mdev->miscdev.fops = &mic_fops; - mdev->miscdev.parent = &mdev->pdev->dev; - rc = misc_register(&mdev->miscdev); - if (rc) { - dev_err(&pdev->dev, "misc_register err id %d rc %d\n", - mdev->id, rc); - goto cleanup_debug_dir; - } - mdev->cosm_dev = cosm_register_device(&mdev->pdev->dev, &cosm_hw_ops); if (IS_ERR(mdev->cosm_dev)) { rc = PTR_ERR(mdev->cosm_dev); dev_err(&pdev->dev, "cosm_add_device failed rc %d\n", rc); - goto misc_dereg; + goto cleanup_debug_dir; } return 0; -misc_dereg: - misc_deregister(&mdev->miscdev); cleanup_debug_dir: mic_delete_debug_dir(mdev); mic_dp_uninit(mdev); @@ -323,7 +294,6 @@ static void mic_remove(struct pci_dev *pdev) return; cosm_unregister_device(mdev->cosm_dev); - misc_deregister(&mdev->miscdev); mic_delete_debug_dir(mdev); mic_dp_uninit(mdev); mic_smpt_uninit(mdev); @@ -347,26 +317,17 @@ static int __init mic_init(void) { int ret; - ret = alloc_chrdev_region(&g_mic_devno, 0, - MIC_MAX_NUM_DEVS, mic_driver_name); - if (ret) { - pr_err("alloc_chrdev_region failed ret %d\n", ret); - goto error; - } - mic_init_debugfs(); ida_init(&g_mic_ida); ret = pci_register_driver(&mic_driver); if (ret) { pr_err("pci_register_driver failed ret %d\n", ret); - goto cleanup_chrdev; + goto cleanup_debugfs; } - return ret; -cleanup_chrdev: + return 0; +cleanup_debugfs: ida_destroy(&g_mic_ida); mic_exit_debugfs(); - unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); -error: return ret; } @@ -375,7 +336,6 @@ static void __exit mic_exit(void) pci_unregister_driver(&mic_driver); ida_destroy(&g_mic_ida); mic_exit_debugfs(); - unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); } module_init(mic_init); diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c deleted file mode 100644 index 58b107a24a8b..000000000000 --- a/drivers/misc/mic/host/mic_virtio.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * Intel MIC Platform Software Stack (MPSS) - * - * Copyright(c) 2013 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Intel MIC Host driver. - * - */ -#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" - -/* - * Size of the internal buffer used during DMA's as an intermediate buffer - * for copy to/from user. - */ -#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 = 0; - struct dma_async_tx_descriptor *tx; - struct dma_chan *mic_ch = mdev->dma_ch[0]; - - if (!mic_ch) { - err = -EBUSY; - goto error; - } - - 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->pdev->dev, "%s %d err %d\n", - __func__, __LINE__, err); - return err; -} - -/* - * 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_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[0]->device->copy_align; - size_t dma_offset; - size_t partlen; - int err; - - 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[0]->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; - goto err; - } - mvdev->out_bytes += len; - return 0; -err: - dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); - return err; -} - -#define MIC_VRINGH_READ true - -/* The function to call to notify the card about added buffers */ -static void mic_notify(struct vringh *vrh) -{ - struct mic_vringh *mvrh = container_of(vrh, struct mic_vringh, vrh); - struct mic_vdev *mvdev = mvrh->mvdev; - s8 db = mvdev->dc->h2c_vdev_db; - - if (db != -1) - mvdev->mdev->ops->send_intr(mvdev->mdev, db); -} - -/* Determine the total number of bytes consumed in a VRINGH KIOV */ -static inline u32 mic_vringh_iov_consumed(struct vringh_kiov *iov) -{ - int i; - u32 total = iov->consumed; - - for (i = 0; i < iov->i; i++) - total += iov->iov[i].iov_len; - return total; -} - -/* - * Traverse the VRINGH KIOV and issue the APIs to trigger the copies. - * This API is heavily based on the vringh_iov_xfer(..) implementation - * in vringh.c. The reason we cannot reuse vringh_iov_pull_kern(..) - * and vringh_iov_push_kern(..) directly is because there is no - * 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, int vr_idx, - size_t *out_len) -{ - int ret = 0; - size_t partlen, tot_len = 0; - - 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, - 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, - iov->iov[iov->i].iov_len, - vr_idx); - if (ret) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - break; - } - len -= partlen; - ubuf += partlen; - tot_len += partlen; - iov->consumed += partlen; - iov->iov[iov->i].iov_len -= partlen; - iov->iov[iov->i].iov_base += partlen; - if (!iov->iov[iov->i].iov_len) { - /* Fix up old iov element then increment. */ - iov->iov[iov->i].iov_len = iov->consumed; - iov->iov[iov->i].iov_base -= iov->consumed; - - iov->consumed = 0; - iov->i++; - } - } - *out_len = tot_len; - return ret; -} - -/* - * Use the standard VRINGH infrastructure in the kernel to fetch new - * descriptors, initiate the copies and update the used ring. - */ -static int _mic_virtio_copy(struct mic_vdev *mvdev, - struct mic_copy_desc *copy) -{ - int ret = 0; - u32 iovcnt = copy->iovcnt; - struct iovec iov; - struct iovec __user *u_iov = copy->iov; - void __user *ubuf = NULL; - struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx]; - struct vringh_kiov *riov = &mvr->riov; - struct vringh_kiov *wiov = &mvr->wiov; - struct vringh *vrh = &mvr->vrh; - u16 *head = &mvr->head; - struct mic_vring *vr = &mvr->vring; - size_t len = 0, out_len; - - copy->out_len = 0; - /* Fetch a new IOVEC if all previous elements have been processed */ - if (riov->i == riov->used && wiov->i == wiov->used) { - ret = vringh_getdesc_kern(vrh, riov, wiov, - head, GFP_KERNEL); - /* Check if there are available descriptors */ - if (ret <= 0) - return ret; - } - while (iovcnt) { - if (!len) { - /* Copy over a new iovec from user space. */ - ret = copy_from_user(&iov, u_iov, sizeof(*u_iov)); - if (ret) { - ret = -EINVAL; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - break; - } - len = iov.iov_len; - ubuf = iov.iov_base; - } - /* Issue all the read descriptors first */ - 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); - break; - } - len -= out_len; - ubuf += out_len; - copy->out_len += out_len; - /* Issue the write descriptors next */ - 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); - break; - } - len -= out_len; - ubuf += out_len; - copy->out_len += out_len; - if (!len) { - /* One user space iovec is now completed */ - iovcnt--; - u_iov++; - } - /* Exit loop if all elements in KIOVs have been processed. */ - if (riov->i == riov->used && wiov->i == wiov->used) - break; - } - /* - * Update the used ring if a descriptor was available and some data was - * copied in/out and the user asked for a used ring update. - */ - if (*head != USHRT_MAX && copy->out_len && copy->update_used) { - u32 total = 0; - - /* Determine the total data consumed */ - total += mic_vringh_iov_consumed(riov); - total += mic_vringh_iov_consumed(wiov); - vringh_complete_kern(vrh, *head, total); - *head = USHRT_MAX; - if (vringh_need_notify_kern(vrh) > 0) - vringh_notify(vrh); - vringh_kiov_cleanup(riov); - vringh_kiov_cleanup(wiov); - /* Update avail idx for user space */ - vr->info->avail_idx = vrh->last_avail_idx; - } - return ret; -} - -static inline int mic_verify_copy_args(struct mic_vdev *mvdev, - struct mic_copy_desc *copy) -{ - if (copy->vr_idx >= mvdev->dd->num_vq) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -EINVAL); - return -EINVAL; - } - return 0; -} - -/* Copy a specified number of virtio descriptors in a chain */ -int mic_virtio_copy_desc(struct mic_vdev *mvdev, - struct mic_copy_desc *copy) -{ - int err; - struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx]; - - err = mic_verify_copy_args(mvdev, copy); - if (err) - return err; - - mutex_lock(&mvr->vr_mutex); - if (!mic_vdevup(mvdev)) { - err = -ENODEV; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, err); - goto err; - } - err = _mic_virtio_copy(mvdev, copy); - if (err) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, err); - } -err: - mutex_unlock(&mvr->vr_mutex); - return err; -} - -static void mic_virtio_init_post(struct mic_vdev *mvdev) -{ - struct mic_vqconfig *vqconfig = mic_vq_config(mvdev->dd); - int i; - - for (i = 0; i < mvdev->dd->num_vq; i++) { - if (!le64_to_cpu(vqconfig[i].used_address)) { - dev_warn(mic_dev(mvdev), "used_address zero??\n"); - continue; - } - mvdev->mvr[i].vrh.vring.used = - (void __force *)mvdev->mdev->aper.va + - le64_to_cpu(vqconfig[i].used_address); - } - - mvdev->dc->used_address_updated = 0; - - dev_dbg(mic_dev(mvdev), "%s: device type %d LINKUP\n", - __func__, mvdev->virtio_id); -} - -static inline void mic_virtio_device_reset(struct mic_vdev *mvdev) -{ - int i; - - dev_dbg(mic_dev(mvdev), "%s: status %d device type %d RESET\n", - __func__, mvdev->dd->status, mvdev->virtio_id); - - for (i = 0; i < mvdev->dd->num_vq; i++) - /* - * Avoid lockdep false positive. The + 1 is for the mic - * mutex which is held in the reset devices code path. - */ - mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1); - - /* 0 status means "reset" */ - mvdev->dd->status = 0; - mvdev->dc->vdev_reset = 0; - mvdev->dc->host_ack = 1; - - for (i = 0; i < mvdev->dd->num_vq; i++) { - struct vringh *vrh = &mvdev->mvr[i].vrh; - mvdev->mvr[i].vring.info->avail_idx = 0; - vrh->completed = 0; - vrh->last_avail_idx = 0; - vrh->last_used_idx = 0; - } - - for (i = 0; i < mvdev->dd->num_vq; i++) - mutex_unlock(&mvdev->mvr[i].vr_mutex); -} - -void mic_virtio_reset_devices(struct mic_device *mdev) -{ - struct list_head *pos, *tmp; - struct mic_vdev *mvdev; - - dev_dbg(&mdev->pdev->dev, "%s\n", __func__); - - list_for_each_safe(pos, tmp, &mdev->vdev_list) { - mvdev = list_entry(pos, struct mic_vdev, list); - mic_virtio_device_reset(mvdev); - mvdev->poll_wake = 1; - wake_up(&mvdev->waitq); - } -} - -void mic_bh_handler(struct work_struct *work) -{ - struct mic_vdev *mvdev = container_of(work, struct mic_vdev, - virtio_bh_work); - - if (mvdev->dc->used_address_updated) - mic_virtio_init_post(mvdev); - - if (mvdev->dc->vdev_reset) - mic_virtio_device_reset(mvdev); - - mvdev->poll_wake = 1; - wake_up(&mvdev->waitq); -} - -static irqreturn_t mic_virtio_intr_handler(int irq, void *data) -{ - struct mic_vdev *mvdev = data; - struct mic_device *mdev = mvdev->mdev; - - mdev->ops->intr_workarounds(mdev); - schedule_work(&mvdev->virtio_bh_work); - return IRQ_HANDLED; -} - -int mic_virtio_config_change(struct mic_vdev *mvdev, - void __user *argp) -{ - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); - int ret = 0, retry, i; - struct mic_bootparam *bootparam = mvdev->mdev->dp; - s8 db = bootparam->h2c_config_db; - - mutex_lock(&mvdev->mdev->mic_mutex); - for (i = 0; i < mvdev->dd->num_vq; i++) - mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1); - - if (db == -1 || mvdev->dd->type == -1) { - ret = -EIO; - goto exit; - } - - if (copy_from_user(mic_vq_configspace(mvdev->dd), - argp, mvdev->dd->config_len)) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -EFAULT); - ret = -EFAULT; - goto exit; - } - mvdev->dc->config_change = MIC_VIRTIO_PARAM_CONFIG_CHANGED; - mvdev->mdev->ops->send_intr(mvdev->mdev, db); - - for (retry = 100; retry--;) { - ret = wait_event_timeout(wake, - mvdev->dc->guest_ack, msecs_to_jiffies(100)); - if (ret) - break; - } - - dev_dbg(mic_dev(mvdev), - "%s %d retry: %d\n", __func__, __LINE__, retry); - mvdev->dc->config_change = 0; - mvdev->dc->guest_ack = 0; -exit: - for (i = 0; i < mvdev->dd->num_vq; i++) - mutex_unlock(&mvdev->mvr[i].vr_mutex); - mutex_unlock(&mvdev->mdev->mic_mutex); - return ret; -} - -static int mic_copy_dp_entry(struct mic_vdev *mvdev, - void __user *argp, - __u8 *type, - struct mic_device_desc **devpage) -{ - struct mic_device *mdev = mvdev->mdev; - struct mic_device_desc dd, *dd_config, *devp; - struct mic_vqconfig *vqconfig; - int ret = 0, i; - bool slot_found = false; - - if (copy_from_user(&dd, argp, sizeof(dd))) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -EFAULT); - return -EFAULT; - } - - if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE || - dd.num_vq > MIC_MAX_VRINGS) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -EINVAL); - return -EINVAL; - } - - dd_config = kmalloc(mic_desc_size(&dd), GFP_KERNEL); - if (dd_config == NULL) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -ENOMEM); - return -ENOMEM; - } - if (copy_from_user(dd_config, argp, mic_desc_size(&dd))) { - ret = -EFAULT; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - goto exit; - } - - vqconfig = mic_vq_config(dd_config); - for (i = 0; i < dd.num_vq; i++) { - if (le16_to_cpu(vqconfig[i].num) > MIC_MAX_VRING_ENTRIES) { - ret = -EINVAL; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - goto exit; - } - } - - /* Find the first free device page entry */ - for (i = sizeof(struct mic_bootparam); - i < MIC_DP_SIZE - mic_total_desc_size(dd_config); - i += mic_total_desc_size(devp)) { - devp = mdev->dp + i; - if (devp->type == 0 || devp->type == -1) { - slot_found = true; - break; - } - } - if (!slot_found) { - ret = -EINVAL; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - goto exit; - } - /* - * Save off the type before doing the memcpy. Type will be set in the - * end after completing all initialization for the new device. - */ - *type = dd_config->type; - dd_config->type = 0; - memcpy(devp, dd_config, mic_desc_size(dd_config)); - - *devpage = devp; -exit: - kfree(dd_config); - return ret; -} - -static void mic_init_device_ctrl(struct mic_vdev *mvdev, - struct mic_device_desc *devpage) -{ - struct mic_device_ctrl *dc; - - dc = (void *)devpage + mic_aligned_desc_size(devpage); - - dc->config_change = 0; - dc->guest_ack = 0; - dc->vdev_reset = 0; - dc->host_ack = 0; - dc->used_address_updated = 0; - dc->c2h_vdev_db = -1; - dc->h2c_vdev_db = -1; - mvdev->dc = dc; -} - -int mic_virtio_add_device(struct mic_vdev *mvdev, - void __user *argp) -{ - struct mic_device *mdev = mvdev->mdev; - struct mic_device_desc *dd = NULL; - struct mic_vqconfig *vqconfig; - int vr_size, i, j, ret; - u8 type = 0; - s8 db; - char irqname[10]; - struct mic_bootparam *bootparam = mdev->dp; - u16 num; - dma_addr_t vr_addr; - - mutex_lock(&mdev->mic_mutex); - - ret = mic_copy_dp_entry(mvdev, argp, &type, &dd); - if (ret) { - mutex_unlock(&mdev->mic_mutex); - return ret; - } - - mic_init_device_ctrl(mvdev, dd); - - mvdev->dd = dd; - mvdev->virtio_id = type; - vqconfig = mic_vq_config(dd); - INIT_WORK(&mvdev->virtio_bh_work, mic_bh_handler); - - for (i = 0; i < dd->num_vq; i++) { - struct mic_vringh *mvr = &mvdev->mvr[i]; - struct mic_vring *vr = &mvdev->mvr[i].vring; - num = le16_to_cpu(vqconfig[i].num); - mutex_init(&mvr->vr_mutex); - vr_size = PAGE_ALIGN(vring_size(num, MIC_VIRTIO_RING_ALIGN) + - sizeof(struct _mic_vring_info)); - vr->va = (void *) - __get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(vr_size)); - if (!vr->va) { - ret = -ENOMEM; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - goto err; - } - vr->len = vr_size; - vr->info = vr->va + vring_size(num, MIC_VIRTIO_RING_ALIGN); - vr->info->magic = cpu_to_le32(MIC_MAGIC + mvdev->virtio_id + i); - vr_addr = mic_map_single(mdev, vr->va, vr_size); - if (mic_map_error(vr_addr)) { - free_pages((unsigned long)vr->va, get_order(vr_size)); - ret = -ENOMEM; - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - goto err; - } - vqconfig[i].address = cpu_to_le64(vr_addr); - - vring_init(&vr->vr, num, vr->va, MIC_VIRTIO_RING_ALIGN); - ret = vringh_init_kern(&mvr->vrh, - *(u32 *)mic_vq_features(mvdev->dd), num, false, - vr->vr.desc, vr->vr.avail, vr->vr.used); - if (ret) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, ret); - goto err; - } - vringh_kiov_init(&mvr->riov, NULL, 0); - vringh_kiov_init(&mvr->wiov, NULL, 0); - mvr->head = USHRT_MAX; - mvr->mvdev = mvdev; - mvr->vrh.notify = mic_notify; - dev_dbg(&mdev->pdev->dev, - "%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, - mvdev->virtio_id); - mvdev->virtio_db = mic_next_db(mdev); - mvdev->virtio_cookie = mic_request_threaded_irq(mdev, - mic_virtio_intr_handler, - NULL, irqname, mvdev, - mvdev->virtio_db, MIC_INTR_DB); - if (IS_ERR(mvdev->virtio_cookie)) { - ret = PTR_ERR(mvdev->virtio_cookie); - dev_dbg(&mdev->pdev->dev, "request irq failed\n"); - goto err; - } - - mvdev->dc->c2h_vdev_db = mvdev->virtio_db; - - list_add_tail(&mvdev->list, &mdev->vdev_list); - /* - * Order the type update with previous stores. This write barrier - * is paired with the corresponding read barrier before the uncached - * system memory read of the type, on the card while scanning the - * device page. - */ - smp_wmb(); - dd->type = type; - - dev_dbg(&mdev->pdev->dev, "Added virtio device id %d\n", dd->type); - - db = bootparam->h2c_config_db; - if (db != -1) - mdev->ops->send_intr(mdev, db); - mutex_unlock(&mdev->mic_mutex); - return 0; -err: - vqconfig = mic_vq_config(dd); - for (j = 0; j < i; j++) { - struct mic_vringh *mvr = &mvdev->mvr[j]; - mic_unmap_single(mdev, le64_to_cpu(vqconfig[j].address), - mvr->vring.len); - free_pages((unsigned long)mvr->vring.va, - get_order(mvr->vring.len)); - } - mutex_unlock(&mdev->mic_mutex); - return ret; -} - -void mic_virtio_del_device(struct mic_vdev *mvdev) -{ - struct list_head *pos, *tmp; - struct mic_vdev *tmp_mvdev; - struct mic_device *mdev = mvdev->mdev; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); - int i, ret, retry; - struct mic_vqconfig *vqconfig; - struct mic_bootparam *bootparam = mdev->dp; - s8 db; - - mutex_lock(&mdev->mic_mutex); - db = bootparam->h2c_config_db; - if (db == -1) - goto skip_hot_remove; - dev_dbg(&mdev->pdev->dev, - "Requesting hot remove id %d\n", mvdev->virtio_id); - mvdev->dc->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE; - mdev->ops->send_intr(mdev, db); - for (retry = 100; retry--;) { - ret = wait_event_timeout(wake, - mvdev->dc->guest_ack, msecs_to_jiffies(100)); - if (ret) - break; - } - dev_dbg(&mdev->pdev->dev, - "Device id %d config_change %d guest_ack %d retry %d\n", - mvdev->virtio_id, mvdev->dc->config_change, - mvdev->dc->guest_ack, retry); - mvdev->dc->config_change = 0; - mvdev->dc->guest_ack = 0; -skip_hot_remove: - mic_free_irq(mdev, mvdev->virtio_cookie, mvdev); - flush_work(&mvdev->virtio_bh_work); - 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), - mvr->vring.len); - free_pages((unsigned long)mvr->vring.va, - get_order(mvr->vring.len)); - } - - list_for_each_safe(pos, tmp, &mdev->vdev_list) { - tmp_mvdev = list_entry(pos, struct mic_vdev, list); - if (tmp_mvdev == mvdev) { - list_del(pos); - dev_dbg(&mdev->pdev->dev, - "Removing virtio device id %d\n", - mvdev->virtio_id); - break; - } - } - /* - * Order the type update with previous stores. This write barrier - * is paired with the corresponding read barrier before the uncached - * system memory read of the type, on the card while scanning the - * device page. - */ - smp_wmb(); - mvdev->dd->type = -1; - mutex_unlock(&mdev->mic_mutex); -} diff --git a/drivers/misc/mic/host/mic_virtio.h b/drivers/misc/mic/host/mic_virtio.h deleted file mode 100644 index a80631f2790d..000000000000 --- a/drivers/misc/mic/host/mic_virtio.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Intel MIC Platform Software Stack (MPSS) - * - * Copyright(c) 2013 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Intel MIC Host driver. - * - */ -#ifndef MIC_VIRTIO_H -#define MIC_VIRTIO_H - -#include <linux/virtio_config.h> -#include <linux/mic_ioctl.h> - -/* - * Note on endianness. - * 1. Host can be both BE or LE - * 2. Guest/card is LE. Host uses le_to_cpu to access desc/avail - * rings and ioreadXX/iowriteXX to access used ring. - * 3. Device page exposed by host to guest contains LE values. Guest - * accesses these using ioreadXX/iowriteXX etc. This way in general we - * obey the virtio spec according to which guest works with native - * endianness and host is aware of guest endianness and does all - * required endianness conversion. - * 4. Data provided from user space to guest (in ADD_DEVICE and - * CONFIG_CHANGE ioctl's) is not interpreted by the driver and should be - * in guest endianness. - */ - -/** - * struct mic_vringh - Virtio ring host information. - * - * @vring: The MIC vring used for setting up user space mappings. - * @vrh: The host VRINGH used for accessing the card vrings. - * @riov: The VRINGH read kernel IOV. - * @wiov: The VRINGH write kernel IOV. - * @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; - struct mutex vr_mutex; - void *buf; - dma_addr_t buf_da; - struct mic_vdev *mvdev; - u16 head; -}; - -/** - * struct mic_vdev - Host information for a card Virtio device. - * - * @virtio_id - Virtio device id. - * @waitq - Waitqueue to allow ring3 apps to poll. - * @mdev - Back pointer to host MIC device. - * @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. - * @dc - Virtio device control fields. - * @list - List of Virtio devices. - * @virtio_db - The doorbell used by the card to interrupt the host. - * @virtio_cookie - The cookie returned while requesting interrupts. - */ -struct mic_vdev { - int virtio_id; - wait_queue_head_t waitq; - struct mic_device *mdev; - 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; - struct mic_device_ctrl *dc; - struct list_head list; - int virtio_db; - struct mic_irq *virtio_cookie; -}; - -void mic_virtio_uninit(struct mic_device *mdev); -int mic_virtio_add_device(struct mic_vdev *mvdev, - void __user *argp); -void mic_virtio_del_device(struct mic_vdev *mvdev); -int mic_virtio_config_change(struct mic_vdev *mvdev, - void __user *argp); -int mic_virtio_copy_desc(struct mic_vdev *mvdev, - struct mic_copy_desc *request); -void mic_virtio_reset_devices(struct mic_device *mdev); -void mic_bh_handler(struct work_struct *work); - -/* Helper API to obtain the MIC PCIe device */ -static inline struct device *mic_dev(struct mic_vdev *mvdev) -{ - return &mvdev->mdev->pdev->dev; -} - -/* Helper API to check if a virtio device is initialized */ -static inline int mic_vdev_inited(struct mic_vdev *mvdev) -{ - /* Device has not been created yet */ - if (!mvdev->dd || !mvdev->dd->type) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -EINVAL); - return -EINVAL; - } - - /* Device has been removed/deleted */ - if (mvdev->dd->type == -1) { - dev_err(mic_dev(mvdev), "%s %d err %d\n", - __func__, __LINE__, -ENODEV); - return -ENODEV; - } - - return 0; -} - -/* Helper API to check if a virtio device is running */ -static inline bool mic_vdevup(struct mic_vdev *mvdev) -{ - return !!mvdev->dd->status; -} -#endif |