diff --git a/hw/arm/virt.c b/hw/arm/virt.c index e046fff5dd8ab0de7778f299f4c0feca88088f52..b2091406849961e161cf6d6b216a2e600fc2c91b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -87,6 +87,13 @@ #include "hw/char/pl011.h" #include "qemu/guest-random.h" #include "qapi/qmp/qdict.h" +#include "qemu/log.h" +#ifdef CONFIG_UB +#include "hw/ub/ub.h" +#include "hw/ub/ub_ubc.h" +#include "hw/ub/hisi/ubc.h" +#include "hw/ub/hisi/ub_fm.h" +#endif // CONFIG_UB #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ @@ -1714,7 +1721,17 @@ static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) 0x0, vms->iommu_phandle, 0x0, bdf, bdf + 1, vms->iommu_phandle, bdf + 1, 0xffff - bdf); } +#ifdef CONFIG_UB +static void create_ub(VirtMachineState *vms) +{ + DeviceState *ubc; + ubc = qdev_new(TYPE_BUS_CONTROLLER); + qdev_prop_set_uint32(ubc, "ub-bus-controller-msgq-reg-size", UBC_MSGQ_REG_SIZE); + qdev_prop_set_uint32(ubc, "ub-bus-controller-fm-msgq-reg-size", FM_MSGQ_REG_SIZE); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ubc), &error_fatal); +} +#endif // CONFIG_UB static void create_pcie(VirtMachineState *vms) { hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base; @@ -2874,6 +2891,9 @@ static void machvirt_init(MachineState *machine) create_rtc(vms); create_pcie(vms); +#ifdef CONFIG_UB + create_ub(vms); +#endif // CONFIG_UB if (!has_ged) { create_gpio_devices(vms, VIRT_GPIO, sysmem); diff --git a/hw/ub/meson.build b/hw/ub/meson.build index 21c3f0ea6c208b2c473af9746c698cedf681194a..b6d5f4beffcab8640fdf52cafdb98c3f847c7230 100644 --- a/hw/ub/meson.build +++ b/hw/ub/meson.build @@ -1,5 +1,6 @@ ub_ss = ss.source_set() ub_ss.add(files( + 'ub_ubc.c', )) system_ss.add_all(when: 'CONFIG_HW_UB', if_true: ub_ss) subdir('hisi') diff --git a/hw/ub/ub_ubc.c b/hw/ub/ub_ubc.c new file mode 100644 index 0000000000000000000000000000000000000000..a0bc907ec8011cc2aaaf04f160e595542f9c5b7d --- /dev/null +++ b/hw/ub/ub_ubc.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "hw/arm/virt.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/ub/ub.h" +#include "hw/ub/ub_ubc.h" +#include "migration/vmstate.h" + +static uint64_t ub_msgq_reg_read(void *opaque, hwaddr addr, unsigned len) +{ + BusControllerState *s = opaque; + uint64_t val; + + switch (len) { + case BYTE_SIZE: + val = ub_get_byte(s->msgq_reg + addr); + break; + case WORD_SIZE: + val = ub_get_word(s->msgq_reg + addr); + break; + case DWORD_SIZE: + val = ub_get_long(s->msgq_reg + addr); + break; + default: + qemu_log("invalid argument len 0x%x\n", len); + val = ~0x0; + break; + } + + return val; +} + +static void ub_msgq_reg_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) +{ + BusControllerState *s = opaque; + + switch (len) { + case BYTE_SIZE: + ub_set_byte(s->msgq_reg + addr, val); + break; + case WORD_SIZE: + ub_set_word(s->msgq_reg + addr, val); + break; + case DWORD_SIZE: + ub_set_long(s->msgq_reg + addr, val); + break; + default: + /* As length is under guest control, handle illegal values. */ + qemu_log("invalid argument len 0x%x val 0x%lx\n", len, val); + return; + } +} + +static const MemoryRegionOps ub_msgq_reg_ops = { + .read = ub_msgq_reg_read, + .write = ub_msgq_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps ub_fm_msgq_reg_ops = { + +}; + +static void ub_reg_alloc(DeviceState *dev) +{ + BusControllerState *s = BUS_CONTROLLER(dev); + + s->msgq_reg = g_malloc0(s->msgq_reg_size); + s->fm_msgq_reg = g_malloc0(s->fm_msgq_reg_size); + qemu_log("alloc ub reg mem size: msgq_reg %u, " + "fm_msgq_reg %u\n", + s->msgq_reg_size, s->fm_msgq_reg_size); +} + +static void ub_reg_free(DeviceState *dev) +{ + BusControllerState *s = BUS_CONTROLLER(dev); + + g_free(s->msgq_reg); + g_free(s->fm_msgq_reg); + qemu_log("free ub reg mem\n"); +} + +static void ub_bus_controller_realize(DeviceState *dev, Error **errp) +{ + BusControllerState *s = BUS_CONTROLLER(dev); + SysBusDevice *sysdev = SYS_BUS_DEVICE(dev); + static uint8_t NO = 0; + char *name = g_strdup_printf("ubus.%u", NO); + + sysdev->parent_obj.id = g_strdup_printf("ubc.%u", NO++); + /* for msgq reg */ + memory_region_init_io(&s->msgq_reg_mem, OBJECT(s), &ub_msgq_reg_ops, + s, TYPE_BUS_CONTROLLER, s->msgq_reg_size); + sysbus_init_mmio(sysdev, &s->msgq_reg_mem); + /* for fm msgq reg */ + memory_region_init_io(&s->fm_msgq_reg_mem, OBJECT(s), &ub_fm_msgq_reg_ops, + s, TYPE_BUS_CONTROLLER, s->fm_msgq_reg_size); + sysbus_init_mmio(sysdev, &s->fm_msgq_reg_mem); + ub_reg_alloc(dev); + /* for ub controller mmio */ + memory_region_init(&s->io_mmio, OBJECT(s), "UB_MMIO", UINT64_MAX); + sysbus_init_mmio(sysdev, &s->io_mmio); + + g_free(name); +} + +static void ub_bus_controller_unrealize(DeviceState *dev) +{ + BusControllerState *s = BUS_CONTROLLER(dev); + SysBusDevice *sysdev = SYS_BUS_DEVICE(dev); + g_free(sysdev->parent_obj.id); + QLIST_REMOVE(s, node); + ub_reg_free(dev); +} + +static bool ub_bus_controller_needed(void *opaque) +{ + BusControllerState *s = opaque; + return s->mig_enabled; +} + +static Property ub_bus_controller_properties[] = { + DEFINE_PROP_UINT32("ub-bus-controller-msgq-reg-size", BusControllerState, + msgq_reg_size, 0), + DEFINE_PROP_UINT32("ub-bus-controller-fm-msgq-reg-size", BusControllerState, + fm_msgq_reg_size, 0), + DEFINE_PROP_BOOL("ub-bus-controller-migration-enabled", BusControllerState, + mig_enabled, true), + DEFINE_PROP_END_OF_LIST(), +}; + +const VMStateDescription vmstate_ub_bus_controller = { + .name = TYPE_BUS_CONTROLLER, + .needed = ub_bus_controller_needed, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + /* support migration later */ + VMSTATE_END_OF_LIST() + } +}; + +static void ub_bus_controller_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + + device_class_set_props(dc, ub_bus_controller_properties); + dc->realize = ub_bus_controller_realize; + dc->unrealize = ub_bus_controller_unrealize; + dc->vmsd = &vmstate_ub_bus_controller; +} + +static void ub_bus_controller_instance_init(Object *obj) +{ + /* do nothing now */ +} + +static void ub_bus_controller_instance_finalize(Object *obj) +{ + /* do nothing now */ +} +static const TypeInfo ub_bus_controller_type_info = { + .name = TYPE_BUS_CONTROLLER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BusControllerState), + .instance_init = ub_bus_controller_instance_init, + .instance_finalize = ub_bus_controller_instance_finalize, + .class_size = sizeof(BusControllerClass), + .class_init = ub_bus_controller_class_init, +}; + +static void ub_bus_controller_register_types(void) +{ + type_register_static(&ub_bus_controller_type_info); +} +type_init(ub_bus_controller_register_types) diff --git a/include/hw/ub/hisi/ub_fm.h b/include/hw/ub/hisi/ub_fm.h new file mode 100644 index 0000000000000000000000000000000000000000..bd606227a6e099417660de1dc99ebd9428f2be96 --- /dev/null +++ b/include/hw/ub/hisi/ub_fm.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef UB_HISI_FM_H +#define UB_HISI_FM_H +#include "hw/ub/hisi/ubc.h" + +#define FM_MSGQ_REG_OFFSET (UBC_MSGQ_REG_OFFSET + UBC_MSGQ_REG_SIZE) +#define FM_MSGQ_REG_SIZE 0x100000 /* 1MiB */ + +#endif diff --git a/include/hw/ub/hisi/ubc.h b/include/hw/ub/hisi/ubc.h new file mode 100644 index 0000000000000000000000000000000000000000..fdaeae7b3e2ecc43b5b9300fbfe316cfa7d60284 --- /dev/null +++ b/include/hw/ub/hisi/ubc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HISI_UBC_H +#define HISI_UBC_H + +/* + * Address space layout of the UB controller + * References: LinQuickCV100 Programming User Guide + * + * +----------------------------+ BA_ADDR+0xFFFF_FFFF + * | UMMU REG (3G) | + * +----------------------------+ BA_ADDR+0x4000_0000 + * | ... | + * +----------------------------+ + * | UB MSGQ(32M) only 2MB used | + * +----------------------------+ BA_ADDR+0x1000_0000 + * | Local Register (256M) | + * +----------------------------+ BA_ADDR+0x0000_0000 +*/ +#define BASE_REG_SIZE 0x100000000 /* 4GiB */ +#define LOCAL_REG_SIZE 0x10000000 /* 256MiB */ +#define UBC_MSGQ_REG_SIZE 0x100000 /* 1MiB */ +#define UMMU_REG_SIZE 0xC0000000 /* 3GiB */ +#define UMMU_REG_OFFSET 0x40000000 +#define UBC_MSGQ_REG_OFFSET LOCAL_REG_SIZE +#define LOCAL_REG_OFFSET 0 +#define SINGLE_UMMU_REG_SIZE 0x5000 /* 20KiB */ +#define SINGLE_UMMU_PMU_REG_SIZE 0x1000 /* 4KiB */ +#define UBC_INTERRUPT_ID_START 0x1FFF +#define UBC_INTERRUPT_ID_CNT 0x1000 +#define VENDER_ID_HUAWEI 0xCC08 + +#endif diff --git a/include/hw/ub/ub.h b/include/hw/ub/ub.h new file mode 100644 index 0000000000000000000000000000000000000000..4e3ed8a919a3c84b198b0ab259b6d66058bfc83c --- /dev/null +++ b/include/hw/ub/ub.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef UB_H +#define UB_H +#include +#include "qemu/typedefs.h" +#include "exec/memory.h" + +#define BYTE_SIZE 1 +#define WORD_SIZE 2 +#define DWORD_SIZE 4 + +static inline void ub_set_byte(uint8_t *config, uint8_t val) +{ + *config = val; +} + +static inline uint8_t ub_get_byte(const uint8_t *config) +{ + return *config; +} + +static inline void ub_set_word(uint8_t *config, uint16_t val) +{ + stw_le_p(config, val); +} + +static inline uint16_t ub_get_word(const uint8_t *config) +{ + return lduw_le_p(config); +} + +static inline void ub_set_long(uint8_t *config, uint32_t val) +{ + stl_le_p(config, val); +} + +static inline uint32_t ub_get_long(const uint8_t *config) +{ + return ldl_le_p(config); +} + +static inline void ub_set_quad(uint8_t *config, uint64_t val) +{ + stq_le_p(config, val); +} + +static inline uint64_t ub_get_quad(const uint8_t *config) +{ + return ldq_le_p(config); +} + +#endif diff --git a/include/hw/ub/ub_ubc.h b/include/hw/ub/ub_ubc.h new file mode 100644 index 0000000000000000000000000000000000000000..5e791fbcf310b151825e21136ec9f19eb6ece527 --- /dev/null +++ b/include/hw/ub/ub_ubc.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef UB_UBC_H +#define UB_UBC_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_BUS_CONTROLLER "ub-bus-controller" +OBJECT_DECLARE_TYPE(BusControllerState, BusControllerClass, BUS_CONTROLLER) + +typedef struct BusControllerState BusControllerState; +struct BusControllerState { + SysBusDevice busdev; + + MemoryRegion msgq_reg_mem; /* ubc msgq */ + uint32_t msgq_reg_size; + uint8_t *msgq_reg; + MemoryRegion fm_msgq_reg_mem; /* fm msgq */ + uint32_t fm_msgq_reg_size; + uint8_t *fm_msgq_reg; + MemoryRegion io_mmio; /* ub mmio hpa memory region */ + uint32_t mmio_size; + bool mig_enabled; + QLIST_ENTRY(BusControllerState) node; +}; + +struct BusControllerClass { + SysBusDeviceClass parent_class; +}; + +#endif