Commit 73fa21ea authored by Cornelia Huck's avatar Cornelia Huck Committed by Marcelo Tosatti

KVM: s390: Dynamic allocation of virtio-ccw I/O data.

Dynamically allocate any data structures like ccw used when
doing channel I/O. Otherwise, we'd need to add extra serialization
for the different callbacks using the same data structures.
Reported-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent fb864fbc
...@@ -46,11 +46,9 @@ struct vq_config_block { ...@@ -46,11 +46,9 @@ struct vq_config_block {
struct virtio_ccw_device { struct virtio_ccw_device {
struct virtio_device vdev; struct virtio_device vdev;
__u8 status; __u8 *status;
__u8 config[VIRTIO_CCW_CONFIG_SIZE]; __u8 config[VIRTIO_CCW_CONFIG_SIZE];
struct ccw_device *cdev; struct ccw_device *cdev;
struct ccw1 *ccw;
__u32 area;
__u32 curr_io; __u32 curr_io;
int err; int err;
wait_queue_head_t wait_q; wait_queue_head_t wait_q;
...@@ -127,14 +125,15 @@ static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag) ...@@ -127,14 +125,15 @@ static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag)
return ret; return ret;
} }
static int ccw_io_helper(struct virtio_ccw_device *vcdev, __u32 intparm) static int ccw_io_helper(struct virtio_ccw_device *vcdev,
struct ccw1 *ccw, __u32 intparm)
{ {
int ret; int ret;
unsigned long flags; unsigned long flags;
int flag = intparm & VIRTIO_CCW_INTPARM_MASK; int flag = intparm & VIRTIO_CCW_INTPARM_MASK;
spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
ret = ccw_device_start(vcdev->cdev, vcdev->ccw, intparm, 0, 0); ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0);
if (!ret) if (!ret)
vcdev->curr_io |= flag; vcdev->curr_io |= flag;
spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags);
...@@ -167,18 +166,19 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq) ...@@ -167,18 +166,19 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq)
do_kvm_notify(schid, virtqueue_get_queue_index(vq)); do_kvm_notify(schid, virtqueue_get_queue_index(vq));
} }
static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, int index) static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
struct ccw1 *ccw, int index)
{ {
vcdev->config_block->index = index; vcdev->config_block->index = index;
vcdev->ccw->cmd_code = CCW_CMD_READ_VQ_CONF; ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(struct vq_config_block); ccw->count = sizeof(struct vq_config_block);
vcdev->ccw->cda = (__u32)(unsigned long)(vcdev->config_block); ccw->cda = (__u32)(unsigned long)(vcdev->config_block);
ccw_io_helper(vcdev, VIRTIO_CCW_DOING_READ_VQ_CONF); ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
return vcdev->config_block->num; return vcdev->config_block->num;
} }
static void virtio_ccw_del_vq(struct virtqueue *vq) static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev); struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev);
struct virtio_ccw_vq_info *info = vq->priv; struct virtio_ccw_vq_info *info = vq->priv;
...@@ -197,11 +197,12 @@ static void virtio_ccw_del_vq(struct virtqueue *vq) ...@@ -197,11 +197,12 @@ static void virtio_ccw_del_vq(struct virtqueue *vq)
info->info_block->align = 0; info->info_block->align = 0;
info->info_block->index = index; info->info_block->index = index;
info->info_block->num = 0; info->info_block->num = 0;
vcdev->ccw->cmd_code = CCW_CMD_SET_VQ; ccw->cmd_code = CCW_CMD_SET_VQ;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(*info->info_block); ccw->count = sizeof(*info->info_block);
vcdev->ccw->cda = (__u32)(unsigned long)(info->info_block); ccw->cda = (__u32)(unsigned long)(info->info_block);
ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_VQ | index); ret = ccw_io_helper(vcdev, ccw,
VIRTIO_CCW_DOING_SET_VQ | index);
/* /*
* -ENODEV isn't considered an error: The device is gone anyway. * -ENODEV isn't considered an error: The device is gone anyway.
* This may happen on device detach. * This may happen on device detach.
...@@ -220,14 +221,23 @@ static void virtio_ccw_del_vq(struct virtqueue *vq) ...@@ -220,14 +221,23 @@ static void virtio_ccw_del_vq(struct virtqueue *vq)
static void virtio_ccw_del_vqs(struct virtio_device *vdev) static void virtio_ccw_del_vqs(struct virtio_device *vdev)
{ {
struct virtqueue *vq, *n; struct virtqueue *vq, *n;
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
list_for_each_entry_safe(vq, n, &vdev->vqs, list) list_for_each_entry_safe(vq, n, &vdev->vqs, list)
virtio_ccw_del_vq(vq); virtio_ccw_del_vq(vq, ccw);
kfree(ccw);
} }
static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
int i, vq_callback_t *callback, int i, vq_callback_t *callback,
const char *name) const char *name,
struct ccw1 *ccw)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
int err; int err;
...@@ -250,7 +260,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -250,7 +260,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
err = -ENOMEM; err = -ENOMEM;
goto out_err; goto out_err;
} }
info->num = virtio_ccw_read_vq_conf(vcdev, i); info->num = virtio_ccw_read_vq_conf(vcdev, ccw, i);
size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN)); size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
if (info->queue == NULL) { if (info->queue == NULL) {
...@@ -277,11 +287,11 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -277,11 +287,11 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
info->info_block->align = KVM_VIRTIO_CCW_RING_ALIGN; info->info_block->align = KVM_VIRTIO_CCW_RING_ALIGN;
info->info_block->index = i; info->info_block->index = i;
info->info_block->num = info->num; info->info_block->num = info->num;
vcdev->ccw->cmd_code = CCW_CMD_SET_VQ; ccw->cmd_code = CCW_CMD_SET_VQ;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(*info->info_block); ccw->count = sizeof(*info->info_block);
vcdev->ccw->cda = (__u32)(unsigned long)(info->info_block); ccw->cda = (__u32)(unsigned long)(info->info_block);
err = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_VQ | i); err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
if (err) { if (err) {
dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
free_pages_exact(info->queue, size); free_pages_exact(info->queue, size);
...@@ -312,9 +322,15 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -312,9 +322,15 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
unsigned long *indicatorp = NULL; unsigned long *indicatorp = NULL;
int ret, i; int ret, i;
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return -ENOMEM;
for (i = 0; i < nvqs; ++i) { for (i = 0; i < nvqs; ++i) {
vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i]); vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i],
ccw);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
ret = PTR_ERR(vqs[i]); ret = PTR_ERR(vqs[i]);
vqs[i] = NULL; vqs[i] = NULL;
...@@ -329,28 +345,30 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -329,28 +345,30 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
*indicatorp = (unsigned long) &vcdev->indicators; *indicatorp = (unsigned long) &vcdev->indicators;
/* Register queue indicators with host. */ /* Register queue indicators with host. */
vcdev->indicators = 0; vcdev->indicators = 0;
vcdev->ccw->cmd_code = CCW_CMD_SET_IND; ccw->cmd_code = CCW_CMD_SET_IND;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(vcdev->indicators); ccw->count = sizeof(vcdev->indicators);
vcdev->ccw->cda = (__u32)(unsigned long) indicatorp; ccw->cda = (__u32)(unsigned long) indicatorp;
ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_IND); ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
if (ret) if (ret)
goto out; goto out;
/* Register indicators2 with host for config changes */ /* Register indicators2 with host for config changes */
*indicatorp = (unsigned long) &vcdev->indicators2; *indicatorp = (unsigned long) &vcdev->indicators2;
vcdev->indicators2 = 0; vcdev->indicators2 = 0;
vcdev->ccw->cmd_code = CCW_CMD_SET_CONF_IND; ccw->cmd_code = CCW_CMD_SET_CONF_IND;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(vcdev->indicators2); ccw->count = sizeof(vcdev->indicators2);
vcdev->ccw->cda = (__u32)(unsigned long) indicatorp; ccw->cda = (__u32)(unsigned long) indicatorp;
ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_CONF_IND); ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
if (ret) if (ret)
goto out; goto out;
kfree(indicatorp); kfree(indicatorp);
kfree(ccw);
return 0; return 0;
out: out:
kfree(indicatorp); kfree(indicatorp);
kfree(ccw);
virtio_ccw_del_vqs(vdev); virtio_ccw_del_vqs(vdev);
return ret; return ret;
} }
...@@ -358,64 +376,95 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -358,64 +376,95 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
static void virtio_ccw_reset(struct virtio_device *vdev) static void virtio_ccw_reset(struct virtio_device *vdev)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
/* Zero status bits. */ /* Zero status bits. */
vcdev->status = 0; *vcdev->status = 0;
/* Send a reset ccw on device. */ /* Send a reset ccw on device. */
vcdev->ccw->cmd_code = CCW_CMD_VDEV_RESET; ccw->cmd_code = CCW_CMD_VDEV_RESET;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = 0; ccw->count = 0;
vcdev->ccw->cda = 0; ccw->cda = 0;
ccw_io_helper(vcdev, VIRTIO_CCW_DOING_RESET); ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET);
kfree(ccw);
} }
static u32 virtio_ccw_get_features(struct virtio_device *vdev) static u32 virtio_ccw_get_features(struct virtio_device *vdev)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct virtio_feature_desc features; struct virtio_feature_desc *features;
int ret; int ret, rc;
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return 0;
features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
if (!features) {
rc = 0;
goto out_free;
}
/* Read the feature bits from the host. */ /* Read the feature bits from the host. */
/* TODO: Features > 32 bits */ /* TODO: Features > 32 bits */
features.index = 0; features->index = 0;
vcdev->ccw->cmd_code = CCW_CMD_READ_FEAT; ccw->cmd_code = CCW_CMD_READ_FEAT;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(features); ccw->count = sizeof(*features);
vcdev->ccw->cda = vcdev->area; ccw->cda = (__u32)(unsigned long)features;
ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_READ_FEAT); ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
if (ret) if (ret) {
return 0; rc = 0;
goto out_free;
}
memcpy(&features, (void *)(unsigned long)vcdev->area, rc = le32_to_cpu(features->features);
sizeof(features));
return le32_to_cpu(features.features); out_free:
kfree(features);
kfree(ccw);
return rc;
} }
static void virtio_ccw_finalize_features(struct virtio_device *vdev) static void virtio_ccw_finalize_features(struct virtio_device *vdev)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct virtio_feature_desc features; struct virtio_feature_desc *features;
int i; int i;
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
if (!features)
goto out_free;
/* Give virtio_ring a chance to accept features. */ /* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev); vring_transport_features(vdev);
for (i = 0; i < sizeof(*vdev->features) / sizeof(features.features); for (i = 0; i < sizeof(*vdev->features) / sizeof(features->features);
i++) { i++) {
int highbits = i % 2 ? 32 : 0; int highbits = i % 2 ? 32 : 0;
features.index = i; features->index = i;
features.features = cpu_to_le32(vdev->features[i / 2] features->features = cpu_to_le32(vdev->features[i / 2]
>> highbits); >> highbits);
memcpy((void *)(unsigned long)vcdev->area, &features,
sizeof(features));
/* Write the feature bits to the host. */ /* Write the feature bits to the host. */
vcdev->ccw->cmd_code = CCW_CMD_WRITE_FEAT; ccw->cmd_code = CCW_CMD_WRITE_FEAT;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = sizeof(features); ccw->count = sizeof(*features);
vcdev->ccw->cda = vcdev->area; ccw->cda = (__u32)(unsigned long)features;
ccw_io_helper(vcdev, VIRTIO_CCW_DOING_WRITE_FEAT); ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
} }
out_free:
kfree(features);
kfree(ccw);
} }
static void virtio_ccw_get_config(struct virtio_device *vdev, static void virtio_ccw_get_config(struct virtio_device *vdev,
...@@ -423,19 +472,32 @@ static void virtio_ccw_get_config(struct virtio_device *vdev, ...@@ -423,19 +472,32 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
int ret; int ret;
struct ccw1 *ccw;
void *config_area;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
if (!config_area)
goto out_free;
/* Read the config area from the host. */ /* Read the config area from the host. */
vcdev->ccw->cmd_code = CCW_CMD_READ_CONF; ccw->cmd_code = CCW_CMD_READ_CONF;
vcdev->ccw->flags = 0; ccw->flags = 0;
vcdev->ccw->count = offset + len; ccw->count = offset + len;
vcdev->ccw->cda = vcdev->area; ccw->cda = (__u32)(unsigned long)config_area;
ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_READ_CONFIG); ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG);
if (ret) if (ret)
return; goto out_free;
memcpy(vcdev->config, (void *)(unsigned long)vcdev->area, memcpy(vcdev->config, config_area, sizeof(vcdev->config));
sizeof(vcdev->config));
memcpy(buf, &vcdev->config[offset], len); memcpy(buf, &vcdev->config[offset], len);
out_free:
kfree(config_area);
kfree(ccw);
} }
static void virtio_ccw_set_config(struct virtio_device *vdev, static void virtio_ccw_set_config(struct virtio_device *vdev,
...@@ -443,37 +505,55 @@ static void virtio_ccw_set_config(struct virtio_device *vdev, ...@@ -443,37 +505,55 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
unsigned len) unsigned len)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct ccw1 *ccw;
void *config_area;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
if (!config_area)
goto out_free;
memcpy(&vcdev->config[offset], buf, len); memcpy(&vcdev->config[offset], buf, len);
/* Write the config area to the host. */ /* Write the config area to the host. */
memcpy((void *)(unsigned long)vcdev->area, vcdev->config, memcpy(config_area, vcdev->config, sizeof(vcdev->config));
sizeof(vcdev->config)); ccw->cmd_code = CCW_CMD_WRITE_CONF;
vcdev->ccw->cmd_code = CCW_CMD_WRITE_CONF; ccw->flags = 0;
vcdev->ccw->flags = 0; ccw->count = offset + len;
vcdev->ccw->count = offset + len; ccw->cda = (__u32)(unsigned long)config_area;
vcdev->ccw->cda = vcdev->area; ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
ccw_io_helper(vcdev, VIRTIO_CCW_DOING_WRITE_CONFIG);
out_free:
kfree(config_area);
kfree(ccw);
} }
static u8 virtio_ccw_get_status(struct virtio_device *vdev) static u8 virtio_ccw_get_status(struct virtio_device *vdev)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
return vcdev->status; return *vcdev->status;
} }
static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status) static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
/* Write the status to the host. */ /* Write the status to the host. */
vcdev->status = status; *vcdev->status = status;
memcpy((void *)(unsigned long)vcdev->area, &status, sizeof(status)); ccw->cmd_code = CCW_CMD_WRITE_STATUS;
vcdev->ccw->cmd_code = CCW_CMD_WRITE_STATUS; ccw->flags = 0;
vcdev->ccw->flags = 0; ccw->count = sizeof(status);
vcdev->ccw->count = sizeof(status); ccw->cda = (__u32)(unsigned long)vcdev->status;
vcdev->ccw->cda = vcdev->area; ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
ccw_io_helper(vcdev, VIRTIO_CCW_DOING_WRITE_STATUS); kfree(ccw);
} }
static struct virtio_config_ops virtio_ccw_config_ops = { static struct virtio_config_ops virtio_ccw_config_ops = {
...@@ -499,9 +579,8 @@ static void virtio_ccw_release_dev(struct device *_d) ...@@ -499,9 +579,8 @@ static void virtio_ccw_release_dev(struct device *_d)
dev); dev);
struct virtio_ccw_device *vcdev = to_vc_device(dev); struct virtio_ccw_device *vcdev = to_vc_device(dev);
kfree((void *)(unsigned long)vcdev->area); kfree(vcdev->status);
kfree(vcdev->config_block); kfree(vcdev->config_block);
kfree(vcdev->ccw);
kfree(vcdev); kfree(vcdev);
} }
...@@ -657,9 +736,6 @@ static int virtio_ccw_offline(struct ccw_device *cdev) ...@@ -657,9 +736,6 @@ static int virtio_ccw_offline(struct ccw_device *cdev)
} }
/* Area needs to be big enough to fit status, features or configuration. */
#define VIRTIO_AREA_SIZE VIRTIO_CCW_CONFIG_SIZE /* biggest possible use */
static int virtio_ccw_online(struct ccw_device *cdev) static int virtio_ccw_online(struct ccw_device *cdev)
{ {
int ret; int ret;
...@@ -671,21 +747,14 @@ static int virtio_ccw_online(struct ccw_device *cdev) ...@@ -671,21 +747,14 @@ static int virtio_ccw_online(struct ccw_device *cdev)
ret = -ENOMEM; ret = -ENOMEM;
goto out_free; goto out_free;
} }
vcdev->area = (__u32)(unsigned long)kzalloc(VIRTIO_AREA_SIZE,
GFP_DMA | GFP_KERNEL);
if (!vcdev->area) {
dev_warn(&cdev->dev, "Cound not get memory for virtio\n");
ret = -ENOMEM;
goto out_free;
}
vcdev->config_block = kzalloc(sizeof(*vcdev->config_block), vcdev->config_block = kzalloc(sizeof(*vcdev->config_block),
GFP_DMA | GFP_KERNEL); GFP_DMA | GFP_KERNEL);
if (!vcdev->config_block) { if (!vcdev->config_block) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_free; goto out_free;
} }
vcdev->ccw = kzalloc(sizeof(*vcdev->ccw), GFP_DMA | GFP_KERNEL); vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL);
if (!vcdev->ccw) { if (!vcdev->status) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_free; goto out_free;
} }
...@@ -714,9 +783,8 @@ static int virtio_ccw_online(struct ccw_device *cdev) ...@@ -714,9 +783,8 @@ static int virtio_ccw_online(struct ccw_device *cdev)
return ret; return ret;
out_free: out_free:
if (vcdev) { if (vcdev) {
kfree((void *)(unsigned long)vcdev->area); kfree(vcdev->status);
kfree(vcdev->config_block); kfree(vcdev->config_block);
kfree(vcdev->ccw);
} }
kfree(vcdev); kfree(vcdev);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment