Commit 81a054ce0b469b66c88e9da6403082759c64bf73

Authored by Pawel Moll
Committed by Rusty Russell
1 parent f65ca1dc6a

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>

Showing 3 changed files with 191 additions and 0 deletions Side-by-side Diff

Documentation/kernel-parameters.txt
... ... @@ -110,6 +110,7 @@
110 110 USB USB support is enabled.
111 111 USBHID USB Human Interface Device support is enabled.
112 112 V4L Video For Linux support is enabled.
  113 + VMMIO Driver for memory mapped virtio devices is enabled.
113 114 VGA The VGA console has been enabled.
114 115 VT Virtual terminal support is enabled.
115 116 WDT Watchdog support is enabled.
... ... @@ -2846,6 +2847,22 @@
2846 2847  
2847 2848 video= [FB] Frame buffer configuration
2848 2849 See Documentation/fb/modedb.txt.
  2850 +
  2851 + virtio_mmio.device=
  2852 + [VMMIO] Memory mapped virtio (platform) device.
  2853 +
  2854 + <size>@<baseaddr>:<irq>[:<id>]
  2855 + where:
  2856 + <size> := size (can use standard suffixes
  2857 + like K, M and G)
  2858 + <baseaddr> := physical base address
  2859 + <irq> := interrupt number (as passed to
  2860 + request_irq())
  2861 + <id> := (optional) platform device id
  2862 + example:
  2863 + virtio_mmio.device=1K@0x100b0000:48:7
  2864 +
  2865 + Can be used multiple times for multiple devices.
2849 2866  
2850 2867 vga= [BOOT,X86-32] Select a particular video mode
2851 2868 See Documentation/x86/boot.txt and
drivers/virtio/Kconfig
... ... @@ -46,5 +46,16 @@
46 46  
47 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 60 endmenu
drivers/virtio/virtio_mmio.c
... ... @@ -6,6 +6,50 @@
6 6 * This module allows virtio devices to be used over a virtual, memory mapped
7 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 53 * Registers layout (all 32-bit wide):
10 54 *
11 55 * offset d. name description
... ... @@ -42,6 +86,8 @@
42 86 * See the COPYING file in the top-level directory.
43 87 */
44 88  
  89 +#define pr_fmt(fmt) "virtio-mmio: " fmt
  90 +
45 91 #include <linux/highmem.h>
46 92 #include <linux/interrupt.h>
47 93 #include <linux/io.h>
... ... @@ -449,6 +495,122 @@
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 614 /* Platform driver */
453 615  
454 616 static struct of_device_id virtio_mmio_match[] = {
... ... @@ -475,6 +637,7 @@
475 637 static void __exit virtio_mmio_exit(void)
476 638 {
477 639 platform_driver_unregister(&virtio_mmio_driver);
  640 + vm_unregister_cmdline_devices();
478 641 }
479 642  
480 643 module_init(virtio_mmio_init);