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,1K@0x1001e000:74 Signed-off-by: Pawel Moll <pawel.moll@xxxxxxx> --- drivers/virtio/Kconfig | 31 +++++++ drivers/virtio/virtio_mmio.c | 181 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 211 insertions(+), 1 deletions(-) Hi Rusty, This version adds the "first_id" parameter I mentioned yesterday, but still using single charp parameter instead of the _cb version. And unless you are really (_really_) against it, I'd rather see this variant. Cheers! Paweł diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 816ed08..00f2c82 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -46,4 +46,35 @@ config VIRTIO_BALLOON If unsure, say N. +config VIRTIO_MMIO_CMDLINE_DEVICES + bool "Memory mapped virtio devices parameter parsing" + depends on VIRTIO_MMIO + ---help--- + Allow virtio-mmio devices instantiation via the kernel command line + or module parameter. Be aware that using incorrect parameters (base + address in particular) can crash your system - you have been warned. + + The format for the parameter is as follows: + + [virtio_mmio.]devices=<device>[<delim><device>] + + where: + <device> := <size>@<baseaddr>:<irq> + <delim> := ',' or ';' + <size> := size (can use standard suffixes like K or M) + <baseaddr> := physical base address + <irq> := interrupt number (as passed to request_irq()) + + Example kernel command line parameter: + + virtio_mmio.devices=0x100@0x100b0000:48,1K@0x1001e000:74 + + This will register platform devices virtio_mmio.<id>, where <id> + values are consecutive integer numbers starting from 0 by default. + The first id value can be changed with "first_id" parameter: + + [virtio_mmio.]first_id=<id> + + If unsure, say 'N'. + endmenu diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index acc5e43..05b39c1 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -6,6 +6,55 @@ * This module allows virtio devices to be used over a virtual, memory mapped * platform device. * + * The guest device(s) may be instantiated in one of three equivalent ways: + * + * 1. Static platform device in board's code, eg.: + * + * static struct platform_device v2m_virtio_device = { + * .name = "virtio-mmio", + * .id = -1, + * .num_resources = 2, + * .resource = (struct resource []) { + * { + * .start = 0x1001e000, + * .end = 0x1001e0ff, + * .flags = IORESOURCE_MEM, + * }, { + * .start = 42 + 32, + * .end = 42 + 32, + * .flags = IORESOURCE_IRQ, + * }, + * } + * }; + * + * 2. Device Tree node, eg.: + * + * virtio_block@1e000 { + * compatible = "virtio,mmio"; + * reg = <0x1e000 0x100>; + * interrupts = <42>; + * } + * + * 3. Kernel module (or command line) parameter: + * + * [virtio_mmio.]devices=<device>[<delim><device>] + * where: + * <device> := <size>@<baseaddr>:<irq> + * <delim> := ',' or ';' + * <size> := size (can use standard suffixes like K or M) + * <baseaddr> := physical base address + * <irq> := interrupt number (as passed to request_irq()) + * eg.: + * virtio_mmio.devices=0x100@0x100b0000:48,1K@0x1001e000:74 + * + * This will register platform devices virtio_mmio.<id>, where <id> + * values are consecutive integer numbers starting from 0 by default. + * The first id value can be changed with "first_id" parameter: + * + * [virtio_mmio.]first_id=<id> + * + * + * * Registers layout (all 32-bit wide): * * offset d. name description @@ -42,6 +91,8 @@ * See the COPYING file in the top-level directory. */ +#define pr_fmt(fmt) "virtio-mmio: " fmt + #include <linux/highmem.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -443,6 +494,130 @@ static int __devexit virtio_mmio_remove(struct platform_device *pdev) +/* Devices list parameter */ + +#if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES) + +static char *virtio_mmio_cmdline_devices; +module_param_named(devices, virtio_mmio_cmdline_devices, charp, 0); + +static int virtio_mmio_cmdline_id; +module_param_named(first_id, virtio_mmio_cmdline_id, int, 0); + +static struct device virtio_mmio_cmdline_parent = { + .init_name = "virtio-mmio-cmdline", +}; + +static int virtio_mmio_register_cmdline_devices(void) +{ + int err; + char *device; + char *token = NULL; + + err = device_register(&virtio_mmio_cmdline_parent); + if (err) { + pr_err("Failed to register %s!\n", + virtio_mmio_cmdline_parent.init_name); + return err; + } + + /* Split colon-or-semicolon-separated devices */ + while ((device = strsep(&virtio_mmio_cmdline_devices, ",;")) != NULL) { + struct resource resources[] = { + { + .flags = IORESOURCE_IRQ, + }, { + .flags = IORESOURCE_MEM, + } + }; + char *size, *base; + unsigned long long val; + + if (!*device) + continue; + + kfree(token); + token = kstrdup(device, GFP_KERNEL); + + /* Split memory and IRQ resources */ + base = strsep(&token, ":"); + if (base == token || !token || !*token) { + pr_err("No IRQ in '%s'!\n", device); + continue; + } + + /* Get IRQ */ + if (kstrtoull(token, 0, &val) != 0) { + pr_err("Wrong IRQ in '%s'!\n", device); + continue; + } + resources[0].start = val; + resources[0].end = val; + + /* Split base address and size */ + size = strsep(&base, "@"); + if (size == base || !base || !*base) { + pr_err("No base in '%s'!\n", device); + continue; + } + + /* Get base address */ + if (kstrtoull(base, 0, &val) != 0) { + pr_err("Wrong base in '%s'!\n", device); + continue; + } + resources[1].start = val; + resources[1].end = val; + + /* Get size */ + resources[1].end += memparse(size, &token) - 1; + if (size == token || *token) { + pr_err("Wrong size in '%s'!\n", device); + continue; + } + + pr_info("Registering device %d at 0x%x-0x%x, IRQ %u.\n", + virtio_mmio_cmdline_id, resources[1].start, + resources[1].end, resources[0].start); + + platform_device_register_resndata(&virtio_mmio_cmdline_parent, + "virtio-mmio", virtio_mmio_cmdline_id++, + resources, ARRAY_SIZE(resources), NULL, 0); + } + + kfree(token); + + return 0; +} + +static int virtio_mmio_unregister_cmdline_device(struct device *dev, + void *data) +{ + platform_device_unregister(to_platform_device(dev)); + + return 0; +} + +static void virtio_mmio_unregister_cmdline_devices(void) +{ + device_for_each_child(&virtio_mmio_cmdline_parent, NULL, + virtio_mmio_unregister_cmdline_device); + device_unregister(&virtio_mmio_cmdline_parent); +} + +#else + +static int virtio_mmio_register_cmdline_devices(void) +{ + return 0; +} + +static void virtio_mmio_unregister_cmdline_devices(void) +{ +} + +#endif + /* Platform driver */ static struct of_device_id virtio_mmio_match[] = { @@ -463,11 +638,15 @@ static struct platform_driver virtio_mmio_driver = { static int __init virtio_mmio_init(void) { - return platform_driver_register(&virtio_mmio_driver); + int err = virtio_mmio_register_cmdline_devices(); + + return err ? err : platform_driver_register(&virtio_mmio_driver); } static void __exit virtio_mmio_exit(void) { + virtio_mmio_unregister_cmdline_devices(); + platform_driver_unregister(&virtio_mmio_driver); } -- 1.6.3.3 _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/virtualization