Commit 8adc56b0 authored by Halil Pasic's avatar Halil Pasic Committed by Heiko Carstens
Browse files

s390/virtio_ccw: avoid converting dma addresses / handles



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: default avatarHalil Pasic <pasic@linux.ibm.com>
Reviewed-by: default avatarEric Farman <farman@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent e3e9bda3
Loading
Loading
Loading
Loading
+53 −18
Original line number Diff line number Diff line
@@ -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;