aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
diff options
context:
space:
mode:
authorPawel Moll <pawel.moll@arm.com>2012-05-09 13:30:16 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-05-21 22:46:15 -0400
commit81a054ce0b469b66c88e9da6403082759c64bf73 (patch)
tree4736df1e0d7c7d9143a1e6dbbfe8947d8079f934 /drivers/virtio
parentf65ca1dc6a8c81c6bd72297d4399ec5f4c1f3a01 (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/Kconfig11
-rw-r--r--drivers/virtio/virtio_mmio.c163
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
49config 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
49endmenu 60endmenu
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
502static struct device vm_cmdline_parent = {
503 .init_name = "virtio-mmio-cmdline",
504};
505
506static int vm_cmdline_parent_registered;
507static int vm_cmdline_id;
508
509static 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
559static 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
573static 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
581static struct kernel_param_ops vm_cmdline_param_ops = {
582 .set = vm_cmdline_set,
583 .get = vm_cmdline_get,
584};
585
586device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR);
587
588static 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
596static 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
608static void vm_unregister_cmdline_devices(void)
609{
610}
611
612#endif
613
452/* Platform driver */ 614/* Platform driver */
453 615
454static struct of_device_id virtio_mmio_match[] = { 616static struct of_device_id virtio_mmio_match[] = {
@@ -475,6 +637,7 @@ static int __init virtio_mmio_init(void)
475static void __exit virtio_mmio_exit(void) 637static 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
480module_init(virtio_mmio_init); 643module_init(virtio_mmio_init);