diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/virtio_blk.c | 21 | ||||
-rw-r--r-- | drivers/virtio/Kconfig | 11 | ||||
-rw-r--r-- | drivers/virtio/virtio.c | 11 | ||||
-rw-r--r-- | drivers/virtio/virtio_balloon.c | 33 | ||||
-rw-r--r-- | drivers/virtio/virtio_mmio.c | 163 |
5 files changed, 207 insertions, 32 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 0d39f2f4294a..693187df7601 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -29,9 +29,6 @@ struct virtio_blk | |||
29 | /* The disk structure for the kernel. */ | 29 | /* The disk structure for the kernel. */ |
30 | struct gendisk *disk; | 30 | struct gendisk *disk; |
31 | 31 | ||
32 | /* Request tracking. */ | ||
33 | struct list_head reqs; | ||
34 | |||
35 | mempool_t *pool; | 32 | mempool_t *pool; |
36 | 33 | ||
37 | /* Process context for config space updates */ | 34 | /* Process context for config space updates */ |
@@ -55,7 +52,6 @@ struct virtio_blk | |||
55 | 52 | ||
56 | struct virtblk_req | 53 | struct virtblk_req |
57 | { | 54 | { |
58 | struct list_head list; | ||
59 | struct request *req; | 55 | struct request *req; |
60 | struct virtio_blk_outhdr out_hdr; | 56 | struct virtio_blk_outhdr out_hdr; |
61 | struct virtio_scsi_inhdr in_hdr; | 57 | struct virtio_scsi_inhdr in_hdr; |
@@ -99,7 +95,6 @@ static void blk_done(struct virtqueue *vq) | |||
99 | } | 95 | } |
100 | 96 | ||
101 | __blk_end_request_all(vbr->req, error); | 97 | __blk_end_request_all(vbr->req, error); |
102 | list_del(&vbr->list); | ||
103 | mempool_free(vbr, vblk->pool); | 98 | mempool_free(vbr, vblk->pool); |
104 | } | 99 | } |
105 | /* In case queue is stopped waiting for more buffers. */ | 100 | /* In case queue is stopped waiting for more buffers. */ |
@@ -184,7 +179,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, | |||
184 | return false; | 179 | return false; |
185 | } | 180 | } |
186 | 181 | ||
187 | list_add_tail(&vbr->list, &vblk->reqs); | ||
188 | return true; | 182 | return true; |
189 | } | 183 | } |
190 | 184 | ||
@@ -437,7 +431,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
437 | goto out_free_index; | 431 | goto out_free_index; |
438 | } | 432 | } |
439 | 433 | ||
440 | INIT_LIST_HEAD(&vblk->reqs); | ||
441 | spin_lock_init(&vblk->lock); | 434 | spin_lock_init(&vblk->lock); |
442 | vblk->vdev = vdev; | 435 | vblk->vdev = vdev; |
443 | vblk->sg_elems = sg_elems; | 436 | vblk->sg_elems = sg_elems; |
@@ -583,21 +576,29 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) | |||
583 | { | 576 | { |
584 | struct virtio_blk *vblk = vdev->priv; | 577 | struct virtio_blk *vblk = vdev->priv; |
585 | int index = vblk->index; | 578 | int index = vblk->index; |
579 | struct virtblk_req *vbr; | ||
580 | unsigned long flags; | ||
586 | 581 | ||
587 | /* Prevent config work handler from accessing the device. */ | 582 | /* Prevent config work handler from accessing the device. */ |
588 | mutex_lock(&vblk->config_lock); | 583 | mutex_lock(&vblk->config_lock); |
589 | vblk->config_enable = false; | 584 | vblk->config_enable = false; |
590 | mutex_unlock(&vblk->config_lock); | 585 | mutex_unlock(&vblk->config_lock); |
591 | 586 | ||
592 | /* Nothing should be pending. */ | ||
593 | BUG_ON(!list_empty(&vblk->reqs)); | ||
594 | |||
595 | /* Stop all the virtqueues. */ | 587 | /* Stop all the virtqueues. */ |
596 | vdev->config->reset(vdev); | 588 | vdev->config->reset(vdev); |
597 | 589 | ||
598 | flush_work(&vblk->config_work); | 590 | flush_work(&vblk->config_work); |
599 | 591 | ||
600 | del_gendisk(vblk->disk); | 592 | del_gendisk(vblk->disk); |
593 | |||
594 | /* Abort requests dispatched to driver. */ | ||
595 | spin_lock_irqsave(&vblk->lock, flags); | ||
596 | while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) { | ||
597 | __blk_end_request_all(vbr->req, -EIO); | ||
598 | mempool_free(vbr, vblk->pool); | ||
599 | } | ||
600 | spin_unlock_irqrestore(&vblk->lock, flags); | ||
601 | |||
601 | blk_cleanup_queue(vblk->disk->queue); | 602 | blk_cleanup_queue(vblk->disk->queue); |
602 | put_disk(vblk->disk); | 603 | put_disk(vblk->disk); |
603 | mempool_destroy(vblk->pool); | 604 | mempool_destroy(vblk->pool); |
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 1a61939b85fc..f38b17a86c35 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig | |||
@@ -46,4 +46,15 @@ config VIRTIO_BALLOON | |||
46 | 46 | ||
47 | If unsure, say N. | 47 | If unsure, say N. |
48 | 48 | ||
49 | config VIRTIO_MMIO_CMDLINE_DEVICES | ||
50 | bool "Memory mapped virtio devices parameter parsing" | ||
51 | depends on VIRTIO_MMIO | ||
52 | ---help--- | ||
53 | Allow virtio-mmio devices instantiation via the kernel command line | ||
54 | or module parameters. Be aware that using incorrect parameters (base | ||
55 | address in particular) can crash your system - you have been warned. | ||
56 | See Documentation/kernel-parameters.txt for details. | ||
57 | |||
58 | If unsure, say 'N'. | ||
59 | |||
49 | endmenu | 60 | endmenu |
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 984c501c258f..f3558070e375 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c | |||
@@ -2,9 +2,10 @@ | |||
2 | #include <linux/spinlock.h> | 2 | #include <linux/spinlock.h> |
3 | #include <linux/virtio_config.h> | 3 | #include <linux/virtio_config.h> |
4 | #include <linux/module.h> | 4 | #include <linux/module.h> |
5 | #include <linux/idr.h> | ||
5 | 6 | ||
6 | /* Unique numbering for virtio devices. */ | 7 | /* Unique numbering for virtio devices. */ |
7 | static unsigned int dev_index; | 8 | static DEFINE_IDA(virtio_index_ida); |
8 | 9 | ||
9 | static ssize_t device_show(struct device *_d, | 10 | static ssize_t device_show(struct device *_d, |
10 | struct device_attribute *attr, char *buf) | 11 | struct device_attribute *attr, char *buf) |
@@ -193,7 +194,11 @@ int register_virtio_device(struct virtio_device *dev) | |||
193 | dev->dev.bus = &virtio_bus; | 194 | dev->dev.bus = &virtio_bus; |
194 | 195 | ||
195 | /* Assign a unique device index and hence name. */ | 196 | /* Assign a unique device index and hence name. */ |
196 | dev->index = dev_index++; | 197 | err = ida_simple_get(&virtio_index_ida, 0, 0, GFP_KERNEL); |
198 | if (err < 0) | ||
199 | goto out; | ||
200 | |||
201 | dev->index = err; | ||
197 | dev_set_name(&dev->dev, "virtio%u", dev->index); | 202 | dev_set_name(&dev->dev, "virtio%u", dev->index); |
198 | 203 | ||
199 | /* We always start by resetting the device, in case a previous | 204 | /* We always start by resetting the device, in case a previous |
@@ -208,6 +213,7 @@ int register_virtio_device(struct virtio_device *dev) | |||
208 | /* device_register() causes the bus infrastructure to look for a | 213 | /* device_register() causes the bus infrastructure to look for a |
209 | * matching driver. */ | 214 | * matching driver. */ |
210 | err = device_register(&dev->dev); | 215 | err = device_register(&dev->dev); |
216 | out: | ||
211 | if (err) | 217 | if (err) |
212 | add_status(dev, VIRTIO_CONFIG_S_FAILED); | 218 | add_status(dev, VIRTIO_CONFIG_S_FAILED); |
213 | return err; | 219 | return err; |
@@ -217,6 +223,7 @@ EXPORT_SYMBOL_GPL(register_virtio_device); | |||
217 | void unregister_virtio_device(struct virtio_device *dev) | 223 | void unregister_virtio_device(struct virtio_device *dev) |
218 | { | 224 | { |
219 | device_unregister(&dev->dev); | 225 | device_unregister(&dev->dev); |
226 | ida_simple_remove(&virtio_index_ida, dev->index); | ||
220 | } | 227 | } |
221 | EXPORT_SYMBOL_GPL(unregister_virtio_device); | 228 | EXPORT_SYMBOL_GPL(unregister_virtio_device); |
222 | 229 | ||
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 8807fe501d20..bfbc15ca38dd 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c | |||
@@ -381,21 +381,25 @@ out: | |||
381 | return err; | 381 | return err; |
382 | } | 382 | } |
383 | 383 | ||
384 | static void __devexit virtballoon_remove(struct virtio_device *vdev) | 384 | static void remove_common(struct virtio_balloon *vb) |
385 | { | 385 | { |
386 | struct virtio_balloon *vb = vdev->priv; | ||
387 | |||
388 | kthread_stop(vb->thread); | ||
389 | |||
390 | /* There might be pages left in the balloon: free them. */ | 386 | /* There might be pages left in the balloon: free them. */ |
391 | while (vb->num_pages) | 387 | while (vb->num_pages) |
392 | leak_balloon(vb, vb->num_pages); | 388 | leak_balloon(vb, vb->num_pages); |
393 | update_balloon_size(vb); | 389 | update_balloon_size(vb); |
394 | 390 | ||
395 | /* Now we reset the device so we can clean up the queues. */ | 391 | /* Now we reset the device so we can clean up the queues. */ |
396 | vdev->config->reset(vdev); | 392 | vb->vdev->config->reset(vb->vdev); |
397 | 393 | ||
398 | vdev->config->del_vqs(vdev); | 394 | vb->vdev->config->del_vqs(vb->vdev); |
395 | } | ||
396 | |||
397 | static void __devexit virtballoon_remove(struct virtio_device *vdev) | ||
398 | { | ||
399 | struct virtio_balloon *vb = vdev->priv; | ||
400 | |||
401 | kthread_stop(vb->thread); | ||
402 | remove_common(vb); | ||
399 | kfree(vb); | 403 | kfree(vb); |
400 | } | 404 | } |
401 | 405 | ||
@@ -409,17 +413,11 @@ static int virtballoon_freeze(struct virtio_device *vdev) | |||
409 | * function is called. | 413 | * function is called. |
410 | */ | 414 | */ |
411 | 415 | ||
412 | while (vb->num_pages) | 416 | remove_common(vb); |
413 | leak_balloon(vb, vb->num_pages); | ||
414 | update_balloon_size(vb); | ||
415 | |||
416 | /* Ensure we don't get any more requests from the host */ | ||
417 | vdev->config->reset(vdev); | ||
418 | vdev->config->del_vqs(vdev); | ||
419 | return 0; | 417 | return 0; |
420 | } | 418 | } |
421 | 419 | ||
422 | static int restore_common(struct virtio_device *vdev) | 420 | static int virtballoon_restore(struct virtio_device *vdev) |
423 | { | 421 | { |
424 | struct virtio_balloon *vb = vdev->priv; | 422 | struct virtio_balloon *vb = vdev->priv; |
425 | int ret; | 423 | int ret; |
@@ -432,11 +430,6 @@ static int restore_common(struct virtio_device *vdev) | |||
432 | update_balloon_size(vb); | 430 | update_balloon_size(vb); |
433 | return 0; | 431 | return 0; |
434 | } | 432 | } |
435 | |||
436 | static int virtballoon_restore(struct virtio_device *vdev) | ||
437 | { | ||
438 | return restore_common(vdev); | ||
439 | } | ||
440 | #endif | 433 | #endif |
441 | 434 | ||
442 | static unsigned int features[] = { | 435 | static unsigned int features[] = { |
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 01d6dc250d5c..453db0c403d8 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c | |||
@@ -6,6 +6,50 @@ | |||
6 | * This module allows virtio devices to be used over a virtual, memory mapped | 6 | * This module allows virtio devices to be used over a virtual, memory mapped |
7 | * platform device. | 7 | * platform device. |
8 | * | 8 | * |
9 | * The guest device(s) may be instantiated in one of three equivalent ways: | ||
10 | * | ||
11 | * 1. Static platform device in board's code, eg.: | ||
12 | * | ||
13 | * static struct platform_device v2m_virtio_device = { | ||
14 | * .name = "virtio-mmio", | ||
15 | * .id = -1, | ||
16 | * .num_resources = 2, | ||
17 | * .resource = (struct resource []) { | ||
18 | * { | ||
19 | * .start = 0x1001e000, | ||
20 | * .end = 0x1001e0ff, | ||
21 | * .flags = IORESOURCE_MEM, | ||
22 | * }, { | ||
23 | * .start = 42 + 32, | ||
24 | * .end = 42 + 32, | ||
25 | * .flags = IORESOURCE_IRQ, | ||
26 | * }, | ||
27 | * } | ||
28 | * }; | ||
29 | * | ||
30 | * 2. Device Tree node, eg.: | ||
31 | * | ||
32 | * virtio_block@1e000 { | ||
33 | * compatible = "virtio,mmio"; | ||
34 | * reg = <0x1e000 0x100>; | ||
35 | * interrupts = <42>; | ||
36 | * } | ||
37 | * | ||
38 | * 3. Kernel module (or command line) parameter. Can be used more than once - | ||
39 | * one device will be created for each one. Syntax: | ||
40 | * | ||
41 | * [virtio_mmio.]device=<size>@<baseaddr>:<irq>[:<id>] | ||
42 | * where: | ||
43 | * <size> := size (can use standard suffixes like K, M or G) | ||
44 | * <baseaddr> := physical base address | ||
45 | * <irq> := interrupt number (as passed to request_irq()) | ||
46 | * <id> := (optional) platform device id | ||
47 | * eg.: | ||
48 | * virtio_mmio.device=0x100@0x100b0000:48 \ | ||
49 | * virtio_mmio.device=1K@0x1001e000:74 | ||
50 | * | ||
51 | * | ||
52 | * | ||
9 | * Registers layout (all 32-bit wide): | 53 | * Registers layout (all 32-bit wide): |
10 | * | 54 | * |
11 | * offset d. name description | 55 | * offset d. name description |
@@ -42,6 +86,8 @@ | |||
42 | * See the COPYING file in the top-level directory. | 86 | * See the COPYING file in the top-level directory. |
43 | */ | 87 | */ |
44 | 88 | ||
89 | #define pr_fmt(fmt) "virtio-mmio: " fmt | ||
90 | |||
45 | #include <linux/highmem.h> | 91 | #include <linux/highmem.h> |
46 | #include <linux/interrupt.h> | 92 | #include <linux/interrupt.h> |
47 | #include <linux/io.h> | 93 | #include <linux/io.h> |
@@ -449,6 +495,122 @@ static int __devexit virtio_mmio_remove(struct platform_device *pdev) | |||
449 | 495 | ||
450 | 496 | ||
451 | 497 | ||
498 | /* Devices list parameter */ | ||
499 | |||
500 | #if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES) | ||
501 | |||
502 | static struct device vm_cmdline_parent = { | ||
503 | .init_name = "virtio-mmio-cmdline", | ||
504 | }; | ||
505 | |||
506 | static int vm_cmdline_parent_registered; | ||
507 | static int vm_cmdline_id; | ||
508 | |||
509 | static int vm_cmdline_set(const char *device, | ||
510 | const struct kernel_param *kp) | ||
511 | { | ||
512 | int err; | ||
513 | struct resource resources[2] = {}; | ||
514 | char *str; | ||
515 | long long int base; | ||
516 | int processed, consumed = 0; | ||
517 | struct platform_device *pdev; | ||
518 | |||
519 | resources[0].flags = IORESOURCE_MEM; | ||
520 | resources[1].flags = IORESOURCE_IRQ; | ||
521 | |||
522 | resources[0].end = memparse(device, &str) - 1; | ||
523 | |||
524 | processed = sscanf(str, "@%lli:%u%n:%d%n", | ||
525 | &base, &resources[1].start, &consumed, | ||
526 | &vm_cmdline_id, &consumed); | ||
527 | |||
528 | if (processed < 2 || processed > 3 || str[consumed]) | ||
529 | return -EINVAL; | ||
530 | |||
531 | resources[0].start = base; | ||
532 | resources[0].end += base; | ||
533 | resources[1].end = resources[1].start; | ||
534 | |||
535 | if (!vm_cmdline_parent_registered) { | ||
536 | err = device_register(&vm_cmdline_parent); | ||
537 | if (err) { | ||
538 | pr_err("Failed to register parent device!\n"); | ||
539 | return err; | ||
540 | } | ||
541 | vm_cmdline_parent_registered = 1; | ||
542 | } | ||
543 | |||
544 | pr_info("Registering device virtio-mmio.%d at 0x%llx-0x%llx, IRQ %d.\n", | ||
545 | vm_cmdline_id, | ||
546 | (unsigned long long)resources[0].start, | ||
547 | (unsigned long long)resources[0].end, | ||
548 | (int)resources[1].start); | ||
549 | |||
550 | pdev = platform_device_register_resndata(&vm_cmdline_parent, | ||
551 | "virtio-mmio", vm_cmdline_id++, | ||
552 | resources, ARRAY_SIZE(resources), NULL, 0); | ||
553 | if (IS_ERR(pdev)) | ||
554 | return PTR_ERR(pdev); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int vm_cmdline_get_device(struct device *dev, void *data) | ||
560 | { | ||
561 | char *buffer = data; | ||
562 | unsigned int len = strlen(buffer); | ||
563 | struct platform_device *pdev = to_platform_device(dev); | ||
564 | |||
565 | snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n", | ||
566 | pdev->resource[0].end - pdev->resource[0].start + 1ULL, | ||
567 | (unsigned long long)pdev->resource[0].start, | ||
568 | (unsigned long long)pdev->resource[1].start, | ||
569 | pdev->id); | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int vm_cmdline_get(char *buffer, const struct kernel_param *kp) | ||
574 | { | ||
575 | buffer[0] = '\0'; | ||
576 | device_for_each_child(&vm_cmdline_parent, buffer, | ||
577 | vm_cmdline_get_device); | ||
578 | return strlen(buffer) + 1; | ||
579 | } | ||
580 | |||
581 | static struct kernel_param_ops vm_cmdline_param_ops = { | ||
582 | .set = vm_cmdline_set, | ||
583 | .get = vm_cmdline_get, | ||
584 | }; | ||
585 | |||
586 | device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR); | ||
587 | |||
588 | static int vm_unregister_cmdline_device(struct device *dev, | ||
589 | void *data) | ||
590 | { | ||
591 | platform_device_unregister(to_platform_device(dev)); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static void vm_unregister_cmdline_devices(void) | ||
597 | { | ||
598 | if (vm_cmdline_parent_registered) { | ||
599 | device_for_each_child(&vm_cmdline_parent, NULL, | ||
600 | vm_unregister_cmdline_device); | ||
601 | device_unregister(&vm_cmdline_parent); | ||
602 | vm_cmdline_parent_registered = 0; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | #else | ||
607 | |||
608 | static void vm_unregister_cmdline_devices(void) | ||
609 | { | ||
610 | } | ||
611 | |||
612 | #endif | ||
613 | |||
452 | /* Platform driver */ | 614 | /* Platform driver */ |
453 | 615 | ||
454 | static struct of_device_id virtio_mmio_match[] = { | 616 | static struct of_device_id virtio_mmio_match[] = { |
@@ -475,6 +637,7 @@ static int __init virtio_mmio_init(void) | |||
475 | static void __exit virtio_mmio_exit(void) | 637 | static void __exit virtio_mmio_exit(void) |
476 | { | 638 | { |
477 | platform_driver_unregister(&virtio_mmio_driver); | 639 | platform_driver_unregister(&virtio_mmio_driver); |
640 | vm_unregister_cmdline_devices(); | ||
478 | } | 641 | } |
479 | 642 | ||
480 | module_init(virtio_mmio_init); | 643 | module_init(virtio_mmio_init); |