hw/arm/sysbus-fdt: enable vfio-calxeda-xgmac dynamic instantiation

This patch allows the instantiation of the vfio-calxeda-xgmac device
from the QEMU command line (-device vfio-calxeda-xgmac,host="<device>").

A specialized device tree node is created for the guest, containing
compat, dma-coherent, reg and interrupts properties.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Acked-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1434455898-17895-1-git-send-email-eric.auger@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Eric Auger 2015-06-19 14:17:44 +01:00 committed by Peter Maydell
parent ba890a9b25
commit decf4f807b
3 changed files with 108 additions and 11 deletions

View file

@ -26,6 +26,9 @@
#include "sysemu/device_tree.h"
#include "hw/platform-bus.h"
#include "sysemu/sysemu.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
#include "hw/arm/fdt.h"
/*
* internal struct that contains the information to create dynamic
@ -53,11 +56,81 @@ typedef struct NodeCreationPair {
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
} NodeCreationPair;
/* Device Specific Code */
/**
* add_calxeda_midway_xgmac_fdt_node
*
* Generates a simple node with following properties:
* compatible string, regs, interrupts, dma-coherent
*/
static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque)
{
PlatformBusFDTData *data = opaque;
PlatformBusDevice *pbus = data->pbus;
void *fdt = data->fdt;
const char *parent_node = data->pbus_node_name;
int compat_str_len, i, ret = -1;
char *nodename;
uint32_t *irq_attr, *reg_attr;
uint64_t mmio_base, irq_number;
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
VFIODevice *vbasedev = &vdev->vbasedev;
mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
vbasedev->name, mmio_base);
qemu_fdt_add_subnode(fdt, nodename);
compat_str_len = strlen(vdev->compat) + 1;
qemu_fdt_setprop(fdt, nodename, "compatible",
vdev->compat, compat_str_len);
qemu_fdt_setprop(fdt, nodename, "dma-coherent", "", 0);
reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
for (i = 0; i < vbasedev->num_regions; i++) {
mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
reg_attr[2 * i] = cpu_to_be32(mmio_base);
reg_attr[2 * i + 1] = cpu_to_be32(
memory_region_size(&vdev->regions[i]->mem));
}
ret = qemu_fdt_setprop(fdt, nodename, "reg", reg_attr,
vbasedev->num_regions * 2 * sizeof(uint32_t));
if (ret) {
error_report("could not set reg property of node %s", nodename);
goto fail_reg;
}
irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
for (i = 0; i < vbasedev->num_irqs; i++) {
irq_number = platform_bus_get_irqn(pbus, sbdev , i)
+ data->irq_start;
irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
irq_attr[3 * i + 1] = cpu_to_be32(irq_number);
irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
}
ret = qemu_fdt_setprop(fdt, nodename, "interrupts",
irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t));
if (ret) {
error_report("could not set interrupts property of node %s",
nodename);
}
g_free(irq_attr);
fail_reg:
g_free(reg_attr);
g_free(nodename);
return ret;
}
/* list of supported dynamic sysbus devices */
static const NodeCreationPair add_fdt_node_functions[] = {
{TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node},
{"", NULL}, /* last element */
};
/* Generic Code */
/**
* add_fdt_node - add the device tree node of a dynamic sysbus device
*