On Wed, Mar 29, 2023 at 11:08 PM Johannes Thumshirn <j...@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 <j...@kernel.org>

I don't know a lot about MEN Chameleon Bus, but this looks fine to me

Acked-by: Alistair Francis <alistair.fran...@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 <pbonz...@redhat.com>
>  S: Odd Fixes
>  F: hw/char/
>
> +MEN Chameleon Bus
> +M: Johannes Thumshirn <j...@kernel.org>
> +S: Maintained
> +F: hw/mcb/
> +F: include/hw/mcb/
> +
>  Network devices
>  M: Jason Wang <jasow...@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 <j...@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 <j...@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
>
>

Reply via email to