diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 3dc61a666695416e55bdf3bf0a06dc67dfa00a36..96d88358c31502ea6982d729ed9e839a2e321e86 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -6385,6 +6385,7 @@ CONFIG_VHOST_NET=m CONFIG_VHOST_SCSI=m CONFIG_VHOST_VSOCK=m CONFIG_VHOST_VDPA=m +# CONFIG_VHOST_VDPA_MIGRATION is not set # CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set # diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index 66c0fa6705b4909ee987bdb1e7b521658714c62c..ca1d561bb7ba21306857f5d2f9605df6b5abef94 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -7067,6 +7067,7 @@ CONFIG_VHOST_MENU=y CONFIG_VHOST_NET=m # CONFIG_VHOST_SCSI is not set CONFIG_VHOST_VSOCK=m +# CONFIG_VHOST_VDPA_MIGRATION is not set # CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set # diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index e98fa8100f3cc796f2f3b543cadd7f9a694313c7..ec72505bbe1a4c396dc40ebcd90e336be7879f13 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -434,7 +434,7 @@ static void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) ifcvf_set_status(vf, status); } -static int ifcvf_vdpa_reset(struct vdpa_device *vdpa_dev) +static int ifcvf_vdpa_reset(struct vdpa_device *vdpa_dev, int state) { struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); u8 status = ifcvf_get_status(vf); diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index ca972af3c89a2b932d791c1e99156b18c043ec0b..50031a833ac837e5ccf8cd14712daa680bcdfba2 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2861,7 +2861,7 @@ static void init_group_to_asid_map(struct mlx5_vdpa_dev *mvdev) mvdev->group2asid[i] = 0; } -static int mlx5_vdpa_reset(struct vdpa_device *vdev) +static int mlx5_vdpa_reset(struct vdpa_device *vdev, int state) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); diff --git a/drivers/vdpa/pds/vdpa_dev.c b/drivers/vdpa/pds/vdpa_dev.c index 52b2449182ad71976cc68cb58aa8b52a77ff5cea..e7aead514000c2edc6012c301f8129fd3e7241df 100644 --- a/drivers/vdpa/pds/vdpa_dev.c +++ b/drivers/vdpa/pds/vdpa_dev.c @@ -496,7 +496,7 @@ static void pds_vdpa_init_vqs_entry(struct pds_vdpa_device *pdsv, int qid, pdsv->vqs[qid].notify = notify; } -static int pds_vdpa_reset(struct vdpa_device *vdpa_dev) +static int pds_vdpa_reset(struct vdpa_device *vdpa_dev, int state) { struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev); struct device *dev; diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index 99428a04068d2d4f1c3507455a63dd522187b745..c0ddeb9ded1175f858caee78d944950a633f0c4f 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -245,7 +245,7 @@ static int snet_reset_dev(struct snet *snet) return 0; } -static int snet_reset(struct vdpa_device *vdev) +static int snet_reset(struct vdpa_device *vdev, int state) { struct snet *snet = vdpa_to_snet(vdev); diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 76d41058add9a8a5f45edb405ed822efba6de67f..c2ec1bc83170bcd158193e5d8a9b1b3a36b01b4b 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -480,7 +480,7 @@ static void vdpasim_set_status(struct vdpa_device *vdpa, u8 status) mutex_unlock(&vdpasim->mutex); } -static int vdpasim_reset(struct vdpa_device *vdpa) +static int vdpasim_reset(struct vdpa_device *vdpa, int state) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index df7869537ef146fdc62b6d29180e5e051c7c8d2c..f0c48f9efe4e97f08d41e333cc8a9d675af6c6bd 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -704,7 +704,7 @@ static void vduse_vdpa_set_config(struct vdpa_device *vdpa, unsigned int offset, /* Now we only support read-only configuration space */ } -static int vduse_vdpa_reset(struct vdpa_device *vdpa) +static int vduse_vdpa_reset(struct vdpa_device *vdpa, int state) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); int ret = vduse_dev_set_status(dev, 0); diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c index 281287fae89f137e18e09d5c259115f3af1fcb4f..0e16dd08968bb210b8f1a5ff32164d0ebd3ec825 100644 --- a/drivers/vdpa/virtio_pci/vp_vdpa.c +++ b/drivers/vdpa/virtio_pci/vp_vdpa.c @@ -222,7 +222,7 @@ static void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status) vp_modern_set_status(mdev, status); } -static int vp_vdpa_reset(struct vdpa_device *vdpa) +static int vp_vdpa_reset(struct vdpa_device *vdpa, int state) { struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa); struct virtio_pci_modern_device *mdev = vp_vdpa_to_mdev(vp_vdpa); diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index b455d9ab6f3d9c989ca10f37efd1fbebbcae665b..90301436b41e03807775922e45453e333e636243 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -79,6 +79,17 @@ config VHOST_VDPA To compile this driver as a module, choose M here: the module will be called vhost_vdpa. +config VHOST_VDPA_MIGRATION + tristate "vdpa migration support for vhost-vdpa" + default n + help + This option allows vhost vdpa to support migration. + Userspace programs can migration vdpa device using + VHOST_SET_LOG_BASE/VHOST_SET_LOG_SIZE/VHOST_LOG_SYNC/VHOST_LOG_SYNC/ + VHOST_LOG_SYNC/VHOST_GET_DEV_BUFFER_SIZE ioctls. + + This is only support arm64 platform. + config VHOST_CROSS_ENDIAN_LEGACY bool "Cross-endian support for vhost" default n diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index fb590e346e43d5465ad32fffa30d959bd9e97d01..d22d6623aebd90ab039e3e000dddd9d895cb58ae 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -49,6 +49,7 @@ struct vhost_vdpa { struct completion completion; struct vdpa_device *vdpa; struct hlist_head as[VHOST_VDPA_IOTLB_BUCKETS]; + struct vhost_iotlb resv_iotlb; struct device dev; struct cdev cdev; atomic_t opened; @@ -210,13 +211,13 @@ static void vhost_vdpa_unsetup_vq_irq(struct vhost_vdpa *v, u16 qid) irq_bypass_unregister_producer(&vq->call_ctx.producer); } -static int vhost_vdpa_reset(struct vhost_vdpa *v) +static int vhost_vdpa_reset(struct vhost_vdpa *v, int state) { struct vdpa_device *vdpa = v->vdpa; v->in_batch = 0; - return vdpa_reset(vdpa); + return vdpa_reset(vdpa, state); } static long vhost_vdpa_bind_mm(struct vhost_vdpa *v) @@ -295,7 +296,7 @@ static long vhost_vdpa_set_status(struct vhost_vdpa *v, u8 __user *statusp) vhost_vdpa_unsetup_vq_irq(v, i); if (status == 0) { - ret = vdpa_reset(vdpa); + ret = vdpa_reset(vdpa, VDPA_DEV_RESET_VIRTIO); if (ret) return ret; } else @@ -423,16 +424,19 @@ static long vhost_vdpa_set_features(struct vhost_vdpa *v, u64 __user *featurep) u64 features; int i; + if (copy_from_user(&features, featurep, sizeof(features))) + return -EFAULT; + + actual_features = ops->get_driver_features(vdpa); + /* * It's not allowed to change the features after they have - * been negotiated. + * been negotiated. But log start/end is allowed. */ - if (ops->get_status(vdpa) & VIRTIO_CONFIG_S_FEATURES_OK) + if ((ops->get_status(vdpa) & VIRTIO_CONFIG_S_FEATURES_OK) && + (features & ~(BIT_ULL(VHOST_F_LOG_ALL))) != actual_features) return -EBUSY; - if (copy_from_user(&features, featurep, sizeof(features))) - return -EFAULT; - if (vdpa_set_features(vdpa, features)) return -EINVAL; @@ -567,6 +571,126 @@ static long vhost_vdpa_resume(struct vhost_vdpa *v) return ops->resume(vdpa); } +#ifdef CONFIG_VHOST_VDPA_MIGRATION +static int vhost_vdpa_get_dev_buffer_size(struct vhost_vdpa *v, + uint32_t __user *argp) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + uint32_t size; + + if (!ops->get_dev_buffer_size) + return -EOPNOTSUPP; + + size = ops->get_dev_buffer_size(vdpa); + + if (copy_to_user(argp, &size, sizeof(size))) + return -EFAULT; + + return 0; +} + +static int vhost_vdpa_get_dev_buffer(struct vhost_vdpa *v, + struct vhost_vdpa_config __user *c) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + struct vhost_vdpa_config config; + int ret; + unsigned long size = offsetof(struct vhost_vdpa_config, buf); + + if (copy_from_user(&config, c, size)) + return -EFAULT; + + if (!ops->get_dev_buffer) + return -EOPNOTSUPP; + + down_read(&vdpa->cf_lock); + ret = ops->get_dev_buffer(vdpa, config.off, c->buf, config.len); + up_read(&vdpa->cf_lock); + + return ret; +} + +static int vhost_vdpa_set_dev_buffer(struct vhost_vdpa *v, + struct vhost_vdpa_config __user *c) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + struct vhost_vdpa_config config; + int ret; + unsigned long size = offsetof(struct vhost_vdpa_config, buf); + + if (copy_from_user(&config, c, size)) + return -EFAULT; + + if (!ops->set_dev_buffer) + return -EOPNOTSUPP; + + down_write(&vdpa->cf_lock); + ret = ops->set_dev_buffer(vdpa, config.off, c->buf, config.len); + up_write(&vdpa->cf_lock); + + return ret; +} + +static int vhost_vdpa_set_mig_state(struct vhost_vdpa *v, u8 __user *c) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + u8 state; + + if (!ops->set_mig_state) + return -EOPNOTSUPP; + + if (get_user(state, c)) + return -EFAULT; + + return ops->set_mig_state(vdpa, state); +} + +static long vhost_vdpa_set_log_base(struct vhost_vdpa *v, u64 __user *argp) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + u64 log; + + if (!ops->set_log_base) + return -EOPNOTSUPP; + + if (copy_from_user(&log, argp, sizeof(uint64_t))) + return -EFAULT; + + return ops->set_log_base(vdpa, log); +} + +static long vhost_vdpa_set_log_size(struct vhost_vdpa *v, u64 __user *sizep) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + u64 log_size; + + if (!ops->set_log_size) + return -EOPNOTSUPP; + + if (copy_from_user(&log_size, sizep, sizeof(log_size))) + return -EFAULT; + + return ops->set_log_size(vdpa, log_size); +} + +static long vhost_vdpa_log_sync(struct vhost_vdpa *v) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + + if (!ops->log_sync) + return -EOPNOTSUPP; + + return ops->log_sync(vdpa); +} +#endif + static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, void __user *argp) { @@ -692,7 +816,8 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep, if (features & ~(VHOST_VDPA_BACKEND_FEATURES | BIT_ULL(VHOST_BACKEND_F_SUSPEND) | BIT_ULL(VHOST_BACKEND_F_RESUME) | - BIT_ULL(VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK))) + BIT_ULL(VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK) | + BIT_ULL(VHOST_BACKEND_F_BYTEMAPLOG))) return -EOPNOTSUPP; if ((features & BIT_ULL(VHOST_BACKEND_F_SUSPEND)) && !vhost_vdpa_can_suspend(v)) @@ -741,6 +866,16 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep, r = -EFAULT; break; case VHOST_SET_LOG_BASE: +#ifdef CONFIG_VHOST_VDPA_MIGRATION + r = vhost_vdpa_set_log_base(v, argp); + break; + case VHOST_SET_LOG_SIZE: + r = vhost_vdpa_set_log_size(v, argp); + break; + case VHOST_LOG_SYNC: + r = vhost_vdpa_log_sync(v); + break; +#endif case VHOST_SET_LOG_FD: r = -ENOIOCTLCMD; break; @@ -772,6 +907,20 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep, case VHOST_VDPA_RESUME: r = vhost_vdpa_resume(v); break; +#ifdef CONFIG_VHOST_VDPA_MIGRATION + case VHOST_GET_DEV_BUFFER_SIZE: + r = vhost_vdpa_get_dev_buffer_size(v, argp); + break; + case VHOST_GET_DEV_BUFFER: + r = vhost_vdpa_get_dev_buffer(v, argp); + break; + case VHOST_SET_DEV_BUFFER: + r = vhost_vdpa_set_dev_buffer(v, argp); + break; + case VHOST_VDPA_SET_MIG_STATE: + r = vhost_vdpa_set_mig_state(v, argp); + break; +#endif default: r = vhost_dev_ioctl(&v->vdev, cmd, argp); if (r == -ENOIOCTLCMD) @@ -1115,6 +1264,10 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v, msg->iova + msg->size - 1 > v->range.last) return -EINVAL; + if (vhost_iotlb_itree_first(&v->resv_iotlb, msg->iova, + msg->iova + msg->size - 1)) + return -EINVAL; + if (vhost_iotlb_itree_first(iotlb, msg->iova, msg->iova + msg->size - 1)) return -EEXIST; @@ -1203,6 +1356,46 @@ static ssize_t vhost_vdpa_chr_write_iter(struct kiocb *iocb, return vhost_chr_write_iter(dev, from); } +static int vhost_vdpa_resv_iommu_region(struct iommu_domain *domain, struct device *dma_dev, + struct vhost_iotlb *resv_iotlb) +{ + struct list_head dev_resv_regions; + phys_addr_t resv_msi_base = 0; + struct iommu_resv_region *region; + int ret = 0; + bool with_sw_msi = false; + bool with_hw_msi = false; + + INIT_LIST_HEAD(&dev_resv_regions); + iommu_get_resv_regions(dma_dev, &dev_resv_regions); + + list_for_each_entry(region, &dev_resv_regions, list) { + ret = vhost_iotlb_add_range_ctx(resv_iotlb, region->start, + region->start + region->length - 1, + 0, 0, NULL); + if (ret) { + vhost_iotlb_reset(resv_iotlb); + break; + } + + if (region->type == IOMMU_RESV_MSI) + with_hw_msi = true; + + if (region->type == IOMMU_RESV_SW_MSI) { + resv_msi_base = region->start; + with_sw_msi = true; + } + + } + + if (!ret && !with_hw_msi && with_sw_msi) + ret = iommu_get_msi_cookie(domain, resv_msi_base); + + iommu_put_resv_regions(dma_dev, &dev_resv_regions); + + return ret; +} + static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v) { struct vdpa_device *vdpa = v->vdpa; @@ -1231,11 +1424,16 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v) ret = iommu_attach_device(v->domain, dma_dev); if (ret) - goto err_attach; + goto err_alloc_domain; - return 0; + ret = vhost_vdpa_resv_iommu_region(v->domain, dma_dev, &v->resv_iotlb); + if (ret) + goto err_attach_device; -err_attach: + return 0; +err_attach_device: + iommu_detach_device(v->domain, dma_dev); +err_alloc_domain: iommu_domain_free(v->domain); v->domain = NULL; return ret; @@ -1300,9 +1498,12 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep) opened = atomic_cmpxchg(&v->opened, 0, 1); if (opened) return -EBUSY; + r = vhost_vdpa_alloc_domain(v); + if (r) + return r; nvqs = v->nvqs; - r = vhost_vdpa_reset(v); + r = vhost_vdpa_reset(v, VDPA_DEV_RESET_OPEN); if (r) goto err; @@ -1320,19 +1521,14 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep) vhost_dev_init(dev, vqs, nvqs, 0, 0, 0, false, vhost_vdpa_process_iotlb_msg); - r = vhost_vdpa_alloc_domain(v); - if (r) - goto err_alloc_domain; - vhost_vdpa_set_iova_range(v); filep->private_data = v; return 0; -err_alloc_domain: - vhost_vdpa_cleanup(v); err: + vhost_vdpa_free_domain(v); atomic_dec(&v->opened); return r; } @@ -1353,7 +1549,7 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) mutex_lock(&d->mutex); filep->private_data = NULL; vhost_vdpa_clean_irq(v); - vhost_vdpa_reset(v); + vhost_vdpa_reset(v, VDPA_DEV_RESET_CLOSE); vhost_dev_stop(&v->vdev); vhost_vdpa_unbind_mm(v); vhost_vdpa_config_put(v); @@ -1490,6 +1686,8 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa) goto err; } + vhost_iotlb_init(&v->resv_iotlb, 0, 0); + r = dev_set_name(&v->dev, "vhost-vdpa-%u", minor); if (r) goto err; diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index 06ce6d8c2e00473bea0df046f296b3ad17838f65..13f69bfb9c98f9caafe9af66c602ec6f0695ff06 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -100,7 +100,7 @@ static void virtio_vdpa_reset(struct virtio_device *vdev) { struct vdpa_device *vdpa = vd_get_vdpa(vdev); - vdpa_reset(vdpa); + vdpa_reset(vdpa, VDPA_DEV_RESET_VIRTIO); } static bool virtio_vdpa_notify(struct virtqueue *vq) diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index 0e652026b776f81b697f7fa93c3183b67ee46203..3120a1a600ddc3a2105a3ee4b9052c9bba8a34b8 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -129,6 +129,12 @@ struct vdpa_map_file { u64 offset; }; +enum vdpa_reset_state { + VDPA_DEV_RESET_VIRTIO = 0, + VDPA_DEV_RESET_OPEN = 1, + VDPA_DEV_RESET_CLOSE = 2, +}; + /** * struct vdpa_config_ops - operations for configuring a vDPA device. * Note: vDPA device drivers are required to implement all of the @@ -241,6 +247,10 @@ struct vdpa_map_file { * @status: virtio device status * @reset: Reset device * @vdev: vdpa device + * @state: state for reset + * VDPA_DEV_RESET_VIRTIO for virtio reset + * VDPA_DEV_RESET_OPEN for vhost-vdpa device open + * VDPA_DEV_RESET_CLOSE for vhost-vdpa device close * Returns integer: success (0) or error (< 0) * @suspend: Suspend the device (optional) * @vdev: vdpa device @@ -330,6 +340,31 @@ struct vdpa_map_file { * @unbind_mm: Unbind the device from the address space * bound using the bind_mm callback. (optional) * @vdev: vdpa device + * @set_log_base Set base address for logging. (optional) + * @vdev: vdpa device + * @base: base address + * @set_log_size Set buffer size for logging. (optional) + * @vdev: vdpa device + * @size: logging buffer size + * @log_sync Synchronize logging buffer from kernel space to + * user space. (optional) + * @vdev: vdpa device + * @get_dev_buffer_size Get device state buffer size. (optional) + * @vdev: vdpa device + * Return device status buffer size of vdpa device. + * @get_dev_buffer Get device state buffer. (optional) + * @vdev: vdpa device + * @offset: offset of dest for saving device state. + * @dest: userspace address for saving device state. + * @len: device state buffer length. + * @set_dev_buffer Set device state buffer. (opetional) + * @vdev: vdpa device + * @offset: offset of src addr of device state. + * @src: userspace addr of device state + * @len: device state buffer length. + * @set_mig_state Set device migration status. (optional) + * @vdev: vdpa device + * @status: migration status * @free: Free resources that belongs to vDPA (optional) * @vdev: vdpa device */ @@ -372,7 +407,7 @@ struct vdpa_config_ops { u32 (*get_vendor_id)(struct vdpa_device *vdev); u8 (*get_status)(struct vdpa_device *vdev); void (*set_status)(struct vdpa_device *vdev, u8 status); - int (*reset)(struct vdpa_device *vdev); + int (*reset)(struct vdpa_device *vdev, int state); int (*suspend)(struct vdpa_device *vdev); int (*resume)(struct vdpa_device *vdev); size_t (*get_config_size)(struct vdpa_device *vdev); @@ -400,6 +435,21 @@ struct vdpa_config_ops { int (*bind_mm)(struct vdpa_device *vdev, struct mm_struct *mm); void (*unbind_mm)(struct vdpa_device *vdev); + /* Log ops */ + int (*set_log_base)(struct vdpa_device *vdev, uint64_t base); + int (*set_log_size)(struct vdpa_device *vdev, uint64_t size); + int (*log_sync)(struct vdpa_device *vdev); + + /* device state ops */ + uint32_t (*get_dev_buffer_size)(struct vdpa_device *vdpa); + int (*get_dev_buffer)(struct vdpa_device *vdev, unsigned int offset, + void __user *dest, unsigned int len); + int (*set_dev_buffer)(struct vdpa_device *vdev, unsigned int offset, + const void __user *src, unsigned int len); + + /* device mig state ops */ + int (*set_mig_state)(struct vdpa_device *v, u8 state); + /* Free device resources */ void (*free)(struct vdpa_device *vdev); }; @@ -485,14 +535,14 @@ static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev) return vdev->dma_dev; } -static inline int vdpa_reset(struct vdpa_device *vdev) +static inline int vdpa_reset(struct vdpa_device *vdev, int state) { const struct vdpa_config_ops *ops = vdev->config; int ret; down_write(&vdev->cf_lock); vdev->features_valid = false; - ret = ops->reset(vdev); + ret = ops->reset(vdev, state); up_write(&vdev->cf_lock); return ret; } diff --git a/include/linux/vdpa_vmstate.h b/include/linux/vdpa_vmstate.h new file mode 100644 index 0000000000000000000000000000000000000000..0e577a9605f17990871cb795a6fe6611ecb0ded7 --- /dev/null +++ b/include/linux/vdpa_vmstate.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Description: vdpa vmstate header file + * Author: jiangdongxu + * Create: 2023-12-3 + * Note: + * History: 2023-12-3: Create file + */ + +#ifndef VDPA_VMSTATE_H +#define VDPA_VMSTATE_H + +#include +#include + + +#define VIRTIO_MIG_STATE_TYPE_DEVICE 0 +#define VIRTIO_MIG_STATE_TYPE_VQ 1 +#define VIRTIO_MIG_STATE_TYPE_CONFIG 2 +#define VIRTIO_MIG_STATE_TYPE_FEATURE 3 +#define VIRTIO_MIG_STATE_TYPE_PLATFORM 4 +#define VIRTIO_MIG_STATE_TYPE_VENDOR 255 + +#define VIRTIO_MIG_DEVICE_T_COMMON 0 +#define VIRTIO_MIG_DEVICE_T_NET 1 +#define VIRTIO_MIG_DEVICE_T_BLK 2 +#define VIRTIO_MIG_DEVICE_T_SCSI 8 + +#define VIRTIO_MIG_CONFIG_T_NET 1 +#define VIRTIO_MIG_CONFIG_T_BLK 2 +#define VIRTIO_MIG_CONFIG_T_SCSI 8 + +#define MAC_LEN 6 + +struct virtio_mig_state_header { + le32 type; + le32 len; +}; + +struct virtio_mig_dev_common_data { + le32 vendor_id; + le32 device_id; + le32 device_features_l; + le32 device_features_h; + le32 driver_features_l; + le32 driver_features_h; + le32 status; + le32 generation; + le32 msix_en; +}; + +struct virtio_mig_dev_common_state { + struct virtio_mig_state_header hdr; + struct virtio_mig_dev_common_data data; +}; + +struct virtio_mig_vq_split_state { + le16 avail_index; + le16 used_index; +}; +struct virtio_mig_vq_packed_state { + le16 avail_wrapped : 1; + le16 avail_index : 15; + le16 used_wrapped : 1; + le16 used_index : 15; +}; + +struct virtio_mig_per_vq_data { + le32 qsize; + + u8 qenabled; + le16 msix_vector; + + le32 desc_l; + le32 desc_h; + le32 avail_l; + le32 avail_h; + le32 used_l; + le32 used_h; + union { + struct virtio_mig_vq_split_state split; + struct virtio_mig_vq_packed_state packed; + } version; +}; + +/* vq state */ +struct virtio_mig_vq_state { + struct virtio_mig_state_header hdr; + + le16 msix_config; + le16 valid_queues; + + le16 num_queues; + + struct virtio_mig_per_vq_data vq_state[]; +}; + +/* config space */ +struct virtio_mig_config_state { + struct virtio_mig_state_header hdr; + union { + struct virtio_net_config net; + struct virtio_blk_config blk; + struct virtio_scsi_config scsi; + } dev; +}; + +struct virtio_mig_cfg_blk_features { + +}; + +struct virtio_mig_cfg_scsi_features { + +}; + +struct virtio_mig_cfg_net_ctrl_guest_offloads { + struct virtio_mig_state_header hdr; + le64 offloads; + le64 reserved; +}; + +struct virtio_mig_cfg_net_ctrl_mq_vq_pairs { + struct virtio_mig_state_header hdr; + le16 cur_virtqueue_pairs; +}; + +struct virtio_mig_cfg_net_ctrl_mac_table { + struct virtio_mig_state_header hdr; + le16 num_unicast; + /* TODO: need to be implemented later */ + // u8 unicast_macs[][6]; + le16 num_multicast; + /* TODO: need to be implemented later */ + // u8 multicast_macs[][6]; +}; + +struct virtio_mig_cfg_net_ctrl_vlan { + struct virtio_mig_state_header hdr; + le32 vlans[128]; +}; + +struct virtio_mig_cfg_net_data { + le32 nfeatures; + struct virtio_mig_cfg_net_ctrl_guest_offloads offloads; + struct virtio_mig_cfg_net_ctrl_mq_vq_pairs mq_pairs; + struct virtio_mig_cfg_net_ctrl_mac_table mac_table; + struct virtio_mig_cfg_net_ctrl_vlan vlan_table; +}; + +struct virtio_mig_cfg_net_features { + struct virtio_mig_state_header hdr; + struct virtio_mig_cfg_net_data data; +}; + +/* feature */ +struct virtio_mig_feat_state { + union { + struct virtio_mig_cfg_net_features net; + struct virtio_mig_cfg_blk_features blk; + struct virtio_mig_cfg_scsi_features scsi; + }; +}; + +struct vdpa_mig_state { + struct virtio_mig_dev_common_state dev_state; + struct virtio_mig_config_state cfg_state; + struct virtio_mig_feat_state feat_state; + struct virtio_mig_vq_state vq_state; +}; + +#endif /* VDPA_VMSTATE_H */ diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index f5c48b61ab62244104bbf1b2100d3db7286f8c82..a54098c7b0bc6b6df250f9addcd2935ec06affba 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -43,6 +43,10 @@ * The bit is set using an atomic 32 bit operation. */ /* Set base address for logging. */ #define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) +/* Set buffer size for logging */ +#define VHOST_SET_LOG_SIZE _IOW(VHOST_VIRTIO, 0x05, __u64) +/* Synchronize logging buffer from kernel space to user space */ +#define VHOST_LOG_SYNC _IO(VHOST_VIRTIO, 0x06) /* Specify an eventfd file descriptor to signal on log write. */ #define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) /* By default, a device gets one vhost_worker that its virtqueues share. This @@ -219,4 +223,12 @@ */ #define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) +/* set and get device buffer */ +#define VHOST_GET_DEV_BUFFER _IOR(VHOST_VIRTIO, 0xb0, struct vhost_vdpa_config) +#define VHOST_SET_DEV_BUFFER _IOW(VHOST_VIRTIO, 0xb1, struct vhost_vdpa_config) +#define VHOST_GET_DEV_BUFFER_SIZE _IOR(VHOST_VIRTIO, 0xb3, __u32) + +/* set device migtration state */ +#define VHOST_VDPA_SET_MIG_STATE _IOW(VHOST_VIRTIO, 0xb2, __u8) + #endif diff --git a/include/uapi/linux/vhost_types.h b/include/uapi/linux/vhost_types.h index 2d827d22cd99d2e507acaebcb3d502ac15417770..c7f25b0f7645929af99e5de9a396eb9aabab7326 100644 --- a/include/uapi/linux/vhost_types.h +++ b/include/uapi/linux/vhost_types.h @@ -163,6 +163,22 @@ struct vhost_vdpa_iova_range { __u64 last; }; +/* vhost vdpa device migration statue */ +enum { + VHOST_VDPA_DEVICE_START, + VHOST_VDPA_DEVICE_STOP, + VHOST_VDPA_DEVICE_PRE_START, + VHOST_VDPA_DEVICE_PRE_STOP, + VHOST_VDPA_DEVICE_CANCEL, + VHOST_VDPA_DEVICE_POST_START, + VHOST_VDPA_DEVICE_START_ASYNC, + VHOST_VDPA_DEVICE_STOP_ASYNC, + VHOST_VDPA_DEVICE_PRE_START_ASYNC, + VHOST_VDPA_DEVICE_QUERY_OP_STATE, + VHOST_VDPA_DEVICE_MSIX_MASK, + VHOST_VDPA_DEVICE_MSIX_UNMASK, +}; + /* Feature bits */ /* Log all write descriptors. Can be changed while device is active. */ #define VHOST_F_LOG_ALL 26 @@ -186,4 +202,7 @@ struct vhost_vdpa_iova_range { */ #define VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK 0x6 +/* Device can use bytemap to deal log */ +#define VHOST_BACKEND_F_BYTEMAPLOG 0x3f + #endif