s390/virtio_ccw: avoid converting dma addresses / handles
authorHalil Pasic <pasic@linux.ibm.com>
Thu, 7 Mar 2024 12:28:09 +0000 (13:28 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 13 Mar 2024 08:23:46 +0000 (09:23 +0100)
Instead of converting virtual to physical addresses with the virt_to_dma*()
functions, use dma addresses as provided by DMA API and only add offsets to
these addresses. This makes sure that address conversion is only done by
the DMA API.

Signed-off-by: Halil Pasic <pasic@linux.ibm.com>
Reviewed-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/virtio/virtio_ccw.c

index ee9c82721a7e55e3c74522486c5e6f512a649dc4..d7569f3955591acc43dcb0e5df58c3104e3eea65 100644 (file)
@@ -72,6 +72,7 @@ struct virtio_ccw_device {
        unsigned int config_ready;
        void *airq_info;
        struct vcdev_dma_area *dma_area;
+       dma32_t dma_area_addr;
 };
 
 static inline unsigned long *indicators(struct virtio_ccw_device *vcdev)
@@ -84,6 +85,36 @@ static inline unsigned long *indicators2(struct virtio_ccw_device *vcdev)
        return &vcdev->dma_area->indicators2;
 }
 
+/* Spec stipulates a 64 bit address */
+static inline dma64_t indicators_dma(struct virtio_ccw_device *vcdev)
+{
+       u64 dma_area_addr = dma32_to_u32(vcdev->dma_area_addr);
+
+       return dma64_add(u64_to_dma64(dma_area_addr),
+                        offsetof(struct vcdev_dma_area, indicators));
+}
+
+/* Spec stipulates a 64 bit address */
+static inline dma64_t indicators2_dma(struct virtio_ccw_device *vcdev)
+{
+       u64 dma_area_addr = dma32_to_u32(vcdev->dma_area_addr);
+
+       return dma64_add(u64_to_dma64(dma_area_addr),
+                        offsetof(struct vcdev_dma_area, indicators2));
+}
+
+static inline dma32_t config_block_dma(struct virtio_ccw_device *vcdev)
+{
+       return dma32_add(vcdev->dma_area_addr,
+                        offsetof(struct vcdev_dma_area, config_block));
+}
+
+static inline dma32_t status_dma(struct virtio_ccw_device *vcdev)
+{
+       return dma32_add(vcdev->dma_area_addr,
+                        offsetof(struct vcdev_dma_area, status));
+}
+
 struct vq_info_block_legacy {
        dma64_t queue;
        __u32 align;
@@ -157,6 +188,11 @@ static inline u8 *get_summary_indicator(struct airq_info *info)
        return summary_indicators + info->summary_indicator_idx;
 }
 
+static inline dma64_t get_summary_indicator_dma(struct airq_info *info)
+{
+       return virt_to_dma64(get_summary_indicator(info));
+}
+
 #define CCW_CMD_SET_VQ 0x13
 #define CCW_CMD_VDEV_RESET 0x33
 #define CCW_CMD_SET_IND 0x43
@@ -349,9 +385,9 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
                                      struct ccw1 *ccw)
 {
        int ret;
-       unsigned long *indicatorp = NULL;
        struct virtio_thinint_area *thinint_area = NULL;
        struct airq_info *airq_info = vcdev->airq_info;
+       dma64_t *indicatorp = NULL;
 
        if (vcdev->is_thinint) {
                thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
@@ -360,20 +396,20 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
                if (!thinint_area)
                        return;
                thinint_area->summary_indicator =
-                       virt_to_dma64(get_summary_indicator(airq_info));
+                       get_summary_indicator_dma(airq_info);
                thinint_area->isc = VIRTIO_AIRQ_ISC;
                ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
                ccw->count = sizeof(*thinint_area);
        } else {
                /* payload is the address of the indicators */
                indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
-                                                  sizeof(indicators(vcdev)),
+                                                  sizeof(*indicatorp),
                                                   &ccw->cda);
                if (!indicatorp)
                        return;
                *indicatorp = 0;
                ccw->cmd_code = CCW_CMD_SET_IND;
-               ccw->count = sizeof(indicators(vcdev));
+               ccw->count = sizeof(*indicatorp);
        }
        /* Deregister indicators from host. */
        *indicators(vcdev) = 0;
