@@ -28,6 +28,7 @@
#include "sysemu/sysemu.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
+#include "hw/virtio/virtio-mmio.h"
#include "hw/arm/fdt.h"
/*
@@ -245,3 +246,53 @@ void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params)
p->notifier.notify = platform_bus_fdt_notify;
qemu_add_machine_init_done_notifier(&p->notifier);
}
+
+int add_virtio_mmio_fdt_nodes(hwaddr addr, int irq, unsigned int num,
+ void *fdt, int intc)
+{
+ uint32_t acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells");
+ uint32_t scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells");
+ int i;
+
+ /* We add dtb nodes in reverse order so that they appear in the finished
+ * device tree lowest address first.
+ *
+ * Note that this mapping is independent of the virtio_mmio_create(). That
+ * loop influences virtio device to virtio transport assignment, whereas
+ * this loop controls how virtio transports are laid out in the dtb.
+ */
+ for (i = num - 1; i >= 0; i--) {
+ hwaddr base = addr + VIRTIO_MMIO_SIZE * i;
+ char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
+ int rc;
+
+ /* Add a virtio_mmio node to the device tree blob:
+ * virtio_mmio@ADDRESS {
+ * compatible = "virtio,mmio";
+ * reg = <ADDRESS, SIZE>;
+ * interrupt-parent = <&intc>;
+ * interrupts = <0, irq, 1>;
+ * }
+ * (Note that the format of the interrupts property is dependent on the
+ * interrupt controller that interrupt-parent points to; these are for
+ * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.)
+ */
+ rc = qemu_fdt_add_subnode(fdt, nodename);
+ rc |= qemu_fdt_setprop_string(fdt, nodename,
+ "compatible", "virtio,mmio");
+ rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells, base,
+ scells, VIRTIO_MMIO_SIZE);
+ if (intc) {
+ qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc);
+ }
+ qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq + i,
+ GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
+ g_free(nodename);
+ if (rc) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
@@ -24,7 +24,9 @@
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
#include "hw/arm/primecell.h"
+#include "hw/arm/sysbus-fdt.h"
#include "hw/devices.h"
+#include "hw/virtio/virtio-mmio.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
@@ -427,38 +429,6 @@ static VEDBoardInfo a15_daughterboard = {
.init = a15_daughterboard_init,
};
-static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells,
- hwaddr addr, hwaddr size, uint32_t intc,
- int irq)
-{
- /* Add a virtio_mmio node to the device tree blob:
- * virtio_mmio@ADDRESS {
- * compatible = "virtio,mmio";
- * reg = <ADDRESS, SIZE>;
- * interrupt-parent = <&intc>;
- * interrupts = <0, irq, 1>;
- * }
- * (Note that the format of the interrupts property is dependent on the
- * interrupt controller that interrupt-parent points to; these are for
- * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.)
- */
- int rc;
- char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr);
-
- rc = qemu_fdt_add_subnode(fdt, nodename);
- rc |= qemu_fdt_setprop_string(fdt, nodename,
- "compatible", "virtio,mmio");
- rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
- acells, addr, scells, size);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
- g_free(nodename);
- if (rc) {
- return -1;
- }
- return 0;
-}
-
static uint32_t find_int_controller(void *fdt)
{
/* Find the FDT node corresponding to the interrupt controller
@@ -479,12 +449,9 @@ static uint32_t find_int_controller(void *fdt)
static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
- uint32_t acells, scells, intc;
const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info;
+ uint32 intc = find_int_controller(fdt);
- acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells");
- scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells");
- intc = find_int_controller(fdt);
if (!intc) {
/* Not fatal, we just won't provide virtio. This will
* happen with older device tree blobs.
@@ -492,17 +459,10 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in "
"dtb; will not include virtio-mmio devices in the dtb.\n");
} else {
- int i;
const hwaddr *map = daughterboard->motherboard_map;
- /* We iterate backwards here because adding nodes
- * to the dtb puts them in last-first.
- */
- for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
- add_virtio_mmio_node(fdt, acells, scells,
- map[VE_VIRTIO] + 0x200 * i,
- 0x200, intc, 40 + i);
- }
+ add_virtio_mmio_fdt_nodes(map[VE_VIRTIO], 40, NUM_VIRTIO_TRANSPORTS,
+ fdt, intc);
}
}
@@ -694,10 +654,7 @@ static void vexpress_common_init(MachineState *machine)
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
*/
- for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
- sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i,
- pic[40 + i]);
- }
+ virtio_mmio_create(map[VE_VIRTIO], &pic[40], NUM_VIRTIO_TRANSPORTS);
daughterboard->bootinfo.ram_size = machine->ram_size;
daughterboard->bootinfo.kernel_filename = machine->kernel_filename;
@@ -41,6 +41,7 @@
#include "hw/acpi/aml-build.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
+#include "hw/virtio/virtio-mmio.h"
#define ARM_SPI_BASE 32
@@ -136,11 +137,10 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
static void acpi_dsdt_add_virtio(Aml *scope,
const MemMapEntry *virtio_mmio_memmap,
- int mmio_irq, int num)
+ int irq)
{
hwaddr base = virtio_mmio_memmap->base;
- hwaddr size = virtio_mmio_memmap->size;
- int irq = mmio_irq;
+ int num = virtio_mmio_memmap->size / VIRTIO_MMIO_SIZE;
int i;
for (i = 0; i < num; i++) {
@@ -149,13 +149,14 @@ static void acpi_dsdt_add_virtio(Aml *scope,
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
Aml *crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
+ aml_append(crs, aml_memory32_fixed(base, VIRTIO_MMIO_SIZE,
+ AML_READ_WRITE));
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, irq + i));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
- base += size;
+ base += VIRTIO_MMIO_SIZE;
}
}
@@ -521,7 +522,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
(irqmap[VIRT_RTC] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
- (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
+ irqmap[VIRT_MMIO] + ARM_SPI_BASE);
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
guest_info->use_highmem);
@@ -32,6 +32,7 @@
#include "hw/arm/arm.h"
#include "hw/arm/primecell.h"
#include "hw/arm/virt.h"
+#include "hw/virtio/virtio-mmio.h"
#include "hw/devices.h"
#include "net/net.h"
#include "sysemu/block-backend.h"
@@ -120,8 +121,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
- [VIRT_MMIO] = { 0x0a000000, 0x00000200 },
- /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
+ [VIRT_MMIO] = { 0x0a000000, 0x00004000 }, /* 32 transports */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
@@ -568,66 +568,12 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
{
- int i;
- hwaddr size = vbi->memmap[VIRT_MMIO].size;
-
- /* We create the transports in forwards order. Since qbus_realize()
- * prepends (not appends) new child buses, the incrementing loop below will
- * create a list of virtio-mmio buses with decreasing base addresses.
- *
- * When a -device option is processed from the command line,
- * qbus_find_recursive() picks the next free virtio-mmio bus in forwards
- * order. The upshot is that -device options in increasing command line
- * order are mapped to virtio-mmio buses with decreasing base addresses.
- *
- * When this code was originally written, that arrangement ensured that the
- * guest Linux kernel would give the lowest "name" (/dev/vda, eth0, etc) to
- * the first -device on the command line. (The end-to-end order is a
- * function of this loop, qbus_realize(), qbus_find_recursive(), and the
- * guest kernel's name-to-address assignment strategy.)
- *
- * Meanwhile, the kernel's traversal seems to have been reversed; see eg.
- * the message, if not necessarily the code, of commit 70161ff336.
- * Therefore the loop now establishes the inverse of the original intent.
- *
- * Unfortunately, we can't counteract the kernel change by reversing the
- * loop; it would break existing command lines.
- *
- * In any case, the kernel makes no guarantee about the stability of
- * enumeration order of virtio devices (as demonstrated by it changing
- * between kernel versions). For reliable and stable identification
- * of disks users must use UUIDs or similar mechanisms.
- */
- for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
- int irq = vbi->irqmap[VIRT_MMIO] + i;
- hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
-
- sysbus_create_simple("virtio-mmio", base, pic[irq]);
- }
+ unsigned int num = vbi->memmap[VIRT_MMIO].size / VIRTIO_MMIO_SIZE;
+ int irq = vbi->irqmap[VIRT_MMIO];
- /* We add dtb nodes in reverse order so that they appear in the finished
- * device tree lowest address first.
- *
- * Note that this mapping is independent of the loop above. The previous
- * loop influences virtio device to virtio transport assignment, whereas
- * this loop controls how virtio transports are laid out in the dtb.
- */
- for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
- char *nodename;
- int irq = vbi->irqmap[VIRT_MMIO] + i;
- hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
-
- nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
- qemu_fdt_add_subnode(vbi->fdt, nodename);
- qemu_fdt_setprop_string(vbi->fdt, nodename,
- "compatible", "virtio,mmio");
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
- 2, base, 2, size);
- qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq,
- GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
- g_free(nodename);
- }
+ virtio_mmio_create(vbi->memmap[VIRT_MMIO].base, &pic[irq], num);
+ add_virtio_mmio_fdt_nodes(vbi->memmap[VIRT_MMIO].base, irq, num,
+ vbi->fdt, 0);
}
static void create_one_flash(const char *name, hwaddr flashbase,
@@ -22,8 +22,10 @@
#include "hw/sysbus.h"
#include "hw/virtio/virtio.h"
#include "qemu/host-utils.h"
+#include "sysemu/device_tree.h"
#include "sysemu/kvm.h"
#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-mmio.h"
#include "qemu/error-report.h"
#define DEBUG_VIRTIO_MMIO
@@ -531,7 +533,7 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
d, NULL);
sysbus_init_irq(sbd, &proxy->irq);
memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy,
- TYPE_VIRTIO_MMIO, 0x200);
+ TYPE_VIRTIO_MMIO, VIRTIO_MMIO_SIZE);
sysbus_init_mmio(sbd, &proxy->iomem);
}
@@ -581,3 +583,40 @@ static void virtio_mmio_register_types(void)
}
type_init(virtio_mmio_register_types)
+
+void virtio_mmio_create(hwaddr addr, qemu_irq *irqs, unsigned int num)
+{
+ unsigned int i;
+
+ /* We create the transports in forwards order. Since qbus_realize()
+ * prepends (not appends) new child buses, the incrementing loop below will
+ * create a list of virtio-mmio buses with decreasing base addresses.
+ *
+ * When a -device option is processed from the command line,
+ * qbus_find_recursive() picks the next free virtio-mmio bus in forwards
+ * order. The upshot is that -device options in increasing command line
+ * order are mapped to virtio-mmio buses with decreasing base addresses.
+ *
+ * When this code was originally written, that arrangement ensured that the
+ * guest Linux kernel would give the lowest "name" (/dev/vda, eth0, etc) to
+ * the first -device on the command line. (The end-to-end order is a
+ * function of this loop, qbus_realize(), qbus_find_recursive(), and the
+ * guest kernel's name-to-address assignment strategy.)
+ *
+ * Meanwhile, the kernel's traversal seems to have been reversed; see eg.
+ * the message, if not necessarily the code, of commit 70161ff336.
+ * Therefore the loop now establishes the inverse of the original intent.
+ *
+ * Unfortunately, we can't counteract the kernel change by reversing the
+ * loop; it would break existing command lines.
+ *
+ * In any case, the kernel makes no guarantee about the stability of
+ * enumeration order of virtio devices (as demonstrated by it changing
+ * between kernel versions). For reliable and stable identification
+ * of disks users must use UUIDs or similar mechanisms.
+ */
+ for (i = 0; i < num; i++) {
+ sysbus_create_simple(TYPE_VIRTIO_MMIO,
+ addr + VIRTIO_MMIO_SIZE * i, irqs[i]);
+ }
+}
@@ -57,4 +57,20 @@ typedef struct {
*/
void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params);
+/**
+ * add_virtio_mmio_fdt_nodes:
+ * @addr: Starting physical address of virtio region
+ * @irq: IRQ number for the first device in a row
+ * @num: Number of virtio devices
+ * @fdt: Opaque pointer to the device tree
+ * @intc: Optional handle to put as a value of interrupt-parent
+ * property
+ *
+ * Insert description of virtio-mmio devices into device tree
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int add_virtio_mmio_fdt_nodes(hwaddr addr, int irq, unsigned int num,
+ void *fdt, int intc);
+
#endif
new file mode 100644
@@ -0,0 +1,38 @@
+/*
+ * Virtio-mmio public utilities
+ *
+ * Copyright (c) 2015 Samsung Electronics Co. Ltd.
+ *
+ * Author:
+ * Pavel Fedin <p.fedin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _QEMU_VIRTIO_MMIO_H
+#define _QEMU_VIRTIO_MMIO_H
+
+#include "hw/irq.h"
+
+#define VIRTIO_MMIO_SIZE 0x0200
+
+/**
+ * virtio_mmio_create:
+ * @addr: Starting physical address of virtio region
+ * @irqs: Array of IRQ objects, one per virtio device
+ * @num: Number of virtio devices to create
+ *
+ * Create a bunch of virtio-mmio devices
+ */
+void virtio_mmio_create(hwaddr addr, qemu_irq *irqs, unsigned int num);
+
+#endif
Extract common code for virtio-mmio creation and FDT node addition and put it into reusable functions. Use new functions in vexpress and virt machines. Signed-off-by: Pavel Fedin <p.fedin@samsung.com> --- hw/arm/sysbus-fdt.c | 51 +++++++++++++++++++++++++++++++ hw/arm/vexpress.c | 55 ++++----------------------------- hw/arm/virt-acpi-build.c | 13 ++++---- hw/arm/virt.c | 68 +++++------------------------------------ hw/virtio/virtio-mmio.c | 41 ++++++++++++++++++++++++- include/hw/arm/sysbus-fdt.h | 16 ++++++++++ include/hw/virtio/virtio-mmio.h | 38 +++++++++++++++++++++++ 7 files changed, 165 insertions(+), 117 deletions(-) create mode 100644 include/hw/virtio/virtio-mmio.h