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; |