Example #1
0
static int i2c_bus_fdt_init(char *node_path, FDTMachineInfo *fdti, void *priv)
{
    Object *parent;
    DeviceState *dev;
    char parent_node_path[DT_PATH_LENGTH];
    char *node_name = qemu_devtree_get_node_name(fdti->fdt, node_path);

    DB_PRINT_NP(1, "\n");
    /* FIXME: share this code with fdt_generic_util.c/fdt_init_qdev() */
    if (qemu_devtree_getparent(fdti->fdt, parent_node_path, node_path)) {
        abort();
    }
    while (!fdt_init_has_opaque(fdti, parent_node_path)) {
        fdt_init_yield(fdti);
    }
    parent = fdt_init_get_opaque(fdti, parent_node_path);
    dev = (DeviceState *)object_dynamic_cast(parent, TYPE_DEVICE);
    if (parent && dev) {
        while (!dev->realized) {
            fdt_init_yield(fdti);
        }
        DB_PRINT_NP(0, "parenting i2c bus to %s bus %s\n", parent_node_path,
                 node_name);
        fdt_init_set_opaque(fdti, node_path,
                            qdev_get_child_bus(dev, node_name));
    } else {
        DB_PRINT_NP(0, "orphaning i2c bus\n");
    }
    return 0;
}
Example #2
0
qemu_irq fdt_get_irq_info(FDTMachineInfo *fdti, char *node_path, int irq_idx,
        int *err, char *info) {
    void *fdt = fdti->fdt;
    int intc_phandle, intc_cells, idx, errl;
    char intc_node_path[DT_PATH_LENGTH];
    Error *errp = NULL;
    DeviceState *intc;

    if (!err) {
        err = &errl;
    }
    intc_phandle = qemu_fdt_getprop_cell(fdt, node_path, "interrupt-parent",
                                                                0, true, &errp);
    if (errp) {
        goto fail;
    }

    if (qemu_fdt_get_node_by_phandle(fdt, intc_node_path, intc_phandle)) {
        goto fail;
    }
    intc_cells = qemu_fdt_getprop_cell(fdt, intc_node_path,
                                       "#interrupt-cells", 0, false, &errp);
    if (errp) {
        goto fail;
    }
    idx = qemu_fdt_getprop_cell(fdt, node_path, "interrupts",
                                        intc_cells * irq_idx, false, &errp);
    if (errp) {
        goto fail;
    }

    while (!fdt_init_has_opaque(fdti, intc_node_path)) {
        fdt_init_yield(fdti);
    }
    intc = DEVICE(fdt_init_get_opaque(fdti, intc_node_path));
    if (!intc) {
        goto fail;
    }
    if (info) {
        char *node_name = qemu_fdt_get_node_name(fdt, intc_node_path);
        sprintf(info, "%d (%s)", idx, node_name);
        g_free((void *)node_name);
    }
    *err = 0;
    return qdev_get_gpio_in(intc, idx);
fail:
    *err = 1;
    if (info) {
        sprintf(info, "(none)");
    }
    return NULL;
}
Example #3
0
static void fdt_init_node(void *args)
{

    struct FDTInitNodeArgs *a = args;
    char *node_path = a->node_path;
    FDTMachineInfo *fdti = a->fdti;
    g_free(a);

    char *all_compats = NULL, *compat, *node_name, *next_compat;
    int compat_len;

#ifdef FDT_GENERIC_UTIL_ERR_DEBUG
    static int entry_index;
    int this_entry = entry_index++;
#endif
    DB_PRINT("enter %d %s\n", this_entry, node_path);

    /* try instance binding first */
    node_name = qemu_fdt_get_node_name(fdti->fdt, node_path);
    if (!node_name) {
        fprintf(stderr, "FDT: ERROR: nameless node: %s\n", node_path);
    }
    if (!fdt_init_inst_bind(node_path, fdti, node_name)) {
        goto exit;
    }

    /* fallback to compatibility binding */
    all_compats = qemu_fdt_getprop(fdti->fdt, node_path,
        "compatible", &compat_len, false, NULL);
    if (!all_compats) {
        fprintf(stderr, "FDT: ERROR: no compatibility found for node %s/%s\n", node_path,
            node_name);
        DB_PRINT("exit %d\n", this_entry);
        fdti->routinesPending--;
        return;
    }
    compat = all_compats;

try_next_compat:
    if (compat_len == 0) {
        goto invalidate;
    }
    if (!fdt_init_compat(node_path, fdti, compat)) {
        goto exit;
    }
    if (!fdt_init_qdev(node_path, fdti, compat)) {
        goto exit;
    }
    next_compat = rawmemchr(compat, '\0');
    compat_len -= (next_compat + 1 - compat);
    if (compat_len > 0) {
        *next_compat = ' ';
    }
    compat = next_compat+1;
    goto try_next_compat;
invalidate:
    fprintf(stderr, "FDT: Unsupported peripheral invalidated %s compatibilities %s\n",
        node_name, all_compats);
    qemu_fdt_setprop_string(fdti->fdt, node_path, "compatible",
        "invalidated");
exit:

    DB_PRINT("exit %d\n", this_entry);

    if (!fdt_init_has_opaque(fdti, node_path)) {
        fdt_init_set_opaque(fdti, node_path, NULL);
    }
    g_free(node_path);
    g_free(all_compats);
    fdti->routinesPending--;
    return;
}
Example #4
0
static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
{
    int err;
    qemu_irq irq;
    hwaddr base;
    int offset;
    DeviceState *dev;
    char *dev_type = NULL;
    int is_intc;
    int i;

    dev = fdt_create_qdev_from_compat(compat, &dev_type);
    if (!dev) {
        DB_PRINT("no match found for %s\n", compat);
        return 1;
    }
    /* FIXME: attach to the sysbus instead */
    object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
                              qemu_fdt_get_node_name(fdti->fdt, node_path),
                              OBJECT(dev), NULL);

    fdt_init_set_opaque(fdti, node_path, dev);

    /* connect nic if appropriate */
    static int nics;
    if (object_property_find(OBJECT(dev), "mac", NULL)) {
        qdev_set_nic_properties(dev, &nd_table[nics]);
        if (nd_table[nics].instantiated) {
            DB_PRINT("NIC instantiated: %s\n", dev_type);
            nics++;
        }
    }

    offset = fdt_path_offset(fdti->fdt, node_path);
    for (offset = fdt_first_property_offset(fdti->fdt, offset);
            offset != -FDT_ERR_NOTFOUND;
            offset = fdt_next_property_offset(fdti->fdt, offset)) {
        const char *propname;
        int len;
        const void *val = fdt_getprop_by_offset(fdti->fdt, offset,
                                                    &propname, &len);

        propname = trim_vendor(propname);
        ObjectProperty *p = object_property_find(OBJECT(dev), propname, NULL);
        if (p) {
            DB_PRINT("matched property: %s of type %s, len %d\n",
                                            propname, p->type, len);
        }
        if (!p) {
            continue;
        }

        /* FIXME: handle generically using accessors and stuff */
        if (!strcmp(p->type, "uint8") || !strcmp(p->type, "uint16") ||
                !strcmp(p->type, "uint32") || !strcmp(p->type, "uint64")) {
            uint64_t offset = (!strcmp(propname, "reg")) ?
                              fdt_get_parent_base(node_path, fdti) : 0;
            object_property_set_int(OBJECT(dev), get_int_be(val, len) + offset,
                                    propname, &error_abort);
            DB_PRINT("set property %s to %#llx\n", propname,
                                            (long long unsigned int)get_int_be(val, len));
        } else if (!strcmp(p->type, "bool")) {
            object_property_set_bool(OBJECT(dev), !!get_int_be(val, len),
                        propname, &error_abort);
            DB_PRINT("set property %s to %#llx\n", propname,
                                            (long long unsigned int)get_int_be(val, len));
        } else if (!strncmp(p->type, "link", 4)) {
            char target_node_path[DT_PATH_LENGTH];
            DeviceState *linked_dev;

            if (qemu_fdt_get_node_by_phandle(fdti->fdt, target_node_path,
                                                get_int_be(val, len))) {
                abort();
            }
            while (!fdt_init_has_opaque(fdti, target_node_path)) {
                fdt_init_yield(fdti);
            }
            linked_dev = fdt_init_get_opaque(fdti, target_node_path);
            object_property_set_link(OBJECT(dev), OBJECT(linked_dev), propname,
                                        &error_abort);
        } else if (!strcmp(p->type, "string")) {
            object_property_set_str(OBJECT(dev), strndup(val, len), propname, &error_abort);
	}
    }

    qdev_init_nofail(dev);
    /* map slave attachment */
    base = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0, false, &error_abort);

    base += fdt_get_parent_base(node_path, fdti);
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);

    {
        int len;
        fdt_get_property(fdti->fdt, fdt_path_offset(fdti->fdt, node_path),
                                "interrupt-controller", &len);
        is_intc = len >= 0;
        DB_PRINT("is interrupt controller: %c\n", is_intc ? 'y' : 'n');
    }
    /* connect irq */
    for (i = 0; ; ++i) {
        char irq_info[1024];
        irq = fdt_get_irq_info(fdti, node_path, i, &err, irq_info);
        /* INTCs inferr their top level, if no IRQ connection specified */
        if (err && is_intc) {
            irq = fdti->irq_base;
            sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
            fprintf(stderr, "FDT: (%s) connected top level irq %s\n", dev_type,
                        irq_info);
            break;
        }
        if (!err) {
            sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
            fprintf(stderr, "FDT: (%s) connected irq %s\n", dev_type, irq_info);
        } else {
            break;
        }
    }

    if (dev_type) {
        g_free(dev_type);
    }

    return 0;
}
Example #5
0
static qemu_irq fdt_get_gpio(FDTMachineInfo *fdti, char *node_path,
                             int* cur_cell, qemu_irq input,
                             const FDTGenericGPIOSet *gpio_set,
                             const char *debug_success, bool *end) {
    void *fdt = fdti->fdt;
    uint32_t parent_phandle, parent_cells = 0, cells[32];
    char parent_node_path[DT_PATH_LENGTH];
    DeviceState *parent;
    int i;
    Error *errp = NULL;
    const char *reason;
    bool free_reason = false;
    const char *propname = gpio_set->names->propname;
    const char *cells_propname = gpio_set->names->cells_propname;

    cells[0] = 0;

    parent_phandle = qemu_fdt_getprop_cell(fdt, node_path, propname,
                                           (*cur_cell)++, false, &errp);
    if (errp) {
        reason = g_strdup_printf("Cant get phandle from \"%s\" property\n",
                                 propname);
        *end = true;
        free_reason = true;
        goto fail_silent;
    }
    if (qemu_devtree_get_node_by_phandle(fdt, parent_node_path,
                                         parent_phandle)) {
        *end = true;
        reason = "cant get node from phandle\n";
        goto fail;
    }
    parent_cells = qemu_fdt_getprop_cell(fdt, parent_node_path,
                                         cells_propname, 0, false, &errp);
    if (errp) {
        *end = true;
        reason = g_strdup_printf("cant get the property \"%s\" from the " \
                                 "parent \"%s\"\n",
                                 cells_propname, parent_node_path);
        free_reason = true;
        goto fail;
    }

    for (i = 0; i < parent_cells; ++i) {
        cells[i] = qemu_fdt_getprop_cell(fdt, node_path, propname,
                                         (*cur_cell)++, false, &errp);
        if (errp) {
            *end = true;
            reason = "cant get cell value";
            goto fail;
        }
    }

    while (!fdt_init_has_opaque(fdti, parent_node_path)) {
        fdt_init_yield(fdti);
    }
    parent = DEVICE(fdt_init_get_opaque(fdti, parent_node_path));

    if (!parent) {
        reason = "parent is not a device";
        goto fail_silent;
    }

    while (!parent->realized) {
        fdt_init_yield(fdti);
    }

    {
        const FDTGenericGPIOConnection *fgg_con = NULL;
        uint16_t range, idx;
        const char *gpio_name = NULL;
        qemu_irq ret;

        if (object_dynamic_cast(OBJECT(parent), TYPE_FDT_GENERIC_GPIO)) {
            const FDTGenericGPIOSet *set;
            FDTGenericGPIOClass *parent_fggc =
                        FDT_GENERIC_GPIO_GET_CLASS(parent);

            for (set = parent_fggc->controller_gpios; set && set->names;
                 set++) {
                if (!strcmp(gpio_set->names->cells_propname,
                            set->names->cells_propname)) {
                    fgg_con = set->gpios;
                    break;
                }
            }
        }

        /* FIXME: cells[0] is not always the fdt indexing match system */
        idx = cells[0] & ~(1ul << 31);
        if (fgg_con) {
            range = fgg_con->range ? fgg_con->range : 1;
            while (!(idx >= fgg_con->fdt_index
                     && idx < (fgg_con->fdt_index + range))
                   && fgg_con->name) {
                fgg_con++;
            }
            if (!fgg_con) {
                goto fail;
            }

            idx -= fgg_con->fdt_index;
            gpio_name = fgg_con->name;
        }

        if (input) {
            FDTIRQConnection *irq = g_new0(FDTIRQConnection, 1);
            bool (*merge_fn)(bool *, int) = qemu_irq_shared_or_handler;

            /* FIXME: I am kind of stealing here. Use the msb of the first
             * cell to indicate the merge function. This needs to be discussed
             * with device-tree community on how this should be done properly.
             */
            if (cells[0] & (1 << 31)) {
                merge_fn = qemu_irq_shared_and_handler;
            }

            DB_PRINT_NP(1, "%s GPIO output %s[%d] on %s\n", debug_success,
                        gpio_name ? gpio_name : "unnamed", idx,
                        parent_node_path);
            *irq = (FDTIRQConnection) {
                .dev = parent,
                .name = gpio_name,
                .merge_fn = merge_fn,
                .i = idx,
                .irq = input,
                .sink_info = NULL, /* FIMXE */
                .next = fdti->irqs
            };
            fdti->irqs = irq;
        }
        ret = qdev_get_gpio_in_named(parent, gpio_name, idx);

        if (ret) {
            DB_PRINT_NP(1, "wiring GPIO input %s on %s ... \n",
                        fgg_con ? fgg_con->name : "unnamed", parent_node_path);
        }
        return ret;
    }
fail:
    fprintf(stderr, "%s Failed: %s\n", node_path, reason);
fail_silent:
    if (free_reason) {
        g_free((void *)reason);
    }
    return NULL;
}

