forked from Minki/linux
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>
This commit is contained in:
parent
f65ca1dc6a
commit
81a054ce0b
@ -110,6 +110,7 @@ parameter is applicable:
|
||||
USB USB support is enabled.
|
||||
USBHID USB Human Interface Device support is enabled.
|
||||
V4L Video For Linux support is enabled.
|
||||
VMMIO Driver for memory mapped virtio devices is enabled.
|
||||
VGA The VGA console has been enabled.
|
||||
VT Virtual terminal support is enabled.
|
||||
WDT Watchdog support is enabled.
|
||||
@ -2847,6 +2848,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
video= [FB] Frame buffer configuration
|
||||
See Documentation/fb/modedb.txt.
|
||||
|
||||
virtio_mmio.device=
|
||||
[VMMIO] Memory mapped virtio (platform) device.
|
||||
|
||||
<size>@<baseaddr>:<irq>[:<id>]
|
||||
where:
|
||||
<size> := size (can use standard suffixes
|
||||
like K, M and G)
|
||||
<baseaddr> := physical base address
|
||||
<irq> := interrupt number (as passed to
|
||||
request_irq())
|
||||
<id> := (optional) platform device id
|
||||
example:
|
||||
virtio_mmio.device=1K@0x100b0000:48:7
|
||||
|
||||
Can be used multiple times for multiple devices.
|
||||
|
||||
vga= [BOOT,X86-32] Select a particular video mode
|
||||
See Documentation/x86/boot.txt and
|
||||
Documentation/svga.txt.
|
||||
|
@ -46,4 +46,15 @@ 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 parameters. Be aware that using incorrect parameters (base
|
||||
address in particular) can crash your system - you have been warned.
|
||||
See Documentation/kernel-parameters.txt for details.
|
||||
|
||||
If unsure, say 'N'.
|
||||
|
||||
endmenu
|
||||
|
@ -6,6 +6,50 @@
|
||||
* 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. Can be used more than once -
|
||||
* one device will be created for each one. Syntax:
|
||||
*
|
||||
* [virtio_mmio.]device=<size>@<baseaddr>:<irq>[:<id>]
|
||||
* where:
|
||||
* <size> := size (can use standard suffixes like K, M or G)
|
||||
* <baseaddr> := physical base address
|
||||
* <irq> := interrupt number (as passed to request_irq())
|
||||
* <id> := (optional) platform device id
|
||||
* eg.:
|
||||
* virtio_mmio.device=0x100@0x100b0000:48 \
|
||||
* virtio_mmio.device=1K@0x1001e000:74
|
||||
*
|
||||
*
|
||||
*
|
||||
* Registers layout (all 32-bit wide):
|
||||
*
|
||||
* offset d. name description
|
||||
@ -42,6 +86,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>
|
||||
@ -449,6 +495,122 @@ static int __devexit virtio_mmio_remove(struct platform_device *pdev)
|
||||
|
||||
|
||||
|
||||
/* Devices list parameter */
|
||||
|
||||
#if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES)
|
||||
|
||||
static struct device vm_cmdline_parent = {
|
||||
.init_name = "virtio-mmio-cmdline",
|
||||
};
|
||||
|
||||
static int vm_cmdline_parent_registered;
|
||||
static int vm_cmdline_id;
|
||||
|
||||
static int vm_cmdline_set(const char *device,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
int err;
|
||||
struct resource resources[2] = {};
|
||||
char *str;
|
||||
long long int base;
|
||||
int processed, consumed = 0;
|
||||
struct platform_device *pdev;
|
||||
|
||||
resources[0].flags = IORESOURCE_MEM;
|
||||
resources[1].flags = IORESOURCE_IRQ;
|
||||
|
||||
resources[0].end = memparse(device, &str) - 1;
|
||||
|
||||
processed = sscanf(str, "@%lli:%u%n:%d%n",
|
||||
&base, &resources[1].start, &consumed,
|
||||
&vm_cmdline_id, &consumed);
|
||||
|
||||
if (processed < 2 || processed > 3 || str[consumed])
|
||||
return -EINVAL;
|
||||
|
||||
resources[0].start = base;
|
||||
resources[0].end += base;
|
||||
resources[1].end = resources[1].start;
|
||||
|
||||
if (!vm_cmdline_parent_registered) {
|
||||
err = device_register(&vm_cmdline_parent);
|
||||
if (err) {
|
||||
pr_err("Failed to register parent device!\n");
|
||||
return err;
|
||||
}
|
||||
vm_cmdline_parent_registered = 1;
|
||||
}
|
||||
|
||||
pr_info("Registering device virtio-mmio.%d at 0x%llx-0x%llx, IRQ %d.\n",
|
||||
vm_cmdline_id,
|
||||
(unsigned long long)resources[0].start,
|
||||
(unsigned long long)resources[0].end,
|
||||
(int)resources[1].start);
|
||||
|
||||
pdev = platform_device_register_resndata(&vm_cmdline_parent,
|
||||
"virtio-mmio", vm_cmdline_id++,
|
||||
resources, ARRAY_SIZE(resources), NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vm_cmdline_get_device(struct device *dev, void *data)
|
||||
{
|
||||
char *buffer = data;
|
||||
unsigned int len = strlen(buffer);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n",
|
||||
pdev->resource[0].end - pdev->resource[0].start + 1ULL,
|
||||
(unsigned long long)pdev->resource[0].start,
|
||||
(unsigned long long)pdev->resource[1].start,
|
||||
pdev->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
device_for_each_child(&vm_cmdline_parent, buffer,
|
||||
vm_cmdline_get_device);
|
||||
return strlen(buffer) + 1;
|
||||
}
|
||||
|
||||
static struct kernel_param_ops vm_cmdline_param_ops = {
|
||||
.set = vm_cmdline_set,
|
||||
.get = vm_cmdline_get,
|
||||
};
|
||||
|
||||
device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR);
|
||||
|
||||
static int vm_unregister_cmdline_device(struct device *dev,
|
||||
void *data)
|
||||
{
|
||||
platform_device_unregister(to_platform_device(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vm_unregister_cmdline_devices(void)
|
||||
{
|
||||
if (vm_cmdline_parent_registered) {
|
||||
device_for_each_child(&vm_cmdline_parent, NULL,
|
||||
vm_unregister_cmdline_device);
|
||||
device_unregister(&vm_cmdline_parent);
|
||||
vm_cmdline_parent_registered = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void vm_unregister_cmdline_devices(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Platform driver */
|
||||
|
||||
static struct of_device_id virtio_mmio_match[] = {
|
||||
@ -475,6 +637,7 @@ static int __init virtio_mmio_init(void)
|
||||
static void __exit virtio_mmio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&virtio_mmio_driver);
|
||||
vm_unregister_cmdline_devices();
|
||||
}
|
||||
|
||||
module_init(virtio_mmio_init);
|
||||
|
Loading…
Reference in New Issue
Block a user