@samitouri / QOSamiQemu / commits / 2b85bfa1f0

hw/arm/virt: Advertise GICv5 in the DTB

Advertise the GICv5 in the DTB. This binding is final as it is in the upstream Linux kernel as: Documentation/devicetree/bindings/interrupt-controller/arm,gic-v5.yaml Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260327111700.795099-62-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC 2b85bfa1f07cf3a8fe8d5884d81ac10e1ddec4dd
1 file changed +68
hw/arm/virt.c
+68
@@ -1120,6 +1120,72 @@ static void create_v2m(VirtMachineState *vms)
1120 vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
1121 }
1122
1123 +static void fdt_add_gicv5_node(VirtMachineState *vms)
1124 +{
1125 + MachineState *ms = MACHINE(vms);
1126 + const char *nodename = "/intc";
1127 + g_autofree char *irsnodename = NULL;
1128 + g_autofree uint32_t *cpu_phandles = g_new(uint32_t, ms->smp.cpus);
1129 + g_autofree uint16_t *iaffids = g_new(uint16_t, ms->smp.cpus);
1130 +
1131 + vms->gic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
1132 + qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", vms->gic_phandle);
1133 +
1134 + qemu_fdt_add_subnode(ms->fdt, nodename);
1135 + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", vms->gic_phandle);
1136 + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "arm,gic-v5");
1137 + qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
1138 + qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
1139 + qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
1140 + qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
1141 + qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
1142 +
1143 + /* The IRS node is a child of the top level /intc node */
1144 + irsnodename = g_strdup_printf("%s/irs@%" PRIx64,
1145 + nodename,
1146 + vms->memmap[VIRT_GICV5_IRS_NS].base);
1147 + qemu_fdt_add_subnode(ms->fdt, irsnodename);
1148 + qemu_fdt_setprop_string(ms->fdt, irsnodename, "compatible",
1149 + "arm,gic-v5-irs");
1150 + /*
1151 + * "reg-names" describes the frames whose address/size is in "reg";
1152 + * at the moment we have only the NS config register frame.
1153 + */
1154 + qemu_fdt_setprop_string(ms->fdt, irsnodename, "reg-names", "ns-config");
1155 + qemu_fdt_setprop_sized_cells(ms->fdt, irsnodename, "reg",
1156 + 2, vms->memmap[VIRT_GICV5_IRS_NS].base,
1157 + 2, vms->memmap[VIRT_GICV5_IRS_NS].size);
1158 + qemu_fdt_setprop_cell(ms->fdt, irsnodename, "#address-cells", 0x2);
1159 + qemu_fdt_setprop_cell(ms->fdt, irsnodename, "#size-cells", 0x2);
1160 + qemu_fdt_setprop(ms->fdt, irsnodename, "ranges", NULL, 0);
1161 +
1162 + /*
1163 + * The "cpus" property is an array of phandles to the CPUs, and
1164 + * "iaffids" is an array of uint16 IAFFIDs. For virt, our IAFFIDs
1165 + * are the CPU indexes. This function is called after
1166 + * fdt_add_cpu_nodes(), which allocates the cpu_phandles array.
1167 + */
1168 + assert(vms->cpu_phandles);
1169 + for (int i = 0; i < ms->smp.cpus; i++) {
1170 + /*
1171 + * We have to byteswap each element here because we're setting the
1172 + * whole property value at once as a lump of raw data, not via a
1173 + * helper like qemu_fdt_setprop_cell() that does the swapping for us.
1174 + */
1175 + cpu_phandles[i] = cpu_to_be32(vms->cpu_phandles[i]);
1176 + iaffids[i] = cpu_to_be16(i);
1177 + }
1178 + qemu_fdt_setprop(ms->fdt, irsnodename, "cpus", cpu_phandles,
1179 + ms->smp.cpus * sizeof(*cpu_phandles));
1180 + qemu_fdt_setprop(ms->fdt, irsnodename, "arm,iaffids", iaffids,
1181 + ms->smp.cpus * sizeof(*iaffids));
1182 +
1183 + /*
1184 + * When we implement the GICv5 IRS, it gets a DTB node which is a
1185 + * child of the IRS node.
1186 + */
1187 +}
1188 +
1189 static void create_gicv5(VirtMachineState *vms, MemoryRegion *mem)
1190 {
1191 MachineState *ms = MACHINE(vms);
@@ -1161,6 +1227,8 @@ static void create_gicv5(VirtMachineState *vms, MemoryRegion *mem)
1227 * that information is communicated directly between a GICv5 IRS and
1228 * the GICv5 CPU interface via our equivalent of the stream protocol.
1229 */
1230 +
1231 + fdt_add_gicv5_node(vms);
1232 }
1233
1234 /*