@@ -387,7 +423,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
                         "Failed to deregister indicators (%d)\n", ret);
        else if (vcdev->is_thinint)
                virtio_ccw_drop_indicators(vcdev);
-       ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(indicators(vcdev)));
+       ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(*indicatorp));
        ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
 }
 
@@ -427,7 +463,7 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
        ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
        ccw->flags = 0;
        ccw->count = sizeof(struct vq_config_block);
-       ccw->cda = virt_to_dma32(&vcdev->dma_area->config_block);
+       ccw->cda = config_block_dma(vcdev);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
        if (ret)
                return ret;
@@ -627,8 +663,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
        }
        thinint_area->indicator = virt_to_dma64(indicator_addr);
        info = vcdev->airq_info;
-       thinint_area->summary_indicator =
-               virt_to_dma64(get_summary_indicator(info));
+       thinint_area->summary_indicator = get_summary_indicator_dma(info);
        thinint_area->isc = VIRTIO_AIRQ_ISC;
        ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
        ccw->flags = CCW_FLAG_SLI;
@@ -689,11 +724,11 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
         * the address of the indicators.
        */
        indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
-                                          sizeof(indicators(vcdev)),
+                                          sizeof(*indicatorp),
                                           &ccw->cda);
        if (!indicatorp)
                goto out;
-       *indicatorp = virt_to_dma64(indicators(vcdev));
+       *indicatorp = indicators_dma(vcdev);
        if (vcdev->is_thinint) {
                ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
                if (ret)
@@ -705,30 +740,30 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                *indicators(vcdev) = 0;
                ccw->cmd_code = CCW_CMD_SET_IND;
                ccw->flags = 0;
-               ccw->count = sizeof(indicators(vcdev));
+               ccw->count = sizeof(*indicatorp);
                ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
                if (ret)
                        goto out;
        }
        /* Register indicators2 with host for config changes */
-       *indicatorp = virt_to_dma64(indicators2(vcdev));
+       *indicatorp = indicators2_dma(vcdev);
        *indicators2(vcdev) = 0;
        ccw->cmd_code = CCW_CMD_SET_CONF_IND;
        ccw->flags = 0;
-       ccw->count = sizeof(indicators2(vcdev));
+       ccw->count = sizeof(*indicatorp);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
        if (ret)
                goto out;
 
        if (indicatorp)
                ccw_device_dma_free(vcdev->cdev, indicatorp,
-                                   sizeof(indicators(vcdev)));
+                                   sizeof(*indicatorp));
        ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
        return 0;
 out:
        if (indicatorp)
                ccw_device_dma_free(vcdev->cdev, indicatorp,
-                                   sizeof(indicators(vcdev)));
+                                   sizeof(*indicatorp));
        ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
        virtio_ccw_del_vqs(vdev);
        return ret;
@@ -962,7 +997,7 @@ static u8 virtio_ccw_get_status(struct virtio_device *vdev)
        ccw->cmd_code = CCW_CMD_READ_STATUS;
        ccw->flags = 0;
        ccw->count = sizeof(vcdev->dma_area->status);
-       ccw->cda = virt_to_dma32(&vcdev->dma_area->status);
+       ccw->cda = status_dma(vcdev);
        ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
 /*
  * If the channel program failed (should only happen if the device
@@ -995,7 +1030,7 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
         * instruction that guarantees the memory writes have
         * completed before ssch.
         */
-       ccw->cda = virt_to_dma32(&vcdev->dma_area->status);
+       ccw->cda = status_dma(vcdev);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
        /* Write failed? We assume status is unchanged. */
        if (ret)
@@ -1332,7 +1367,7 @@ static int virtio_ccw_online(struct ccw_device *cdev)
        vcdev->cdev = cdev;
        vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev,
                                                sizeof(*vcdev->dma_area),
-                                               NULL);
+                                               &vcdev->dma_area_addr);
        if (!vcdev->dma_area) {
                ret = -ENOMEM;
                goto out_free;