Commit 05c19438 authored by David Gibson's avatar David Gibson Committed by Alexander Graf
Browse files

pseries: Emit device tree nodes in reg order



Although in theory the device tree has no inherent ordering, in practice
the order of nodes in the device tree does effect the order that devices
are detected by software.

Currently the ordering is determined by the order the devices appear on
the QEMU command line. Although that does give the user control over the
ordering, it is fragile, especially when the user does not generate the
command line manually - eg. when using libvirt etc.

So order the device tree based on the reg value, ie. the address of on
the VIO bus of the devices. This gives us a sane and stable ordering.

Signed-off-by: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>

[agraf] add braces
parent 6e806cc3
Loading
Loading
Loading
Loading
+45 −5
Original line number Diff line number Diff line
@@ -736,21 +736,61 @@ static void spapr_vio_register_devices(void)
device_init(spapr_vio_register_devices)

#ifdef CONFIG_FDT
static int compare_reg(const void *p1, const void *p2)
{
    VIOsPAPRDevice const *dev1, *dev2;

    dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
    dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;

    if (dev1->reg < dev2->reg) {
        return -1;
    }
    if (dev1->reg == dev2->reg) {
        return 0;
    }

    /* dev1->reg > dev2->reg */
    return 1;
}

int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
{
    DeviceState *qdev;
    int ret = 0;
    DeviceState *qdev, **qdevs;
    int i, num, ret = 0;

    /* Count qdevs on the bus list */
    num = 0;
    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
        num++;
    }

    /* Copy out into an array of pointers */
    qdevs = g_malloc(sizeof(qdev) * num);
    num = 0;
    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
        qdevs[num++] = qdev;
    }

    /* Sort the array */
    qsort(qdevs, num, sizeof(qdev), compare_reg);

    /* Hack alert. Give the devices to libfdt in reverse order, we happen
     * to know that will mean they are in forward order in the tree. */
    for (i = num - 1; i >= 0; i--) {
        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);

        ret = vio_make_devnode(dev, fdt);

        if (ret < 0) {
            return ret;
            goto out;
        }
    }

    return 0;
    ret = 0;
out:
    free(qdevs);

    return ret;
}
#endif /* CONFIG_FDT */