diff options
Diffstat (limited to 'qemu/hw/intc/arm_gicv2m.c')
-rw-r--r-- | qemu/hw/intc/arm_gicv2m.c | 194 |
1 files changed, 0 insertions, 194 deletions
diff --git a/qemu/hw/intc/arm_gicv2m.c b/qemu/hw/intc/arm_gicv2m.c deleted file mode 100644 index e8b5177dc..000000000 --- a/qemu/hw/intc/arm_gicv2m.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * GICv2m extension for MSI/MSI-x support with a GICv2-based system - * - * Copyright (C) 2015 Linaro, All rights reserved. - * - * Author: Christoffer Dall <christoffer.dall@linaro.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -/* This file implements an emulated GICv2m widget as described in the ARM - * Server Base System Architecture (SBSA) specification Version 2.2 - * (ARM-DEN-0029 v2.2) pages 35-39 without any optional implementation defined - * identification registers and with a single non-secure MSI register frame. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "hw/pci/msi.h" - -#define TYPE_ARM_GICV2M "arm-gicv2m" -#define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M) - -#define GICV2M_NUM_SPI_MAX 128 - -#define V2M_MSI_TYPER 0x008 -#define V2M_MSI_SETSPI_NS 0x040 -#define V2M_MSI_IIDR 0xFCC -#define V2M_IIDR0 0xFD0 -#define V2M_IIDR11 0xFFC - -#define PRODUCT_ID_QEMU 0x51 /* ASCII code Q */ - -typedef struct ARMGICv2mState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq spi[GICV2M_NUM_SPI_MAX]; - - uint32_t base_spi; - uint32_t num_spi; -} ARMGICv2mState; - -static void gicv2m_set_irq(void *opaque, int irq) -{ - ARMGICv2mState *s = (ARMGICv2mState *)opaque; - - qemu_irq_pulse(s->spi[irq]); -} - -static uint64_t gicv2m_read(void *opaque, hwaddr offset, - unsigned size) -{ - ARMGICv2mState *s = (ARMGICv2mState *)opaque; - uint32_t val; - - if (size != 4) { - qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_read: bad size %u\n", size); - return 0; - } - - switch (offset) { - case V2M_MSI_TYPER: - val = (s->base_spi + 32) << 16; - val |= s->num_spi; - return val; - case V2M_MSI_IIDR: - /* We don't have any valid implementor so we leave that field as zero - * and we return 0 in the arch revision as per the spec. - */ - return (PRODUCT_ID_QEMU << 20); - case V2M_IIDR0 ... V2M_IIDR11: - /* We do not implement any optional identification registers and the - * mandatory MSI_PIDR2 register reads as 0x0, so we capture all - * implementation defined registers here. - */ - return 0; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "gicv2m_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void gicv2m_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - ARMGICv2mState *s = (ARMGICv2mState *)opaque; - - if (size != 2 && size != 4) { - qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_write: bad size %u\n", size); - return; - } - - switch (offset) { - case V2M_MSI_SETSPI_NS: { - int spi; - - spi = (value & 0x3ff) - (s->base_spi + 32); - if (spi >= 0 && spi < s->num_spi) { - gicv2m_set_irq(s, spi); - } - return; - } - default: - qemu_log_mask(LOG_GUEST_ERROR, - "gicv2m_write: Bad offset %x\n", (int)offset); - } -} - -static const MemoryRegionOps gicv2m_ops = { - .read = gicv2m_read, - .write = gicv2m_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void gicv2m_realize(DeviceState *dev, Error **errp) -{ - ARMGICv2mState *s = ARM_GICV2M(dev); - int i; - - if (s->num_spi > GICV2M_NUM_SPI_MAX) { - error_setg(errp, - "requested %u SPIs exceeds GICv2m frame maximum %d", - s->num_spi, GICV2M_NUM_SPI_MAX); - return; - } - - if (s->base_spi + 32 > 1020 - s->num_spi) { - error_setg(errp, - "requested base SPI %u+%u exceeds max. number 1020", - s->base_spi + 32, s->num_spi); - return; - } - - for (i = 0; i < s->num_spi; i++) { - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->spi[i]); - } - - msi_nonbroken = true; - kvm_gsi_direct_mapping = true; - kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); -} - -static void gicv2m_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - ARMGICv2mState *s = ARM_GICV2M(obj); - - memory_region_init_io(&s->iomem, OBJECT(s), &gicv2m_ops, s, - "gicv2m", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); -} - -static Property gicv2m_properties[] = { - DEFINE_PROP_UINT32("base-spi", ARMGICv2mState, base_spi, 0), - DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64), - DEFINE_PROP_END_OF_LIST(), -}; - -static void gicv2m_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->props = gicv2m_properties; - dc->realize = gicv2m_realize; -} - -static const TypeInfo gicv2m_info = { - .name = TYPE_ARM_GICV2M, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ARMGICv2mState), - .instance_init = gicv2m_init, - .class_init = gicv2m_class_init, -}; - -static void gicv2m_register_types(void) -{ - type_register_static(&gicv2m_info); -} - -type_init(gicv2m_register_types) |