* [PATCH 0/4] Add emulation of MEN Chameleon Hardware
@ 2023-03-29 8:45 Johannes Thumshirn
2023-03-29 8:45 ` [PATCH 1/4] Add MEN Chameleon Bus emulation Johannes Thumshirn
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Johannes Thumshirn @ 2023-03-29 8:45 UTC (permalink / raw)
To: qemu-devel
Cc: Alistair Francis, Javier Rodriguez, Dmitry Fomichev,
Johannes Thumshirn
Add emulation of MEN Chameleon Hardware to Qemu.
This emulation is specifically designed to test the upstream Linux kernel
drivers when one has no access to the hardware.
The emulation consists of the bus itself, a PCI hardware target creating the
bus, MEN Micro Electronic's 8250 based UART via MCB and a watchdog timer.
Johannes Thumshirn (4):
Add MEN Chameleon Bus emulation
Add MEN Chameleon Bus via PCI carrier
serial-mcb: Add serial via MEN chameleon bus
wdt_z069: Add support for MEN 16z069 Watchdog
MAINTAINERS | 6 +
hw/Kconfig | 1 +
hw/char/Kconfig | 6 +
hw/char/meson.build | 1 +
hw/char/serial-mcb.c | 115 +++++++++++++++
hw/mcb/Kconfig | 8 ++
hw/mcb/mcb-pci.c | 307 ++++++++++++++++++++++++++++++++++++++++
hw/mcb/mcb.c | 182 ++++++++++++++++++++++++
hw/mcb/meson.build | 2 +
hw/meson.build | 1 +
hw/watchdog/Kconfig | 5 +
hw/watchdog/meson.build | 1 +
hw/watchdog/wdt_z069.c | 218 ++++++++++++++++++++++++++++
include/hw/mcb/mcb.h | 106 ++++++++++++++
14 files changed, 959 insertions(+)
create mode 100644 hw/char/serial-mcb.c
create mode 100644 hw/mcb/Kconfig
create mode 100644 hw/mcb/mcb-pci.c
create mode 100644 hw/mcb/mcb.c
create mode 100644 hw/mcb/meson.build
create mode 100644 hw/watchdog/wdt_z069.c
create mode 100644 include/hw/mcb/mcb.h
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/4] Add MEN Chameleon Bus emulation
2023-03-29 8:45 [PATCH 0/4] Add emulation of MEN Chameleon Hardware Johannes Thumshirn
@ 2023-03-29 8:45 ` Johannes Thumshirn
2023-04-05 9:09 ` Alistair Francis
2023-03-29 8:45 ` [PATCH 2/4] Add MEN Chameleon Bus via PCI carrier Johannes Thumshirn
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Johannes Thumshirn @ 2023-03-29 8:45 UTC (permalink / raw)
To: qemu-devel
Cc: Alistair Francis, Javier Rodriguez, Dmitry Fomichev,
Johannes Thumshirn
The MEN Chameleon Bus (MCB) is an on-chip bus system exposing IP Cores of an
FPGA to a outside bus system like PCIe.
Signed-off-by: Johannes Thumshirn <jth@kernel.org>
---
MAINTAINERS | 6 ++
hw/Kconfig | 1 +
hw/mcb/Kconfig | 2 +
hw/mcb/mcb.c | 182 +++++++++++++++++++++++++++++++++++++++++++
hw/mcb/meson.build | 1 +
hw/meson.build | 1 +
include/hw/mcb/mcb.h | 106 +++++++++++++++++++++++++
7 files changed, 299 insertions(+)
create mode 100644 hw/mcb/Kconfig
create mode 100644 hw/mcb/mcb.c
create mode 100644 hw/mcb/meson.build
create mode 100644 include/hw/mcb/mcb.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 98cb2d64cf..badec8abdd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1947,6 +1947,12 @@ R: Paolo Bonzini <pbonzini@redhat.com>
S: Odd Fixes
F: hw/char/
+MEN Chameleon Bus
+M: Johannes Thumshirn <jth@kernel.org>
+S: Maintained
+F: hw/mcb/
+F: include/hw/mcb/
+
Network devices
M: Jason Wang <jasowang@redhat.com>
S: Odd Fixes
diff --git a/hw/Kconfig b/hw/Kconfig
index ba62ff6417..f5ef84b10b 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -18,6 +18,7 @@ source intc/Kconfig
source ipack/Kconfig
source ipmi/Kconfig
source isa/Kconfig
+source mcb/Kconfig
source mem/Kconfig
source misc/Kconfig
source net/Kconfig
diff --git a/hw/mcb/Kconfig b/hw/mcb/Kconfig
new file mode 100644
index 0000000000..36a7a583a8
--- /dev/null
+++ b/hw/mcb/Kconfig
@@ -0,0 +1,2 @@
+config MCB
+ bool
diff --git a/hw/mcb/mcb.c b/hw/mcb/mcb.c
new file mode 100644
index 0000000000..f2bf722de5
--- /dev/null
+++ b/hw/mcb/mcb.c
@@ -0,0 +1,182 @@
+/*
+ * QEMU MEN Chameleon Bus emulation
+ *
+ * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/mcb/mcb.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+ChameleonDeviceDescriptor *mcb_new_chameleon_descriptor(MCBus *bus, uint8_t id,
+ uint8_t rev,
+ uint8_t var,
+ uint32_t size)
+{
+ BusChild *kid;
+ ChameleonDeviceDescriptor *gdd;
+ uint32_t reg1 = 0;
+ uint32_t offset = 0x200;
+ uint32_t end = 0;
+
+ gdd = g_new0(ChameleonDeviceDescriptor, 1);
+ if (!gdd) {
+ return NULL;
+ }
+
+ reg1 |= GDD_DEV(id);
+ reg1 |= GDD_DTY(CHAMELEON_DTYPE_GENERAL);
+ reg1 |= GDD_REV(rev);
+ reg1 |= GDD_VAR(var);
+ gdd->reg1 = cpu_to_le32(reg1);
+
+ QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
+ DeviceState *qdev = kid->child;
+ MCBDevice *mdev = MCB_DEVICE(qdev);
+
+ if (mdev->gdd) {
+ offset = mdev->gdd->offset;
+ end = offset + mdev->gdd->size;
+ }
+ }
+
+ gdd->offset = offset + end;
+ gdd->size = size;
+
+ return gdd;
+}
+
+static void mcb_irq_handler(void *opaque, int irq_num, int level)
+{
+ MCBDevice *dev = opaque;
+ MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(dev)));
+
+ if (bus->set_irq) {
+ bus->set_irq(dev, irq_num, level);
+ }
+}
+
+qemu_irq mcb_allocate_irq(MCBDevice *dev)
+{
+ int irq = 0;
+ return qemu_allocate_irq(mcb_irq_handler, dev, irq);
+}
+
+MCBDevice *mcb_device_find(MCBus *bus, hwaddr addr)
+{
+ BusChild *kid;
+ uint32_t start;
+ uint32_t end;
+
+ QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
+ DeviceState *qdev = kid->child;
+ MCBDevice *mdev = MCB_DEVICE(qdev);
+
+ start = mdev->gdd->offset;
+ end = start + mdev->gdd->size;
+
+ if (addr >= start && addr <= end) {
+ return mdev;
+ }
+ }
+ return NULL;
+}
+
+void mcb_bus_init(MCBus *bus, size_t bus_size,
+ DeviceState *parent,
+ uint8_t n_slots,
+ qemu_irq_handler handler)
+{
+ qbus_init(bus, bus_size, TYPE_MCB_BUS, parent, NULL);
+ bus->n_slots = n_slots;
+ bus->set_irq = handler;
+}
+
+static void mcb_device_realize(DeviceState *dev, Error **errp)
+{
+ MCBDevice *mdev = MCB_DEVICE(dev);
+ MCBus *bus = MCB_BUS(qdev_get_parent_bus(dev));
+ MCBDeviceClass *k = MCB_DEVICE_GET_CLASS(dev);
+
+ if (mdev->slot < 0) {
+ mdev->slot = bus->free_slot;
+ }
+
+ if (mdev->slot >= bus->n_slots) {
+ error_setg(errp, "Only %" PRIu8 " slots available.", bus->n_slots);
+ return;
+ }
+ bus->free_slot = mdev->slot + 1;
+
+ mdev->irq = qemu_allocate_irqs(bus->set_irq, mdev, 1);
+
+ k->realize(dev, errp);
+}
+
+static void mcb_device_unrealize(DeviceState *dev)
+{
+ MCBDevice *mdev = MCB_DEVICE(dev);
+ MCBDeviceClass *k = MCB_DEVICE_GET_CLASS(dev);
+
+ if (k->unrealize) {
+ k->unrealize(dev);
+ return;
+ }
+
+ qemu_free_irqs(mdev->irq, 1);
+}
+
+static Property mcb_device_props[] = {
+ DEFINE_PROP_INT32("slot", MCBDevice, slot, -1),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void mcb_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_INPUT, k->categories);
+ k->bus_type = TYPE_MCB_BUS;
+ k->realize = mcb_device_realize;
+ k->unrealize = mcb_device_unrealize;
+ device_class_set_props(k, mcb_device_props);
+}
+
+const VMStateDescription vmstate_mcb_device = {
+ .name = "mcb_device",
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(slot, MCBDevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const TypeInfo mcb_device_info = {
+ .name = TYPE_MCB_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(MCBDevice),
+ .class_size = sizeof(MCBDeviceClass),
+ .class_init = mcb_device_class_init,
+ .abstract = true,
+};
+
+static const TypeInfo mcb_bus_info = {
+ .name = TYPE_MCB_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(MCBus),
+};
+
+static void mcb_register_types(void)
+{
+ type_register_static(&mcb_device_info);
+ type_register_static(&mcb_bus_info);
+}
+
+type_init(mcb_register_types);
diff --git a/hw/mcb/meson.build b/hw/mcb/meson.build
new file mode 100644
index 0000000000..a385edc07c
--- /dev/null
+++ b/hw/mcb/meson.build
@@ -0,0 +1 @@
+softmmu_ss.add(when: 'CONFIG_MCB', if_true: files('mcb.c'))
diff --git a/hw/meson.build b/hw/meson.build
index c7ac7d3d75..3d1462ad8b 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -18,6 +18,7 @@ subdir('intc')
subdir('ipack')
subdir('ipmi')
subdir('isa')
+subdir('mcb')
subdir('mem')
subdir('misc')
subdir('net')
diff --git a/include/hw/mcb/mcb.h b/include/hw/mcb/mcb.h
new file mode 100644
index 0000000000..ff120073e1
--- /dev/null
+++ b/include/hw/mcb/mcb.h
@@ -0,0 +1,106 @@
+/*
+ * QEMU MEN Chameleon Bus emulation
+ *
+ * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_MCB_H
+#define QEMU_MCB_H
+
+#include "hw/qdev-core.h"
+#include "qom/object.h"
+#include "exec/memory.h"
+
+#define CHAMELEON_DTYPE_GENERAL 0x0
+#define CHAMELEON_DTYPE_END 0xf
+
+typedef struct {
+ uint32_t reg1;
+ uint32_t reg2;
+ uint32_t offset;
+ uint32_t size;
+} ChameleonDeviceDescriptor;
+
+#define GDD_DEV(x) (((x) & 0x3ff) << 18)
+#define GDD_DTY(x) (((x) & 0xf) << 28)
+#define GDD_REV(x) (((x) & 0x3f) << 5)
+#define GDD_VAR(x) (((x) & 0x3f) << 11)
+
+/* GDD Register 1 fields */
+#define GDD_IRQ(x) ((x) & 0x1f)
+
+/* GDD Register 2 fields */
+#define GDD_BAR(x) ((x) & 0x7)
+#define GDD_INS(x) (((x) >> 3) & 0x3f)
+#define GDD_GRP(x) (((x) >> 9) & 0x3f)
+
+typedef struct MCBus MCBus;
+
+#define TYPE_MCB_BUS "MEN Chameleon Bus"
+OBJECT_DECLARE_SIMPLE_TYPE(MCBus, MCB_BUS)
+
+struct MCBus {
+ /*< private >*/
+ BusState parent_obj;
+
+ uint8_t n_slots;
+ uint8_t free_slot;
+ qemu_irq_handler set_irq;
+ MemoryRegion mmio_region;
+};
+
+typedef struct MCBDevice MCBDevice;
+typedef struct MCBDeviceClass MCBDeviceClass;
+
+#define TYPE_MCB_DEVICE "mcb-device"
+#define MCB_DEVICE(obj) \
+ OBJECT_CHECK(MCBDevice, (obj), TYPE_MCB_DEVICE)
+#define MCB_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MCBDeviceClass, (klass), TYPE_MCB_DEVICE)
+#define MCB_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MCBDeviceClass, (obj), TYPE_MCB_DEVICE)
+
+struct MCBDeviceClass {
+ /*< private >*/
+ DeviceClass parent_class;
+ /*< public >*/
+
+
+ DeviceRealize realize;
+ DeviceUnrealize unrealize;
+};
+
+struct MCBDevice {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+
+ qemu_irq *irq;
+ ChameleonDeviceDescriptor *gdd;
+ int slot;
+
+ uint8_t rev;
+ uint8_t var;
+};
+
+extern const VMStateDescription vmstate_mcb_device;
+
+ChameleonDeviceDescriptor *mcb_new_chameleon_descriptor(MCBus *bus, uint8_t id,
+ uint8_t rev,
+ uint8_t var,
+ uint32_t size);
+
+#define VMSTATE_MCB_DEVICE(_field, _state) \
+ VMSTATE_STRUCT(_field, _state, 1, vmstate_mcb_device, MCBDevice)
+
+MCBDevice *mcb_device_find(MCBus *bus, hwaddr addr);
+void mcb_bus_init(MCBus *bus, size_t bus_size,
+ DeviceState *parent,
+ uint8_t n_slots,
+ qemu_irq_handler handler);
+
+qemu_irq mcb_allocate_irq(MCBDevice *dev);
+#endif
--
2.39.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/4] Add MEN Chameleon Bus via PCI carrier
2023-03-29 8:45 [PATCH 0/4] Add emulation of MEN Chameleon Hardware Johannes Thumshirn
2023-03-29 8:45 ` [PATCH 1/4] Add MEN Chameleon Bus emulation Johannes Thumshirn
@ 2023-03-29 8:45 ` Johannes Thumshirn
2023-04-05 6:29 ` Alistair Francis
2023-03-29 8:45 ` [PATCH 3/4] serial-mcb: Add serial via MEN chameleon bus Johannes Thumshirn
2023-03-29 8:45 ` [PATCH 4/4] wdt_z069: Add support for MEN 16z069 Watchdog Johannes Thumshirn
3 siblings, 1 reply; 8+ messages in thread
From: Johannes Thumshirn @ 2023-03-29 8:45 UTC (permalink / raw)
To: qemu-devel
Cc: Alistair Francis, Javier Rodriguez, Dmitry Fomichev,
Johannes Thumshirn
Add PCI based MEN Chameleon Bus carrier emulation.
Signed-off-by: Johannes Thumshirn <jth@kernel.org>
---
hw/mcb/Kconfig | 6 +
hw/mcb/mcb-pci.c | 307 +++++++++++++++++++++++++++++++++++++++++++++
hw/mcb/meson.build | 1 +
3 files changed, 314 insertions(+)
create mode 100644 hw/mcb/mcb-pci.c
diff --git a/hw/mcb/Kconfig b/hw/mcb/Kconfig
index 36a7a583a8..7deb96c2fe 100644
--- a/hw/mcb/Kconfig
+++ b/hw/mcb/Kconfig
@@ -1,2 +1,8 @@
config MCB
bool
+
+config MCB_PCI
+ bool
+ default y if PCI_DEVICES
+ depends on PCI
+ select MCB
diff --git a/hw/mcb/mcb-pci.c b/hw/mcb/mcb-pci.c
new file mode 100644
index 0000000000..442e65e24c
--- /dev/null
+++ b/hw/mcb/mcb-pci.c
@@ -0,0 +1,307 @@
+/*
+ * QEMU MEN Chameleon Bus emulation
+ *
+ * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/mcb/mcb.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_device.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+/* #define DEBUG_MPCI 1 */
+
+#ifdef DEBUG_MPCI
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "mcb-pci: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct {
+ uint8_t revision;
+ char model;
+ uint8_t minor;
+ uint8_t bus_type;
+ uint16_t magic;
+ uint16_t reserved;
+ /* This one has no '\0' at the end!!! */
+ char filename[12];
+} ChameleonFPGAHeader;
+#define CHAMELEON_BUS_TYPE_WISHBONE 0
+#define CHAMELEONV2_MAGIC 0xabce
+
+typedef struct {
+ PCIDevice dev;
+ MCBus bus;
+ MemoryRegion ctbl;
+ uint16_t status;
+ uint8_t int_set;
+ ChameleonFPGAHeader *header;
+
+ uint8_t minor;
+ uint8_t rev;
+ uint8_t model;
+} MPCIState;
+
+#define TYPE_MCB_PCI "mcb-pci"
+
+#define MPCI(obj) \
+ OBJECT_CHECK(MPCIState, (obj), TYPE_MCB_PCI)
+
+#define CHAMELEON_TABLE_SIZE 0x200
+#define N_MODULES 32
+
+#define PCI_VENDOR_ID_MEN 0x1a88
+#define PCI_DEVICE_ID_MEN_MCBPCI 0x4d45
+
+static uint32_t read_header(MPCIState *s, hwaddr addr)
+{
+ uint32_t ret = 0;
+ ChameleonFPGAHeader *header = s->header;
+
+ switch (addr >> 2) {
+ case 0:
+ ret |= header->revision;
+ ret |= header->model << 8;
+ ret |= header->minor << 16;
+ ret |= header->bus_type << 24;
+ break;
+ case 1:
+ ret |= header->magic;
+ ret |= header->reserved << 16;
+ break;
+ case 2:
+ memcpy(&ret, header->filename, sizeof(uint32_t));
+ break;
+ case 3:
+ memcpy(&ret, header->filename + sizeof(uint32_t),
+ sizeof(uint32_t));
+ break;
+ case 4:
+ memcpy(&ret, header->filename + 2 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ }
+
+ return ret;
+}
+
+static uint32_t read_gdd(MCBDevice *mdev, int reg)
+{
+ ChameleonDeviceDescriptor *gdd;
+ uint32_t ret = 0;
+
+ gdd = mdev->gdd;
+
+ switch (reg) {
+ case 0:
+ ret = gdd->reg1;
+ break;
+ case 1:
+ ret = gdd->reg2;
+ break;
+ case 2:
+ ret = gdd->offset;
+ break;
+ case 3:
+ ret = gdd->size;
+ break;
+ }
+
+ return ret;
+}
+
+static uint64_t mpci_chamtbl_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MPCIState *s = opaque;
+ MCBus *bus = &s->bus;
+ MCBDevice *mdev;
+ uint32_t ret = 0;
+
+ DPRINTF("Read from address 0x%lx size %d\n", addr, size);
+
+ if (addr < sizeof(ChameleonFPGAHeader)) {
+ return le32_to_cpu(read_header(s, addr));
+ } else if (addr >= sizeof(ChameleonFPGAHeader) &&
+ addr < CHAMELEON_TABLE_SIZE) {
+ /* Handle read on chameleon table */
+ BusChild *kid;
+ DeviceState *qdev;
+ int slot;
+ int offset;
+ int i;
+
+ offset = addr - sizeof(ChameleonFPGAHeader);
+ slot = offset / sizeof(ChameleonDeviceDescriptor);
+
+ kid = QTAILQ_FIRST(&BUS(bus)->children);
+ for (i = 0; i < slot; i++) {
+ kid = QTAILQ_NEXT(kid, sibling);
+ if (!kid) { /* Last element */
+ DPRINTF("Last element: 0x%08x\n", ~0U);
+ return ~0U;
+ }
+ }
+ qdev = kid->child;
+ mdev = MCB_DEVICE(qdev);
+ offset -= slot * 16;
+
+ ret = read_gdd(mdev, offset / 4);
+ return le32_to_cpu(ret);
+ }
+
+ return ret;
+}
+
+static void mpci_chamtbl_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+
+ if (addr < CHAMELEON_TABLE_SIZE)
+ DPRINTF("Invalid write to 0x%x: 0x%x\n", (unsigned) addr,
+ (unsigned) val);
+
+ return;
+}
+
+static const MemoryRegionOps mpci_chamtbl_ops = {
+ .read = mpci_chamtbl_read,
+ .write = mpci_chamtbl_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ },
+};
+
+static void mcb_pci_set_irq(void *opaque, int intno, int level)
+{
+ MCBDevice *mdev = opaque;
+ MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(mdev)));
+ PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
+ MPCIState *dev = MPCI(pcidev);
+
+ if (level) {
+ pci_set_irq(&dev->dev, !dev->int_set);
+ pci_set_irq(&dev->dev, dev->int_set);
+ } else {
+ uint16_t level_status = dev->status;
+
+ if (level_status && !dev->int_set) {
+ pci_irq_assert(&dev->dev);
+ dev->int_set = 1;
+ } else if (!level_status && dev->int_set) {
+ pci_irq_deassert(&dev->dev);
+ dev->int_set = 0;
+ }
+ }
+}
+
+static void mcb_pci_write_config(PCIDevice *pci_dev, uint32_t address,
+ uint32_t val, int len)
+{
+ pci_default_write_config(pci_dev, address, val, len);
+}
+
+static void mcb_pci_realize(PCIDevice *pci_dev, Error **errp)
+{
+ MPCIState *s = MPCI(pci_dev);
+ uint8_t *pci_conf = s->dev.config;
+ ChameleonFPGAHeader *header;
+ MCBus *bus = &s->bus;
+
+ header = g_new0(ChameleonFPGAHeader, 1);
+
+ s->header = header;
+
+ header->revision = s->rev;
+ header->model = (char) s->model;
+ header->minor = s->minor;
+ header->bus_type = CHAMELEON_BUS_TYPE_WISHBONE;
+ header->magic = CHAMELEONV2_MAGIC;
+ memcpy(&header->filename, "QEMU MCB PCI", 12);
+
+ pci_dev->config_write = mcb_pci_write_config;
+ pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
+ pci_conf[PCI_COMMAND] = PCI_COMMAND_MEMORY;
+
+ mcb_bus_init(bus, sizeof(MCBus), DEVICE(pci_dev), N_MODULES, mcb_pci_set_irq);
+
+ memory_region_init(&bus->mmio_region, OBJECT(s), "mcb-pci.mmio",
+ 2048 * 1024);
+ memory_region_init_io(&s->ctbl, OBJECT(s), &mpci_chamtbl_ops,
+ s, "mpci_chamtbl_ops", CHAMELEON_TABLE_SIZE);
+ memory_region_add_subregion(&bus->mmio_region, 0, &s->ctbl);
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ &bus->mmio_region);
+
+}
+
+static void mcb_pci_unrealize(PCIDevice *pci_dev)
+{
+ MPCIState *s = MPCI(pci_dev);
+
+ g_free(s->header);
+ s->header = NULL;
+}
+
+static const VMStateDescription vmstate_mcb_pci = {
+ .name = "mcb-pci",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, MPCIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property mcb_pci_props[] = {
+ DEFINE_PROP_UINT8("revision", MPCIState, rev, 1),
+ DEFINE_PROP_UINT8("minor", MPCIState, minor, 0),
+ DEFINE_PROP_UINT8("model", MPCIState, model, 0x41),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mcb_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = mcb_pci_realize;
+ k->exit = mcb_pci_unrealize;
+ k->vendor_id = PCI_VENDOR_ID_MEN;
+ k->device_id = PCI_DEVICE_ID_MEN_MCBPCI;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->desc = "MEN Chameleon Bus over PCI";
+ dc->vmsd = &vmstate_mcb_pci;
+ device_class_set_props(dc, mcb_pci_props);
+}
+
+static const TypeInfo mcb_pci_info = {
+ .name = TYPE_MCB_PCI,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MPCIState),
+ .class_init = mcb_pci_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { }
+ },
+};
+
+static void mcb_pci_register_types(void)
+{
+ type_register(&mcb_pci_info);
+}
+type_init(mcb_pci_register_types);
diff --git a/hw/mcb/meson.build b/hw/mcb/meson.build
index a385edc07c..4e1a0f0cdb 100644
--- a/hw/mcb/meson.build
+++ b/hw/mcb/meson.build
@@ -1 +1,2 @@
softmmu_ss.add(when: 'CONFIG_MCB', if_true: files('mcb.c'))
+softmmu_ss.add(when: 'CONFIG_MCB_PCI', if_true: files('mcb-pci.c'))
--
2.39.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] serial-mcb: Add serial via MEN chameleon bus
2023-03-29 8:45 [PATCH 0/4] Add emulation of MEN Chameleon Hardware Johannes Thumshirn
2023-03-29 8:45 ` [PATCH 1/4] Add MEN Chameleon Bus emulation Johannes Thumshirn
2023-03-29 8:45 ` [PATCH 2/4] Add MEN Chameleon Bus via PCI carrier Johannes Thumshirn
@ 2023-03-29 8:45 ` Johannes Thumshirn
2023-04-05 8:32 ` Alistair Francis
2023-03-29 8:45 ` [PATCH 4/4] wdt_z069: Add support for MEN 16z069 Watchdog Johannes Thumshirn
3 siblings, 1 reply; 8+ messages in thread
From: Johannes Thumshirn @ 2023-03-29 8:45 UTC (permalink / raw)
To: qemu-devel
Cc: Alistair Francis, Javier Rodriguez, Dmitry Fomichev,
Johannes Thumshirn
Add MEN z125 UART over MEN Chameleon Bus emulation.
Signed-off-by: Johannes Thumshirn <jth@kernel.org>
---
hw/char/Kconfig | 6 +++
hw/char/meson.build | 1 +
hw/char/serial-mcb.c | 115 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 122 insertions(+)
create mode 100644 hw/char/serial-mcb.c
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 6b6cf2fc1d..9e8ebf1d3d 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -71,3 +71,9 @@ config GOLDFISH_TTY
config SHAKTI_UART
bool
+
+config SERIAL_MCB
+ bool
+ default y if MCB
+ depends on MCB
+ select SERIAL
diff --git a/hw/char/meson.build b/hw/char/meson.build
index e02c60dd54..d5893a142d 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -20,6 +20,7 @@ softmmu_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
softmmu_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c'))
softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
+softmmu_ss.add(when: 'CONFIG_SERIAL_MCB', if_true: files('serial-mcb.c'))
softmmu_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
diff --git a/hw/char/serial-mcb.c b/hw/char/serial-mcb.c
new file mode 100644
index 0000000000..7ca8a248ac
--- /dev/null
+++ b/hw/char/serial-mcb.c
@@ -0,0 +1,115 @@
+/*
+ * QEMU MEN 16z125 UART over MCB emulation
+ *
+ * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/char/serial.h"
+#include "hw/mcb/mcb.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "migration/vmstate.h"
+
+struct MCBSerialState {
+ MCBDevice dev;
+ SerialState state;
+};
+
+#define TYPE_MCB_SERIAL "mcb-serial"
+OBJECT_DECLARE_SIMPLE_TYPE(MCBSerialState, MCB_SERIAL)
+
+static void serial_mcb_realize(DeviceState *dev, Error **errp)
+{
+ MCBDevice *mdev = MCB_DEVICE(dev);
+ MCBSerialState *mss = DO_UPCAST(MCBSerialState, dev, mdev);
+ MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(dev)));
+ SerialState *s = &mss->state;
+
+ mdev->gdd = mcb_new_chameleon_descriptor(bus, 125, mdev->rev,
+ mdev->var, 0x10);
+ if (!mdev->gdd) {
+ return;
+ }
+
+ s->baudbase = 115200;
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ return;
+ }
+
+ s->irq = mcb_allocate_irq(&mss->dev);
+ memory_region_init_io(&s->io, OBJECT(mss), &serial_io_ops, s, "serial", 8);
+ memory_region_add_subregion(&bus->mmio_region, mdev->gdd->offset, &s->io);
+}
+
+static void serial_mcb_unrealize(DeviceState *dev)
+{
+ MCBDevice *mdev = MCB_DEVICE(dev);
+ MCBSerialState *mss = DO_UPCAST(MCBSerialState, dev, mdev);
+ SerialState *s = &mss->state;
+
+ qdev_unrealize(DEVICE(s));
+ qemu_free_irq(s->irq);
+ g_free(&mdev->gdd);
+}
+
+static const VMStateDescription vmstate_mcb_serial = {
+ .name = "mcb-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_MCB_DEVICE(dev, MCBSerialState),
+ VMSTATE_STRUCT(state, MCBSerialState, 0, vmstate_serial, SerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property serial_mcb_properties[] = {
+ DEFINE_PROP_UINT8("rev", MCBSerialState, dev.rev, 0),
+ DEFINE_PROP_UINT8("var", MCBSerialState, dev.var, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_mcb_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ MCBDeviceClass *mc = MCB_DEVICE_CLASS(klass);
+
+ mc->realize = serial_mcb_realize;
+ mc->unrealize = serial_mcb_unrealize;
+
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+ dc->desc = "MEN 16z125 UART over MCB";
+ dc->vmsd = &vmstate_mcb_serial;
+ device_class_set_props(dc, serial_mcb_properties);
+}
+
+static void serial_mcb_init(Object *o)
+{
+ MCBSerialState *mss = MCB_SERIAL(o);
+
+ object_initialize_child(o, "serial", &mss->state, TYPE_SERIAL);
+
+ qdev_alias_all_properties(DEVICE(&mss->state), o);
+}
+
+static const TypeInfo serial_mcb_info = {
+ .name = "mcb-serial",
+ .parent = TYPE_MCB_DEVICE,
+ .instance_size = sizeof(MCBSerialState),
+ .instance_init = serial_mcb_init,
+ .class_init = serial_mcb_class_initfn,
+};
+
+static void serial_mcb_register_types(void)
+{
+ type_register_static(&serial_mcb_info);
+}
+
+type_init(serial_mcb_register_types);
--
2.39.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/4] wdt_z069: Add support for MEN 16z069 Watchdog
2023-03-29 8:45 [PATCH 0/4] Add emulation of MEN Chameleon Hardware Johannes Thumshirn
` (2 preceding siblings ...)
2023-03-29 8:45 ` [PATCH 3/4] serial-mcb: Add serial via MEN chameleon bus Johannes Thumshirn
@ 2023-03-29 8:45 ` Johannes Thumshirn
3 siblings, 0 replies; 8+ messages in thread
From: Johannes Thumshirn @ 2023-03-29 8:45 UTC (permalink / raw)
To: qemu-devel
Cc: Alistair Francis, Javier Rodriguez, Dmitry Fomichev,
Johannes Thumshirn
Add 16z069 Watchdog over MEN Chameleon BUS emulation.
Signed-off-by: Johannes Thumshirn <jth@kernel.org>
---
hw/watchdog/Kconfig | 5 +
hw/watchdog/meson.build | 1 +
hw/watchdog/wdt_z069.c | 218 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 224 insertions(+)
create mode 100644 hw/watchdog/wdt_z069.c
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 66e1d029e3..a3f1196f66 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -20,3 +20,8 @@ config WDT_IMX2
config WDT_SBSA
bool
+
+config WDT_Z069
+ bool
+ default y if MCB
+ depends on MCB
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
index 8974b5cf4c..7bc353774e 100644
--- a/hw/watchdog/meson.build
+++ b/hw/watchdog/meson.build
@@ -6,4 +6,5 @@ softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
+softmmu_ss.add(when: 'CONFIG_WDT_Z069', if_true: files('wdt_z069.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
diff --git a/hw/watchdog/wdt_z069.c b/hw/watchdog/wdt_z069.c
new file mode 100644
index 0000000000..cb67519032
--- /dev/null
+++ b/hw/watchdog/wdt_z069.c
@@ -0,0 +1,218 @@
+/*
+ * QEMU MEN 16z069 Watchdog over MCB emulation
+ *
+ * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/timer.h"
+#include "sysemu/watchdog.h"
+#include "hw/mcb/mcb.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+
+/* #define Z069_DEBUG 1 */
+
+#ifdef Z069_DEBUG
+#define z069_debug(fmt, ...) \
+ fprintf(stderr, "wdt_z069: %s: "fmt, __func__, ##__VA_ARGS__)
+#else
+#define z069_debug(fmt, ...)
+#endif
+
+#define MEN_Z069_WTR 0x10
+#define MEN_Z069_WTR_WDEN BIT(15)
+#define MEN_Z069_WTR_WDET_MASK 0x7fff
+#define MEN_Z069_WVR 0x14
+
+#define CLK_500(x) ((x) * 2) /* 500Hz in ms */
+
+typedef struct {
+ /*< private >*/
+ MCBDevice dev;
+
+ /*< public >*/
+ QEMUTimer *timer;
+
+ bool enabled;
+ unsigned int timeout;
+
+ MemoryRegion mmio;
+
+ /* Registers */
+ uint16_t wtr;
+ uint16_t wvr;
+} MENZ069State;
+
+static void men_z069_wdt_enable(MENZ069State *s)
+{
+ z069_debug("next timeout will fire in +%dms\n", s->timeout);
+ timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->timeout);
+}
+
+static void men_z069_wdt_disable(MENZ069State *s)
+{
+ timer_del(s->timer);
+}
+
+static uint64_t men_z069_wdt_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MENZ069State *s = opaque;
+ uint64_t ret;
+
+ switch (addr) {
+ case MEN_Z069_WTR:
+ ret = s->wtr;
+ break;
+ case MEN_Z069_WVR:
+ ret = s->wvr;
+ break;
+ default:
+ ret = 0UL;
+ break;
+ }
+
+ z069_debug("returning: 0x%"PRIx64" @ 0x%lx\n", ret, addr);
+ return ret;
+}
+
+static void men_z069_wdt_write(void *opaque, hwaddr addr, uint64_t v,
+ unsigned size)
+{
+ MENZ069State *s = opaque;
+ bool old_ena = s->enabled;
+ uint16_t val = v & 0xffff;
+ uint16_t tout;
+
+ z069_debug("got: 0x%"PRIx64" @ 0x%lx\n", v, addr);
+
+ switch (addr) {
+ case MEN_Z069_WTR:
+ s->wtr = val;
+ tout = val & MEN_Z069_WTR_WDET_MASK;
+ s->timeout = CLK_500(tout);
+ s->enabled = val & MEN_Z069_WTR_WDEN;
+ z069_debug("new timeout: %u (0x%x) %u\n", tout, tout, s->timeout);
+
+ if (old_ena && !s->enabled) {
+ men_z069_wdt_disable(s);
+ } else if (!old_ena && s->enabled) {
+ men_z069_wdt_enable(s);
+ }
+
+ break;
+ case MEN_Z069_WVR:
+ /* The watchdog trigger value toggles between 0x5555 and 0xaaaa */
+ if (val == (s->wvr ^ 0xffff)) {
+ s->wvr = val;
+ z069_debug("watchdog triggered, next timeout will fire in +%dms\n",
+ s->timeout);
+ timer_mod(s->timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->timeout);
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static const MemoryRegionOps men_z069_io_ops = {
+ .read = men_z069_wdt_read,
+ .write = men_z069_wdt_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ },
+};
+
+static void men_z069_timer_expired(void *opaque)
+{
+ MENZ069State *s = opaque;
+
+ watchdog_perform_action();
+ timer_del(s->timer);
+}
+
+static void men_z069_wdt_realize(DeviceState *dev, Error **errp)
+{
+ MCBDevice *mdev = MCB_DEVICE(dev);
+ MENZ069State *s = DO_UPCAST(MENZ069State, dev, mdev);
+ MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(dev)));
+
+ mdev->gdd = mcb_new_chameleon_descriptor(bus, 69, mdev->rev,
+ mdev->var, 0x18);
+ if (!mdev->gdd) {
+ return;
+ }
+
+ s->wvr = 0x5555;
+ s->wtr = 0x7fff;
+ s->timeout = CLK_500(s->wtr & MEN_Z069_WTR_WDET_MASK);
+ s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ men_z069_timer_expired, s);
+
+ memory_region_init_io(&s->mmio, OBJECT(s),
+ &men_z069_io_ops, s, "z069.wdt", 0x16);
+ memory_region_add_subregion(&bus->mmio_region, mdev->gdd->offset,
+ &s->mmio);
+}
+
+static void men_z069_wdt_unrealize(DeviceState *dev)
+{
+ MCBDevice *mdev = MCB_DEVICE(dev);
+
+ g_free(&mdev->gdd);
+}
+
+static const VMStateDescription vmstate_z069_wdt = {
+ .name = "z069-wdt",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_MCB_DEVICE(dev, MENZ069State),
+ VMSTATE_TIMER_PTR(timer, MENZ069State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property men_z069_wdt_properties[] = {
+ DEFINE_PROP_UINT8("rev", MENZ069State, dev.rev, 0),
+ DEFINE_PROP_UINT8("var", MENZ069State, dev.var, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void men_z069_wdt_class_intifn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ MCBDeviceClass *mc = MCB_DEVICE_CLASS(klass);
+
+ mc->realize = men_z069_wdt_realize;
+ mc->unrealize = men_z069_wdt_unrealize;
+
+ dc->desc = "MEN 16z069 Watchdog Timer";
+ dc->vmsd = &vmstate_z069_wdt;
+ device_class_set_props(dc, men_z069_wdt_properties);
+}
+
+static const TypeInfo men_z069_wdt_info = {
+ .name = "z069-wdt",
+ .parent = TYPE_MCB_DEVICE,
+ .instance_size = sizeof(MENZ069State),
+ .class_init = men_z069_wdt_class_intifn,
+};
+
+static void men_z069_wdt_register_types(void)
+{
+ type_register_static(&men_z069_wdt_info);
+}
+
+type_init(men_z069_wdt_register_types);
--
2.39.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] Add MEN Chameleon Bus via PCI carrier
2023-03-29 8:45 ` [PATCH 2/4] Add MEN Chameleon Bus via PCI carrier Johannes Thumshirn
@ 2023-04-05 6:29 ` Alistair Francis
0 siblings, 0 replies; 8+ messages in thread
From: Alistair Francis @ 2023-04-05 6:29 UTC (permalink / raw)
To: Johannes Thumshirn
Cc: qemu-devel, Alistair Francis, Javier Rodriguez, Dmitry Fomichev
On Wed, Mar 29, 2023 at 11:09 PM Johannes Thumshirn <jth@kernel.org> wrote:
>
> Add PCI based MEN Chameleon Bus carrier emulation.
>
> Signed-off-by: Johannes Thumshirn <jth@kernel.org>
> ---
> hw/mcb/Kconfig | 6 +
> hw/mcb/mcb-pci.c | 307 +++++++++++++++++++++++++++++++++++++++++++++
> hw/mcb/meson.build | 1 +
> 3 files changed, 314 insertions(+)
> create mode 100644 hw/mcb/mcb-pci.c
>
> diff --git a/hw/mcb/Kconfig b/hw/mcb/Kconfig
> index 36a7a583a8..7deb96c2fe 100644
> --- a/hw/mcb/Kconfig
> +++ b/hw/mcb/Kconfig
> @@ -1,2 +1,8 @@
> config MCB
> bool
> +
> +config MCB_PCI
> + bool
> + default y if PCI_DEVICES
> + depends on PCI
> + select MCB
> diff --git a/hw/mcb/mcb-pci.c b/hw/mcb/mcb-pci.c
> new file mode 100644
> index 0000000000..442e65e24c
> --- /dev/null
> +++ b/hw/mcb/mcb-pci.c
> @@ -0,0 +1,307 @@
> +/*
> + * QEMU MEN Chameleon Bus emulation
> + *
> + * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/mcb/mcb.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pci_device.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +
> +/* #define DEBUG_MPCI 1 */
> +
> +#ifdef DEBUG_MPCI
> +#define DPRINTF(fmt, ...) \
> + do { fprintf(stderr, "mcb-pci: " fmt, ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) do { } while (0)
> +#endif
We don't use these #ifdefs for debug prints anymore in QEMU (at least
not in new code). It should be converted to the tracing architecture.
See https://qemu-project.gitlab.io/qemu/devel/tracing.html for user
documentation.
> +
> +typedef struct {
> + uint8_t revision;
> + char model;
> + uint8_t minor;
> + uint8_t bus_type;
> + uint16_t magic;
> + uint16_t reserved;
> + /* This one has no '\0' at the end!!! */
> + char filename[12];
> +} ChameleonFPGAHeader;
> +#define CHAMELEON_BUS_TYPE_WISHBONE 0
> +#define CHAMELEONV2_MAGIC 0xabce
> +
> +typedef struct {
> + PCIDevice dev;
> + MCBus bus;
> + MemoryRegion ctbl;
> + uint16_t status;
> + uint8_t int_set;
> + ChameleonFPGAHeader *header;
> +
> + uint8_t minor;
> + uint8_t rev;
> + uint8_t model;
> +} MPCIState;
> +
> +#define TYPE_MCB_PCI "mcb-pci"
> +
> +#define MPCI(obj) \
> + OBJECT_CHECK(MPCIState, (obj), TYPE_MCB_PCI)
> +
> +#define CHAMELEON_TABLE_SIZE 0x200
> +#define N_MODULES 32
> +
> +#define PCI_VENDOR_ID_MEN 0x1a88
> +#define PCI_DEVICE_ID_MEN_MCBPCI 0x4d45
> +
> +static uint32_t read_header(MPCIState *s, hwaddr addr)
> +{
> + uint32_t ret = 0;
> + ChameleonFPGAHeader *header = s->header;
> +
> + switch (addr >> 2) {
> + case 0:
> + ret |= header->revision;
> + ret |= header->model << 8;
> + ret |= header->minor << 16;
> + ret |= header->bus_type << 24;
> + break;
> + case 1:
> + ret |= header->magic;
> + ret |= header->reserved << 16;
> + break;
> + case 2:
> + memcpy(&ret, header->filename, sizeof(uint32_t));
> + break;
> + case 3:
> + memcpy(&ret, header->filename + sizeof(uint32_t),
> + sizeof(uint32_t));
> + break;
> + case 4:
> + memcpy(&ret, header->filename + 2 * sizeof(uint32_t),
> + sizeof(uint32_t));
> + }
> +
> + return ret;
> +}
> +
> +static uint32_t read_gdd(MCBDevice *mdev, int reg)
> +{
> + ChameleonDeviceDescriptor *gdd;
> + uint32_t ret = 0;
> +
> + gdd = mdev->gdd;
> +
> + switch (reg) {
> + case 0:
> + ret = gdd->reg1;
> + break;
> + case 1:
> + ret = gdd->reg2;
> + break;
> + case 2:
> + ret = gdd->offset;
> + break;
> + case 3:
> + ret = gdd->size;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static uint64_t mpci_chamtbl_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + MPCIState *s = opaque;
> + MCBus *bus = &s->bus;
> + MCBDevice *mdev;
> + uint32_t ret = 0;
> +
> + DPRINTF("Read from address 0x%lx size %d\n", addr, size);
> +
> + if (addr < sizeof(ChameleonFPGAHeader)) {
> + return le32_to_cpu(read_header(s, addr));
I always thought you don't need the le32_to_cpu() as the
DEVICE_LITTLE_ENDIAN should handle this.
I do see other PCI devices with it though, so maybe it's a PCI thing
> + } else if (addr >= sizeof(ChameleonFPGAHeader) &&
> + addr < CHAMELEON_TABLE_SIZE) {
> + /* Handle read on chameleon table */
> + BusChild *kid;
> + DeviceState *qdev;
> + int slot;
> + int offset;
> + int i;
> +
> + offset = addr - sizeof(ChameleonFPGAHeader);
> + slot = offset / sizeof(ChameleonDeviceDescriptor);
> +
> + kid = QTAILQ_FIRST(&BUS(bus)->children);
> + for (i = 0; i < slot; i++) {
> + kid = QTAILQ_NEXT(kid, sibling);
> + if (!kid) { /* Last element */
> + DPRINTF("Last element: 0x%08x\n", ~0U);
> + return ~0U;
> + }
> + }
> + qdev = kid->child;
> + mdev = MCB_DEVICE(qdev);
> + offset -= slot * 16;
> +
> + ret = read_gdd(mdev, offset / 4);
> + return le32_to_cpu(ret);
> + }
> +
> + return ret;
ret isn't used here
> +}
> +
> +static void mpci_chamtbl_write(void *opaque, hwaddr addr, uint64_t val,
> + unsigned size)
> +{
> +
> + if (addr < CHAMELEON_TABLE_SIZE)
> + DPRINTF("Invalid write to 0x%x: 0x%x\n", (unsigned) addr,
> + (unsigned) val);
This isn't Linux, brackets are required :)
You can run checkpatch to catch these types of style issues.
Alistair
> +
> + return;
> +}
> +
> +static const MemoryRegionOps mpci_chamtbl_ops = {
> + .read = mpci_chamtbl_read,
> + .write = mpci_chamtbl_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 4
> + },
> + .impl = {
> + .min_access_size = 4,
> + .max_access_size = 4
> + },
> +};
> +
> +static void mcb_pci_set_irq(void *opaque, int intno, int level)
> +{
> + MCBDevice *mdev = opaque;
> + MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(mdev)));
> + PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
> + MPCIState *dev = MPCI(pcidev);
> +
> + if (level) {
> + pci_set_irq(&dev->dev, !dev->int_set);
> + pci_set_irq(&dev->dev, dev->int_set);
> + } else {
> + uint16_t level_status = dev->status;
> +
> + if (level_status && !dev->int_set) {
> + pci_irq_assert(&dev->dev);
> + dev->int_set = 1;
> + } else if (!level_status && dev->int_set) {
> + pci_irq_deassert(&dev->dev);
> + dev->int_set = 0;
> + }
> + }
> +}
> +
> +static void mcb_pci_write_config(PCIDevice *pci_dev, uint32_t address,
> + uint32_t val, int len)
> +{
> + pci_default_write_config(pci_dev, address, val, len);
> +}
> +
> +static void mcb_pci_realize(PCIDevice *pci_dev, Error **errp)
> +{
> + MPCIState *s = MPCI(pci_dev);
> + uint8_t *pci_conf = s->dev.config;
> + ChameleonFPGAHeader *header;
> + MCBus *bus = &s->bus;
> +
> + header = g_new0(ChameleonFPGAHeader, 1);
> +
> + s->header = header;
> +
> + header->revision = s->rev;
> + header->model = (char) s->model;
> + header->minor = s->minor;
> + header->bus_type = CHAMELEON_BUS_TYPE_WISHBONE;
> + header->magic = CHAMELEONV2_MAGIC;
> + memcpy(&header->filename, "QEMU MCB PCI", 12);
> +
> + pci_dev->config_write = mcb_pci_write_config;
> + pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
> + pci_conf[PCI_COMMAND] = PCI_COMMAND_MEMORY;
> +
> + mcb_bus_init(bus, sizeof(MCBus), DEVICE(pci_dev), N_MODULES, mcb_pci_set_irq);
> +
> + memory_region_init(&bus->mmio_region, OBJECT(s), "mcb-pci.mmio",
> + 2048 * 1024);
> + memory_region_init_io(&s->ctbl, OBJECT(s), &mpci_chamtbl_ops,
> + s, "mpci_chamtbl_ops", CHAMELEON_TABLE_SIZE);
> + memory_region_add_subregion(&bus->mmio_region, 0, &s->ctbl);
> + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
> + &bus->mmio_region);
> +
> +}
> +
> +static void mcb_pci_unrealize(PCIDevice *pci_dev)
> +{
> + MPCIState *s = MPCI(pci_dev);
> +
> + g_free(s->header);
> + s->header = NULL;
> +}
> +
> +static const VMStateDescription vmstate_mcb_pci = {
> + .name = "mcb-pci",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_PCI_DEVICE(dev, MPCIState),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static Property mcb_pci_props[] = {
> + DEFINE_PROP_UINT8("revision", MPCIState, rev, 1),
> + DEFINE_PROP_UINT8("minor", MPCIState, minor, 0),
> + DEFINE_PROP_UINT8("model", MPCIState, model, 0x41),
> + DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void mcb_pci_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> + k->realize = mcb_pci_realize;
> + k->exit = mcb_pci_unrealize;
> + k->vendor_id = PCI_VENDOR_ID_MEN;
> + k->device_id = PCI_DEVICE_ID_MEN_MCBPCI;
> + k->class_id = PCI_CLASS_BRIDGE_OTHER;
> +
> + set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> + dc->desc = "MEN Chameleon Bus over PCI";
> + dc->vmsd = &vmstate_mcb_pci;
> + device_class_set_props(dc, mcb_pci_props);
> +}
> +
> +static const TypeInfo mcb_pci_info = {
> + .name = TYPE_MCB_PCI,
> + .parent = TYPE_PCI_DEVICE,
> + .instance_size = sizeof(MPCIState),
> + .class_init = mcb_pci_class_init,
> + .interfaces = (InterfaceInfo[]) {
> + { INTERFACE_PCIE_DEVICE },
> + { }
> + },
> +};
> +
> +static void mcb_pci_register_types(void)
> +{
> + type_register(&mcb_pci_info);
> +}
> +type_init(mcb_pci_register_types);
> diff --git a/hw/mcb/meson.build b/hw/mcb/meson.build
> index a385edc07c..4e1a0f0cdb 100644
> --- a/hw/mcb/meson.build
> +++ b/hw/mcb/meson.build
> @@ -1 +1,2 @@
> softmmu_ss.add(when: 'CONFIG_MCB', if_true: files('mcb.c'))
> +softmmu_ss.add(when: 'CONFIG_MCB_PCI', if_true: files('mcb-pci.c'))
> --
> 2.39.2
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] serial-mcb: Add serial via MEN chameleon bus
2023-03-29 8:45 ` [PATCH 3/4] serial-mcb: Add serial via MEN chameleon bus Johannes Thumshirn
@ 2023-04-05 8:32 ` Alistair Francis
0 siblings, 0 replies; 8+ messages in thread
From: Alistair Francis @ 2023-04-05 8:32 UTC (permalink / raw)
To: Johannes Thumshirn
Cc: qemu-devel, Alistair Francis, Javier Rodriguez, Dmitry Fomichev
On Wed, Mar 29, 2023 at 11:09 PM Johannes Thumshirn <jth@kernel.org> wrote:
>
> Add MEN z125 UART over MEN Chameleon Bus emulation.
>
> Signed-off-by: Johannes Thumshirn <jth@kernel.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/char/Kconfig | 6 +++
> hw/char/meson.build | 1 +
> hw/char/serial-mcb.c | 115 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 122 insertions(+)
> create mode 100644 hw/char/serial-mcb.c
>
> diff --git a/hw/char/Kconfig b/hw/char/Kconfig
> index 6b6cf2fc1d..9e8ebf1d3d 100644
> --- a/hw/char/Kconfig
> +++ b/hw/char/Kconfig
> @@ -71,3 +71,9 @@ config GOLDFISH_TTY
>
> config SHAKTI_UART
> bool
> +
> +config SERIAL_MCB
> + bool
> + default y if MCB
> + depends on MCB
> + select SERIAL
> diff --git a/hw/char/meson.build b/hw/char/meson.build
> index e02c60dd54..d5893a142d 100644
> --- a/hw/char/meson.build
> +++ b/hw/char/meson.build
> @@ -20,6 +20,7 @@ softmmu_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
> softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
> softmmu_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c'))
> softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
> +softmmu_ss.add(when: 'CONFIG_SERIAL_MCB', if_true: files('serial-mcb.c'))
>
> softmmu_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
> softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
> diff --git a/hw/char/serial-mcb.c b/hw/char/serial-mcb.c
> new file mode 100644
> index 0000000000..7ca8a248ac
> --- /dev/null
> +++ b/hw/char/serial-mcb.c
> @@ -0,0 +1,115 @@
> +/*
> + * QEMU MEN 16z125 UART over MCB emulation
> + *
> + * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/module.h"
> +#include "hw/char/serial.h"
> +#include "hw/mcb/mcb.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/qdev-properties-system.h"
> +#include "migration/vmstate.h"
> +
> +struct MCBSerialState {
> + MCBDevice dev;
> + SerialState state;
> +};
> +
> +#define TYPE_MCB_SERIAL "mcb-serial"
> +OBJECT_DECLARE_SIMPLE_TYPE(MCBSerialState, MCB_SERIAL)
> +
> +static void serial_mcb_realize(DeviceState *dev, Error **errp)
> +{
> + MCBDevice *mdev = MCB_DEVICE(dev);
> + MCBSerialState *mss = DO_UPCAST(MCBSerialState, dev, mdev);
> + MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(dev)));
> + SerialState *s = &mss->state;
> +
> + mdev->gdd = mcb_new_chameleon_descriptor(bus, 125, mdev->rev,
> + mdev->var, 0x10);
> + if (!mdev->gdd) {
> + return;
> + }
> +
> + s->baudbase = 115200;
> + if (!qdev_realize(DEVICE(s), NULL, errp)) {
> + return;
> + }
> +
> + s->irq = mcb_allocate_irq(&mss->dev);
> + memory_region_init_io(&s->io, OBJECT(mss), &serial_io_ops, s, "serial", 8);
> + memory_region_add_subregion(&bus->mmio_region, mdev->gdd->offset, &s->io);
> +}
> +
> +static void serial_mcb_unrealize(DeviceState *dev)
> +{
> + MCBDevice *mdev = MCB_DEVICE(dev);
> + MCBSerialState *mss = DO_UPCAST(MCBSerialState, dev, mdev);
> + SerialState *s = &mss->state;
> +
> + qdev_unrealize(DEVICE(s));
> + qemu_free_irq(s->irq);
> + g_free(&mdev->gdd);
> +}
> +
> +static const VMStateDescription vmstate_mcb_serial = {
> + .name = "mcb-serial",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_MCB_DEVICE(dev, MCBSerialState),
> + VMSTATE_STRUCT(state, MCBSerialState, 0, vmstate_serial, SerialState),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static Property serial_mcb_properties[] = {
> + DEFINE_PROP_UINT8("rev", MCBSerialState, dev.rev, 0),
> + DEFINE_PROP_UINT8("var", MCBSerialState, dev.var, 0),
> + DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void serial_mcb_class_initfn(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + MCBDeviceClass *mc = MCB_DEVICE_CLASS(klass);
> +
> + mc->realize = serial_mcb_realize;
> + mc->unrealize = serial_mcb_unrealize;
> +
> + set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> + dc->desc = "MEN 16z125 UART over MCB";
> + dc->vmsd = &vmstate_mcb_serial;
> + device_class_set_props(dc, serial_mcb_properties);
> +}
> +
> +static void serial_mcb_init(Object *o)
> +{
> + MCBSerialState *mss = MCB_SERIAL(o);
> +
> + object_initialize_child(o, "serial", &mss->state, TYPE_SERIAL);
> +
> + qdev_alias_all_properties(DEVICE(&mss->state), o);
> +}
> +
> +static const TypeInfo serial_mcb_info = {
> + .name = "mcb-serial",
> + .parent = TYPE_MCB_DEVICE,
> + .instance_size = sizeof(MCBSerialState),
> + .instance_init = serial_mcb_init,
> + .class_init = serial_mcb_class_initfn,
> +};
> +
> +static void serial_mcb_register_types(void)
> +{
> + type_register_static(&serial_mcb_info);
> +}
> +
> +type_init(serial_mcb_register_types);
> --
> 2.39.2
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] Add MEN Chameleon Bus emulation
2023-03-29 8:45 ` [PATCH 1/4] Add MEN Chameleon Bus emulation Johannes Thumshirn
@ 2023-04-05 9:09 ` Alistair Francis
0 siblings, 0 replies; 8+ messages in thread
From: Alistair Francis @ 2023-04-05 9:09 UTC (permalink / raw)
To: Johannes Thumshirn
Cc: qemu-devel, Alistair Francis, Javier Rodriguez, Dmitry Fomichev
On Wed, Mar 29, 2023 at 11:08 PM Johannes Thumshirn <jth@kernel.org> wrote:
>
> The MEN Chameleon Bus (MCB) is an on-chip bus system exposing IP Cores of an
> FPGA to a outside bus system like PCIe.
>
> Signed-off-by: Johannes Thumshirn <jth@kernel.org>
I don't know a lot about MEN Chameleon Bus, but this looks fine to me
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> MAINTAINERS | 6 ++
> hw/Kconfig | 1 +
> hw/mcb/Kconfig | 2 +
> hw/mcb/mcb.c | 182 +++++++++++++++++++++++++++++++++++++++++++
> hw/mcb/meson.build | 1 +
> hw/meson.build | 1 +
> include/hw/mcb/mcb.h | 106 +++++++++++++++++++++++++
> 7 files changed, 299 insertions(+)
> create mode 100644 hw/mcb/Kconfig
> create mode 100644 hw/mcb/mcb.c
> create mode 100644 hw/mcb/meson.build
> create mode 100644 include/hw/mcb/mcb.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 98cb2d64cf..badec8abdd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1947,6 +1947,12 @@ R: Paolo Bonzini <pbonzini@redhat.com>
> S: Odd Fixes
> F: hw/char/
>
> +MEN Chameleon Bus
> +M: Johannes Thumshirn <jth@kernel.org>
> +S: Maintained
> +F: hw/mcb/
> +F: include/hw/mcb/
> +
> Network devices
> M: Jason Wang <jasowang@redhat.com>
> S: Odd Fixes
> diff --git a/hw/Kconfig b/hw/Kconfig
> index ba62ff6417..f5ef84b10b 100644
> --- a/hw/Kconfig
> +++ b/hw/Kconfig
> @@ -18,6 +18,7 @@ source intc/Kconfig
> source ipack/Kconfig
> source ipmi/Kconfig
> source isa/Kconfig
> +source mcb/Kconfig
> source mem/Kconfig
> source misc/Kconfig
> source net/Kconfig
> diff --git a/hw/mcb/Kconfig b/hw/mcb/Kconfig
> new file mode 100644
> index 0000000000..36a7a583a8
> --- /dev/null
> +++ b/hw/mcb/Kconfig
> @@ -0,0 +1,2 @@
> +config MCB
> + bool
> diff --git a/hw/mcb/mcb.c b/hw/mcb/mcb.c
> new file mode 100644
> index 0000000000..f2bf722de5
> --- /dev/null
> +++ b/hw/mcb/mcb.c
> @@ -0,0 +1,182 @@
> +/*
> + * QEMU MEN Chameleon Bus emulation
> + *
> + * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/module.h"
> +#include "hw/mcb/mcb.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +
> +ChameleonDeviceDescriptor *mcb_new_chameleon_descriptor(MCBus *bus, uint8_t id,
> + uint8_t rev,
> + uint8_t var,
> + uint32_t size)
> +{
> + BusChild *kid;
> + ChameleonDeviceDescriptor *gdd;
> + uint32_t reg1 = 0;
> + uint32_t offset = 0x200;
> + uint32_t end = 0;
> +
> + gdd = g_new0(ChameleonDeviceDescriptor, 1);
> + if (!gdd) {
> + return NULL;
> + }
> +
> + reg1 |= GDD_DEV(id);
> + reg1 |= GDD_DTY(CHAMELEON_DTYPE_GENERAL);
> + reg1 |= GDD_REV(rev);
> + reg1 |= GDD_VAR(var);
> + gdd->reg1 = cpu_to_le32(reg1);
> +
> + QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
> + DeviceState *qdev = kid->child;
> + MCBDevice *mdev = MCB_DEVICE(qdev);
> +
> + if (mdev->gdd) {
> + offset = mdev->gdd->offset;
> + end = offset + mdev->gdd->size;
> + }
> + }
> +
> + gdd->offset = offset + end;
> + gdd->size = size;
> +
> + return gdd;
> +}
> +
> +static void mcb_irq_handler(void *opaque, int irq_num, int level)
> +{
> + MCBDevice *dev = opaque;
> + MCBus *bus = MCB_BUS(qdev_get_parent_bus(DEVICE(dev)));
> +
> + if (bus->set_irq) {
> + bus->set_irq(dev, irq_num, level);
> + }
> +}
> +
> +qemu_irq mcb_allocate_irq(MCBDevice *dev)
> +{
> + int irq = 0;
> + return qemu_allocate_irq(mcb_irq_handler, dev, irq);
> +}
> +
> +MCBDevice *mcb_device_find(MCBus *bus, hwaddr addr)
> +{
> + BusChild *kid;
> + uint32_t start;
> + uint32_t end;
> +
> + QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
> + DeviceState *qdev = kid->child;
> + MCBDevice *mdev = MCB_DEVICE(qdev);
> +
> + start = mdev->gdd->offset;
> + end = start + mdev->gdd->size;
> +
> + if (addr >= start && addr <= end) {
> + return mdev;
> + }
> + }
> + return NULL;
> +}
> +
> +void mcb_bus_init(MCBus *bus, size_t bus_size,
> + DeviceState *parent,
> + uint8_t n_slots,
> + qemu_irq_handler handler)
> +{
> + qbus_init(bus, bus_size, TYPE_MCB_BUS, parent, NULL);
> + bus->n_slots = n_slots;
> + bus->set_irq = handler;
> +}
> +
> +static void mcb_device_realize(DeviceState *dev, Error **errp)
> +{
> + MCBDevice *mdev = MCB_DEVICE(dev);
> + MCBus *bus = MCB_BUS(qdev_get_parent_bus(dev));
> + MCBDeviceClass *k = MCB_DEVICE_GET_CLASS(dev);
> +
> + if (mdev->slot < 0) {
> + mdev->slot = bus->free_slot;
> + }
> +
> + if (mdev->slot >= bus->n_slots) {
> + error_setg(errp, "Only %" PRIu8 " slots available.", bus->n_slots);
> + return;
> + }
> + bus->free_slot = mdev->slot + 1;
> +
> + mdev->irq = qemu_allocate_irqs(bus->set_irq, mdev, 1);
> +
> + k->realize(dev, errp);
> +}
> +
> +static void mcb_device_unrealize(DeviceState *dev)
> +{
> + MCBDevice *mdev = MCB_DEVICE(dev);
> + MCBDeviceClass *k = MCB_DEVICE_GET_CLASS(dev);
> +
> + if (k->unrealize) {
> + k->unrealize(dev);
> + return;
> + }
> +
> + qemu_free_irqs(mdev->irq, 1);
> +}
> +
> +static Property mcb_device_props[] = {
> + DEFINE_PROP_INT32("slot", MCBDevice, slot, -1),
> + DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static void mcb_device_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *k = DEVICE_CLASS(klass);
> +
> + set_bit(DEVICE_CATEGORY_INPUT, k->categories);
> + k->bus_type = TYPE_MCB_BUS;
> + k->realize = mcb_device_realize;
> + k->unrealize = mcb_device_unrealize;
> + device_class_set_props(k, mcb_device_props);
> +}
> +
> +const VMStateDescription vmstate_mcb_device = {
> + .name = "mcb_device",
> + .version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_INT32(slot, MCBDevice),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static const TypeInfo mcb_device_info = {
> + .name = TYPE_MCB_DEVICE,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(MCBDevice),
> + .class_size = sizeof(MCBDeviceClass),
> + .class_init = mcb_device_class_init,
> + .abstract = true,
> +};
> +
> +static const TypeInfo mcb_bus_info = {
> + .name = TYPE_MCB_BUS,
> + .parent = TYPE_BUS,
> + .instance_size = sizeof(MCBus),
> +};
> +
> +static void mcb_register_types(void)
> +{
> + type_register_static(&mcb_device_info);
> + type_register_static(&mcb_bus_info);
> +}
> +
> +type_init(mcb_register_types);
> diff --git a/hw/mcb/meson.build b/hw/mcb/meson.build
> new file mode 100644
> index 0000000000..a385edc07c
> --- /dev/null
> +++ b/hw/mcb/meson.build
> @@ -0,0 +1 @@
> +softmmu_ss.add(when: 'CONFIG_MCB', if_true: files('mcb.c'))
> diff --git a/hw/meson.build b/hw/meson.build
> index c7ac7d3d75..3d1462ad8b 100644
> --- a/hw/meson.build
> +++ b/hw/meson.build
> @@ -18,6 +18,7 @@ subdir('intc')
> subdir('ipack')
> subdir('ipmi')
> subdir('isa')
> +subdir('mcb')
> subdir('mem')
> subdir('misc')
> subdir('net')
> diff --git a/include/hw/mcb/mcb.h b/include/hw/mcb/mcb.h
> new file mode 100644
> index 0000000000..ff120073e1
> --- /dev/null
> +++ b/include/hw/mcb/mcb.h
> @@ -0,0 +1,106 @@
> +/*
> + * QEMU MEN Chameleon Bus emulation
> + *
> + * Copyright (C) 2023 Johannes Thumshirn <jth@kernel.org>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#ifndef QEMU_MCB_H
> +#define QEMU_MCB_H
> +
> +#include "hw/qdev-core.h"
> +#include "qom/object.h"
> +#include "exec/memory.h"
> +
> +#define CHAMELEON_DTYPE_GENERAL 0x0
> +#define CHAMELEON_DTYPE_END 0xf
> +
> +typedef struct {
> + uint32_t reg1;
> + uint32_t reg2;
> + uint32_t offset;
> + uint32_t size;
> +} ChameleonDeviceDescriptor;
> +
> +#define GDD_DEV(x) (((x) & 0x3ff) << 18)
> +#define GDD_DTY(x) (((x) & 0xf) << 28)
> +#define GDD_REV(x) (((x) & 0x3f) << 5)
> +#define GDD_VAR(x) (((x) & 0x3f) << 11)
> +
> +/* GDD Register 1 fields */
> +#define GDD_IRQ(x) ((x) & 0x1f)
> +
> +/* GDD Register 2 fields */
> +#define GDD_BAR(x) ((x) & 0x7)
> +#define GDD_INS(x) (((x) >> 3) & 0x3f)
> +#define GDD_GRP(x) (((x) >> 9) & 0x3f)
> +
> +typedef struct MCBus MCBus;
> +
> +#define TYPE_MCB_BUS "MEN Chameleon Bus"
> +OBJECT_DECLARE_SIMPLE_TYPE(MCBus, MCB_BUS)
> +
> +struct MCBus {
> + /*< private >*/
> + BusState parent_obj;
> +
> + uint8_t n_slots;
> + uint8_t free_slot;
> + qemu_irq_handler set_irq;
> + MemoryRegion mmio_region;
> +};
> +
> +typedef struct MCBDevice MCBDevice;
> +typedef struct MCBDeviceClass MCBDeviceClass;
> +
> +#define TYPE_MCB_DEVICE "mcb-device"
> +#define MCB_DEVICE(obj) \
> + OBJECT_CHECK(MCBDevice, (obj), TYPE_MCB_DEVICE)
> +#define MCB_DEVICE_CLASS(klass) \
> + OBJECT_CLASS_CHECK(MCBDeviceClass, (klass), TYPE_MCB_DEVICE)
> +#define MCB_DEVICE_GET_CLASS(obj) \
> + OBJECT_GET_CLASS(MCBDeviceClass, (obj), TYPE_MCB_DEVICE)
> +
> +struct MCBDeviceClass {
> + /*< private >*/
> + DeviceClass parent_class;
> + /*< public >*/
> +
> +
> + DeviceRealize realize;
> + DeviceUnrealize unrealize;
> +};
> +
> +struct MCBDevice {
> + /*< private >*/
> + DeviceState parent_obj;
> + /*< public >*/
> +
> + qemu_irq *irq;
> + ChameleonDeviceDescriptor *gdd;
> + int slot;
> +
> + uint8_t rev;
> + uint8_t var;
> +};
> +
> +extern const VMStateDescription vmstate_mcb_device;
> +
> +ChameleonDeviceDescriptor *mcb_new_chameleon_descriptor(MCBus *bus, uint8_t id,
> + uint8_t rev,
> + uint8_t var,
> + uint32_t size);
> +
> +#define VMSTATE_MCB_DEVICE(_field, _state) \
> + VMSTATE_STRUCT(_field, _state, 1, vmstate_mcb_device, MCBDevice)
> +
> +MCBDevice *mcb_device_find(MCBus *bus, hwaddr addr);
> +void mcb_bus_init(MCBus *bus, size_t bus_size,
> + DeviceState *parent,
> + uint8_t n_slots,
> + qemu_irq_handler handler);
> +
> +qemu_irq mcb_allocate_irq(MCBDevice *dev);
> +#endif
> --
> 2.39.2
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-04-05 9:10 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-29 8:45 [PATCH 0/4] Add emulation of MEN Chameleon Hardware Johannes Thumshirn
2023-03-29 8:45 ` [PATCH 1/4] Add MEN Chameleon Bus emulation Johannes Thumshirn
2023-04-05 9:09 ` Alistair Francis
2023-03-29 8:45 ` [PATCH 2/4] Add MEN Chameleon Bus via PCI carrier Johannes Thumshirn
2023-04-05 6:29 ` Alistair Francis
2023-03-29 8:45 ` [PATCH 3/4] serial-mcb: Add serial via MEN chameleon bus Johannes Thumshirn
2023-04-05 8:32 ` Alistair Francis
2023-03-29 8:45 ` [PATCH 4/4] wdt_z069: Add support for MEN 16z069 Watchdog Johannes Thumshirn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).