"Edgar E. Iglesias" edgar.iglesias@amd.com writes:
Signed-off-by: Edgar E. Iglesias edgar.iglesias@amd.com
hw/misc/Kconfig | 7 + hw/misc/meson.build | 1 + hw/misc/virtio-msg-amp-pci.c | 324 +++++++++++++++++++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 hw/misc/virtio-msg-amp-pci.c
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 4e35657468..53124f5c9b 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -25,6 +25,13 @@ config PCI_TESTDEV default y if TEST_DEVICES depends on PCI +config VIRTIO_MSG_AMP_PCI
- bool
- default y if PCI_DEVICES
- depends on PCI
- select VIRTIO
- select VIRTIO_MSG
config EDU bool default y if TEST_DEVICES diff --git a/hw/misc/meson.build b/hw/misc/meson.build index b1d8d8e5d2..80d4886808 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -8,6 +8,7 @@ system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) system_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) system_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) system_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) +system_ss.add(when: 'CONFIG_VIRTIO_MSG_AMP_PCI', if_true: files('virtio-msg-amp-pci.c')) # ARM devices system_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) diff --git a/hw/misc/virtio-msg-amp-pci.c b/hw/misc/virtio-msg-amp-pci.c new file mode 100644 index 0000000000..6926da848c --- /dev/null +++ b/hw/misc/virtio-msg-amp-pci.c @@ -0,0 +1,324 @@ +/*
- Model of a virtio-msg AMP capable PCI device.
- Copyright (C) 2025 Advanced Micro Devices, Inc.
- Written by Edgar E. Iglesias edgar.iglesias@amd.com
- SPDX-License-Identifier: GPL-2.0-or-later
- */
+#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/log.h"
+#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/pci/pci_device.h" +#include "hw/pci/msix.h" +#include "hw/sysbus.h" +#include "hw/register.h"
+#include "hw/virtio/virtio-msg.h" +#include "hw/virtio/virtio-msg-bus.h" +#include "hw/virtio/spsc_queue.h"
This is missing from the patch set.
+#define TYPE_VMSG_AMP_PCI "virtio-msg-amp-pci" +OBJECT_DECLARE_SIMPLE_TYPE(VmsgAmpPciState, VMSG_AMP_PCI)
+#define TYPE_VMSG_BUS_AMP_PCI "virtio-msg-bus-amp-pci" +OBJECT_DECLARE_SIMPLE_TYPE(VmsgBusAmpPciState, VMSG_BUS_AMP_PCI) +#define VMSG_BUS_AMP_PCI_GET_PARENT_CLASS(obj) \
OBJECT_GET_PARENT_CLASS(obj, TYPE_VMSG_BUS_AMP_PCI)+REG32(VERSION, 0x00) +REG32(FEATURES, 0x04) +REG32(NOTIFY, 0x20)
+#define MAX_FIFOS 1
+typedef struct VmsgBusAmpPciState {
- VirtIOMSGBusDevice parent;
- PCIDevice *pcidev;
- unsigned int queue_index;
- struct {
void *va;spsc_queue driver;spsc_queue device;unsigned int mapcount;- } shm;
+} VmsgBusAmpPciState;
+typedef struct VmsgAmpPciState {
- PCIDevice dev;
- MemoryRegion mr_mmio;
- MemoryRegion mr_ram;
- struct fifo_bus {
VmsgBusAmpPciState dev;VirtIOMSGProxy proxy;BusState bus;- } fifo[MAX_FIFOS];
- struct {
uint32_t num_fifos;- } cfg;
+} VmsgAmpPciState;
+static void vmsg_bus_amp_pci_process(VirtIOMSGBusDevice *bd);
+static uint64_t vmsg_read(void *opaque, hwaddr addr, unsigned int size) +{
- uint64_t r = 0;
- assert(size == 4);
- switch (addr) {
- case A_VERSION:
/* v0.1 */r = 0x0001;break;- case A_FEATURES:
/* No features bit yet. */break;- default:
break;- }
- return r;
+}
+static void vmsg_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)+{
- VmsgAmpPciState *s = VMSG_AMP_PCI(opaque);
- VmsgBusAmpPciState *dev;
- unsigned int q;
- assert(size == 4);
- if (addr >= A_NOTIFY) {
q = (addr - A_NOTIFY) / 4;dev = &s->fifo[q].dev;vmsg_bus_amp_pci_process(VIRTIO_MSG_BUS_DEVICE(dev));- } else {
qemu_log_mask(LOG_GUEST_ERROR,"%s: write to read-only reg 0x%" HWADDR_PRIx "\n",__func__, addr);- }
+}
+static const MemoryRegionOps vmsg_pci_ops = {
- .read = vmsg_read,
- .write = vmsg_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
.min_access_size = 4,.max_access_size = 4,- },
+};
+static void vmsg_create_bus(VmsgAmpPciState *s, unsigned int i) +{
- DeviceState *dev = DEVICE(s);
- Object *o = OBJECT(s);
- struct fifo_bus *fifo = &s->fifo[i];
- g_autofree char *name = g_strdup_printf("vmsg.%d", i);
- qbus_init(&fifo->bus, sizeof(fifo->bus), TYPE_SYSTEM_BUS, dev, name);
- /* Create the proxy. */
- object_initialize_child(o, "proxy[*]", &fifo->proxy, TYPE_VIRTIO_MSG);
- qdev_realize(DEVICE(&fifo->proxy), &fifo->bus, &error_fatal);
- object_initialize_child(o, "dev[*]", &fifo->dev,
TYPE_VMSG_BUS_AMP_PCI);- qdev_realize(DEVICE(&fifo->dev), &fifo->proxy.msg_bus, &error_fatal);
- msix_vector_use(PCI_DEVICE(s), i);
- /* Caches for quick lookup. */
- fifo->dev.queue_index = i;
- fifo->dev.pcidev = PCI_DEVICE(s);
+}
+static void vmsg_amp_pci_realizefn(PCIDevice *dev, Error **errp) +{
- VmsgAmpPciState *s = VMSG_AMP_PCI(dev);
- int i;
- if (!s->cfg.num_fifos || s->cfg.num_fifos > MAX_FIFOS) {
error_setg(errp, "Unsupported number of FIFOs (%u)", s->cfg.num_fifos);- }
- memory_region_init_io(&s->mr_mmio, OBJECT(s), &vmsg_pci_ops, s,
TYPE_VMSG_AMP_PCI, 16 * KiB);- /* 16KB per FIFO. */
- memory_region_init_ram(&s->mr_ram, OBJECT(s), "ram",
s->cfg.num_fifos * 16 * KiB, &error_fatal);- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mr_mmio);
- pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_PREFETCH,&s->mr_ram);- msix_init_exclusive_bar(PCI_DEVICE(s), s->cfg.num_fifos, 2, &error_fatal);
- for (i = 0; i < s->cfg.num_fifos; i++) {
vmsg_create_bus(s, i);- }
+}
+static const Property vmsg_properties[] = {
- DEFINE_PROP_UINT32("num-fifos", VmsgAmpPciState, cfg.num_fifos, 1),
+};
+static const VMStateDescription vmstate_vmsg_pci = {
- .name = TYPE_VMSG_AMP_PCI,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, VmsgAmpPciState),/* TODO: Add all the sub-devs. */VMSTATE_END_OF_LIST()- }
+};
+static void vmsg_amp_pci_class_init(ObjectClass *klass, const void *data) +{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
- device_class_set_props(dc, vmsg_properties);
- pc->realize = vmsg_amp_pci_realizefn;
- pc->vendor_id = PCI_VENDOR_ID_XILINX;
- pc->device_id = 0x9039;
- pc->revision = 1;
- pc->class_id = PCI_CLASS_SYSTEM_OTHER;
- dc->vmsd = &vmstate_vmsg_pci;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+static bool vmsg_bus_amp_pci_map_fifo(VmsgBusAmpPciState *s) +{
- VmsgAmpPciState *pci_s = VMSG_AMP_PCI(s->pcidev);
- void *va;
- if (s->shm.mapcount) {
s->shm.mapcount++;return true;- }
- va = memory_region_get_ram_ptr(&pci_s->mr_ram);
- if (!va) {
return false;- }
- if (!s->shm.driver.shm) {
int capacity = spsc_capacity(4 * KiB);/** Layout:* 0 - 4KB Reserved* 4KB - 8KB Driver queue* 8KB - 12KB Device queue*/spsc_init(&s->shm.driver, "driver", capacity, va + 4 * KiB);spsc_init(&s->shm.device, "device", capacity, va + 8 * KiB);- }
- /* Map queues. */
- s->shm.va = va;
- s->shm.mapcount++;
- return true;
+}
+static void vmsg_bus_amp_pci_unmap_fifo(VmsgBusAmpPciState *s) +{
- assert(s->shm.mapcount);
- if (--s->shm.mapcount) {
return;- }
- /* TODO: Actually unmap. */
+}
+static void vmsg_bus_amp_pci_process(VirtIOMSGBusDevice *bd) +{
- VmsgBusAmpPciState *s = VMSG_BUS_AMP_PCI(bd);
- spsc_queue *q;
- VirtIOMSG msg;
- bool r;
- if (!vmsg_bus_amp_pci_map_fifo(s)) {
return;- }
- /*
* We process the opposite queue, i.e, a driver will want to receive* messages on the backend queue (and send messages on the driver queue).*/- q = bd->peer->is_driver ? &s->shm.device : &s->shm.driver;
- do {
r = spsc_recv(q, &msg, sizeof msg);if (r) {virtio_msg_bus_receive(bd, &msg);}- } while (r);
- vmsg_bus_amp_pci_unmap_fifo(s);
+}
+static int vmsg_bus_amp_pci_send(VirtIOMSGBusDevice *bd, VirtIOMSG *msg_req) +{
- VmsgAmpPciState *pci_s = VMSG_AMP_PCI(OBJECT(bd)->parent);
- VmsgBusAmpPciState *s = VMSG_BUS_AMP_PCI(bd);
- if (!vmsg_bus_amp_pci_map_fifo(s)) {
return VIRTIO_MSG_ERROR_MEMORY;- }
- spsc_send(&s->shm.device, msg_req, sizeof *msg_req);
- /* Notify. */
- msix_notify(PCI_DEVICE(pci_s), s->queue_index);
- vmsg_bus_amp_pci_unmap_fifo(s);
- return VIRTIO_MSG_NO_ERROR;
+}
+static void vmsg_bus_amp_pci_class_init(ObjectClass *klass,
const void *data)+{
- VirtIOMSGBusDeviceClass *bdc = VIRTIO_MSG_BUS_DEVICE_CLASS(klass);
- bdc->process = vmsg_bus_amp_pci_process;
- bdc->send = vmsg_bus_amp_pci_send;
+}
+static const TypeInfo vmsg_pci_info[] = {
- {
.name = TYPE_VMSG_AMP_PCI,.parent = TYPE_PCI_DEVICE,.instance_size = sizeof(VmsgAmpPciState),.class_init = vmsg_amp_pci_class_init,.interfaces = (const InterfaceInfo[]) {{ INTERFACE_CONVENTIONAL_PCI_DEVICE },{ }},- }, {
.name = TYPE_VMSG_BUS_AMP_PCI,.parent = TYPE_VIRTIO_MSG_BUS_DEVICE,.instance_size = sizeof(VmsgBusAmpPciState),.class_init = vmsg_bus_amp_pci_class_init,- },
+};
+static void vmsg_pci_register_types(void) +{
- type_register_static_array(vmsg_pci_info, ARRAY_SIZE(vmsg_pci_info));
+}
+type_init(vmsg_pci_register_types);