From e79b445d896deb61909be52b61b87c98a9ed96f7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2018 14:02:29 +0100 Subject: [PATCH 01/21] target/arm: Fix cpu_get_tb_cpu_state() for non-SVE CPUs Not only are the sve-related tb_flags fields unused when SVE is disabled, but not all of the cpu registers are initialized properly for computing same. This can corrupt other fields by ORing in -1, which might result in QEMU crashing. This bug was not present in 3.0, but this patch is cc'd to stable because adf92eab90e3f5f34c285 where the bug was introduced was marked for stable. Fixes: adf92eab90e3f5f34c285 Cc: qemu-stable@nongnu.org (3.0.1) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 088f452716..64b1564594 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12587,36 +12587,39 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, uint32_t flags; if (is_a64(env)) { - int sve_el = sve_exception_el(env); - uint32_t zcr_len; - *pc = env->pc; flags = ARM_TBFLAG_AARCH64_STATE_MASK; /* Get control bits for tagged addresses */ flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT); flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT); - flags |= sve_el << ARM_TBFLAG_SVEEXC_EL_SHIFT; - /* If SVE is disabled, but FP is enabled, - then the effective len is 0. */ - if (sve_el != 0 && fp_el == 0) { - zcr_len = 0; - } else { - int current_el = arm_current_el(env); - ARMCPU *cpu = arm_env_get_cpu(env); + if (arm_feature(env, ARM_FEATURE_SVE)) { + int sve_el = sve_exception_el(env); + uint32_t zcr_len; - zcr_len = cpu->sve_max_vq - 1; - if (current_el <= 1) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); - } - if (current_el < 2 && arm_feature(env, ARM_FEATURE_EL2)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]); - } - if (current_el < 3 && arm_feature(env, ARM_FEATURE_EL3)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]); + /* If SVE is disabled, but FP is enabled, + * then the effective len is 0. + */ + if (sve_el != 0 && fp_el == 0) { + zcr_len = 0; + } else { + int current_el = arm_current_el(env); + ARMCPU *cpu = arm_env_get_cpu(env); + + zcr_len = cpu->sve_max_vq - 1; + if (current_el <= 1) { + zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); + } + if (current_el < 2 && arm_feature(env, ARM_FEATURE_EL2)) { + zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]); + } + if (current_el < 3 && arm_feature(env, ARM_FEATURE_EL3)) { + zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]); + } } + flags |= sve_el << ARM_TBFLAG_SVEEXC_EL_SHIFT; + flags |= zcr_len << ARM_TBFLAG_ZCR_LEN_SHIFT; } - flags |= zcr_len << ARM_TBFLAG_ZCR_LEN_SHIFT; } else { *pc = env->regs[15]; flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT) From 5561adf062c97a9c39ff037592b83d9b118f036a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 25 Sep 2018 14:02:30 +0100 Subject: [PATCH 02/21] hw/arm/exynos4210: fix Exynos4210 UART support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 97274d0c05d4 ("hw/char/exynos4210_uart.c: Remove unneeded handling of NULL chardev") broke Exynos4210 support as it removed NULL 'Chardev *chr' handling from exynos4210_uart_create() and currently exynos4210_init() always passes NULL as 'Chardev *chr' argument to exynos4210_uart_create() calls. Fix it by adding missing serial_hd() calls to exynos4210_init(). Signed-off-by: Bartlomiej Zolnierkiewicz Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-id: 9310418.Wg32kryeWE@amdc3058 Signed-off-by: Peter Maydell --- hw/arm/exynos4210.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index b7463a71ec..827318a003 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -352,19 +352,19 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem) /*** UARTs ***/ exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR, - EXYNOS4210_UART0_FIFO_SIZE, 0, NULL, + EXYNOS4210_UART0_FIFO_SIZE, 0, serial_hd(0), s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]); exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR, - EXYNOS4210_UART1_FIFO_SIZE, 1, NULL, + EXYNOS4210_UART1_FIFO_SIZE, 1, serial_hd(1), s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]); exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR, - EXYNOS4210_UART2_FIFO_SIZE, 2, NULL, + EXYNOS4210_UART2_FIFO_SIZE, 2, serial_hd(2), s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]); exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR, - EXYNOS4210_UART3_FIFO_SIZE, 3, NULL, + EXYNOS4210_UART3_FIFO_SIZE, 3, serial_hd(3), s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]); /*** SD/MMC host controllers ***/ From 66c353cea6c06c64fc68d1f663fdfdca55d4e421 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Tue, 25 Sep 2018 14:02:30 +0100 Subject: [PATCH 03/21] hw/arm/virt-acpi-build: Add a check for memory-less NUMA nodes Like commit 16b4226(hw/acpi-build: Add a check for memory-less NUMA node ), it also needs to check memory length for NUMA nodes on ARM. Signed-off-by: Shannon Zhao Reviewed-by: Andrew Jones Message-id: 20180911112643.19296-1-shenglong.zsl@alibaba-inc.com Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index ce31abd62c..5785fb697c 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -562,10 +562,12 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) mem_base = vms->memmap[VIRT_MEM].base; for (i = 0; i < nb_numa_nodes; ++i) { - numamem = acpi_data_push(table_data, sizeof(*numamem)); - build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i, - MEM_AFFINITY_ENABLED); - mem_base += numa_info[i].node_mem; + if (numa_info[i].node_mem > 0) { + numamem = acpi_data_push(table_data, sizeof(*numamem)); + build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i, + MEM_AFFINITY_ENABLED); + mem_base += numa_info[i].node_mem; + } } build_header(linker, table_data, (void *)(table_data->data + srat_start), From c0066d1a1900e8f44a004c588257116c25bbde55 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 25 Sep 2018 14:02:30 +0100 Subject: [PATCH 04/21] MAINTAINERS: Add NRF51 entry This contains the NRF51, and the machine that uses it, the BBC micro:bit. Reviewed-by: Stefan Hajnoczi Reviewed-by: Peter Maydell Signed-off-by: Joel Stanley Message-id: 20180831220920.27113-2-joel@jms.id.au Signed-off-by: Peter Maydell --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index c8480e8640..ce7c351afa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -671,6 +671,14 @@ F: include/hw/*/*aspeed* F: hw/net/ftgmac100.c F: include/hw/net/ftgmac100.h +NRF51 +M: Joel Stanley +L: qemu-arm@nongnu.org +S: Maintained +F: hw/arm/nrf51_soc.c +F: hw/arm/microbit.c +F: include/hw/arm/nrf51_soc.h + CRIS Machines ------------- Axis Dev88 From 673b2d42a8bfbc36bbfd9aad18410b3970913043 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 25 Sep 2018 14:02:31 +0100 Subject: [PATCH 05/21] arm: Add Nordic Semiconductor nRF51 SoC The nRF51 is a Cortex-M0 microcontroller with an on-board radio module, plus other common ARM SoC peripherals. http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf This defines a basic model of the CPU and memory, with no peripherals implemented at this stage. Signed-off-by: Joel Stanley Message-id: 20180831220920.27113-3-joel@jms.id.au Reviewed-by: Peter Maydell [PMM: wrapped a few long lines] Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 1 + hw/arm/Makefile.objs | 1 + hw/arm/nrf51_soc.c | 133 ++++++++++++++++++++++++++++++++ include/hw/arm/nrf51_soc.h | 41 ++++++++++ 4 files changed, 176 insertions(+) create mode 100644 hw/arm/nrf51_soc.c create mode 100644 include/hw/arm/nrf51_soc.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 0483d548d9..2420491aac 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -101,6 +101,7 @@ CONFIG_STM32F2XX_SYSCFG=y CONFIG_STM32F2XX_ADC=y CONFIG_STM32F2XX_SPI=y CONFIG_STM32F205_SOC=y +CONFIG_NRF51_SOC=y CONFIG_CMSDK_APB_TIMER=y CONFIG_CMSDK_APB_DUALTIMER=y diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2902f47b4c..ae4e20373b 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -37,3 +37,4 @@ obj-$(CONFIG_IOTKIT) += iotkit.o obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o smmuv3.o obj-$(CONFIG_FSL_IMX6UL) += fsl-imx6ul.o mcimx6ul-evk.o +obj-$(CONFIG_NRF51_SOC) += nrf51_soc.o diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c new file mode 100644 index 0000000000..1a59ef4552 --- /dev/null +++ b/hw/arm/nrf51_soc.c @@ -0,0 +1,133 @@ +/* + * Nordic Semiconductor nRF51 SoC + * http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf + * + * Copyright 2018 Joel Stanley + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/arm.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/devices.h" +#include "hw/misc/unimp.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" +#include "cpu.h" + +#include "hw/arm/nrf51_soc.h" + +#define IOMEM_BASE 0x40000000 +#define IOMEM_SIZE 0x20000000 + +#define FICR_BASE 0x10000000 +#define FICR_SIZE 0x000000fc + +#define FLASH_BASE 0x00000000 +#define SRAM_BASE 0x20000000 + +#define PRIVATE_BASE 0xF0000000 +#define PRIVATE_SIZE 0x10000000 + +/* + * The size and base is for the NRF51822 part. If other parts + * are supported in the future, add a sub-class of NRF51SoC for + * the specific variants + */ +#define NRF51822_FLASH_SIZE (256 * 1024) +#define NRF51822_SRAM_SIZE (16 * 1024) + +static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) +{ + NRF51State *s = NRF51_SOC(dev_soc); + Error *err = NULL; + + if (!s->board_memory) { + error_setg(errp, "memory property was not set"); + return; + } + + object_property_set_link(OBJECT(&s->cpu), OBJECT(&s->container), "memory", + &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -1); + + memory_region_init_rom(&s->flash, OBJECT(s), "nrf51.flash", s->flash_size, + &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(&s->container, FLASH_BASE, &s->flash); + + memory_region_init_ram(&s->sram, NULL, "nrf51.sram", s->sram_size, &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(&s->container, SRAM_BASE, &s->sram); + + create_unimplemented_device("nrf51_soc.io", IOMEM_BASE, IOMEM_SIZE); + create_unimplemented_device("nrf51_soc.ficr", FICR_BASE, FICR_SIZE); + create_unimplemented_device("nrf51_soc.private", + PRIVATE_BASE, PRIVATE_SIZE); +} + +static void nrf51_soc_init(Object *obj) +{ + NRF51State *s = NRF51_SOC(obj); + + memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX); + + sysbus_init_child_obj(OBJECT(s), "armv6m", OBJECT(&s->cpu), sizeof(s->cpu), + TYPE_ARMV7M); + qdev_prop_set_string(DEVICE(&s->cpu), "cpu-type", + ARM_CPU_TYPE_NAME("cortex-m0")); + qdev_prop_set_uint32(DEVICE(&s->cpu), "num-irq", 32); +} + +static Property nrf51_soc_properties[] = { + DEFINE_PROP_LINK("memory", NRF51State, board_memory, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("sram-size", NRF51State, sram_size, NRF51822_SRAM_SIZE), + DEFINE_PROP_UINT32("flash-size", NRF51State, flash_size, + NRF51822_FLASH_SIZE), + DEFINE_PROP_END_OF_LIST(), +}; + +static void nrf51_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = nrf51_soc_realize; + dc->props = nrf51_soc_properties; +} + +static const TypeInfo nrf51_soc_info = { + .name = TYPE_NRF51_SOC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NRF51State), + .instance_init = nrf51_soc_init, + .class_init = nrf51_soc_class_init, +}; + +static void nrf51_soc_types(void) +{ + type_register_static(&nrf51_soc_info); +} +type_init(nrf51_soc_types) diff --git a/include/hw/arm/nrf51_soc.h b/include/hw/arm/nrf51_soc.h new file mode 100644 index 0000000000..f4e092b554 --- /dev/null +++ b/include/hw/arm/nrf51_soc.h @@ -0,0 +1,41 @@ +/* + * Nordic Semiconductor nRF51 SoC + * + * Copyright 2018 Joel Stanley + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#ifndef NRF51_SOC_H +#define NRF51_SOC_H + +#include "hw/sysbus.h" +#include "hw/arm/armv7m.h" + +#define TYPE_NRF51_SOC "nrf51-soc" +#define NRF51_SOC(obj) \ + OBJECT_CHECK(NRF51State, (obj), TYPE_NRF51_SOC) + +typedef struct NRF51State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + ARMv7MState cpu; + + MemoryRegion iomem; + MemoryRegion sram; + MemoryRegion flash; + + uint32_t sram_size; + uint32_t flash_size; + + MemoryRegion *board_memory; + + MemoryRegion container; + +} NRF51State; + +#endif + From b148ed466514c8b50e7cf6fb45985a1ab98db1f8 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 25 Sep 2018 14:02:31 +0100 Subject: [PATCH 06/21] arm: Add BBC micro:bit machine This adds the base for a machine model of the BBC micro:bit: https://en.wikipedia.org/wiki/Micro_Bit This is a system with a nRF51 SoC containing the main processor, with various peripherals on board. Reviewed-by: Stefan Hajnoczi Signed-off-by: Joel Stanley Message-id: 20180831220920.27113-4-joel@jms.id.au Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Makefile.objs | 2 +- hw/arm/microbit.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 hw/arm/microbit.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index ae4e20373b..5f88062c66 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -37,4 +37,4 @@ obj-$(CONFIG_IOTKIT) += iotkit.o obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o smmuv3.o obj-$(CONFIG_FSL_IMX6UL) += fsl-imx6ul.o mcimx6ul-evk.o -obj-$(CONFIG_NRF51_SOC) += nrf51_soc.o +obj-$(CONFIG_NRF51_SOC) += nrf51_soc.o microbit.o diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c new file mode 100644 index 0000000000..e7d74116a5 --- /dev/null +++ b/hw/arm/microbit.c @@ -0,0 +1,67 @@ +/* + * BBC micro:bit machine + * http://tech.microbit.org/hardware/ + * + * Copyright 2018 Joel Stanley + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/arm/arm.h" +#include "exec/address-spaces.h" + +#include "hw/arm/nrf51_soc.h" + +typedef struct { + MachineState parent; + + NRF51State nrf51; +} MicrobitMachineState; + +#define TYPE_MICROBIT_MACHINE MACHINE_TYPE_NAME("microbit") + +#define MICROBIT_MACHINE(obj) \ + OBJECT_CHECK(MicrobitMachineState, obj, TYPE_MICROBIT_MACHINE) + +static void microbit_init(MachineState *machine) +{ + MicrobitMachineState *s = MICROBIT_MACHINE(machine); + MemoryRegion *system_memory = get_system_memory(); + Object *soc = OBJECT(&s->nrf51); + + sysbus_init_child_obj(OBJECT(machine), "nrf51", soc, sizeof(s->nrf51), + TYPE_NRF51_SOC); + object_property_set_link(soc, OBJECT(system_memory), "memory", + &error_fatal); + object_property_set_bool(soc, true, "realized", &error_fatal); + + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, + NRF51_SOC(soc)->flash_size); +} + +static void microbit_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "BBC micro:bit"; + mc->init = microbit_init; + mc->max_cpus = 1; +} + +static const TypeInfo microbit_info = { + .name = TYPE_MICROBIT_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(MicrobitMachineState), + .class_init = microbit_machine_class_init, +}; + +static void microbit_machine_init(void) +{ + type_register_static(µbit_info); +} + +type_init(microbit_machine_init); From 5540cb97f711d191bae6cde89a03a8a9c306b638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 25 Sep 2018 14:02:31 +0100 Subject: [PATCH 07/21] aspeed/i2c: interrupts should be cleared by software only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aspeed i2c interrupts should be cleared by software only, and the bus interrupt should be lowered when all interrupts have been cleared. Signed-off-by: Cédric Le Goater Message-id: 20180914063506.20815-2-clg@kaod.org Reviewed-by: Peter Maydell [PMM: drop TODO comment describing an issue which is fixed later in the patch series, and clean up commit message] Signed-off-by: Peter Maydell --- hw/i2c/aspeed_i2c.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index c762c7366a..9a3a232fb8 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -52,6 +52,13 @@ #define I2CD_AC_TIMING_REG2 0x08 /* Clock and AC Timing Control #1 */ #define I2CD_INTR_CTRL_REG 0x0c /* I2CD Interrupt Control */ #define I2CD_INTR_STS_REG 0x10 /* I2CD Interrupt Status */ + +#define I2CD_INTR_SLAVE_ADDR_MATCH (0x1 << 31) /* 0: addr1 1: addr2 */ +#define I2CD_INTR_SLAVE_ADDR_RX_PENDING (0x1 << 30) +/* bits[19-16] Reserved */ + +/* All bits below are cleared by writing 1 */ +#define I2CD_INTR_SLAVE_INACTIVE_TIMEOUT (0x1 << 15) #define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) #define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) #define I2CD_INTR_SMBUS_ALERT (0x1 << 12) /* Bus [0-3] only */ @@ -59,7 +66,7 @@ #define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) /* Removed */ #define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) /* Removed */ #define I2CD_INTR_GCALL_ADDR (0x1 << 8) /* Removed */ -#define I2CD_INTR_SLAVE_MATCH (0x1 << 7) /* use RX_DONE */ +#define I2CD_INTR_SLAVE_ADDR_RX_MATCH (0x1 << 7) /* use RX_DONE */ #define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) #define I2CD_INTR_ABNORMAL (0x1 << 5) #define I2CD_INTR_NORMAL_STOP (0x1 << 4) @@ -188,7 +195,6 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) { bus->cmd &= ~0xFFFF; bus->cmd |= value & 0xFFFF; - bus->intr_status = 0; if (bus->cmd & I2CD_M_START_CMD) { uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? @@ -284,8 +290,10 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, break; case I2CD_INTR_STS_REG: bus->intr_status &= ~(value & 0x7FFF); - bus->controller->intr_status &= ~(1 << bus->id); - qemu_irq_lower(bus->controller->irq); + if (!bus->intr_status) { + bus->controller->intr_status &= ~(1 << bus->id); + qemu_irq_lower(bus->controller->irq); + } break; case I2CD_DEV_ADDR_REG: qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", From 7bd9c60d4e0d113a8a4428bcbddc5aa9d41d1edc Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 25 Sep 2018 14:02:31 +0100 Subject: [PATCH 08/21] aspeed/i2c: Handle receive command in separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Receive command handling may have to be deferred if a previous receive done interrupt was not yet acknowledged. Move receive command handling into a separate function to prepare for the necessary changes. Signed-off-by: Guenter Roeck Signed-off-by: Cédric Le Goater Message-id: 20180914063506.20815-3-clg@kaod.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/i2c/aspeed_i2c.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 9a3a232fb8..ce16efc136 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -187,6 +187,26 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK; } +static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) +{ + int ret; + + aspeed_i2c_set_state(bus, I2CD_MRXD); + ret = i2c_recv(bus->bus); + if (ret < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__); + ret = 0xff; + } else { + bus->intr_status |= I2CD_INTR_RX_DONE; + } + bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; + if (bus->cmd & I2CD_M_S_RX_CMD_LAST) { + i2c_nack(bus->bus); + } + bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST); + aspeed_i2c_set_state(bus, I2CD_MACTIVE); +} + /* * The state machine needs some refinement. It is only used to track * invalid STOP commands for the moment. @@ -233,22 +253,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) } if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) { - int ret; - - aspeed_i2c_set_state(bus, I2CD_MRXD); - ret = i2c_recv(bus->bus); - if (ret < 0) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__); - ret = 0xff; - } else { - bus->intr_status |= I2CD_INTR_RX_DONE; - } - bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; - if (bus->cmd & I2CD_M_S_RX_CMD_LAST) { - i2c_nack(bus->bus); - } - bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST); - aspeed_i2c_set_state(bus, I2CD_MACTIVE); + aspeed_i2c_handle_rx_cmd(bus); } if (bus->cmd & I2CD_M_STOP_CMD) { From bb626e5b43df996a19b53cb6033b25d83f7b2e73 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 25 Sep 2018 14:02:31 +0100 Subject: [PATCH 09/21] aspeed/i2c: Fix receive done interrupt handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2500 datasheet says: I2CD10 Interrupt Status Register bit 2 Receive Done Interrupt status S/W needs to clear this status bit to allow next data receiving The Rx interrupt done interrupt status bit needs to be cleared explicitly before the next byte can be received, and must therefore not be auto-cleared. Also, receiving the next byte must be delayed until the bit has been cleared. Signed-off-by: Guenter Roeck Signed-off-by: Cédric Le Goater Message-id: 20180914063506.20815-4-clg@kaod.org Signed-off-by: Peter Maydell --- hw/i2c/aspeed_i2c.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index ce16efc136..a2dfa82760 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -252,7 +252,8 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) aspeed_i2c_set_state(bus, I2CD_MACTIVE); } - if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) { + if ((bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) && + !(bus->intr_status & I2CD_INTR_RX_DONE)) { aspeed_i2c_handle_rx_cmd(bus); } @@ -274,6 +275,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { AspeedI2CBus *bus = opaque; + bool handle_rx; switch (offset) { case I2CD_FUN_CTRL_REG: @@ -294,11 +296,17 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, bus->intr_ctrl = value & 0x7FFF; break; case I2CD_INTR_STS_REG: + handle_rx = (bus->intr_status & I2CD_INTR_RX_DONE) && + (value & I2CD_INTR_RX_DONE); bus->intr_status &= ~(value & 0x7FFF); if (!bus->intr_status) { bus->controller->intr_status &= ~(1 << bus->id); qemu_irq_lower(bus->controller->irq); } + if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) { + aspeed_i2c_handle_rx_cmd(bus); + aspeed_i2c_bus_raise_interrupt(bus); + } break; case I2CD_DEV_ADDR_REG: qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", From 6ce9297be69be10465b556a4b3380f70634c16a7 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 10/21] hw/arm/smmu-common: Fix the name of the iommu memory regions At the point smmu_find_add_as() gets called, the bus number might not be computed. Let's change the name of IOMMU memory region and just use the devfn and an incrementing index. The name only is used for debug. Signed-off-by: Eric Auger Message-id: 20180921070138.10114-2-eric.auger@redhat.com Reviewed-by: Peter Maydell [PMM: changed 'uint' to 'unsigned int'] Signed-off-by: Peter Maydell --- hw/arm/smmu-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 55c75d65d2..bbf4b8721a 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -311,6 +311,7 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) SMMUState *s = opaque; SMMUPciBus *sbus = g_hash_table_lookup(s->smmu_pcibus_by_busptr, bus); SMMUDevice *sdev; + static unsigned int index; if (!sbus) { sbus = g_malloc0(sizeof(SMMUPciBus) + @@ -321,9 +322,8 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) sdev = sbus->pbdev[devfn]; if (!sdev) { - char *name = g_strdup_printf("%s-%d-%d", - s->mrtypename, - pci_bus_num(bus), devfn); + char *name = g_strdup_printf("%s-%d-%d", s->mrtypename, devfn, index++); + sdev = sbus->pbdev[devfn] = g_new0(SMMUDevice, 1); sdev->smmu = s; From 9f4d2a1316fc294da5c0646fa93894d5f5f0c9a0 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 11/21] hw/arm/smmuv3: fix eventq recording and IRQ triggerring The event queue management is broken today. Event records are not properly written as EVT_SET_* macro was not updating the actual event record. Also the event queue interrupt is not correctly triggered. Fixes: bb981004eaf4 ("hw/arm/smmuv3: Event queue recording helper") Signed-off-by: Eric Auger Message-id: 20180921070138.10114-3-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/smmuv3-internal.h | 26 +++++++++++++------------- hw/arm/smmuv3.c | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index bab25d640e..19540f8f41 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -442,17 +442,17 @@ typedef struct SMMUEventInfo { #define EVT_Q_OVERFLOW (1 << 31) -#define EVT_SET_TYPE(x, v) deposit32((x)->word[0], 0 , 8 , v) -#define EVT_SET_SSV(x, v) deposit32((x)->word[0], 11, 1 , v) -#define EVT_SET_SSID(x, v) deposit32((x)->word[0], 12, 20, v) -#define EVT_SET_SID(x, v) ((x)->word[1] = v) -#define EVT_SET_STAG(x, v) deposit32((x)->word[2], 0 , 16, v) -#define EVT_SET_STALL(x, v) deposit32((x)->word[2], 31, 1 , v) -#define EVT_SET_PNU(x, v) deposit32((x)->word[3], 1 , 1 , v) -#define EVT_SET_IND(x, v) deposit32((x)->word[3], 2 , 1 , v) -#define EVT_SET_RNW(x, v) deposit32((x)->word[3], 3 , 1 , v) -#define EVT_SET_S2(x, v) deposit32((x)->word[3], 7 , 1 , v) -#define EVT_SET_CLASS(x, v) deposit32((x)->word[3], 8 , 2 , v) +#define EVT_SET_TYPE(x, v) ((x)->word[0] = deposit32((x)->word[0], 0 , 8 , v)) +#define EVT_SET_SSV(x, v) ((x)->word[0] = deposit32((x)->word[0], 11, 1 , v)) +#define EVT_SET_SSID(x, v) ((x)->word[0] = deposit32((x)->word[0], 12, 20, v)) +#define EVT_SET_SID(x, v) ((x)->word[1] = v) +#define EVT_SET_STAG(x, v) ((x)->word[2] = deposit32((x)->word[2], 0 , 16, v)) +#define EVT_SET_STALL(x, v) ((x)->word[2] = deposit32((x)->word[2], 31, 1 , v)) +#define EVT_SET_PNU(x, v) ((x)->word[3] = deposit32((x)->word[3], 1 , 1 , v)) +#define EVT_SET_IND(x, v) ((x)->word[3] = deposit32((x)->word[3], 2 , 1 , v)) +#define EVT_SET_RNW(x, v) ((x)->word[3] = deposit32((x)->word[3], 3 , 1 , v)) +#define EVT_SET_S2(x, v) ((x)->word[3] = deposit32((x)->word[3], 7 , 1 , v)) +#define EVT_SET_CLASS(x, v) ((x)->word[3] = deposit32((x)->word[3], 8 , 2 , v)) #define EVT_SET_ADDR(x, addr) \ do { \ (x)->word[5] = (uint32_t)(addr >> 32); \ @@ -460,8 +460,8 @@ typedef struct SMMUEventInfo { } while (0) #define EVT_SET_ADDR2(x, addr) \ do { \ - deposit32((x)->word[7], 3, 29, addr >> 16); \ - deposit32((x)->word[7], 0, 16, addr & 0xffff);\ + (x)->word[7] = deposit32((x)->word[7], 3, 29, addr >> 16); \ + (x)->word[7] = deposit32((x)->word[7], 0, 16, addr & 0xffff);\ } while (0) void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index bb6a24e9b8..8c4e99fecc 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -136,7 +136,7 @@ static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt) return r; } - if (smmuv3_q_empty(q)) { + if (!smmuv3_q_empty(q)) { smmuv3_trigger_irq(s, SMMU_IRQ_EVTQ, 0); } return MEMTX_OK; From 48314d831679373edb13712ff4a1abcb1937a0bd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 12/21] hw/intc/arm_gic: Document QEMU interface The GICv2's QEMU interface (sysbus MMIO regions, IRQs, etc) is now quite complicated with the addition of the virtualization extensions. Add a comment in the header file which documents it. Signed-off-by: Peter Maydell Reviewed-by: Luc Michel Message-id: 20180823103818.31189-1-peter.maydell@linaro.org --- include/hw/intc/arm_gic.h | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/include/hw/intc/arm_gic.h b/include/hw/intc/arm_gic.h index 42bb535fd4..ed703a1720 100644 --- a/include/hw/intc/arm_gic.h +++ b/include/hw/intc/arm_gic.h @@ -18,6 +18,49 @@ * with this program; if not, see . */ +/* + * QEMU interface: + * + QOM property "num-cpu": number of CPUs to support + * + QOM property "num-irq": number of IRQs (including both SPIs and PPIs) + * + QOM property "revision": GIC version (1 or 2), or 0 for the 11MPCore GIC + * + QOM property "has-security-extensions": set true if the GIC should + * implement the security extensions + * + QOM property "has-virtualization-extensions": set true if the GIC should + * implement the virtualization extensions + * + unnamed GPIO inputs: (where P is number of SPIs, i.e. num-irq - 32) + * [0..P-1] SPIs + * [P..P+31] PPIs for CPU 0 + * [P+32..P+63] PPIs for CPU 1 + * ... + * + sysbus IRQs: (in order; number will vary depending on number of cores) + * - IRQ for CPU 0 + * - IRQ for CPU 1 + * ... + * - FIQ for CPU 0 + * - FIQ for CPU 1 + * ... + * - VIRQ for CPU 0 (exists even if virt extensions not present) + * - VIRQ for CPU 1 (exists even if virt extensions not present) + * ... + * - VFIQ for CPU 0 (exists even if virt extensions not present) + * - VFIQ for CPU 1 (exists even if virt extensions not present) + * ... + * - maintenance IRQ for CPU i/f 0 (only if virt extensions present) + * - maintenance IRQ for CPU i/f 1 (only if virt extensions present) + * + sysbus MMIO regions: (in order; numbers will vary depending on + * whether virtualization extensions are present and on number of cores) + * - distributor registers (GICD*) + * - CPU interface for the accessing core (GICC*) + * - virtual interface control registers (GICH*) (only if virt extns present) + * - virtual CPU interface for the accessing core (GICV*) (only if virt) + * - CPU 0 CPU interface registers + * - CPU 1 CPU interface registers + * ... + * - CPU 0 virtual interface control registers (only if virt extns present) + * - CPU 1 virtual interface control registers (only if virt extns present) + * ... + */ + #ifndef HW_ARM_GIC_H #define HW_ARM_GIC_H From b6e6c65151efb72063a9dd62fbd5baa744d4ab30 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 13/21] hw/intc/arm_gic: Drop GIC_BASE_IRQ macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GIC_BASE_IRQ macro is a leftover from when we shared code between the GICv2 and the v7M NVIC. Since the NVIC is now split off, GIC_BASE_IRQ is always 0, and we can just delete it. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20180824161819.11085-1-peter.maydell@linaro.org --- hw/intc/arm_gic.c | 31 ++++++++++++++----------------- hw/intc/arm_gic_common.c | 1 - hw/intc/gic_internal.h | 2 -- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 542b4b93ea..b3ac2d11fc 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -955,7 +955,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) res = 0; if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { /* Every byte offset holds 8 group status bits */ - irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x080) * 8; if (irq >= s->num_irq) { goto bad_reg; } @@ -974,7 +974,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) irq = (offset - 0x100) * 8; else irq = (offset - 0x180) * 8; - irq += GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; res = 0; @@ -994,7 +993,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) irq = (offset - 0x200) * 8; else irq = (offset - 0x280) * 8; - irq += GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; res = 0; @@ -1019,7 +1017,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) goto bad_reg; } - irq += GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; res = 0; @@ -1036,7 +1033,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) } } else if (offset < 0x800) { /* Interrupt Priority. */ - irq = (offset - 0x400) + GIC_BASE_IRQ; + irq = (offset - 0x400); if (irq >= s->num_irq) goto bad_reg; res = gic_dist_get_priority(s, cpu, irq, attrs); @@ -1046,7 +1043,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) /* For uniprocessor GICs these RAZ/WI */ res = 0; } else { - irq = (offset - 0x800) + GIC_BASE_IRQ; + irq = (offset - 0x800); if (irq >= s->num_irq) { goto bad_reg; } @@ -1060,7 +1057,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) } } else if (offset < 0xf00) { /* Interrupt Configuration. */ - irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; + irq = (offset - 0xc00) * 4; if (irq >= s->num_irq) goto bad_reg; res = 0; @@ -1183,7 +1180,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, */ if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { /* Every byte offset holds 8 group status bits */ - irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x80) * 8; if (irq >= s->num_irq) { goto bad_reg; } @@ -1204,7 +1201,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } } else if (offset < 0x180) { /* Interrupt Set Enable. */ - irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x100) * 8; if (irq >= s->num_irq) goto bad_reg; if (irq < GIC_NR_SGIS) { @@ -1239,7 +1236,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } } else if (offset < 0x200) { /* Interrupt Clear Enable. */ - irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x180) * 8; if (irq >= s->num_irq) goto bad_reg; if (irq < GIC_NR_SGIS) { @@ -1264,7 +1261,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } } else if (offset < 0x280) { /* Interrupt Set Pending. */ - irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x200) * 8; if (irq >= s->num_irq) goto bad_reg; if (irq < GIC_NR_SGIS) { @@ -1283,7 +1280,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } } else if (offset < 0x300) { /* Interrupt Clear Pending. */ - irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x280) * 8; if (irq >= s->num_irq) goto bad_reg; if (irq < GIC_NR_SGIS) { @@ -1309,7 +1306,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, goto bad_reg; } - irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x300) * 8; if (irq >= s->num_irq) { goto bad_reg; } @@ -1333,7 +1330,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, goto bad_reg; } - irq = (offset - 0x380) * 8 + GIC_BASE_IRQ; + irq = (offset - 0x380) * 8; if (irq >= s->num_irq) { goto bad_reg; } @@ -1353,7 +1350,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } } else if (offset < 0x800) { /* Interrupt Priority. */ - irq = (offset - 0x400) + GIC_BASE_IRQ; + irq = (offset - 0x400); if (irq >= s->num_irq) goto bad_reg; gic_dist_set_priority(s, cpu, irq, value, attrs); @@ -1362,7 +1359,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, * annoying exception of the 11MPCore's GIC. */ if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { - irq = (offset - 0x800) + GIC_BASE_IRQ; + irq = (offset - 0x800); if (irq >= s->num_irq) { goto bad_reg; } @@ -1375,7 +1372,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } } else if (offset < 0xf00) { /* Interrupt Configuration. */ - irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; + irq = (offset - 0xc00) * 4; if (irq >= s->num_irq) goto bad_reg; if (irq < GIC_NR_SGIS) diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 547dc41185..57569a4e59 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -191,7 +191,6 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp) s->num_cpu, GIC_NCPU); return; } - s->num_irq += GIC_BASE_IRQ; if (s->num_irq > GIC_MAXIRQ) { error_setg(errp, "requested %u interrupt lines exceeds GIC maximum %d", diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 45c2af0bf5..8d29b40ca1 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -26,8 +26,6 @@ #define ALL_CPU_MASK ((unsigned)(((1 << GIC_NCPU) - 1))) -#define GIC_BASE_IRQ 0 - #define GIC_DIST_SET_ENABLED(irq, cm) (s->irq_state[irq].enabled |= (cm)) #define GIC_DIST_CLEAR_ENABLED(irq, cm) (s->irq_state[irq].enabled &= ~(cm)) #define GIC_DIST_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0) From 5d026de8b6aeb4d494c21ac32112c2821bd05422 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 14/21] hw/net/pcnet-pci: Convert away from old_mmio accessors Convert the pcnet-pci device away from using the old_mmio MemoryRegionOps accessor functions. This commit is a no-behaviour-change API conversion. (Since PCNET_PNPMMIO_SIZE is 0x20, the old "addr & 0x10" check and the new "addr < 0x10" check are exact opposites; the new code is phrased to be parallel with the pcnet_io_read/write functions.) I have left a TODO comment marker because the similarity between the MMIO and IO accessor behaviour is suspicious and they could be combined, but this will be left to a different patch. Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/net/pcnet-pci.c | 133 ++++++++++++++++++-------------------------- hw/net/trace-events | 8 +-- 2 files changed, 57 insertions(+), 84 deletions(-) diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 70dc8b3f0c..248fb3ba29 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -139,92 +139,67 @@ static const MemoryRegionOps pcnet_io_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) +/* + * TODO: should MMIO accesses to the addresses corresponding to the + * APROM also honour the BCR_DWIO() setting? If so, then these functions + * and pcnet_ioport_write/pcnet_ioport_read could be merged. + * If not, then should pcnet_ioport_{read,write}{w,l} really check + * BCR_DWIO() for MMIO writes ? + */ +static void pcnet_mmio_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) { PCNetState *d = opaque; - trace_pcnet_mmio_writeb(opaque, addr, val); - if (!(addr & 0x10)) - pcnet_aprom_writeb(d, addr & 0x0f, val); -} + trace_pcnet_mmio_write(opaque, addr, size, val); -static uint32_t pcnet_mmio_readb(void *opaque, hwaddr addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - - if (!(addr & 0x10)) - val = pcnet_aprom_readb(d, addr & 0x0f); - trace_pcnet_mmio_readb(opaque, addr, val); - return val; -} - -static void pcnet_mmio_writew(void *opaque, hwaddr addr, uint32_t val) -{ - PCNetState *d = opaque; - - trace_pcnet_mmio_writew(opaque, addr, val); - if (addr & 0x10) - pcnet_ioport_writew(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + if (addr < 0x10) { + if (size == 1) { + pcnet_aprom_writeb(d, addr, data); + } else if ((addr & 1) == 0 && size == 2) { + pcnet_aprom_writeb(d, addr, data & 0xff); + pcnet_aprom_writeb(d, addr + 1, data >> 8); + } else if ((addr & 3) == 0 && size == 4) { + pcnet_aprom_writeb(d, addr, data & 0xff); + pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff); + pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff); + pcnet_aprom_writeb(d, addr + 3, data >> 24); + } + } else { + if (size == 2) { + pcnet_ioport_writew(d, addr, data); + } else if (size == 4) { + pcnet_ioport_writel(d, addr, data); + } } } -static uint32_t pcnet_mmio_readw(void *opaque, hwaddr addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - - if (addr & 0x10) - val = pcnet_ioport_readw(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } - trace_pcnet_mmio_readw(opaque, addr, val); - return val; -} - -static void pcnet_mmio_writel(void *opaque, hwaddr addr, uint32_t val) +static uint64_t pcnet_mmio_read(void *opque, hwaddr addr, unsigned size) { PCNetState *d = opaque; - trace_pcnet_mmio_writel(opaque, addr, val); - if (addr & 0x10) - pcnet_ioport_writel(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); - pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); - pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); - } -} + trace_pcnet_ioport_read(opaque, addr, size); -static uint32_t pcnet_mmio_readl(void *opaque, hwaddr addr) -{ - PCNetState *d = opaque; - uint32_t val; - - if (addr & 0x10) - val = pcnet_ioport_readl(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+3); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+2); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); + if (addr < 0x10) { + if (size == 1) { + return pcnet_aprom_readb(d, addr); + } else if ((addr & 1) == 0 && size == 2) { + return pcnet_aprom_readb(d, addr) | + (pcnet_aprom_readb(d, addr + 1) << 8); + } else if ((addr & 3) == 0 && size == 4) { + return pcnet_aprom_readb(d, addr) | + (pcnet_aprom_readb(d, addr + 1) << 8) | + (pcnet_aprom_readb(d, addr + 2) << 16) | + (pcnet_aprom_readb(d, addr + 3) << 24); + } + } else { + if (size == 2) { + return pcnet_ioport_readw(d, addr); + } else if (size == 4) { + return pcnet_ioport_readl(d, addr); + } } - trace_pcnet_mmio_readl(opaque, addr, val); - return val; + return ((uint64_t)1 << (size * 8)) - 1; } static const VMStateDescription vmstate_pci_pcnet = { @@ -241,10 +216,12 @@ static const VMStateDescription vmstate_pci_pcnet = { /* PCI interface */ static const MemoryRegionOps pcnet_mmio_ops = { - .old_mmio = { - .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl }, - .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel }, - }, + .read = pcnet_mmio_read, + .write = pcnet_mmio_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 4, .endianness = DEVICE_LITTLE_ENDIAN, }; diff --git a/hw/net/trace-events b/hw/net/trace-events index 663bea1b74..5cd0ad50ce 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -61,12 +61,8 @@ pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) "opaque=%p addr=0x pcnet_aprom_readb(void *opaque, uint32_t addr, uint32_t val) "opaque=%p addr=0x%08x val=0x%02x" pcnet_ioport_read(void *opaque, uint64_t addr, unsigned size) "opaque=%p addr=0x%"PRIx64" size=%d" pcnet_ioport_write(void *opaque, uint64_t addr, uint64_t data, unsigned size) "opaque=%p addr=0x%"PRIx64" data=0x%"PRIx64" size=%d" -pcnet_mmio_writeb(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=0x%"PRIx64" val=0x%x" -pcnet_mmio_writew(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=0x%"PRIx64" val=0x%x" -pcnet_mmio_writel(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=0x%"PRIx64" val=0x%x" -pcnet_mmio_readb(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=0x%"PRIx64" val=0x%x" -pcnet_mmio_readw(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=0x%"PRIx64" val=0x%x" -pcnet_mmio_readl(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=0x%"PRIx64" val=0x%x" +pcnet_mmio_write(void *opaque, uint64_t addr, uint32_t val, unsigned size) "opaque=%p addr=0x%"PRIx64" val=0x%x size=%d" +pcnet_mmio_read(void *opaque, uint64_t addr, unsigned size) "opaque=%p addr=0x%"PRIx64" size=%d" # hw/net/net_rx_pkt.c net_rx_pkt_parsed(bool ip4, bool ip6, bool udp, bool tcp, size_t l3o, size_t l4o, size_t l5o) "RX packet parsed: ip4: %d, ip6: %d, udp: %d, tcp: %d, l3 offset: %zu, l4 offset: %zu, l5 offset: %zu" From b187e20f9b902b611ca9288cef5c490cbb2d91dd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 15/21] hw/net/pcnet-pci: Unify pcnet_ioport_read/write and pcnet_mmio_read/write The only difference between our implementation of the pcnet ioport accessors and the mmio accessors is that the former check BCR_DWIO to see what access widths are permitted for addresses in the aprom range (0x0..0xf). In fact our failure to do this in the mmio accessors is a bug (one which was fixed for the ioport accessors in commit 7ba79741970 in 2011). The data sheet for the Am79C970A does not describe the DWIO bit as only applying for I/O space mapped I/O resources and not memory mapped I/O resources, and our MMIO accessors already honour DWIO for accesses in the 0x10..0x1f range (since the pcnet_ioport_{read,write}{w,l} functions check it). The data sheet for the later but compatible Am79C976 is clearer: it states specifically "DWIO mode applies to both I/O- and memory-mapped acceses." This seems to be reasonable evidence in favour of interpretating the Am79C970A spec as being the same. (NB: Linux's pcnet driver only supports I/O accesses, so the MMIO access part of this device is probably untested anyway.) Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/net/pcnet-pci.c | 67 ++------------------------------------------- hw/net/trace-events | 2 -- 2 files changed, 2 insertions(+), 67 deletions(-) diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 248fb3ba29..7c73855783 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -139,69 +139,6 @@ static const MemoryRegionOps pcnet_io_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -/* - * TODO: should MMIO accesses to the addresses corresponding to the - * APROM also honour the BCR_DWIO() setting? If so, then these functions - * and pcnet_ioport_write/pcnet_ioport_read could be merged. - * If not, then should pcnet_ioport_{read,write}{w,l} really check - * BCR_DWIO() for MMIO writes ? - */ -static void pcnet_mmio_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - PCNetState *d = opaque; - - trace_pcnet_mmio_write(opaque, addr, size, val); - - if (addr < 0x10) { - if (size == 1) { - pcnet_aprom_writeb(d, addr, data); - } else if ((addr & 1) == 0 && size == 2) { - pcnet_aprom_writeb(d, addr, data & 0xff); - pcnet_aprom_writeb(d, addr + 1, data >> 8); - } else if ((addr & 3) == 0 && size == 4) { - pcnet_aprom_writeb(d, addr, data & 0xff); - pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff); - pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff); - pcnet_aprom_writeb(d, addr + 3, data >> 24); - } - } else { - if (size == 2) { - pcnet_ioport_writew(d, addr, data); - } else if (size == 4) { - pcnet_ioport_writel(d, addr, data); - } - } -} - -static uint64_t pcnet_mmio_read(void *opque, hwaddr addr, unsigned size) -{ - PCNetState *d = opaque; - - trace_pcnet_ioport_read(opaque, addr, size); - - if (addr < 0x10) { - if (size == 1) { - return pcnet_aprom_readb(d, addr); - } else if ((addr & 1) == 0 && size == 2) { - return pcnet_aprom_readb(d, addr) | - (pcnet_aprom_readb(d, addr + 1) << 8); - } else if ((addr & 3) == 0 && size == 4) { - return pcnet_aprom_readb(d, addr) | - (pcnet_aprom_readb(d, addr + 1) << 8) | - (pcnet_aprom_readb(d, addr + 2) << 16) | - (pcnet_aprom_readb(d, addr + 3) << 24); - } - } else { - if (size == 2) { - return pcnet_ioport_readw(d, addr); - } else if (size == 4) { - return pcnet_ioport_readl(d, addr); - } - } - return ((uint64_t)1 << (size * 8)) - 1; -} - static const VMStateDescription vmstate_pci_pcnet = { .name = "pcnet", .version_id = 3, @@ -216,8 +153,8 @@ static const VMStateDescription vmstate_pci_pcnet = { /* PCI interface */ static const MemoryRegionOps pcnet_mmio_ops = { - .read = pcnet_mmio_read, - .write = pcnet_mmio_write, + .read = pcnet_ioport_read, + .write = pcnet_ioport_write, .valid.min_access_size = 1, .valid.max_access_size = 4, .impl.min_access_size = 1, diff --git a/hw/net/trace-events b/hw/net/trace-events index 5cd0ad50ce..c1dea4b156 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -61,8 +61,6 @@ pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) "opaque=%p addr=0x pcnet_aprom_readb(void *opaque, uint32_t addr, uint32_t val) "opaque=%p addr=0x%08x val=0x%02x" pcnet_ioport_read(void *opaque, uint64_t addr, unsigned size) "opaque=%p addr=0x%"PRIx64" size=%d" pcnet_ioport_write(void *opaque, uint64_t addr, uint64_t data, unsigned size) "opaque=%p addr=0x%"PRIx64" data=0x%"PRIx64" size=%d" -pcnet_mmio_write(void *opaque, uint64_t addr, uint32_t val, unsigned size) "opaque=%p addr=0x%"PRIx64" val=0x%x size=%d" -pcnet_mmio_read(void *opaque, uint64_t addr, unsigned size) "opaque=%p addr=0x%"PRIx64" size=%d" # hw/net/net_rx_pkt.c net_rx_pkt_parsed(bool ip4, bool ip6, bool udp, bool tcp, size_t l3o, size_t l4o, size_t l5o) "RX packet parsed: ip4: %d, ip6: %d, udp: %d, tcp: %d, l3 offset: %zu, l4 offset: %zu, l5 offset: %zu" From 3e1dd459cbd95c66753f7c9368e680dde2ba60e2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 25 Sep 2018 14:02:32 +0100 Subject: [PATCH 16/21] hw/timer/cmsdk-apb-dualtimer: Add missing 'break' statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'break' statements missing from a switch in the APB dual-timer write function. Spotted by Coverity as CID 1395626 and 1395633. Reported-by: Paolo Bonzini Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20180924123122.14549-1-peter.maydell@linaro.org --- hw/timer/cmsdk-apb-dualtimer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c index ccd49753b7..30245990f3 100644 --- a/hw/timer/cmsdk-apb-dualtimer.c +++ b/hw/timer/cmsdk-apb-dualtimer.c @@ -296,9 +296,11 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset, case A_TIMERITCR: s->timeritcr = value & R_TIMERITCR_VALID_MASK; cmsdk_apb_dualtimer_update(s); + break; case A_TIMERITOP: s->timeritop = value & R_TIMERITOP_VALID_MASK; cmsdk_apb_dualtimer_update(s); + break; default: bad_offset: qemu_log_mask(LOG_GUEST_ERROR, From 03f1d7201a8ac6adeb3aae8c575f3e67e153c54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 25 Sep 2018 14:02:33 +0100 Subject: [PATCH 17/21] aspeed/timer: fix compile breakage with clang 3.4.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In file included from /home/thuth/devel/qemu/hw/timer/aspeed_timer.c:16: /home/thuth/devel/qemu/include/hw/misc/aspeed_scu.h:37:3: error: redefinition of typedef 'AspeedSCUState' is a C11 feature [-Werror,-Wtypedef-redefinition] } AspeedSCUState; ^ /home/thuth/devel/qemu/include/hw/timer/aspeed_timer.h:27:31: note: previous definition is here typedef struct AspeedSCUState AspeedSCUState; Reported-by: Thomas Huth Signed-off-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-id: 20180921161939.822-2-clg@kaod.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/timer/aspeed_timer.c | 1 - include/hw/timer/aspeed_timer.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 5e3f51b66b..54b400b94a 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -13,7 +13,6 @@ #include "qapi/error.h" #include "hw/sysbus.h" #include "hw/timer/aspeed_timer.h" -#include "hw/misc/aspeed_scu.h" #include "qemu-common.h" #include "qemu/bitops.h" #include "qemu/timer.h" diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_timer.h index 040a088734..1fb949e167 100644 --- a/include/hw/timer/aspeed_timer.h +++ b/include/hw/timer/aspeed_timer.h @@ -23,8 +23,7 @@ #define ASPEED_TIMER_H #include "qemu/timer.h" - -typedef struct AspeedSCUState AspeedSCUState; +#include "hw/misc/aspeed_scu.h" #define ASPEED_TIMER(obj) \ OBJECT_CHECK(AspeedTimerCtrlState, (obj), TYPE_ASPEED_TIMER); From 3d9bada2408329269424628a3be6340c6c28de0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 25 Sep 2018 14:02:33 +0100 Subject: [PATCH 18/21] hw/arm/aspeed: change the FMC flash model of the AST2500 evb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2500 evb is shipped with a W25Q256 which has a non volatile bit to make the chip operate in 4 Byte address mode at power up. This should be an interesting feature to model as it will exercise a bit more the SMC controllers and MMIO execution at boot time. Signed-off-by: Cédric Le Goater Message-id: 20180921161939.822-3-clg@kaod.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index bb9590f1ae..f2d64e4551 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -105,7 +105,7 @@ static const AspeedBoardConfig aspeed_boards[] = { [AST2500_EVB] = { .soc_name = "ast2500-a1", .hw_strap1 = AST2500_EVB_HW_STRAP1, - .fmc_model = "n25q256a", + .fmc_model = "w25q256", .spi_model = "mx25l25635e", .num_cs = 1, .i2c_init = ast2500_evb_i2c_init, From fca9ca1b13593ba23b924ac79212753a43d825d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 25 Sep 2018 14:02:33 +0100 Subject: [PATCH 19/21] hw/arm/aspeed: Add an Aspeed machine class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code looks better, it removes duplicated lines and it will ease the introduction of common properties for the Aspeed machines. Signed-off-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-id: 20180921161939.822-4-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 212 +++++++++++++--------------------------- include/hw/arm/aspeed.h | 46 +++++++++ 2 files changed, 116 insertions(+), 142 deletions(-) create mode 100644 include/hw/arm/aspeed.h diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index f2d64e4551..6b33ecd5aa 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -15,6 +15,7 @@ #include "cpu.h" #include "exec/address-spaces.h" #include "hw/arm/arm.h" +#include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" #include "hw/boards.h" #include "hw/i2c/smbus.h" @@ -34,22 +35,6 @@ typedef struct AspeedBoardState { MemoryRegion max_ram; } AspeedBoardState; -typedef struct AspeedBoardConfig { - const char *soc_name; - uint32_t hw_strap1; - const char *fmc_model; - const char *spi_model; - uint32_t num_cs; - void (*i2c_init)(AspeedBoardState *bmc); -} AspeedBoardConfig; - -enum { - PALMETTO_BMC, - AST2500_EVB, - ROMULUS_BMC, - WITHERSPOON_BMC, -}; - /* Palmetto hardware value: 0x120CE416 */ #define PALMETTO_BMC_HW_STRAP1 ( \ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ @@ -88,46 +73,6 @@ enum { /* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */ #define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 -static void palmetto_bmc_i2c_init(AspeedBoardState *bmc); -static void ast2500_evb_i2c_init(AspeedBoardState *bmc); -static void romulus_bmc_i2c_init(AspeedBoardState *bmc); -static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc); - -static const AspeedBoardConfig aspeed_boards[] = { - [PALMETTO_BMC] = { - .soc_name = "ast2400-a1", - .hw_strap1 = PALMETTO_BMC_HW_STRAP1, - .fmc_model = "n25q256a", - .spi_model = "mx25l25635e", - .num_cs = 1, - .i2c_init = palmetto_bmc_i2c_init, - }, - [AST2500_EVB] = { - .soc_name = "ast2500-a1", - .hw_strap1 = AST2500_EVB_HW_STRAP1, - .fmc_model = "w25q256", - .spi_model = "mx25l25635e", - .num_cs = 1, - .i2c_init = ast2500_evb_i2c_init, - }, - [ROMULUS_BMC] = { - .soc_name = "ast2500-a1", - .hw_strap1 = ROMULUS_BMC_HW_STRAP1, - .fmc_model = "n25q256a", - .spi_model = "mx66l1g45g", - .num_cs = 2, - .i2c_init = romulus_bmc_i2c_init, - }, - [WITHERSPOON_BMC] = { - .soc_name = "ast2500-a1", - .hw_strap1 = WITHERSPOON_BMC_HW_STRAP1, - .fmc_model = "mx25l25635e", - .spi_model = "mx66l1g45g", - .num_cs = 2, - .i2c_init = witherspoon_bmc_i2c_init, - }, -}; - /* * The max ram region is for firmwares that scan the address space * with load/store to guess how much RAM the SoC has. @@ -313,30 +258,6 @@ static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort); } -static void palmetto_bmc_init(MachineState *machine) -{ - aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]); -} - -static void palmetto_bmc_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)"; - mc->init = palmetto_bmc_init; - mc->max_cpus = 1; - mc->no_sdcard = 1; - mc->no_floppy = 1; - mc->no_cdrom = 1; - mc->no_parallel = 1; -} - -static const TypeInfo palmetto_bmc_type = { - .name = MACHINE_TYPE_NAME("palmetto-bmc"), - .parent = TYPE_MACHINE, - .class_init = palmetto_bmc_class_init, -}; - static void ast2500_evb_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -353,30 +274,6 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); } -static void ast2500_evb_init(MachineState *machine) -{ - aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]); -} - -static void ast2500_evb_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Aspeed AST2500 EVB (ARM1176)"; - mc->init = ast2500_evb_init; - mc->max_cpus = 1; - mc->no_sdcard = 1; - mc->no_floppy = 1; - mc->no_cdrom = 1; - mc->no_parallel = 1; -} - -static const TypeInfo ast2500_evb_type = { - .name = MACHINE_TYPE_NAME("ast2500-evb"), - .parent = TYPE_MACHINE, - .class_init = ast2500_evb_class_init, -}; - static void romulus_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -386,30 +283,6 @@ static void romulus_bmc_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); } -static void romulus_bmc_init(MachineState *machine) -{ - aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]); -} - -static void romulus_bmc_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "OpenPOWER Romulus BMC (ARM1176)"; - mc->init = romulus_bmc_init; - mc->max_cpus = 1; - mc->no_sdcard = 1; - mc->no_floppy = 1; - mc->no_cdrom = 1; - mc->no_parallel = 1; -} - -static const TypeInfo romulus_bmc_type = { - .name = MACHINE_TYPE_NAME("romulus-bmc"), - .parent = TYPE_MACHINE, - .class_init = romulus_bmc_class_init, -}; - static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -433,36 +306,91 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) 0x60); } -static void witherspoon_bmc_init(MachineState *machine) +static void aspeed_machine_init(MachineState *machine) { - aspeed_board_init(machine, &aspeed_boards[WITHERSPOON_BMC]); + AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine); + + aspeed_board_init(machine, amc->board); } -static void witherspoon_bmc_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + const AspeedBoardConfig *board = data; - mc->desc = "OpenPOWER Witherspoon BMC (ARM1176)"; - mc->init = witherspoon_bmc_init; + mc->desc = board->desc; + mc->init = aspeed_machine_init; mc->max_cpus = 1; mc->no_sdcard = 1; mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; + amc->board = board; } -static const TypeInfo witherspoon_bmc_type = { - .name = MACHINE_TYPE_NAME("witherspoon-bmc"), +static const TypeInfo aspeed_machine_type = { + .name = TYPE_ASPEED_MACHINE, .parent = TYPE_MACHINE, - .class_init = witherspoon_bmc_class_init, + .instance_size = sizeof(AspeedMachine), + .class_size = sizeof(AspeedMachineClass), + .abstract = true, }; -static void aspeed_machine_init(void) +static const AspeedBoardConfig aspeed_boards[] = { + { + .name = MACHINE_TYPE_NAME("palmetto-bmc"), + .desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)", + .soc_name = "ast2400-a1", + .hw_strap1 = PALMETTO_BMC_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx25l25635e", + .num_cs = 1, + .i2c_init = palmetto_bmc_i2c_init, + }, { + .name = MACHINE_TYPE_NAME("ast2500-evb"), + .desc = "Aspeed AST2500 EVB (ARM1176)", + .soc_name = "ast2500-a1", + .hw_strap1 = AST2500_EVB_HW_STRAP1, + .fmc_model = "w25q256", + .spi_model = "mx25l25635e", + .num_cs = 1, + .i2c_init = ast2500_evb_i2c_init, + }, { + .name = MACHINE_TYPE_NAME("romulus-bmc"), + .desc = "OpenPOWER Romulus BMC (ARM1176)", + .soc_name = "ast2500-a1", + .hw_strap1 = ROMULUS_BMC_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx66l1g45g", + .num_cs = 2, + .i2c_init = romulus_bmc_i2c_init, + }, { + .name = MACHINE_TYPE_NAME("witherspoon-bmc"), + .desc = "OpenPOWER Witherspoon BMC (ARM1176)", + .soc_name = "ast2500-a1", + .hw_strap1 = WITHERSPOON_BMC_HW_STRAP1, + .fmc_model = "mx25l25635e", + .spi_model = "mx66l1g45g", + .num_cs = 2, + .i2c_init = witherspoon_bmc_i2c_init, + }, +}; + +static void aspeed_machine_types(void) { - type_register_static(&palmetto_bmc_type); - type_register_static(&ast2500_evb_type); - type_register_static(&romulus_bmc_type); - type_register_static(&witherspoon_bmc_type); + int i; + + type_register_static(&aspeed_machine_type); + for (i = 0; i < ARRAY_SIZE(aspeed_boards); ++i) { + TypeInfo ti = { + .name = aspeed_boards[i].name, + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_class_init, + .class_data = (void *)&aspeed_boards[i], + }; + type_register(&ti); + } } -type_init(aspeed_machine_init) +type_init(aspeed_machine_types) diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h new file mode 100644 index 0000000000..325c091d09 --- /dev/null +++ b/include/hw/arm/aspeed.h @@ -0,0 +1,46 @@ +/* + * Aspeed Machines + * + * Copyright 2018 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ +#ifndef ARM_ASPEED_H +#define ARM_ASPEED_H + +#include "hw/boards.h" + +typedef struct AspeedBoardState AspeedBoardState; + +typedef struct AspeedBoardConfig { + const char *name; + const char *desc; + const char *soc_name; + uint32_t hw_strap1; + const char *fmc_model; + const char *spi_model; + uint32_t num_cs; + void (*i2c_init)(AspeedBoardState *bmc); +} AspeedBoardConfig; + +#define TYPE_ASPEED_MACHINE MACHINE_TYPE_NAME("aspeed") +#define ASPEED_MACHINE(obj) \ + OBJECT_CHECK(AspeedMachine, (obj), TYPE_ASPEED_MACHINE) + +typedef struct AspeedMachine { + MachineState parent_obj; +} AspeedMachine; + +#define ASPEED_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(AspeedMachineClass, (klass), TYPE_ASPEED_MACHINE) +#define ASPEED_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AspeedMachineClass, (obj), TYPE_ASPEED_MACHINE) + +typedef struct AspeedMachineClass { + MachineClass parent_obj; + const AspeedBoardConfig *board; +} AspeedMachineClass; + + +#endif From b3d6b8f5af62fcfcec53110388a46960e641c5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 25 Sep 2018 14:02:33 +0100 Subject: [PATCH 20/21] aspeed/smc: fix some alignment issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-id: 20180921161939.822-6-clg@kaod.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/ssi/aspeed_smc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index b29bfd3124..1270842dcf 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -388,8 +388,8 @@ static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, static void aspeed_smc_flash_default_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%" - PRIx64 "\n", __func__, addr, size, data); + qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%" + PRIx64 "\n", __func__, addr, size, data); } static const MemoryRegionOps aspeed_smc_flash_default_ops = { @@ -529,7 +529,7 @@ static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr) */ if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) { for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) { - ssi_transfer(fl->controller->spi, 0xFF); + ssi_transfer(fl->controller->spi, 0xFF); } } } @@ -567,7 +567,7 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) } static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size) + unsigned size) { AspeedSMCFlash *fl = opaque; AspeedSMCState *s = fl->controller; From 060a65df056a5d6ca3a6a91e7bf150ca1fbccddf Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 25 Sep 2018 14:02:33 +0100 Subject: [PATCH 21/21] target/arm: Start AArch32 CPUs with EL2 but not EL3 in Hyp mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ARMv8 architecture defines that an AArch32 CPU starts in SVC mode, unless EL2 is the highest available EL, in which case it starts in Hyp mode. (In ARMv7 a CPU with EL2 but not EL3 was not a valid configuration, but we don't specifically reject this if the user asks for one.) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20180823135047.16525-1-peter.maydell@linaro.org --- target/arm/cpu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 258ba6dcaa..b5e61cc177 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -199,8 +199,18 @@ static void arm_cpu_reset(CPUState *s) env->cp15.c15_cpar = 1; } #else - /* SVC mode with interrupts disabled. */ - env->uncached_cpsr = ARM_CPU_MODE_SVC; + + /* + * If the highest available EL is EL2, AArch32 will start in Hyp + * mode; otherwise it starts in SVC. Note that if we start in + * AArch64 then these values in the uncached_cpsr will be ignored. + */ + if (arm_feature(env, ARM_FEATURE_EL2) && + !arm_feature(env, ARM_FEATURE_EL3)) { + env->uncached_cpsr = ARM_CPU_MODE_HYP; + } else { + env->uncached_cpsr = ARM_CPU_MODE_SVC; + } env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F; if (arm_feature(env, ARM_FEATURE_M)) {