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
/*