diff mbox

[v6,11/16] hw/arm/dyn_sysbus_devtree: enable vfio-calxeda-xgmac dynamic instantiation

Message ID 1410247876-4967-12-git-send-email-eric.auger@linaro.org
State New
Headers show

Commit Message

Auger Eric Sept. 9, 2014, 7:31 a.m. UTC
vfio-calxeda-xgmac now can be instantiated using the -device option

Signed-off-by: Eric Auger <eric.auger@linaro.org>

---

v2 -> v3:
- correct bug of reg_attr[2*i] in vfio_fdt_add_device_node
- fix a bug related to compat_str_len computed on original compat
  instead of corrected compat
- wrap_vfio_fdt_add_node take a node creation function: this function
  needs to be specialized for each VFIO device. wrap function must be
  called in sysbus_device_create_devtree
---
 hw/arm/dyn_sysbus_devtree.c | 141 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)

Comments

Alexander Graf Sept. 10, 2014, 1:12 p.m. UTC | #1
On 09.09.14 09:31, Eric Auger wrote:
> vfio-calxeda-xgmac now can be instantiated using the -device option
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> 
> ---
> 
> v2 -> v3:
> - correct bug of reg_attr[2*i] in vfio_fdt_add_device_node
> - fix a bug related to compat_str_len computed on original compat
>   instead of corrected compat
> - wrap_vfio_fdt_add_node take a node creation function: this function
>   needs to be specialized for each VFIO device. wrap function must be
>   called in sysbus_device_create_devtree
> ---
>  hw/arm/dyn_sysbus_devtree.c | 141 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 141 insertions(+)
> 
> diff --git a/hw/arm/dyn_sysbus_devtree.c b/hw/arm/dyn_sysbus_devtree.c
> index 61e5b5f..3ef9430 100644
> --- a/hw/arm/dyn_sysbus_devtree.c
> +++ b/hw/arm/dyn_sysbus_devtree.c
> @@ -20,6 +20,141 @@
>  #include "hw/arm/dyn_sysbus_devtree.h"
>  #include "qemu/error-report.h"
>  #include "sysemu/device_tree.h"
> +#include "hw/vfio/vfio-platform.h"
> +#include "hw/vfio/vfio-calxeda-xgmac.h"
> +
> +typedef void (*vfio_fdt_add_device_node_t)(SysBusDevice *sbdev, void *opaque);
> +
> +static char *format_compat(char * compat)
> +{
> +    char *str_ptr, *corrected_compat;
> +    /*
> +     * process compatibility property string passed by end-user
> +     * replaces / by , and ; by NUL character
> +     */
> +    corrected_compat = g_strdup(compat);
> +
> +    str_ptr = corrected_compat;
> +    while ((str_ptr = strchr(str_ptr, '/')) != NULL) {
> +        *str_ptr = ',';
> +    }
> +
> +    /* substitute ";" with the NUL char */
> +    str_ptr = corrected_compat;
> +    while ((str_ptr = strchr(str_ptr, ';')) != NULL) {
> +        *str_ptr = '\0';
> +    }
> +
> +    /*
> +     * corrected compat includes a "\0" before or at the same location
> +     * as compat's one
> +     */
> +    return corrected_compat;
> +}
> +
> +static void wrap_vfio_fdt_add_node(SysBusDevice *sbdev, void *opaque,
> +                                   vfio_fdt_add_device_node_t add_node_fn)
> +{
> +    PlatformDevtreeData *data = opaque;
> +    VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
> +    VFIODevice *vbasedev = &vdev->vbasedev;
> +    gchar irq_number_prop[8];
> +    Object *obj = OBJECT(sbdev);
> +    char *corrected_compat;
> +    uint64_t irq_number;
> +    int corrected_compat_str_len, i;
> +
> +    corrected_compat = format_compat(vdev->compat);
> +    corrected_compat_str_len = strlen(corrected_compat) + 1;
> +    /* we copy the corrected_compat string + its "\0" */
> +    snprintf(vdev->compat, corrected_compat_str_len, "%s", corrected_compat);
> +    g_free(corrected_compat);
> +
> +    add_node_fn(sbdev, opaque);
> +
> +    for (i = 0; i < vbasedev->num_irqs; i++) {
> +        snprintf(irq_number_prop, sizeof(irq_number_prop), "irq[%d]", i);
> +        irq_number = object_property_get_int(obj, irq_number_prop, NULL)
> +                                                 + data->irq_start;
> +        /*
> +         * for setting irqfd up we must provide the virtual IRQ number
> +         * which is the sum of irq_start and actual platform bus irq
> +         * index. At realize point we do not have this info.
> +         */
> +        vfio_start_irq_injection(sbdev, i, irq_number);

Does this really have anything to do with fdt? Also, don't we have
notifiers that call IRQ holders when an IRQ gets connected? That would
probably be the cleaner approach here.


Alex
Auger Eric Sept. 11, 2014, 2:20 p.m. UTC | #2
On 09/10/2014 03:12 PM, Alexander Graf wrote:
> 
> 
> On 09.09.14 09:31, Eric Auger wrote:
>> vfio-calxeda-xgmac now can be instantiated using the -device option
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>
>> ---
>>
>> v2 -> v3:
>> - correct bug of reg_attr[2*i] in vfio_fdt_add_device_node
>> - fix a bug related to compat_str_len computed on original compat
>>   instead of corrected compat
>> - wrap_vfio_fdt_add_node take a node creation function: this function
>>   needs to be specialized for each VFIO device. wrap function must be
>>   called in sysbus_device_create_devtree
>> ---
>>  hw/arm/dyn_sysbus_devtree.c | 141 ++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 141 insertions(+)
>>
>> diff --git a/hw/arm/dyn_sysbus_devtree.c b/hw/arm/dyn_sysbus_devtree.c
>> index 61e5b5f..3ef9430 100644
>> --- a/hw/arm/dyn_sysbus_devtree.c
>> +++ b/hw/arm/dyn_sysbus_devtree.c
>> @@ -20,6 +20,141 @@
>>  #include "hw/arm/dyn_sysbus_devtree.h"
>>  #include "qemu/error-report.h"
>>  #include "sysemu/device_tree.h"
>> +#include "hw/vfio/vfio-platform.h"
>> +#include "hw/vfio/vfio-calxeda-xgmac.h"
>> +
>> +typedef void (*vfio_fdt_add_device_node_t)(SysBusDevice *sbdev, void *opaque);
>> +
>> +static char *format_compat(char * compat)
>> +{
>> +    char *str_ptr, *corrected_compat;
>> +    /*
>> +     * process compatibility property string passed by end-user
>> +     * replaces / by , and ; by NUL character
>> +     */
>> +    corrected_compat = g_strdup(compat);
>> +
>> +    str_ptr = corrected_compat;
>> +    while ((str_ptr = strchr(str_ptr, '/')) != NULL) {
>> +        *str_ptr = ',';
>> +    }
>> +
>> +    /* substitute ";" with the NUL char */
>> +    str_ptr = corrected_compat;
>> +    while ((str_ptr = strchr(str_ptr, ';')) != NULL) {
>> +        *str_ptr = '\0';
>> +    }
>> +
>> +    /*
>> +     * corrected compat includes a "\0" before or at the same location
>> +     * as compat's one
>> +     */
>> +    return corrected_compat;
>> +}
>> +
>> +static void wrap_vfio_fdt_add_node(SysBusDevice *sbdev, void *opaque,
>> +                                   vfio_fdt_add_device_node_t add_node_fn)
>> +{
>> +    PlatformDevtreeData *data = opaque;
>> +    VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
>> +    VFIODevice *vbasedev = &vdev->vbasedev;
>> +    gchar irq_number_prop[8];
>> +    Object *obj = OBJECT(sbdev);
>> +    char *corrected_compat;
>> +    uint64_t irq_number;
>> +    int corrected_compat_str_len, i;
>> +
>> +    corrected_compat = format_compat(vdev->compat);
>> +    corrected_compat_str_len = strlen(corrected_compat) + 1;
>> +    /* we copy the corrected_compat string + its "\0" */
>> +    snprintf(vdev->compat, corrected_compat_str_len, "%s", corrected_compat);
>> +    g_free(corrected_compat);
>> +
>> +    add_node_fn(sbdev, opaque);
>> +
>> +    for (i = 0; i < vbasedev->num_irqs; i++) {
>> +        snprintf(irq_number_prop, sizeof(irq_number_prop), "irq[%d]", i);
>> +        irq_number = object_property_get_int(obj, irq_number_prop, NULL)
>> +                                                 + data->irq_start;
>> +        /*
>> +         * for setting irqfd up we must provide the virtual IRQ number
>> +         * which is the sum of irq_start and actual platform bus irq
>> +         * index. At realize point we do not have this info.
>> +         */
>> +        vfio_start_irq_injection(sbdev, i, irq_number);
> 
> Does this really have anything to do with fdt?

No it doesn't, I aknowledge ;-)
 Also, don't we have
> notifiers that call IRQ holders when an IRQ gets connected?
Do we? I was not able to identify such modality. the notifier would be
triggered in qemu_allocate_irq right?
 That would
> probably be the cleaner approach here.
If it is and if the functionality does not exist yet, I can it, sure.

Besides I do not get how VFIO-PCI does handle the problem of late irq
binding. If someone can share some knowledge on this, it would be much
appreciated.

Best Regards

Eric

> 
> 
> Alex
>
diff mbox

Patch

diff --git a/hw/arm/dyn_sysbus_devtree.c b/hw/arm/dyn_sysbus_devtree.c
index 61e5b5f..3ef9430 100644
--- a/hw/arm/dyn_sysbus_devtree.c
+++ b/hw/arm/dyn_sysbus_devtree.c
@@ -20,6 +20,141 @@ 
 #include "hw/arm/dyn_sysbus_devtree.h"
 #include "qemu/error-report.h"
 #include "sysemu/device_tree.h"
+#include "hw/vfio/vfio-platform.h"
+#include "hw/vfio/vfio-calxeda-xgmac.h"
+
+typedef void (*vfio_fdt_add_device_node_t)(SysBusDevice *sbdev, void *opaque);
+
+static char *format_compat(char * compat)
+{
+    char *str_ptr, *corrected_compat;
+    /*
+     * process compatibility property string passed by end-user
+     * replaces / by , and ; by NUL character
+     */
+    corrected_compat = g_strdup(compat);
+
+    str_ptr = corrected_compat;
+    while ((str_ptr = strchr(str_ptr, '/')) != NULL) {
+        *str_ptr = ',';
+    }
+
+    /* substitute ";" with the NUL char */
+    str_ptr = corrected_compat;
+    while ((str_ptr = strchr(str_ptr, ';')) != NULL) {
+        *str_ptr = '\0';
+    }
+
+    /*
+     * corrected compat includes a "\0" before or at the same location
+     * as compat's one
+     */
+    return corrected_compat;
+}
+
+static void wrap_vfio_fdt_add_node(SysBusDevice *sbdev, void *opaque,
+                                   vfio_fdt_add_device_node_t add_node_fn)
+{
+    PlatformDevtreeData *data = opaque;
+    VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
+    VFIODevice *vbasedev = &vdev->vbasedev;
+    gchar irq_number_prop[8];
+    Object *obj = OBJECT(sbdev);
+    char *corrected_compat;
+    uint64_t irq_number;
+    int corrected_compat_str_len, i;
+
+    corrected_compat = format_compat(vdev->compat);
+    corrected_compat_str_len = strlen(corrected_compat) + 1;
+    /* we copy the corrected_compat string + its "\0" */
+    snprintf(vdev->compat, corrected_compat_str_len, "%s", corrected_compat);
+    g_free(corrected_compat);
+
+    add_node_fn(sbdev, opaque);
+
+    for (i = 0; i < vbasedev->num_irqs; i++) {
+        snprintf(irq_number_prop, sizeof(irq_number_prop), "irq[%d]", i);
+        irq_number = object_property_get_int(obj, irq_number_prop, NULL)
+                                                 + data->irq_start;
+        /*
+         * for setting irqfd up we must provide the virtual IRQ number
+         * which is the sum of irq_start and actual platform bus irq
+         * index. At realize point we do not have this info.
+         */
+        vfio_start_irq_injection(sbdev, i, irq_number);
+    }
+}
+
+static void vfio_basic_fdt_add_device_node(SysBusDevice *sbdev,
+                                                    void *opaque)
+{
+    PlatformDevtreeData *data = opaque;
+    void *fdt = data->fdt;
+    const char *parent_node = data->node;
+    int compat_str_len;
+    char *nodename;
+    int i, ret;
+    uint32_t *irq_attr;
+    uint64_t *reg_attr;
+    uint64_t mmio_base;
+    uint64_t irq_number;
+    gchar mmio_base_prop[8];
+    gchar irq_number_prop[8];
+    VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
+    VFIODevice *vbasedev = &vdev->vbasedev;
+    Object *obj = OBJECT(sbdev);
+
+    mmio_base = object_property_get_int(obj, "mmio[0]", NULL);
+
+    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);
+
+    reg_attr = g_new(uint64_t, vbasedev->num_regions*4);
+
+    for (i = 0; i < vbasedev->num_regions; i++) {
+        snprintf(mmio_base_prop, sizeof(mmio_base_prop), "mmio[%d]", i);
+        mmio_base = object_property_get_int(obj, mmio_base_prop, NULL);
+        reg_attr[4*i] = 1;
+        reg_attr[4*i+1] = mmio_base;
+        reg_attr[4*i+2] = 1;
+        reg_attr[4*i+3] = memory_region_size(&vdev->regions[i]->mem);
+    }
+
+    ret = qemu_fdt_setprop_sized_cells_from_array(fdt, nodename, "reg",
+                     vbasedev->num_regions*2, reg_attr);
+    if (ret < 0) {
+        error_report("could not set reg property of node %s", nodename);
+    }
+
+    irq_attr = g_new(uint32_t, vbasedev->num_irqs*3);
+
+    for (i = 0; i < vbasedev->num_irqs; i++) {
+        snprintf(irq_number_prop, sizeof(irq_number_prop), "irq[%d]", i);
+        irq_number = object_property_get_int(obj, irq_number_prop, NULL)
+                                                 + data->irq_start;
+        irq_attr[3*i] = cpu_to_be32(0);
+        irq_attr[3*i+1] = cpu_to_be32(irq_number);
+        irq_attr[3*i+2] = cpu_to_be32(0x4);
+    }
+
+   ret = qemu_fdt_setprop(fdt, nodename, "interrupts",
+                     irq_attr, vbasedev->num_irqs*3*sizeof(uint32_t));
+    if (ret < 0) {
+        error_report("could not set interrupts property of node %s",
+                     nodename);
+    }
+
+    g_free(nodename);
+    g_free(irq_attr);
+    g_free(reg_attr);
+}
 
 /**
  * arm_sysbus_device_create_devtree - create the node of devices
@@ -41,6 +176,12 @@  static int arm_sysbus_device_create_devtree(Object *obj, void *opaque)
                                     arm_sysbus_device_create_devtree, data);
     }
 
+    if (object_dynamic_cast(obj, TYPE_VFIO_CALXEDA_XGMAC)) {
+        wrap_vfio_fdt_add_node(sbdev, data,
+                               vfio_basic_fdt_add_device_node);
+        matched = true;
+    }
+
     if (!matched) {
         error_report("Device %s is not supported by this machine yet.",
                      qdev_fw_name(DEVICE(dev)));