diff options
| author | Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> | 2017-03-16 23:17:37 -0400 |
|---|---|---|
| committer | Cornelia Huck <cornelia.huck@de.ibm.com> | 2017-03-31 06:55:08 -0400 |
| commit | 83d1193a96dc78576c15f93cd70e0558763a85b3 (patch) | |
| tree | 3d7e58feeab5cfbeb2f7f42101055b4b3c4e515e | |
| parent | e01bcdd61320c91c826376e0a7dd96ef8e85dd18 (diff) | |
vfio: ccw: realize VFIO_DEVICE_RESET ioctl
Introduce VFIO_DEVICE_RESET ioctl for vfio-ccw to make it possible
to hot-reset the device.
We try to achieve a reset by first disabling the subchannel and
then enabling it again: this should clear all state at the subchannel.
Signed-off-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Message-Id: <20170317031743.40128-11-bjsdjshi@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
| -rw-r--r-- | drivers/s390/cio/vfio_ccw_ops.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index f3300ddded3f..125818cdf305 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c | |||
| @@ -12,6 +12,32 @@ | |||
| 12 | 12 | ||
| 13 | #include "vfio_ccw_private.h" | 13 | #include "vfio_ccw_private.h" |
| 14 | 14 | ||
| 15 | static int vfio_ccw_mdev_reset(struct mdev_device *mdev) | ||
| 16 | { | ||
| 17 | struct vfio_ccw_private *private; | ||
| 18 | struct subchannel *sch; | ||
| 19 | int ret; | ||
| 20 | |||
| 21 | private = dev_get_drvdata(mdev_parent_dev(mdev)); | ||
| 22 | if (!private) | ||
| 23 | return -ENODEV; | ||
| 24 | |||
| 25 | sch = private->sch; | ||
| 26 | /* | ||
| 27 | * TODO: | ||
| 28 | * In the cureent stage, some things like "no I/O running" and "no | ||
| 29 | * interrupt pending" are clear, but we are not sure what other state | ||
| 30 | * we need to care about. | ||
| 31 | * There are still a lot more instructions need to be handled. We | ||
| 32 | * should come back here later. | ||
| 33 | */ | ||
| 34 | ret = vfio_ccw_sch_quiesce(sch); | ||
| 35 | if (ret) | ||
| 36 | return ret; | ||
| 37 | |||
| 38 | return cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
| 39 | } | ||
| 40 | |||
| 15 | static int vfio_ccw_mdev_notifier(struct notifier_block *nb, | 41 | static int vfio_ccw_mdev_notifier(struct notifier_block *nb, |
| 16 | unsigned long action, | 42 | unsigned long action, |
| 17 | void *data) | 43 | void *data) |
| @@ -28,15 +54,11 @@ static int vfio_ccw_mdev_notifier(struct notifier_block *nb, | |||
| 28 | */ | 54 | */ |
| 29 | if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { | 55 | if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { |
| 30 | struct vfio_iommu_type1_dma_unmap *unmap = data; | 56 | struct vfio_iommu_type1_dma_unmap *unmap = data; |
| 31 | struct subchannel *sch = private->sch; | ||
| 32 | 57 | ||
| 33 | if (!cp_iova_pinned(&private->cp, unmap->iova)) | 58 | if (!cp_iova_pinned(&private->cp, unmap->iova)) |
| 34 | return NOTIFY_OK; | 59 | return NOTIFY_OK; |
| 35 | 60 | ||
| 36 | if (vfio_ccw_sch_quiesce(sch)) | 61 | if (vfio_ccw_mdev_reset(private->mdev)) |
| 37 | return NOTIFY_BAD; | ||
| 38 | |||
| 39 | if (cio_enable_subchannel(sch, (u32)(unsigned long)sch)) | ||
| 40 | return NOTIFY_BAD; | 62 | return NOTIFY_BAD; |
| 41 | 63 | ||
| 42 | cp_free(&private->cp); | 64 | cp_free(&private->cp); |
| @@ -100,16 +122,11 @@ static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) | |||
| 100 | 122 | ||
| 101 | static int vfio_ccw_mdev_remove(struct mdev_device *mdev) | 123 | static int vfio_ccw_mdev_remove(struct mdev_device *mdev) |
| 102 | { | 124 | { |
| 103 | struct vfio_ccw_private *private; | 125 | struct vfio_ccw_private *private = |
| 104 | struct subchannel *sch; | 126 | dev_get_drvdata(mdev_parent_dev(mdev)); |
| 105 | int ret; | 127 | int ret; |
| 106 | 128 | ||
| 107 | private = dev_get_drvdata(mdev_parent_dev(mdev)); | 129 | ret = vfio_ccw_mdev_reset(mdev); |
| 108 | sch = private->sch; | ||
| 109 | ret = vfio_ccw_sch_quiesce(sch); | ||
| 110 | if (ret) | ||
| 111 | return ret; | ||
| 112 | ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
| 113 | if (ret) | 130 | if (ret) |
| 114 | return ret; | 131 | return ret; |
| 115 | 132 | ||
| @@ -190,7 +207,7 @@ static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev, | |||
| 190 | 207 | ||
| 191 | static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info) | 208 | static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info) |
| 192 | { | 209 | { |
| 193 | info->flags = VFIO_DEVICE_FLAGS_CCW; | 210 | info->flags = VFIO_DEVICE_FLAGS_CCW | VFIO_DEVICE_FLAGS_RESET; |
| 194 | info->num_regions = VFIO_CCW_NUM_REGIONS; | 211 | info->num_regions = VFIO_CCW_NUM_REGIONS; |
| 195 | info->num_irqs = 0; | 212 | info->num_irqs = 0; |
| 196 | 213 | ||
| @@ -260,6 +277,8 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, | |||
| 260 | 277 | ||
| 261 | return copy_to_user((void __user *)arg, &info, minsz); | 278 | return copy_to_user((void __user *)arg, &info, minsz); |
| 262 | } | 279 | } |
| 280 | case VFIO_DEVICE_RESET: | ||
| 281 | return vfio_ccw_mdev_reset(mdev); | ||
| 263 | default: | 282 | default: |
| 264 | return -ENOTTY; | 283 | return -ENOTTY; |
| 265 | } | 284 | } |
