From: Ruslan Ruslichenko <[email protected]> Add a mechanism to defer device initialization until after the main FDT traversal.
This introduces a deferred queue in FDTMachineInfo. Devices in this queue are processed in fdt_init_deferred(), which handles their realization, reset registration, and resource parsing (interrupts and memory regions). This allows resolving initialization where devices need to be realized on latest stages or outside of co-routine context. Signed-off-by: Ruslan Ruslichenko <[email protected]> --- hw/core/fdt_generic_util.c | 45 +++++++++++++++++++++++++++++++++++ include/hw/core/fdt_generic.h | 8 +++++++ 2 files changed, 53 insertions(+) diff --git a/hw/core/fdt_generic_util.c b/hw/core/fdt_generic_util.c index c58a9ccdc7..4ed9602d47 100644 --- a/hw/core/fdt_generic_util.c +++ b/hw/core/fdt_generic_util.c @@ -99,6 +99,11 @@ static bool qemu_irq_shared_or_handler(bool *inputs, int n) return false; } +static void fdt_parse_node_reg_prop(FDTMachineInfo *fdti, char *node_path, + Object *dev); +static void fdt_parse_node_irq_prop(FDTMachineInfo *fdti, char *node_path, + Object *dev); + static void qemu_irq_shared_handler(void *opaque, int n, int level) { QEMUIRQSharedState *s = opaque; @@ -168,6 +173,45 @@ static void fdt_init_cpu_clusters(FDTMachineInfo *fdti) } } +static void fdt_init_deferred(FDTMachineInfo *fdti) +{ + while (fdti->deferred) { + FDTDeferredNode *dnode = fdti->deferred; + DeviceClass *dc = DEVICE_GET_CLASS(dnode->dev); + int length = 0; + + int offset = fdt_path_offset(fdti->fdt, dnode->node_path); + if (offset < 0) { + error_report("%s Couldn't find node %s: %s", __func__, + dnode->node_path, fdt_strerror(offset)); + } + const char *blockdev = fdt_stringlist_get(fdti->fdt, offset, + "blockdev-node-name", 0, &length); + + DB_PRINT(0, "FDT: Deferred realize node: %s\n", + dnode->node_path); + + if (blockdev && object_property_find(OBJECT(dnode->dev), "drive")) { + fdt_attach_blockdev(fdti, dnode->node_path, OBJECT(dnode->dev)); + } + + object_property_set_bool(OBJECT(dnode->dev), "realized", true, + &error_fatal); + if (dc->legacy_reset) { + qemu_register_reset((void (*)(void *))dc->legacy_reset, + dnode->dev); + } + + fdt_parse_node_reg_prop(fdti, dnode->node_path, OBJECT(dnode->dev)); + + fdt_parse_node_irq_prop(fdti, dnode->node_path, OBJECT(dnode->dev)); + + fdti->deferred = dnode->next; + g_free(dnode->node_path); + g_free(dnode); + } +} + FDTMachineInfo *fdt_generic_create_machine(void *fdt, qemu_irq *cpu_irq) { char node_path[DT_PATH_LENGTH]; @@ -183,6 +227,7 @@ FDTMachineInfo *fdt_generic_create_machine(void *fdt, qemu_irq *cpu_irq) while (qemu_co_enter_next(fdti->cq, NULL)) { ; } + fdt_init_deferred(fdti); fdt_init_cpu_clusters(fdti); fdt_init_all_irqs(fdti); memory_region_transaction_commit(); diff --git a/include/hw/core/fdt_generic.h b/include/hw/core/fdt_generic.h index ad9e249156..dc2d7a8876 100644 --- a/include/hw/core/fdt_generic.h +++ b/include/hw/core/fdt_generic.h @@ -34,6 +34,12 @@ typedef struct FDTIRQConnection { void *next; } FDTIRQConnection; +typedef struct FDTDeferredNode { + DeviceState *dev; + char *node_path; + void *next; +} FDTDeferredNode; + typedef struct FDTMachineInfo { /* the fdt blob */ void *fdt; @@ -47,6 +53,8 @@ typedef struct FDTMachineInfo { FDTIRQConnection *irqs; /* list of all CPU clusters */ FDTCPUCluster *clusters; + /* list of devices for deferred init */ + FDTDeferredNode *deferred; } FDTMachineInfo; /* -- 2.43.0
