diff options
author | Pawel Moll <pawel.moll@arm.com> | 2012-05-09 13:30:16 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-05-21 22:46:15 -0400 |
commit | 81a054ce0b469b66c88e9da6403082759c64bf73 (patch) | |
tree | 4736df1e0d7c7d9143a1e6dbbfe8947d8079f934 /drivers/virtio | |
parent | f65ca1dc6a8c81c6bd72297d4399ec5f4c1f3a01 (diff) |
virtio-mmio: Devices parameter parsing
This patch adds an option to instantiate guest virtio-mmio devices
basing on a kernel command line (or module) parameter, for example:
virtio_mmio.devices=0x100@0x100b0000:48
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/virtio')
-rw-r--r-- | drivers/virtio/Kconfig | 11 | ||||
-rw-r--r-- | drivers/virtio/virtio_mmio.c | 163 |
2 files changed, 174 insertions, 0 deletions
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_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); |