diff options
| author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-01-07 09:51:51 -0500 |
|---|---|---|
| committer | Marcelo Tosatti <mtosatti@redhat.com> | 2013-01-09 15:40:18 -0500 |
| commit | 73fa21ea4fc662a2e8e85f84c4ca3fcb55fa4da2 (patch) | |
| tree | 8bc6c22fd9d2e3db42b95b4aede95dfde8bc8a75 /drivers/s390 | |
| parent | fb864fbc72fd4e2175fb64072fe9134d3a3ab89a (diff) | |
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: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'drivers/s390')
| -rw-r--r-- | drivers/s390/kvm/virtio_ccw.c | 280 |
1 files changed, 174 insertions, 106 deletions
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c index 1a5aff31d752..70419a75d0e0 100644 --- a/drivers/s390/kvm/virtio_ccw.c +++ b/drivers/s390/kvm/virtio_ccw.c | |||
| @@ -46,11 +46,9 @@ struct vq_config_block { | |||
| 46 | 46 | ||
| 47 | struct virtio_ccw_device { | 47 | struct virtio_ccw_device { |
| 48 | struct virtio_device vdev; | 48 | struct virtio_device vdev; |
| 49 | __u8 status; | 49 | __u8 *status; |
| 50 | __u8 config[VIRTIO_CCW_CONFIG_SIZE]; | 50 | __u8 config[VIRTIO_CCW_CONFIG_SIZE]; |
| 51 | struct ccw_device *cdev; | 51 | struct ccw_device *cdev; |
| 52 | struct ccw1 *ccw; | ||
| 53 | __u32 area; | ||
| 54 | __u32 curr_io; | 52 | __u32 curr_io; |
| 55 | int err; | 53 | int err; |
| 56 | wait_queue_head_t wait_q; | 54 | wait_queue_head_t wait_q; |
| @@ -127,14 +125,15 @@ static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag) | |||
| 127 | return ret; | 125 | return ret; |
| 128 | } | 126 | } |
| 129 | 127 | ||
| 130 | static int ccw_io_helper(struct virtio_ccw_device *vcdev, __u32 intparm) | 128 | static int ccw_io_helper(struct virtio_ccw_device *vcdev, |
| 129 | struct ccw1 *ccw, __u32 intparm) | ||
| 131 | { | 130 | { |
| 132 | int ret; | 131 | int ret; |
| 133 | unsigned long flags; | 132 | unsigned long flags; |
| 134 | int flag = intparm & VIRTIO_CCW_INTPARM_MASK; | 133 | int flag = intparm & VIRTIO_CCW_INTPARM_MASK; |
| 135 | 134 | ||
| 136 | spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags); | 135 | spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags); |
| 137 | ret = ccw_device_start(vcdev->cdev, vcdev->ccw, intparm, 0, 0); | 136 | ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0); |
| 138 | if (!ret) | 137 | if (!ret) |
| 139 | vcdev->curr_io |= flag; | 138 | vcdev->curr_io |= flag; |
| 140 | spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags); | 139 | spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags); |
| @@ -167,18 +166,19 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq) | |||
| 167 | do_kvm_notify(schid, virtqueue_get_queue_index(vq)); | 166 | do_kvm_notify(schid, virtqueue_get_queue_index(vq)); |
| 168 | } | 167 | } |
| 169 | 168 | ||
| 170 | static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, int index) | 169 | static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, |
| 170 | struct ccw1 *ccw, int index) | ||
| 171 | { | 171 | { |
| 172 | vcdev->config_block->index = index; | 172 | vcdev->config_block->index = index; |
| 173 | vcdev->ccw->cmd_code = CCW_CMD_READ_VQ_CONF; | 173 | ccw->cmd_code = CCW_CMD_READ_VQ_CONF; |
| 174 | vcdev->ccw->flags = 0; | 174 | ccw->flags = 0; |
| 175 | vcdev->ccw->count = sizeof(struct vq_config_block); | 175 | ccw->count = sizeof(struct vq_config_block); |
| 176 | vcdev->ccw->cda = (__u32)(unsigned long)(vcdev->config_block); | 176 | ccw->cda = (__u32)(unsigned long)(vcdev->config_block); |
| 177 | ccw_io_helper(vcdev, VIRTIO_CCW_DOING_READ_VQ_CONF); | 177 | ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF); |
| 178 | return vcdev->config_block->num; | 178 | return vcdev->config_block->num; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | static void virtio_ccw_del_vq(struct virtqueue *vq) | 181 | static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw) |
| 182 | { | 182 | { |
| 183 | struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev); | 183 | struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev); |
| 184 | struct virtio_ccw_vq_info *info = vq->priv; | 184 | struct virtio_ccw_vq_info *info = vq->priv; |
| @@ -197,11 +197,12 @@ static void virtio_ccw_del_vq(struct virtqueue *vq) | |||
| 197 | info->info_block->align = 0; | 197 | info->info_block->align = 0; |
| 198 | info->info_block->index = index; | 198 | info->info_block->index = index; |
| 199 | info->info_block->num = 0; | 199 | info->info_block->num = 0; |
| 200 | vcdev->ccw->cmd_code = CCW_CMD_SET_VQ; | 200 | ccw->cmd_code = CCW_CMD_SET_VQ; |
| 201 | vcdev->ccw->flags = 0; | 201 | ccw->flags = 0; |
| 202 | vcdev->ccw->count = sizeof(*info->info_block); | 202 | ccw->count = sizeof(*info->info_block); |
| 203 | vcdev->ccw->cda = (__u32)(unsigned long)(info->info_block); | 203 | ccw->cda = (__u32)(unsigned long)(info->info_block); |
| 204 | ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_VQ | index); | 204 | ret = ccw_io_helper(vcdev, ccw, |
| 205 | VIRTIO_CCW_DOING_SET_VQ | index); | ||
| 205 | /* | 206 | /* |
| 206 | * -ENODEV isn't considered an error: The device is gone anyway. | 207 | * -ENODEV isn't considered an error: The device is gone anyway. |
| 207 | * This may happen on device detach. | 208 | * This may happen on device detach. |
| @@ -220,14 +221,23 @@ static void virtio_ccw_del_vq(struct virtqueue *vq) | |||
| 220 | static void virtio_ccw_del_vqs(struct virtio_device *vdev) | 221 | static void virtio_ccw_del_vqs(struct virtio_device *vdev) |
| 221 | { | 222 | { |
| 222 | struct virtqueue *vq, *n; | 223 | struct virtqueue *vq, *n; |
| 224 | struct ccw1 *ccw; | ||
| 225 | |||
| 226 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 227 | if (!ccw) | ||
| 228 | return; | ||
| 229 | |||
| 223 | 230 | ||
| 224 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | 231 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) |
| 225 | virtio_ccw_del_vq(vq); | 232 | virtio_ccw_del_vq(vq, ccw); |
| 233 | |||
| 234 | kfree(ccw); | ||
| 226 | } | 235 | } |
| 227 | 236 | ||
| 228 | static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, | 237 | static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, |
| 229 | int i, vq_callback_t *callback, | 238 | int i, vq_callback_t *callback, |
| 230 | const char *name) | 239 | const char *name, |
| 240 | struct ccw1 *ccw) | ||
| 231 | { | 241 | { |
| 232 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 242 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 233 | int err; | 243 | int err; |
| @@ -250,7 +260,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, | |||
| 250 | err = -ENOMEM; | 260 | err = -ENOMEM; |
| 251 | goto out_err; | 261 | goto out_err; |
| 252 | } | 262 | } |
| 253 | info->num = virtio_ccw_read_vq_conf(vcdev, i); | 263 | info->num = virtio_ccw_read_vq_conf(vcdev, ccw, i); |
| 254 | size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN)); | 264 | size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN)); |
| 255 | info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); | 265 | info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); |
| 256 | if (info->queue == NULL) { | 266 | if (info->queue == NULL) { |
| @@ -277,11 +287,11 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, | |||
| 277 | info->info_block->align = KVM_VIRTIO_CCW_RING_ALIGN; | 287 | info->info_block->align = KVM_VIRTIO_CCW_RING_ALIGN; |
| 278 | info->info_block->index = i; | 288 | info->info_block->index = i; |
| 279 | info->info_block->num = info->num; | 289 | info->info_block->num = info->num; |
| 280 | vcdev->ccw->cmd_code = CCW_CMD_SET_VQ; | 290 | ccw->cmd_code = CCW_CMD_SET_VQ; |
| 281 | vcdev->ccw->flags = 0; | 291 | ccw->flags = 0; |
| 282 | vcdev->ccw->count = sizeof(*info->info_block); | 292 | ccw->count = sizeof(*info->info_block); |
| 283 | vcdev->ccw->cda = (__u32)(unsigned long)(info->info_block); | 293 | ccw->cda = (__u32)(unsigned long)(info->info_block); |
| 284 | err = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_VQ | i); | 294 | err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i); |
| 285 | if (err) { | 295 | if (err) { |
| 286 | dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); | 296 | dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); |
| 287 | free_pages_exact(info->queue, size); | 297 | free_pages_exact(info->queue, size); |
| @@ -312,9 +322,15 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, | |||
| 312 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 322 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 313 | unsigned long *indicatorp = NULL; | 323 | unsigned long *indicatorp = NULL; |
| 314 | int ret, i; | 324 | int ret, i; |
| 325 | struct ccw1 *ccw; | ||
| 326 | |||
| 327 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 328 | if (!ccw) | ||
| 329 | return -ENOMEM; | ||
| 315 | 330 | ||
| 316 | for (i = 0; i < nvqs; ++i) { | 331 | for (i = 0; i < nvqs; ++i) { |
| 317 | vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i]); | 332 | vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i], |
| 333 | ccw); | ||
| 318 | if (IS_ERR(vqs[i])) { | 334 | if (IS_ERR(vqs[i])) { |
| 319 | ret = PTR_ERR(vqs[i]); | 335 | ret = PTR_ERR(vqs[i]); |
| 320 | vqs[i] = NULL; | 336 | vqs[i] = NULL; |
| @@ -329,28 +345,30 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, | |||
| 329 | *indicatorp = (unsigned long) &vcdev->indicators; | 345 | *indicatorp = (unsigned long) &vcdev->indicators; |
| 330 | /* Register queue indicators with host. */ | 346 | /* Register queue indicators with host. */ |
| 331 | vcdev->indicators = 0; | 347 | vcdev->indicators = 0; |
| 332 | vcdev->ccw->cmd_code = CCW_CMD_SET_IND; | 348 | ccw->cmd_code = CCW_CMD_SET_IND; |
| 333 | vcdev->ccw->flags = 0; | 349 | ccw->flags = 0; |
| 334 | vcdev->ccw->count = sizeof(vcdev->indicators); | 350 | ccw->count = sizeof(vcdev->indicators); |
| 335 | vcdev->ccw->cda = (__u32)(unsigned long) indicatorp; | 351 | ccw->cda = (__u32)(unsigned long) indicatorp; |
| 336 | ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_IND); | 352 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND); |
| 337 | if (ret) | 353 | if (ret) |
| 338 | goto out; | 354 | goto out; |
| 339 | /* Register indicators2 with host for config changes */ | 355 | /* Register indicators2 with host for config changes */ |
| 340 | *indicatorp = (unsigned long) &vcdev->indicators2; | 356 | *indicatorp = (unsigned long) &vcdev->indicators2; |
| 341 | vcdev->indicators2 = 0; | 357 | vcdev->indicators2 = 0; |
| 342 | vcdev->ccw->cmd_code = CCW_CMD_SET_CONF_IND; | 358 | ccw->cmd_code = CCW_CMD_SET_CONF_IND; |
| 343 | vcdev->ccw->flags = 0; | 359 | ccw->flags = 0; |
| 344 | vcdev->ccw->count = sizeof(vcdev->indicators2); | 360 | ccw->count = sizeof(vcdev->indicators2); |
| 345 | vcdev->ccw->cda = (__u32)(unsigned long) indicatorp; | 361 | ccw->cda = (__u32)(unsigned long) indicatorp; |
| 346 | ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_SET_CONF_IND); | 362 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND); |
| 347 | if (ret) | 363 | if (ret) |
| 348 | goto out; | 364 | goto out; |
| 349 | 365 | ||
| 350 | kfree(indicatorp); | 366 | kfree(indicatorp); |
| 367 | kfree(ccw); | ||
| 351 | return 0; | 368 | return 0; |
| 352 | out: | 369 | out: |
| 353 | kfree(indicatorp); | 370 | kfree(indicatorp); |
| 371 | kfree(ccw); | ||
| 354 | virtio_ccw_del_vqs(vdev); | 372 | virtio_ccw_del_vqs(vdev); |
| 355 | return ret; | 373 | return ret; |
| 356 | } | 374 | } |
| @@ -358,64 +376,95 @@ out: | |||
| 358 | static void virtio_ccw_reset(struct virtio_device *vdev) | 376 | static void virtio_ccw_reset(struct virtio_device *vdev) |
| 359 | { | 377 | { |
| 360 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 378 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 379 | struct ccw1 *ccw; | ||
| 380 | |||
| 381 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 382 | if (!ccw) | ||
| 383 | return; | ||
| 361 | 384 | ||
| 362 | /* Zero status bits. */ | 385 | /* Zero status bits. */ |
| 363 | vcdev->status = 0; | 386 | *vcdev->status = 0; |
| 364 | 387 | ||
| 365 | /* Send a reset ccw on device. */ | 388 | /* Send a reset ccw on device. */ |
| 366 | vcdev->ccw->cmd_code = CCW_CMD_VDEV_RESET; | 389 | ccw->cmd_code = CCW_CMD_VDEV_RESET; |
| 367 | vcdev->ccw->flags = 0; | 390 | ccw->flags = 0; |
| 368 | vcdev->ccw->count = 0; | 391 | ccw->count = 0; |
| 369 | vcdev->ccw->cda = 0; | 392 | ccw->cda = 0; |
| 370 | ccw_io_helper(vcdev, VIRTIO_CCW_DOING_RESET); | 393 | ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET); |
| 394 | kfree(ccw); | ||
| 371 | } | 395 | } |
| 372 | 396 | ||
| 373 | static u32 virtio_ccw_get_features(struct virtio_device *vdev) | 397 | static u32 virtio_ccw_get_features(struct virtio_device *vdev) |
| 374 | { | 398 | { |
| 375 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 399 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 376 | struct virtio_feature_desc features; | 400 | struct virtio_feature_desc *features; |
| 377 | int ret; | 401 | int ret, rc; |
| 402 | struct ccw1 *ccw; | ||
| 378 | 403 | ||
| 404 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 405 | if (!ccw) | ||
| 406 | return 0; | ||
| 407 | |||
| 408 | features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL); | ||
| 409 | if (!features) { | ||
| 410 | rc = 0; | ||
| 411 | goto out_free; | ||
| 412 | } | ||
| 379 | /* Read the feature bits from the host. */ | 413 | /* Read the feature bits from the host. */ |
| 380 | /* TODO: Features > 32 bits */ | 414 | /* TODO: Features > 32 bits */ |
| 381 | features.index = 0; | 415 | features->index = 0; |
| 382 | vcdev->ccw->cmd_code = CCW_CMD_READ_FEAT; | 416 | ccw->cmd_code = CCW_CMD_READ_FEAT; |
| 383 | vcdev->ccw->flags = 0; | 417 | ccw->flags = 0; |
| 384 | vcdev->ccw->count = sizeof(features); | 418 | ccw->count = sizeof(*features); |
| 385 | vcdev->ccw->cda = vcdev->area; | 419 | ccw->cda = (__u32)(unsigned long)features; |
| 386 | ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_READ_FEAT); | 420 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT); |
| 387 | if (ret) | 421 | if (ret) { |
| 388 | return 0; | 422 | rc = 0; |
| 423 | goto out_free; | ||
| 424 | } | ||
| 425 | |||
| 426 | rc = le32_to_cpu(features->features); | ||
| 389 | 427 | ||
| 390 | memcpy(&features, (void *)(unsigned long)vcdev->area, | 428 | out_free: |
| 391 | sizeof(features)); | 429 | kfree(features); |
| 392 | return le32_to_cpu(features.features); | 430 | kfree(ccw); |
| 431 | return rc; | ||
| 393 | } | 432 | } |
| 394 | 433 | ||
| 395 | static void virtio_ccw_finalize_features(struct virtio_device *vdev) | 434 | static void virtio_ccw_finalize_features(struct virtio_device *vdev) |
| 396 | { | 435 | { |
| 397 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 436 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 398 | struct virtio_feature_desc features; | 437 | struct virtio_feature_desc *features; |
| 399 | int i; | 438 | int i; |
| 439 | struct ccw1 *ccw; | ||
| 440 | |||
| 441 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 442 | if (!ccw) | ||
| 443 | return; | ||
| 444 | |||
| 445 | features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL); | ||
| 446 | if (!features) | ||
| 447 | goto out_free; | ||
| 400 | 448 | ||
| 401 | /* Give virtio_ring a chance to accept features. */ | 449 | /* Give virtio_ring a chance to accept features. */ |
| 402 | vring_transport_features(vdev); | 450 | vring_transport_features(vdev); |
| 403 | 451 | ||
| 404 | for (i = 0; i < sizeof(*vdev->features) / sizeof(features.features); | 452 | for (i = 0; i < sizeof(*vdev->features) / sizeof(features->features); |
| 405 | i++) { | 453 | i++) { |
| 406 | int highbits = i % 2 ? 32 : 0; | 454 | int highbits = i % 2 ? 32 : 0; |
| 407 | features.index = i; | 455 | features->index = i; |
| 408 | features.features = cpu_to_le32(vdev->features[i / 2] | 456 | features->features = cpu_to_le32(vdev->features[i / 2] |
| 409 | >> highbits); | 457 | >> highbits); |
| 410 | memcpy((void *)(unsigned long)vcdev->area, &features, | ||
| 411 | sizeof(features)); | ||
| 412 | /* Write the feature bits to the host. */ | 458 | /* Write the feature bits to the host. */ |
| 413 | vcdev->ccw->cmd_code = CCW_CMD_WRITE_FEAT; | 459 | ccw->cmd_code = CCW_CMD_WRITE_FEAT; |
| 414 | vcdev->ccw->flags = 0; | 460 | ccw->flags = 0; |
| 415 | vcdev->ccw->count = sizeof(features); | 461 | ccw->count = sizeof(*features); |
| 416 | vcdev->ccw->cda = vcdev->area; | 462 | ccw->cda = (__u32)(unsigned long)features; |
| 417 | ccw_io_helper(vcdev, VIRTIO_CCW_DOING_WRITE_FEAT); | 463 | ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT); |
| 418 | } | 464 | } |
| 465 | out_free: | ||
| 466 | kfree(features); | ||
| 467 | kfree(ccw); | ||
| 419 | } | 468 | } |
| 420 | 469 | ||
| 421 | static void virtio_ccw_get_config(struct virtio_device *vdev, | 470 | 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 | { | 472 | { |
| 424 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 473 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 425 | int ret; | 474 | int ret; |
| 475 | struct ccw1 *ccw; | ||
| 476 | void *config_area; | ||
| 477 | |||
| 478 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 479 | if (!ccw) | ||
| 480 | return; | ||
| 481 | |||
| 482 | config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL); | ||
| 483 | if (!config_area) | ||
| 484 | goto out_free; | ||
| 426 | 485 | ||
| 427 | /* Read the config area from the host. */ | 486 | /* Read the config area from the host. */ |
| 428 | vcdev->ccw->cmd_code = CCW_CMD_READ_CONF; | 487 | ccw->cmd_code = CCW_CMD_READ_CONF; |
| 429 | vcdev->ccw->flags = 0; | 488 | ccw->flags = 0; |
| 430 | vcdev->ccw->count = offset + len; | 489 | ccw->count = offset + len; |
| 431 | vcdev->ccw->cda = vcdev->area; | 490 | ccw->cda = (__u32)(unsigned long)config_area; |
| 432 | ret = ccw_io_helper(vcdev, VIRTIO_CCW_DOING_READ_CONFIG); | 491 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG); |
| 433 | if (ret) | 492 | if (ret) |
| 434 | return; | 493 | goto out_free; |
| 435 | 494 | ||
| 436 | memcpy(vcdev->config, (void *)(unsigned long)vcdev->area, | 495 | memcpy(vcdev->config, config_area, sizeof(vcdev->config)); |
| 437 | sizeof(vcdev->config)); | ||
| 438 | memcpy(buf, &vcdev->config[offset], len); | 496 | memcpy(buf, &vcdev->config[offset], len); |
| 497 | |||
| 498 | out_free: | ||
| 499 | kfree(config_area); | ||
| 500 | kfree(ccw); | ||
| 439 | } | 501 | } |
| 440 | 502 | ||
| 441 | static void virtio_ccw_set_config(struct virtio_device *vdev, | 503 | 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 | unsigned len) | 505 | unsigned len) |
| 444 | { | 506 | { |
| 445 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 507 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 508 | struct ccw1 *ccw; | ||
| 509 | void *config_area; | ||
| 510 | |||
| 511 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 512 | if (!ccw) | ||
| 513 | return; | ||
| 514 | |||
| 515 | config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL); | ||
| 516 | if (!config_area) | ||
| 517 | goto out_free; | ||
| 446 | 518 | ||
| 447 | memcpy(&vcdev->config[offset], buf, len); | 519 | memcpy(&vcdev->config[offset], buf, len); |
| 448 | /* Write the config area to the host. */ | 520 | /* Write the config area to the host. */ |
| 449 | memcpy((void *)(unsigned long)vcdev->area, vcdev->config, | 521 | memcpy(config_area, vcdev->config, sizeof(vcdev->config)); |
| 450 | sizeof(vcdev->config)); | 522 | ccw->cmd_code = CCW_CMD_WRITE_CONF; |
| 451 | vcdev->ccw->cmd_code = CCW_CMD_WRITE_CONF; | 523 | ccw->flags = 0; |
| 452 | vcdev->ccw->flags = 0; | 524 | ccw->count = offset + len; |
| 453 | vcdev->ccw->count = offset + len; | 525 | ccw->cda = (__u32)(unsigned long)config_area; |
| 454 | vcdev->ccw->cda = vcdev->area; | 526 | ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG); |
| 455 | ccw_io_helper(vcdev, VIRTIO_CCW_DOING_WRITE_CONFIG); | 527 | |
| 528 | out_free: | ||
| 529 | kfree(config_area); | ||
| 530 | kfree(ccw); | ||
| 456 | } | 531 | } |
| 457 | 532 | ||
| 458 | static u8 virtio_ccw_get_status(struct virtio_device *vdev) | 533 | static u8 virtio_ccw_get_status(struct virtio_device *vdev) |
| 459 | { | 534 | { |
| 460 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 535 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 461 | 536 | ||
| 462 | return vcdev->status; | 537 | return *vcdev->status; |
| 463 | } | 538 | } |
| 464 | 539 | ||
| 465 | static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status) | 540 | static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status) |
| 466 | { | 541 | { |
| 467 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | 542 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); |
| 543 | struct ccw1 *ccw; | ||
| 544 | |||
| 545 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | ||
| 546 | if (!ccw) | ||
| 547 | return; | ||
| 468 | 548 | ||
| 469 | /* Write the status to the host. */ | 549 | /* Write the status to the host. */ |
| 470 | vcdev->status = status; | 550 | *vcdev->status = status; |
| 471 | memcpy((void *)(unsigned long)vcdev->area, &status, sizeof(status)); | 551 | ccw->cmd_code = CCW_CMD_WRITE_STATUS; |
| 472 | vcdev->ccw->cmd_code = CCW_CMD_WRITE_STATUS; | 552 | ccw->flags = 0; |
| 473 | vcdev->ccw->flags = 0; | 553 | ccw->count = sizeof(status); |
| 474 | vcdev->ccw->count = sizeof(status); | 554 | ccw->cda = (__u32)(unsigned long)vcdev->status; |
| 475 | vcdev->ccw->cda = vcdev->area; | 555 | ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS); |
| 476 | ccw_io_helper(vcdev, VIRTIO_CCW_DOING_WRITE_STATUS); | 556 | kfree(ccw); |
| 477 | } | 557 | } |
| 478 | 558 | ||
| 479 | static struct virtio_config_ops virtio_ccw_config_ops = { | 559 | static struct virtio_config_ops virtio_ccw_config_ops = { |
| @@ -499,9 +579,8 @@ static void virtio_ccw_release_dev(struct device *_d) | |||
| 499 | dev); | 579 | dev); |
| 500 | struct virtio_ccw_device *vcdev = to_vc_device(dev); | 580 | struct virtio_ccw_device *vcdev = to_vc_device(dev); |
| 501 | 581 | ||
| 502 | kfree((void *)(unsigned long)vcdev->area); | 582 | kfree(vcdev->status); |
| 503 | kfree(vcdev->config_block); | 583 | kfree(vcdev->config_block); |
| 504 | kfree(vcdev->ccw); | ||
| 505 | kfree(vcdev); | 584 | kfree(vcdev); |
| 506 | } | 585 | } |
| 507 | 586 | ||
| @@ -657,9 +736,6 @@ static int virtio_ccw_offline(struct ccw_device *cdev) | |||
| 657 | } | 736 | } |
| 658 | 737 | ||
| 659 | 738 | ||
| 660 | /* Area needs to be big enough to fit status, features or configuration. */ | ||
| 661 | #define VIRTIO_AREA_SIZE VIRTIO_CCW_CONFIG_SIZE /* biggest possible use */ | ||
| 662 | |||
| 663 | static int virtio_ccw_online(struct ccw_device *cdev) | 739 | static int virtio_ccw_online(struct ccw_device *cdev) |
| 664 | { | 740 | { |
| 665 | int ret; | 741 | int ret; |
| @@ -671,21 +747,14 @@ static int virtio_ccw_online(struct ccw_device *cdev) | |||
| 671 | ret = -ENOMEM; | 747 | ret = -ENOMEM; |
| 672 | goto out_free; | 748 | goto out_free; |
| 673 | } | 749 | } |
| 674 | vcdev->area = (__u32)(unsigned long)kzalloc(VIRTIO_AREA_SIZE, | ||
| 675 | GFP_DMA | GFP_KERNEL); | ||
| 676 | if (!vcdev->area) { | ||
| 677 | dev_warn(&cdev->dev, "Cound not get memory for virtio\n"); | ||
| 678 | ret = -ENOMEM; | ||
| 679 | goto out_free; | ||
| 680 | } | ||
| 681 | vcdev->config_block = kzalloc(sizeof(*vcdev->config_block), | 750 | vcdev->config_block = kzalloc(sizeof(*vcdev->config_block), |
| 682 | GFP_DMA | GFP_KERNEL); | 751 | GFP_DMA | GFP_KERNEL); |
| 683 | if (!vcdev->config_block) { | 752 | if (!vcdev->config_block) { |
| 684 | ret = -ENOMEM; | 753 | ret = -ENOMEM; |
| 685 | goto out_free; | 754 | goto out_free; |
| 686 | } | 755 | } |
| 687 | vcdev->ccw = kzalloc(sizeof(*vcdev->ccw), GFP_DMA | GFP_KERNEL); | 756 | vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL); |
| 688 | if (!vcdev->ccw) { | 757 | if (!vcdev->status) { |
| 689 | ret = -ENOMEM; | 758 | ret = -ENOMEM; |
| 690 | goto out_free; | 759 | goto out_free; |
| 691 | } | 760 | } |
| @@ -714,9 +783,8 @@ out_put: | |||
| 714 | return ret; | 783 | return ret; |
| 715 | out_free: | 784 | out_free: |
| 716 | if (vcdev) { | 785 | if (vcdev) { |
| 717 | kfree((void *)(unsigned long)vcdev->area); | 786 | kfree(vcdev->status); |
| 718 | kfree(vcdev->config_block); | 787 | kfree(vcdev->config_block); |
| 719 | kfree(vcdev->ccw); | ||
| 720 | } | 788 | } |
| 721 | kfree(vcdev); | 789 | kfree(vcdev); |
| 722 | return ret; | 790 | return ret; |