static void fdt_get_irq_info_from_intc(FDTMachineInfo *fdti, qemu_irq *ret,
                                       char *intc_node_path,
                                       uint32_t *cells, uint32_t num_cells,
                                       uint32_t max, Error **errp)
{
    FDTGenericIntcClass *intc_fdt_class;
    DeviceState *intc;

    while (!fdt_init_has_opaque(fdti, intc_node_path)) {
        fdt_init_yield(fdti);
    }
    intc = DEVICE(fdt_init_get_opaque(fdti, intc_node_path));

    if (!intc) {
        goto fail;
    }

    while (!intc->realized) {
        fdt_init_yield(fdti);
    }

    intc_fdt_class = FDT_GENERIC_INTC_GET_CLASS(intc);
    if (!intc_fdt_class) {
        goto fail;
    }

    intc_fdt_class->get_irq(FDT_GENERIC_INTC(intc), ret, cells, num_cells,
                            max, errp);
    return;
fail:
    error_setg(errp, "%s", __func__);
}
Example #6
0
static void fdt_init_node(void *args)
{
    struct FDTInitNodeArgs *a = args;
    char *node_path = a->node_path;
    FDTMachineInfo *fdti = a->fdti;
    g_free(a);

    simple_bus_fdt_init(node_path, fdti);

    char *all_compats = NULL, *compat, *node_name, *next_compat, *device_type;
    int compat_len;

    DB_PRINT_NP(1, "enter\n");

    /* try instance binding first */
    node_name = qemu_devtree_get_node_name(fdti->fdt, node_path);
    DB_PRINT_NP(1, "node with name: %s\n", node_name ? node_name : "(none)");
    if (!node_name) {
        printf("FDT: ERROR: nameless node: %s\n", node_path);
    }
    if (!fdt_init_inst_bind(node_path, fdti, node_name)) {
        DB_PRINT_NP(0, "instance bind successful\n");
        goto exit;
    }

    /* fallback to compatibility binding */
    all_compats = qemu_fdt_getprop(fdti->fdt, node_path, "compatible",
                                   &compat_len, false, NULL);
    if (!all_compats) {
        DB_PRINT_NP(0, "no compatibility found\n");
    }

    for (compat = all_compats; compat && compat_len; compat = next_compat+1) {
        char *compat_prefixed = g_strdup_printf("compatible:%s", compat);
        if (!fdt_init_compat(node_path, fdti, compat_prefixed)) {
            goto exit;
        }
        g_free(compat_prefixed);
        if (!fdt_init_qdev(node_path, fdti, compat)) {
            goto exit;
        }
        next_compat = rawmemchr(compat, '\0');
        compat_len -= (next_compat + 1 - compat);
        if (compat_len > 0) {
            *next_compat = ' ';
        }
    }

    device_type = qemu_fdt_getprop(fdti->fdt, node_path,
                                   "device_type", NULL, false, NULL);
    device_type = g_strdup_printf("device_type:%s", device_type);
    if (!fdt_init_compat(node_path, fdti, device_type)) {
        goto exit;
    }

    if (!all_compats) {
        goto exit;
    }
    DB_PRINT_NP(0, "FDT: Unsupported peripheral invalidated - "
                "compatibilities %s\n", all_compats);
    qemu_fdt_setprop_string(fdti->fdt, node_path, "compatible", "invalidated");
exit:

    DB_PRINT_NP(1, "exit\n");

    if (!fdt_init_has_opaque(fdti, node_path)) {
        fdt_init_set_opaque(fdti, node_path, NULL);
    }
    g_free(node_path);
    g_free(all_compats);
    return;
}