vexpress: Add virtio-mmio transports
Add some virtio-mmio transports to the vexpress board model, together with a modify_dtb hook which adds them to the device tree so that the kernel will probe for them. We put them in a reserved area of the address map. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1373977512-28932-9-git-send-email-peter.maydell@linaro.org
This commit is contained in:
		
							parent
							
								
									cef04a26e7
								
							
						
					
					
						commit
						c8a07b355d
					
				@ -31,11 +31,18 @@
 | 
			
		||||
#include "exec/address-spaces.h"
 | 
			
		||||
#include "sysemu/blockdev.h"
 | 
			
		||||
#include "hw/block/flash.h"
 | 
			
		||||
#include "sysemu/device_tree.h"
 | 
			
		||||
#include <libfdt.h>
 | 
			
		||||
 | 
			
		||||
#define VEXPRESS_BOARD_ID 0x8e0
 | 
			
		||||
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
 | 
			
		||||
#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
 | 
			
		||||
 | 
			
		||||
/* Number of virtio transports to create (0..8; limited by
 | 
			
		||||
 * number of available IRQ lines).
 | 
			
		||||
 */
 | 
			
		||||
#define NUM_VIRTIO_TRANSPORTS 4
 | 
			
		||||
 | 
			
		||||
/* Address maps for peripherals:
 | 
			
		||||
 * the Versatile Express motherboard has two possible maps,
 | 
			
		||||
 * the "legacy" one (used for A9) and the "Cortex-A Series"
 | 
			
		||||
@ -71,6 +78,7 @@ enum {
 | 
			
		||||
    VE_ETHERNET,
 | 
			
		||||
    VE_USB,
 | 
			
		||||
    VE_DAPROM,
 | 
			
		||||
    VE_VIRTIO,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static hwaddr motherboard_legacy_map[] = {
 | 
			
		||||
@ -89,6 +97,7 @@ static hwaddr motherboard_legacy_map[] = {
 | 
			
		||||
    [VE_WDT] = 0x1000f000,
 | 
			
		||||
    [VE_TIMER01] = 0x10011000,
 | 
			
		||||
    [VE_TIMER23] = 0x10012000,
 | 
			
		||||
    [VE_VIRTIO] = 0x10013000,
 | 
			
		||||
    [VE_SERIALDVI] = 0x10016000,
 | 
			
		||||
    [VE_RTC] = 0x10017000,
 | 
			
		||||
    [VE_COMPACTFLASH] = 0x1001a000,
 | 
			
		||||
@ -135,6 +144,7 @@ static hwaddr motherboard_aseries_map[] = {
 | 
			
		||||
    [VE_WDT] = 0x1c0f0000,
 | 
			
		||||
    [VE_TIMER01] = 0x1c110000,
 | 
			
		||||
    [VE_TIMER23] = 0x1c120000,
 | 
			
		||||
    [VE_VIRTIO] = 0x1c130000,
 | 
			
		||||
    [VE_SERIALDVI] = 0x1c160000,
 | 
			
		||||
    [VE_RTC] = 0x1c170000,
 | 
			
		||||
    [VE_COMPACTFLASH] = 0x1c1a0000,
 | 
			
		||||
@ -395,6 +405,85 @@ 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_devtree_add_subnode(fdt, nodename);
 | 
			
		||||
    rc |= qemu_devtree_setprop_string(fdt, nodename,
 | 
			
		||||
                                      "compatible", "virtio,mmio");
 | 
			
		||||
    rc |= qemu_devtree_setprop_sized_cells(fdt, nodename, "reg",
 | 
			
		||||
                                           acells, addr, scells, size);
 | 
			
		||||
    qemu_devtree_setprop_cells(fdt, nodename, "interrupt-parent", intc);
 | 
			
		||||
    qemu_devtree_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
 | 
			
		||||
     * for virtio-mmio devices. We do this by scanning the fdt for
 | 
			
		||||
     * a node with the right compatibility, since we know there is
 | 
			
		||||
     * only one GIC on a vexpress board.
 | 
			
		||||
     * We return the phandle of the node, or 0 if none was found.
 | 
			
		||||
     */
 | 
			
		||||
    const char *compat = "arm,cortex-a9-gic";
 | 
			
		||||
    int offset;
 | 
			
		||||
 | 
			
		||||
    offset = fdt_node_offset_by_compatible(fdt, -1, compat);
 | 
			
		||||
    if (offset >= 0) {
 | 
			
		||||
        return fdt_get_phandle(fdt, offset);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t acells, scells, intc;
 | 
			
		||||
    const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info;
 | 
			
		||||
 | 
			
		||||
    acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells");
 | 
			
		||||
    scells = qemu_devtree_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.
 | 
			
		||||
         */
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void vexpress_common_init(VEDBoardInfo *daughterboard,
 | 
			
		||||
                                 QEMUMachineInitArgs *args)
 | 
			
		||||
{
 | 
			
		||||
@ -523,6 +612,15 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
 | 
			
		||||
 | 
			
		||||
    /* VE_DAPROM: not modelled */
 | 
			
		||||
 | 
			
		||||
    /* Create mmio transports, so the user can create virtio backends
 | 
			
		||||
     * (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]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    daughterboard->bootinfo.ram_size = args->ram_size;
 | 
			
		||||
    daughterboard->bootinfo.kernel_filename = args->kernel_filename;
 | 
			
		||||
    daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
 | 
			
		||||
@ -533,6 +631,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
 | 
			
		||||
    daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
 | 
			
		||||
    daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
 | 
			
		||||
    daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
 | 
			
		||||
    daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
 | 
			
		||||
    arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user