Home Home > GIT Browse > SLE15-SP1
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Tesarik <ptesarik@suse.cz>2019-07-18 11:02:34 +0200
committerPetr Tesarik <ptesarik@suse.cz>2019-07-19 14:09:51 +0200
commitb0dc51c85ff65146b44640359760785196f49ec8 (patch)
treef43b4be37f83dcf792b769f5a94c807c4027f335
parentbd699b0871aa58d0320f9bfe37a3c415576128b8 (diff)
virtio/s390: use DMA memory for ccw I/O and classic notifiers
(jsc#SLE-6197 FATE#327012 bsc#1140559 LTC#173150).
-rw-r--r--patches.suse/virtio-s390-use-dma-memory-for-ccw-i-o-and-classic-notifiers510
-rw-r--r--series.conf1
2 files changed, 511 insertions, 0 deletions
diff --git a/patches.suse/virtio-s390-use-dma-memory-for-ccw-i-o-and-classic-notifiers b/patches.suse/virtio-s390-use-dma-memory-for-ccw-i-o-and-classic-notifiers
new file mode 100644
index 0000000000..9167398fdd
--- /dev/null
+++ b/patches.suse/virtio-s390-use-dma-memory-for-ccw-i-o-and-classic-notifiers
@@ -0,0 +1,510 @@
+From: Halil Pasic <pasic@linux.ibm.com>
+Date: Mon, 1 Oct 2018 19:01:58 +0200
+Subject: virtio/s390: use DMA memory for ccw I/O and classic notifiers
+Git-commit: 48720ba56891570e3b750b271d80efb631478630
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-6197 FATE#327012 bsc#1140559 LTC#173150
+
+Before virtio-ccw could get away with not using DMA API for the pieces of
+memory it does ccw I/O with. With protected virtualization this has to
+change, since the hypervisor needs to read and sometimes also write these
+pieces of memory.
+
+The hypervisor is supposed to poke the classic notifiers, if these are
+used, out of band with regards to ccw I/O. So these need to be allocated
+as DMA memory (which is shared memory for protected virtualization
+guests).
+
+Let us factor out everything from struct virtio_ccw_device that needs to
+be DMA memory in a satellite that is allocated as such.
+
+Note: The control blocks of I/O instructions do not need to be shared.
+These are marshalled by the ultravisor.
+
+Signed-off-by: Halil Pasic <pasic@linux.ibm.com>
+Reviewed-by: Pierre Morel <pmorel@linux.ibm.com>
+Reviewed-by: Cornelia Huck <cohuck@redhat.com>
+Reviewed-by: Michael Mueller <mimu@linux.ibm.com>
+Tested-by: Michael Mueller <mimu@linux.ibm.com>
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ drivers/s390/virtio/virtio_ccw.c | 169 ++++++++++++++++++++-------------------
+ 1 file changed, 89 insertions(+), 80 deletions(-)
+
+--- a/drivers/s390/virtio/virtio_ccw.c
++++ b/drivers/s390/virtio/virtio_ccw.c
+@@ -49,9 +49,15 @@ struct vq_config_block {
+ #define VIRTIO_CCW_CONFIG_SIZE 0x100
+ /* same as PCI config space size, should be enough for all drivers */
+
++struct vcdev_dma_area {
++ unsigned long indicators;
++ unsigned long indicators2;
++ struct vq_config_block config_block;
++ __u8 status;
++};
++
+ struct virtio_ccw_device {
+ struct virtio_device vdev;
+- __u8 *status;
+ __u8 config[VIRTIO_CCW_CONFIG_SIZE];
+ struct ccw_device *cdev;
+ __u32 curr_io;
+@@ -61,24 +67,22 @@ struct virtio_ccw_device {
+ spinlock_t lock;
+ struct mutex io_lock; /* Serializes I/O requests */
+ struct list_head virtqueues;
+- unsigned long indicators;
+- unsigned long indicators2;
+- struct vq_config_block *config_block;
+ bool is_thinint;
+ bool going_away;
+ bool device_lost;
+ unsigned int config_ready;
+ void *airq_info;
++ struct vcdev_dma_area *dma_area;
+ };
+
+ static inline unsigned long *indicators(struct virtio_ccw_device *vcdev)
+ {
+- return &vcdev->indicators;
++ return &vcdev->dma_area->indicators;
+ }
+
+ static inline unsigned long *indicators2(struct virtio_ccw_device *vcdev)
+ {
+- return &vcdev->indicators2;
++ return &vcdev->dma_area->indicators2;
+ }
+
+ struct vq_info_block_legacy {
+@@ -339,8 +343,8 @@ static void virtio_ccw_drop_indicator(st
+ struct airq_info *airq_info = vcdev->airq_info;
+
+ if (vcdev->is_thinint) {
+- thinint_area = kzalloc(sizeof(*thinint_area),
+- GFP_DMA | GFP_KERNEL);
++ thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
++ sizeof(*thinint_area));
+ if (!thinint_area)
+ return;
+ thinint_area->summary_indicator =
+@@ -351,8 +355,8 @@ static void virtio_ccw_drop_indicator(st
+ ccw->cda = (__u32)(unsigned long) thinint_area;
+ } else {
+ /* payload is the address of the indicators */
+- indicatorp = kmalloc(sizeof(indicators(vcdev)),
+- GFP_DMA | GFP_KERNEL);
++ indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
++ sizeof(indicators(vcdev)));
+ if (!indicatorp)
+ return;
+ *indicatorp = 0;
+@@ -372,8 +376,8 @@ static void virtio_ccw_drop_indicator(st
+ "Failed to deregister indicators (%d)\n", ret);
+ else if (vcdev->is_thinint)
+ virtio_ccw_drop_indicators(vcdev);
+- kfree(indicatorp);
+- kfree(thinint_area);
++ ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(indicators(vcdev)));
++ ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
+ }
+
+ static inline long __do_kvm_notify(struct subchannel_id schid,
+@@ -420,15 +424,15 @@ static int virtio_ccw_read_vq_conf(struc
+ {
+ int ret;
+
+- vcdev->config_block->index = index;
++ vcdev->dma_area->config_block.index = index;
+ ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
+ ccw->flags = 0;
+ ccw->count = sizeof(struct vq_config_block);
+- ccw->cda = (__u32)(unsigned long)(vcdev->config_block);
++ ccw->cda = (__u32)(unsigned long)(&vcdev->dma_area->config_block);
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
+ if (ret)
+ return ret;
+- return vcdev->config_block->num ?: -ENOENT;
++ return vcdev->dma_area->config_block.num ?: -ENOENT;
+ }
+
+ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
+@@ -473,7 +477,8 @@ static void virtio_ccw_del_vq(struct vir
+ ret, index);
+
+ vring_del_virtqueue(vq);
+- kfree(info->info_block);
++ ccw_device_dma_free(vcdev->cdev, info->info_block,
++ sizeof(*info->info_block));
+ kfree(info);
+ }
+
+@@ -483,7 +488,7 @@ static void virtio_ccw_del_vqs(struct vi
+ struct ccw1 *ccw;
+ struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return;
+
+@@ -492,7 +497,7 @@ static void virtio_ccw_del_vqs(struct vi
+ list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+ virtio_ccw_del_vq(vq, ccw);
+
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ }
+
+ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
+@@ -515,8 +520,8 @@ static struct virtqueue *virtio_ccw_setu
+ err = -ENOMEM;
+ goto out_err;
+ }
+- info->info_block = kzalloc(sizeof(*info->info_block),
+- GFP_DMA | GFP_KERNEL);
++ info->info_block = ccw_device_dma_zalloc(vcdev->cdev,
++ sizeof(*info->info_block));
+ if (!info->info_block) {
+ dev_warn(&vcdev->cdev->dev, "no info block\n");
+ err = -ENOMEM;
+@@ -580,7 +585,8 @@ out_err:
+ if (vq)
+ vring_del_virtqueue(vq);
+ if (info) {
+- kfree(info->info_block);
++ ccw_device_dma_free(vcdev->cdev, info->info_block,
++ sizeof(*info->info_block));
+ }
+ kfree(info);
+ return ERR_PTR(err);
+@@ -594,7 +600,8 @@ static int virtio_ccw_register_adapter_i
+ struct virtio_thinint_area *thinint_area = NULL;
+ struct airq_info *info;
+
+- thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL);
++ thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
++ sizeof(*thinint_area));
+ if (!thinint_area) {
+ ret = -ENOMEM;
+ goto out;
+@@ -630,7 +637,7 @@ static int virtio_ccw_register_adapter_i
+ virtio_ccw_drop_indicators(vcdev);
+ }
+ out:
+- kfree(thinint_area);
++ ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
+ return ret;
+ }
+
+@@ -646,7 +653,7 @@ static int virtio_ccw_find_vqs(struct vi
+ int ret, i;
+ struct ccw1 *ccw;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return -ENOMEM;
+
+@@ -664,7 +671,8 @@ static int virtio_ccw_find_vqs(struct vi
+ * We need a data area under 2G to communicate. Our payload is
+ * the address of the indicators.
+ */
+- indicatorp = kmalloc(sizeof(indicators(vcdev)), GFP_DMA | GFP_KERNEL);
++ indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
++ sizeof(indicators(vcdev)));
+ if (!indicatorp)
+ goto out;
+ *indicatorp = (unsigned long) indicators(vcdev);
+@@ -696,12 +704,16 @@ static int virtio_ccw_find_vqs(struct vi
+ if (ret)
+ goto out;
+
+- kfree(indicatorp);
+- kfree(ccw);
++ if (indicatorp)
++ ccw_device_dma_free(vcdev->cdev, indicatorp,
++ sizeof(indicators(vcdev)));
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ return 0;
+ out:
+- kfree(indicatorp);
+- kfree(ccw);
++ if (indicatorp)
++ ccw_device_dma_free(vcdev->cdev, indicatorp,
++ sizeof(indicators(vcdev)));
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ virtio_ccw_del_vqs(vdev);
+ return ret;
+ }
+@@ -711,12 +723,12 @@ static void virtio_ccw_reset(struct virt
+ struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+ struct ccw1 *ccw;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return;
+
+ /* Zero status bits. */
+- *vcdev->status = 0;
++ vcdev->dma_area->status = 0;
+
+ /* Send a reset ccw on device. */
+ ccw->cmd_code = CCW_CMD_VDEV_RESET;
+@@ -724,7 +736,7 @@ static void virtio_ccw_reset(struct virt
+ ccw->count = 0;
+ ccw->cda = 0;
+ ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET);
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ }
+
+ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
+@@ -735,11 +747,11 @@ static u64 virtio_ccw_get_features(struc
+ u64 rc;
+ struct ccw1 *ccw;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return 0;
+
+- features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
++ features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features));
+ if (!features) {
+ rc = 0;
+ goto out_free;
+@@ -772,8 +784,8 @@ static u64 virtio_ccw_get_features(struc
+ rc |= (u64)le32_to_cpu(features->features) << 32;
+
+ out_free:
+- kfree(features);
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, features, sizeof(*features));
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ return rc;
+ }
+
+@@ -791,11 +803,11 @@ static int virtio_ccw_finalize_features(
+ return -EINVAL;
+ }
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return -ENOMEM;
+
+- features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
++ features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features));
+ if (!features) {
+ ret = -ENOMEM;
+ goto out_free;
+@@ -827,8 +839,8 @@ static int virtio_ccw_finalize_features(
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
+
+ out_free:
+- kfree(features);
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, features, sizeof(*features));
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+
+ return ret;
+ }
+@@ -842,11 +854,12 @@ static void virtio_ccw_get_config(struct
+ void *config_area;
+ unsigned long flags;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return;
+
+- config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
++ config_area = ccw_device_dma_zalloc(vcdev->cdev,
++ VIRTIO_CCW_CONFIG_SIZE);
+ if (!config_area)
+ goto out_free;
+
+@@ -868,8 +881,8 @@ static void virtio_ccw_get_config(struct
+ memcpy(buf, config_area + offset, len);
+
+ out_free:
+- kfree(config_area);
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, config_area, VIRTIO_CCW_CONFIG_SIZE);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ }
+
+ static void virtio_ccw_set_config(struct virtio_device *vdev,
+@@ -881,11 +894,12 @@ static void virtio_ccw_set_config(struct
+ void *config_area;
+ unsigned long flags;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return;
+
+- config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
++ config_area = ccw_device_dma_zalloc(vcdev->cdev,
++ VIRTIO_CCW_CONFIG_SIZE);
+ if (!config_area)
+ goto out_free;
+
+@@ -904,61 +918,61 @@ static void virtio_ccw_set_config(struct
+ ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
+
+ out_free:
+- kfree(config_area);
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, config_area, VIRTIO_CCW_CONFIG_SIZE);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ }
+
+ static u8 virtio_ccw_get_status(struct virtio_device *vdev)
+ {
+ struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+- u8 old_status = *vcdev->status;
++ u8 old_status = vcdev->dma_area->status;
+ struct ccw1 *ccw;
+
+ if (vcdev->revision < 1)
+- return *vcdev->status;
++ return vcdev->dma_area->status;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return old_status;
+
+ ccw->cmd_code = CCW_CMD_READ_STATUS;
+ ccw->flags = 0;
+- ccw->count = sizeof(*vcdev->status);
+- ccw->cda = (__u32)(unsigned long)vcdev->status;
++ ccw->count = sizeof(vcdev->dma_area->status);
++ ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
+ ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
+ /*
+ * If the channel program failed (should only happen if the device
+ * was hotunplugged, and then we clean up via the machine check
+- * handler anyway), vcdev->status was not overwritten and we just
++ * handler anyway), vcdev->dma_area->status was not overwritten and we just
+ * return the old status, which is fine.
+ */
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+
+- return *vcdev->status;
++ return vcdev->dma_area->status;
+ }
+
+ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
+ {
+ struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+- u8 old_status = *vcdev->status;
++ u8 old_status = vcdev->dma_area->status;
+ struct ccw1 *ccw;
+ int ret;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return;
+
+ /* Write the status to the host. */
+- *vcdev->status = status;
++ vcdev->dma_area->status = status;
+ ccw->cmd_code = CCW_CMD_WRITE_STATUS;
+ ccw->flags = 0;
+ ccw->count = sizeof(status);
+- ccw->cda = (__u32)(unsigned long)vcdev->status;
++ ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
+ /* Write failed? We assume status is unchanged. */
+ if (ret)
+- *vcdev->status = old_status;
+- kfree(ccw);
++ vcdev->dma_area->status = old_status;
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ }
+
+ static const struct virtio_config_ops virtio_ccw_config_ops = {
+@@ -983,8 +997,8 @@ static void virtio_ccw_release_dev(struc
+ struct virtio_device *dev = dev_to_virtio(_d);
+ struct virtio_ccw_device *vcdev = to_vc_device(dev);
+
+- kfree(vcdev->status);
+- kfree(vcdev->config_block);
++ ccw_device_dma_free(vcdev->cdev, vcdev->dma_area,
++ sizeof(*vcdev->dma_area));
+ kfree(vcdev);
+ }
+
+@@ -1192,12 +1206,12 @@ static int virtio_ccw_set_transport_rev(
+ struct ccw1 *ccw;
+ int ret;
+
+- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
++ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+ if (!ccw)
+ return -ENOMEM;
+- rev = kzalloc(sizeof(*rev), GFP_DMA | GFP_KERNEL);
++ rev = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*rev));
+ if (!rev) {
+- kfree(ccw);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ return -ENOMEM;
+ }
+
+@@ -1227,8 +1241,8 @@ static int virtio_ccw_set_transport_rev(
+ }
+ } while (ret == -EOPNOTSUPP);
+
+- kfree(ccw);
+- kfree(rev);
++ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
++ ccw_device_dma_free(vcdev->cdev, rev, sizeof(*rev));
+ return ret;
+ }
+
+@@ -1245,14 +1259,10 @@ static int virtio_ccw_online(struct ccw_
+ goto out_free;
+ }
+ vcdev->vdev.dev.parent = &cdev->dev;
+- vcdev->config_block = kzalloc(sizeof(*vcdev->config_block),
+- GFP_DMA | GFP_KERNEL);
+- if (!vcdev->config_block) {
+- ret = -ENOMEM;
+- goto out_free;
+- }
+- vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL);
+- if (!vcdev->status) {
++ vcdev->cdev = cdev;
++ vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev,
++ sizeof(*vcdev->dma_area));
++ if (!vcdev->dma_area) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+@@ -1261,7 +1271,6 @@ static int virtio_ccw_online(struct ccw_
+
+ vcdev->vdev.dev.release = virtio_ccw_release_dev;
+ vcdev->vdev.config = &virtio_ccw_config_ops;
+- vcdev->cdev = cdev;
+ init_waitqueue_head(&vcdev->wait_q);
+ INIT_LIST_HEAD(&vcdev->virtqueues);
+ spin_lock_init(&vcdev->lock);
+@@ -1292,8 +1301,8 @@ out_put:
+ return ret;
+ out_free:
+ if (vcdev) {
+- kfree(vcdev->status);
+- kfree(vcdev->config_block);
++ ccw_device_dma_free(vcdev->cdev, vcdev->dma_area,
++ sizeof(*vcdev->dma_area));
+ }
+ kfree(vcdev);
+ return ret;
diff --git a/series.conf b/series.conf
index 357a2d5ef5..8e8b61e3ee 100644
--- a/series.conf
+++ b/series.conf
@@ -47726,6 +47726,7 @@
patches.suse/s390-airq-use-dma-memory-for-adapter-interrupts
patches.suse/virtio-s390-use-cacheline-aligned-airq-bit-vectors
patches.suse/virtio-s390-add-indirection-to-indicators-access
+ patches.suse/virtio-s390-use-dma-memory-for-ccw-i-o-and-classic-notifiers
patches.fixes/crypto-ccp-fix-AES-CFB-error-exposed-by-new-test-vec.patch
patches.fixes/crypto-ccp-Fix-3DES-complaint-from-ccp-crypto-module.patch
patches.fixes/crypto-talitos-rename-alternative-AEAD-algos.patch