On Wed, Jul 16, 2025 at 11:53:49AM +0200, Luc Michel wrote: > Refactor the GEM ethernet controllers creation using the VersalMap > structure. > > Note that the connection to the CRL is removed for now and will be > re-added by next commits. > > Signed-off-by: Luc Michel <luc.mic...@amd.com>
Reviewed-by: Francisco Iglesias <francisco.igles...@amd.com> > --- > include/hw/arm/xlnx-versal.h | 3 - > hw/arm/xlnx-versal-virt.c | 54 ------------- > hw/arm/xlnx-versal.c | 151 +++++++++++++++++++++++++---------- > 3 files changed, 108 insertions(+), 100 deletions(-) > > diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h > index 4a7a2d85aac..1fcc2b623da 100644 > --- a/include/hw/arm/xlnx-versal.h > +++ b/include/hw/arm/xlnx-versal.h > @@ -16,11 +16,10 @@ > #include "hw/sysbus.h" > #include "hw/cpu/cluster.h" > #include "hw/or-irq.h" > #include "hw/intc/arm_gicv3.h" > #include "hw/dma/xlnx-zdma.h" > -#include "hw/net/cadence_gem.h" > #include "hw/rtc/xlnx-zynqmp-rtc.h" > #include "qom/object.h" > #include "hw/usb/xlnx-usb-subsystem.h" > #include "hw/misc/xlnx-versal-xramc.h" > #include "hw/nvram/xlnx-bbram.h" > @@ -76,12 +75,10 @@ struct Versal { > > struct { > MemoryRegion mr_ocm; > > struct { > - CadenceGEMState gem[XLNX_VERSAL_NR_GEMS]; > - OrIRQState gem_irq_orgate[XLNX_VERSAL_NR_GEMS]; > XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS]; > VersalUsb2 usb; > } iou; > > /* Real-time Processing Unit. */ > diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c > index 99ce84d5a46..09f87dc76dd 100644 > --- a/hw/arm/xlnx-versal-virt.c > +++ b/hw/arm/xlnx-versal-virt.c > @@ -36,11 +36,10 @@ struct VersalVirt { > > void *fdt; > int fdt_size; > struct { > uint32_t gic; > - uint32_t ethernet_phy[2]; > uint32_t clk_125Mhz; > uint32_t clk_25Mhz; > uint32_t usb; > uint32_t dwc; > } phandle; > @@ -55,23 +54,19 @@ struct VersalVirt { > }; > > static void fdt_create(VersalVirt *s) > { > MachineClass *mc = MACHINE_GET_CLASS(s); > - int i; > > s->fdt = create_device_tree(&s->fdt_size); > if (!s->fdt) { > error_report("create_device_tree() failed"); > exit(1); > } > > /* Allocate all phandles. */ > s->phandle.gic = qemu_fdt_alloc_phandle(s->fdt); > - for (i = 0; i < ARRAY_SIZE(s->phandle.ethernet_phy); i++) { > - s->phandle.ethernet_phy[i] = qemu_fdt_alloc_phandle(s->fdt); > - } > s->phandle.clk_25Mhz = qemu_fdt_alloc_phandle(s->fdt); > s->phandle.clk_125Mhz = qemu_fdt_alloc_phandle(s->fdt); > > s->phandle.usb = qemu_fdt_alloc_phandle(s->fdt); > s->phandle.dwc = qemu_fdt_alloc_phandle(s->fdt); > @@ -207,58 +202,10 @@ static void fdt_add_usb_xhci_nodes(VersalVirt *s) > qemu_fdt_setprop_cell(s->fdt, name, "phandle", s->phandle.dwc); > qemu_fdt_setprop_string(s->fdt, name, "maximum-speed", "high-speed"); > g_free(name); > } > > -static void fdt_add_fixed_link_nodes(VersalVirt *s, char *gemname, > - uint32_t phandle) > -{ > - char *name = g_strdup_printf("%s/fixed-link", gemname); > - > - qemu_fdt_add_subnode(s->fdt, name); > - qemu_fdt_setprop_cell(s->fdt, name, "phandle", phandle); > - qemu_fdt_setprop(s->fdt, name, "full-duplex", NULL, 0); > - qemu_fdt_setprop_cell(s->fdt, name, "speed", 1000); > - g_free(name); > -} > - > -static void fdt_add_gem_nodes(VersalVirt *s) > -{ > - uint64_t addrs[] = { MM_GEM1, MM_GEM0 }; > - unsigned int irqs[] = { VERSAL_GEM1_IRQ_0, VERSAL_GEM0_IRQ_0 }; > - const char clocknames[] = "pclk\0hclk\0tx_clk\0rx_clk"; > - const char compat_gem[] = "cdns,zynqmp-gem\0cdns,gem"; > - int i; > - > - for (i = 0; i < ARRAY_SIZE(addrs); i++) { > - char *name = g_strdup_printf("/ethernet@%" PRIx64, addrs[i]); > - qemu_fdt_add_subnode(s->fdt, name); > - > - fdt_add_fixed_link_nodes(s, name, s->phandle.ethernet_phy[i]); > - qemu_fdt_setprop_string(s->fdt, name, "phy-mode", "rgmii-id"); > - qemu_fdt_setprop_cell(s->fdt, name, "phy-handle", > - s->phandle.ethernet_phy[i]); > - qemu_fdt_setprop_cells(s->fdt, name, "clocks", > - s->phandle.clk_25Mhz, s->phandle.clk_25Mhz, > - s->phandle.clk_125Mhz, s->phandle.clk_125Mhz); > - qemu_fdt_setprop(s->fdt, name, "clock-names", > - clocknames, sizeof(clocknames)); > - qemu_fdt_setprop_cells(s->fdt, name, "interrupts", > - GIC_FDT_IRQ_TYPE_SPI, irqs[i], > - GIC_FDT_IRQ_FLAGS_LEVEL_HI, > - GIC_FDT_IRQ_TYPE_SPI, irqs[i], > - GIC_FDT_IRQ_FLAGS_LEVEL_HI); > - qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", > - 2, addrs[i], 2, 0x1000); > - qemu_fdt_setprop(s->fdt, name, "compatible", > - compat_gem, sizeof(compat_gem)); > - qemu_fdt_setprop_cell(s->fdt, name, "#address-cells", 1); > - qemu_fdt_setprop_cell(s->fdt, name, "#size-cells", 0); > - g_free(name); > - } > -} > - > static void fdt_add_zdma_nodes(VersalVirt *s) > { > const char clocknames[] = "clk_main\0clk_apb"; > const char compat[] = "xlnx,zynqmp-dma-1.0"; > int i; > @@ -607,11 +554,10 @@ static void versal_virt_init(MachineState *machine) > &error_abort); > } > > fdt_create(s); > versal_set_fdt(&s->soc, s->fdt); > - fdt_add_gem_nodes(s); > fdt_add_gic_nodes(s); > fdt_add_timer_nodes(s); > fdt_add_zdma_nodes(s); > fdt_add_usb_xhci_nodes(s); > fdt_add_rtc_node(s); > diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c > index b963a05935b..062f9a91a6c 100644 > --- a/hw/arm/xlnx-versal.c > +++ b/hw/arm/xlnx-versal.c > @@ -27,10 +27,11 @@ > #include "system/device_tree.h" > #include "hw/arm/fdt.h" > #include "hw/char/pl011.h" > #include "hw/net/xlnx-versal-canfd.h" > #include "hw/sd/sdhci.h" > +#include "hw/net/cadence_gem.h" > > #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72") > #define XLNX_VERSAL_RCPU_TYPE ARM_CPU_TYPE_NAME("cortex-r5f") > #define GEM_REVISION 0x40070106 > > @@ -49,10 +50,18 @@ typedef struct VersalMap { > VersalSimplePeriphMap canfd[4]; > size_t num_canfd; > > VersalSimplePeriphMap sdhci[2]; > size_t num_sdhci; > + > + struct VersalGemMap { > + VersalSimplePeriphMap map; > + size_t num_prio_queue; > + const char *phy_mode; > + const uint32_t speed; > + } gem[3]; > + size_t num_gem; > } VersalMap; > > static const VersalMap VERSAL_MAP = { > .uart[0] = { 0xff000000, 18 }, > .uart[1] = { 0xff010000, 19 }, > @@ -63,10 +72,14 @@ static const VersalMap VERSAL_MAP = { > .num_canfd = 2, > > .sdhci[0] = { 0xf1040000, 126 }, > .sdhci[1] = { 0xf1050000, 128 }, > .num_sdhci = 2, > + > + .gem[0] = { { 0xff0c0000, 56 }, 2, "rgmii-id", 1000 }, > + .gem[1] = { { 0xff0d0000, 58 }, 2, "rgmii-id", 1000 }, > + .num_gem = 2, > }; > > static const VersalMap *VERSION_TO_MAP[] = { > [VERSAL_VER_VERSAL] = &VERSAL_MAP, > }; > @@ -109,10 +122,22 @@ static void versal_sysbus_connect_irq(Versal *s, > SysBusDevice *sbd, > } > > sysbus_connect_irq(sbd, sbd_idx, irq); > } > > +static void versal_qdev_connect_gpio_out(Versal *s, DeviceState *dev, > + int dev_idx, int irq_idx) > +{ > + qemu_irq irq = versal_get_irq(s, irq_idx); > + > + if (irq == NULL) { > + return; > + } > + > + qdev_connect_gpio_out(dev, dev_idx, irq); > +} > + > static inline char *versal_fdt_add_subnode(Versal *s, const char *path, > uint64_t at, const char *compat, > size_t compat_sz) > { > char *p; > @@ -138,10 +163,25 @@ static inline char > *versal_fdt_add_simple_subnode(Versal *s, const char *path, > > qemu_fdt_setprop_sized_cells(s->cfg.fdt, p, "reg", 2, addr, 2, len); > return p; > } > > +static inline DeviceState *create_or_gate(Versal *s, Object *parent, > + const char *name, uint16_t > num_lines, > + int irq_idx) > +{ > + DeviceState *or; > + > + or = qdev_new(TYPE_OR_IRQ); > + qdev_prop_set_uint16(or, "num-lines", num_lines); > + object_property_add_child(parent, name, OBJECT(or)); > + qdev_realize_and_unref(or, NULL, &error_abort); > + versal_qdev_connect_gpio_out(s, or, 0, irq_idx); > + > + return or; > +} > + > static void versal_create_apu_cpus(Versal *s) > { > int i; > > object_initialize_child(OBJECT(s), "apu-cluster", &s->fpd.apu.cluster, > @@ -375,50 +415,80 @@ static void versal_create_usbs(Versal *s, qemu_irq *pic) > > mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); > memory_region_add_subregion(&s->mr_ps, MM_USB2_CTRL_REGS, mr); > } > > -static void versal_create_gems(Versal *s, qemu_irq *pic) > +static void versal_create_gem(Versal *s, > + const struct VersalGemMap *map) > { > + DeviceState *dev; > + MemoryRegion *mr; > + DeviceState *or; > int i; > + g_autofree char *node; > + g_autofree char *phy_node; > + int phy_phandle; > + const char compatible[] = "cdns,zynqmp-gem\0cdns,gem"; > + const char clocknames[] = "pclk\0hclk\0tx_clk\0rx_clk"; > + g_autofree uint32_t *irq_prop; > > - for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) { > - static const int irqs[] = { VERSAL_GEM0_IRQ_0, VERSAL_GEM1_IRQ_0}; > - static const uint64_t addrs[] = { MM_GEM0, MM_GEM1 }; > - char *name = g_strdup_printf("gem%d", i); > - DeviceState *dev; > - MemoryRegion *mr; > - OrIRQState *or_irq; > - > - object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i], > - TYPE_CADENCE_GEM); > - or_irq = &s->lpd.iou.gem_irq_orgate[i]; > - object_initialize_child(OBJECT(s), "gem-irq-orgate[*]", > - or_irq, TYPE_OR_IRQ); > - dev = DEVICE(&s->lpd.iou.gem[i]); > - qemu_configure_nic_device(dev, true, NULL); > - object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); > - object_property_set_int(OBJECT(dev), "num-priority-queues", 2, > - &error_abort); > - object_property_set_int(OBJECT(or_irq), > - "num-lines", 2, &error_fatal); > - qdev_realize(DEVICE(or_irq), NULL, &error_fatal); > - qdev_connect_gpio_out(DEVICE(or_irq), 0, pic[irqs[i]]); > - > - object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps), > - &error_abort); > - sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); > - > - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); > - memory_region_add_subregion(&s->mr_ps, addrs[i], mr); > - > - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, > qdev_get_gpio_in(DEVICE(or_irq), 0)); > - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, > qdev_get_gpio_in(DEVICE(or_irq), 1)); > - g_free(name); > + dev = qdev_new(TYPE_CADENCE_GEM); > + object_property_add_child(OBJECT(s), "gem[*]", OBJECT(dev)); > + > + qemu_configure_nic_device(dev, true, NULL); > + object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); > + object_property_set_int(OBJECT(dev), "num-priority-queues", > + map->num_prio_queue, &error_abort); > + > + object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps), > + &error_abort); > + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); > + > + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); > + memory_region_add_subregion(&s->mr_ps, map->map.addr, mr); > + > + /* > + * The GEM controller exposes one IRQ line per priority queue. In Versal > + * family devices, those are OR'ed together. > + */ > + or = create_or_gate(s, OBJECT(dev), "irq-orgate", > + map->num_prio_queue, map->map.irq); > + > + for (i = 0; i < map->num_prio_queue; i++) { > + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, qdev_get_gpio_in(or, i)); > + } > + > + node = versal_fdt_add_simple_subnode(s, "/ethernet", map->map.addr, > 0x1000, > + compatible, sizeof(compatible)); > + phy_node = g_strdup_printf("%s/fixed-link", node); > + phy_phandle = qemu_fdt_alloc_phandle(s->cfg.fdt); > + > + /* Fixed link PHY node */ > + qemu_fdt_add_subnode(s->cfg.fdt, phy_node); > + qemu_fdt_setprop_cell(s->cfg.fdt, phy_node, "phandle", phy_phandle); > + qemu_fdt_setprop(s->cfg.fdt, phy_node, "full-duplex", NULL, 0); > + qemu_fdt_setprop_cell(s->cfg.fdt, phy_node, "speed", map->speed); > + > + qemu_fdt_setprop_string(s->cfg.fdt, node, "phy-mode", map->phy_mode); > + qemu_fdt_setprop_cell(s->cfg.fdt, node, "phy-handle", phy_phandle); > + qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks", > + s->phandle.clk_25mhz, s->phandle.clk_25mhz, > + s->phandle.clk_125mhz, s->phandle.clk_125mhz); > + qemu_fdt_setprop(s->cfg.fdt, node, "clock-names", > + clocknames, sizeof(clocknames)); > + > + irq_prop = g_new(uint32_t, map->num_prio_queue * 3); > + for (i = 0; i < map->num_prio_queue; i++) { > + irq_prop[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI); > + irq_prop[3 * i + 1] = cpu_to_be32(map->map.irq); > + irq_prop[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); > } > + qemu_fdt_setprop(s->cfg.fdt, node, "interrupts", irq_prop, > + sizeof(uint32_t) * map->num_prio_queue * 3); > } > > + > static void versal_create_admas(Versal *s, qemu_irq *pic) > { > int i; > > for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) { > @@ -900,18 +970,10 @@ static void versal_create_crl(Versal *s, qemu_irq *pic) > object_property_set_link(OBJECT(&s->lpd.crl), > name, OBJECT(&s->lpd.rpu.cpu[i]), > &error_abort); > } > > - for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) { > - g_autofree gchar *name = g_strdup_printf("gem[%d]", i); > - > - object_property_set_link(OBJECT(&s->lpd.crl), > - name, OBJECT(&s->lpd.iou.gem[i]), > - &error_abort); > - } > - > for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) { > g_autofree gchar *name = g_strdup_printf("adma[%d]", i); > > object_property_set_link(OBJECT(&s->lpd.crl), > name, OBJECT(&s->lpd.iou.adma[i]), > @@ -1095,12 +1157,15 @@ static void versal_realize(DeviceState *dev, Error > **errp) > > for (i = 0; i < map->num_sdhci; i++) { > versal_create_sdhci(s, &map->sdhci[i]); > } > > + for (i = 0; i < map->num_gem; i++) { > + versal_create_gem(s, &map->gem[i]); > + } > + > versal_create_usbs(s, pic); > - versal_create_gems(s, pic); > versal_create_admas(s, pic); > versal_create_pmc_apb_irq_orgate(s, pic); > versal_create_rtc(s, pic); > versal_create_trng(s, pic); > versal_create_xrams(s, pic); > -- > 2.50.0 >