aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-10-15 18:15:59 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-10-15 18:15:59 +0100
commit69b81893bc28feb678188fbcdce52eff1609bdad (patch)
tree850e918d11bc031e9a2cd07da526dfea4af6bc65
parent3af78db68176a049e2570822f64604e0692c1447 (diff)
parent19845504da1bdee4be7d0fba33da5be9efa4c11b (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20191015' into staging
target-arm queue: * Add Aspeed AST2600 SoC support (but no new board model yet) * aspeed/wdt: Check correct register for clock source * bcm2835: code cleanups, better logging, trace events * implement v2.0 of the Arm semihosting specification * provide new 'transaction-based' ptimer API and use it for the Arm devices that use ptimers * ARM: KVM: support more than 256 CPUs # gpg: Signature made Tue 15 Oct 2019 18:09:42 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20191015: (67 commits) hw/misc/bcm2835_mbox: Add trace events hw/arm/bcm2835: Add various unimplemented peripherals hw/arm/bcm2835: Rename some definitions hw/arm/bcm2835_peripherals: Name various address spaces hw/arm/bcm2835_peripherals: Improve logging hw/arm/raspi: Use the IEC binary prefix definitions aspeed/soc: Add ASPEED Video stub aspeed: add support for the Aspeed MII controller of the AST2600 aspeed: Parameterise number of MACs m25p80: Add support for w25q512jv aspeed/soc: Add AST2600 support aspeed: Introduce an object class per SoC aspeed/i2c: Add AST2600 support aspeed/i2c: Introduce an object class per SoC hw/gpio: Add in AST2600 specific implementation aspeed/smc: Add AST2600 support aspeed/smc: Introduce segment operations hw: wdt_aspeed: Add AST2600 support watchdog/aspeed: Introduce an object class per SoC aspeed/sdmc: Add AST2600 support ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm/aspeed.c19
-rw-r--r--hw/arm/aspeed_ast2600.c523
-rw-r--r--hw/arm/aspeed_soc.c199
-rw-r--r--hw/arm/bcm2835_peripherals.c38
-rw-r--r--hw/arm/bcm2836.c2
-rw-r--r--hw/arm/musicpal.c16
-rw-r--r--hw/arm/raspi.c4
-rw-r--r--hw/block/m25p80.c1
-rw-r--r--hw/char/bcm2835_aux.c5
-rw-r--r--hw/core/ptimer.c154
-rw-r--r--hw/display/bcm2835_fb.c2
-rw-r--r--hw/dma/bcm2835_dma.c10
-rw-r--r--hw/dma/xilinx_axidma.c2
-rw-r--r--hw/gpio/aspeed_gpio.c142
-rw-r--r--hw/i2c/aspeed_i2c.c106
-rw-r--r--hw/intc/arm_gic_kvm.c7
-rw-r--r--hw/intc/bcm2836_control.c7
-rw-r--r--hw/m68k/mcf5206.c2
-rw-r--r--hw/m68k/mcf5208.c2
-rw-r--r--hw/misc/aspeed_scu.c194
-rw-r--r--hw/misc/aspeed_sdmc.c250
-rw-r--r--hw/misc/bcm2835_mbox.c14
-rw-r--r--hw/misc/bcm2835_property.c20
-rw-r--r--hw/misc/trace-events6
-rw-r--r--hw/net/fsl_etsec/etsec.c2
-rw-r--r--hw/net/ftgmac100.c162
-rw-r--r--hw/net/lan9118.c11
-rw-r--r--hw/sd/Makefile.objs1
-rw-r--r--hw/sd/aspeed_sdhci.c198
-rw-r--r--hw/ssi/aspeed_smc.c177
-rw-r--r--hw/timer/allwinner-a10-pit.c12
-rw-r--r--hw/timer/altera_timer.c2
-rw-r--r--hw/timer/arm_mptimer.c18
-rw-r--r--hw/timer/arm_timer.c16
-rw-r--r--hw/timer/aspeed_timer.c213
-rw-r--r--hw/timer/cmsdk-apb-dualtimer.c14
-rw-r--r--hw/timer/cmsdk-apb-timer.c15
-rw-r--r--hw/timer/digic-timer.c16
-rw-r--r--hw/timer/etraxfs_timer.c6
-rw-r--r--hw/timer/exynos4210_mct.c107
-rw-r--r--hw/timer/exynos4210_pwm.c17
-rw-r--r--hw/timer/exynos4210_rtc.c22
-rw-r--r--hw/timer/grlib_gptimer.c2
-rw-r--r--hw/timer/imx_epit.c32
-rw-r--r--hw/timer/imx_gpt.c21
-rw-r--r--hw/timer/lm32_timer.c2
-rw-r--r--hw/timer/milkymist-sysctl.c4
-rw-r--r--hw/timer/mss-timer.c11
-rw-r--r--hw/timer/puv3_ost.c2
-rw-r--r--hw/timer/sh_timer.c2
-rw-r--r--hw/timer/slavio_timer.c2
-rw-r--r--hw/timer/xilinx_timer.c2
-rw-r--r--hw/watchdog/cmsdk-apb-watchdog.c13
-rw-r--r--hw/watchdog/wdt_aspeed.c153
-rw-r--r--include/hw/arm/aspeed_soc.h29
-rw-r--r--include/hw/arm/bcm2835_peripherals.h15
-rw-r--r--include/hw/arm/raspi_platform.h24
-rw-r--r--include/hw/i2c/aspeed_i2c.h20
-rw-r--r--include/hw/misc/aspeed_scu.h7
-rw-r--r--include/hw/misc/aspeed_sdmc.h20
-rw-r--r--include/hw/net/ftgmac100.h17
-rw-r--r--include/hw/ptimer.h83
-rw-r--r--include/hw/sd/aspeed_sdhci.h34
-rw-r--r--include/hw/ssi/aspeed_smc.h4
-rw-r--r--include/hw/timer/aspeed_timer.h18
-rw-r--r--include/hw/timer/mss-timer.h1
-rw-r--r--include/hw/watchdog/wdt_aspeed.h19
-rw-r--r--include/standard-headers/asm-x86/bootparam.h2
-rw-r--r--include/standard-headers/asm-x86/kvm_para.h1
-rw-r--r--include/standard-headers/linux/ethtool.h24
-rw-r--r--include/standard-headers/linux/pci_regs.h19
-rw-r--r--include/standard-headers/linux/virtio_fs.h19
-rw-r--r--include/standard-headers/linux/virtio_ids.h2
-rw-r--r--include/standard-headers/linux/virtio_iommu.h165
-rw-r--r--include/standard-headers/linux/virtio_pmem.h6
-rw-r--r--linux-headers/asm-arm/kvm.h16
-rw-r--r--linux-headers/asm-arm/unistd-common.h2
-rw-r--r--linux-headers/asm-arm64/kvm.h21
-rw-r--r--linux-headers/asm-generic/mman-common.h18
-rw-r--r--linux-headers/asm-generic/mman.h10
-rw-r--r--linux-headers/asm-generic/unistd.h10
-rw-r--r--linux-headers/asm-mips/mman.h3
-rw-r--r--linux-headers/asm-mips/unistd_n32.h1
-rw-r--r--linux-headers/asm-mips/unistd_n64.h1
-rw-r--r--linux-headers/asm-mips/unistd_o32.h1
-rw-r--r--linux-headers/asm-powerpc/mman.h6
-rw-r--r--linux-headers/asm-powerpc/unistd_32.h2
-rw-r--r--linux-headers/asm-powerpc/unistd_64.h2
-rw-r--r--linux-headers/asm-s390/kvm.h6
-rw-r--r--linux-headers/asm-s390/unistd_32.h2
-rw-r--r--linux-headers/asm-s390/unistd_64.h2
-rw-r--r--linux-headers/asm-x86/kvm.h28
-rw-r--r--linux-headers/asm-x86/unistd.h2
-rw-r--r--linux-headers/asm-x86/unistd_32.h2
-rw-r--r--linux-headers/asm-x86/unistd_64.h2
-rw-r--r--linux-headers/asm-x86/unistd_x32.h2
-rw-r--r--linux-headers/linux/kvm.h12
-rw-r--r--linux-headers/linux/psp-sev.h5
-rw-r--r--linux-headers/linux/vfio.h71
-rw-r--r--target/arm/arm-semi.c705
-rw-r--r--target/arm/cpu.c10
-rw-r--r--target/arm/kvm.c22
-rw-r--r--target/arm/kvm_arm.h1
-rw-r--r--tests/ptimer-test.c106
105 files changed, 3933 insertions, 649 deletions
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 43ce8d5b19..fe749f65fd 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -41,7 +41,7 @@ obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
-obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
+obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o aspeed_ast2600.o
obj-$(CONFIG_MPS2) += mps2.o
obj-$(CONFIG_MPS2) += mps2-tz.o
obj-$(CONFIG_MSF2) += msf2-soc.o
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index aa72be309d..52993f84b4 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -170,6 +170,7 @@ static void aspeed_board_init(MachineState *machine,
AspeedSoCClass *sc;
DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
ram_addr_t max_ram_size;
+ int i;
bmc = g_new0(AspeedBoardState, 1);
@@ -214,7 +215,7 @@ static void aspeed_board_init(MachineState *machine,
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
memory_region_add_subregion(&bmc->ram_container, 0, &bmc->ram);
memory_region_add_subregion(get_system_memory(),
- sc->info->memmap[ASPEED_SDRAM],
+ sc->memmap[ASPEED_SDRAM],
&bmc->ram_container);
max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size",
@@ -245,13 +246,26 @@ static void aspeed_board_init(MachineState *machine,
}
aspeed_board_binfo.ram_size = ram_size;
- aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM];
+ aspeed_board_binfo.loader_start = sc->memmap[ASPEED_SDRAM];
aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus;
if (cfg->i2c_init) {
cfg->i2c_init(bmc);
}
+ for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) {
+ SDHCIState *sdhci = &bmc->soc.sdhci.slots[i];
+ DriveInfo *dinfo = drive_get_next(IF_SD);
+ BlockBackend *blk;
+ DeviceState *card;
+
+ blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
+ card = qdev_create(qdev_get_child_bus(DEVICE(sdhci), "sd-bus"),
+ TYPE_SD_CARD);
+ qdev_prop_set_drive(card, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(card), true, "realized", &error_fatal);
+ }
+
arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo);
}
@@ -373,7 +387,6 @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data)
mc->desc = board->desc;
mc->init = aspeed_machine_init;
mc->max_cpus = ASPEED_CPUS_NUM;
- mc->no_sdcard = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
new file mode 100644
index 0000000000..931887ac68
--- /dev/null
+++ b/hw/arm/aspeed_ast2600.c
@@ -0,0 +1,523 @@
+/*
+ * ASPEED SoC 2600 family
+ *
+ * Copyright (c) 2016-2019, IBM Corporation.
+ *
+ * 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 "cpu.h"
+#include "exec/address-spaces.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/aspeed_soc.h"
+#include "hw/char/serial.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/i2c/aspeed_i2c.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+
+#define ASPEED_SOC_IOMEM_SIZE 0x00200000
+
+static const hwaddr aspeed_soc_ast2600_memmap[] = {
+ [ASPEED_SRAM] = 0x10000000,
+ /* 0x16000000 0x17FFFFFF : AHB BUS do LPC Bus bridge */
+ [ASPEED_IOMEM] = 0x1E600000,
+ [ASPEED_PWM] = 0x1E610000,
+ [ASPEED_FMC] = 0x1E620000,
+ [ASPEED_SPI1] = 0x1E630000,
+ [ASPEED_SPI2] = 0x1E641000,
+ [ASPEED_MII1] = 0x1E650000,
+ [ASPEED_MII2] = 0x1E650008,
+ [ASPEED_MII3] = 0x1E650010,
+ [ASPEED_MII4] = 0x1E650018,
+ [ASPEED_ETH1] = 0x1E660000,
+ [ASPEED_ETH3] = 0x1E670000,
+ [ASPEED_ETH2] = 0x1E680000,
+ [ASPEED_ETH4] = 0x1E690000,
+ [ASPEED_VIC] = 0x1E6C0000,
+ [ASPEED_SDMC] = 0x1E6E0000,
+ [ASPEED_SCU] = 0x1E6E2000,
+ [ASPEED_XDMA] = 0x1E6E7000,
+ [ASPEED_ADC] = 0x1E6E9000,
+ [ASPEED_VIDEO] = 0x1E700000,
+ [ASPEED_SDHCI] = 0x1E740000,
+ [ASPEED_GPIO] = 0x1E780000,
+ [ASPEED_GPIO_1_8V] = 0x1E780800,
+ [ASPEED_RTC] = 0x1E781000,
+ [ASPEED_TIMER1] = 0x1E782000,
+ [ASPEED_WDT] = 0x1E785000,
+ [ASPEED_LPC] = 0x1E789000,
+ [ASPEED_IBT] = 0x1E789140,
+ [ASPEED_I2C] = 0x1E78A000,
+ [ASPEED_UART1] = 0x1E783000,
+ [ASPEED_UART5] = 0x1E784000,
+ [ASPEED_VUART] = 0x1E787000,
+ [ASPEED_SDRAM] = 0x80000000,
+};
+
+#define ASPEED_A7MPCORE_ADDR 0x40460000
+
+#define ASPEED_SOC_AST2600_MAX_IRQ 128
+
+static const int aspeed_soc_ast2600_irqmap[] = {
+ [ASPEED_UART1] = 47,
+ [ASPEED_UART2] = 48,
+ [ASPEED_UART3] = 49,
+ [ASPEED_UART4] = 50,
+ [ASPEED_UART5] = 8,
+ [ASPEED_VUART] = 8,
+ [ASPEED_FMC] = 39,
+ [ASPEED_SDMC] = 0,
+ [ASPEED_SCU] = 12,
+ [ASPEED_ADC] = 78,
+ [ASPEED_XDMA] = 6,
+ [ASPEED_SDHCI] = 43,
+ [ASPEED_GPIO] = 40,
+ [ASPEED_GPIO_1_8V] = 11,
+ [ASPEED_RTC] = 13,
+ [ASPEED_TIMER1] = 16,
+ [ASPEED_TIMER2] = 17,
+ [ASPEED_TIMER3] = 18,
+ [ASPEED_TIMER4] = 19,
+ [ASPEED_TIMER5] = 20,
+ [ASPEED_TIMER6] = 21,
+ [ASPEED_TIMER7] = 22,
+ [ASPEED_TIMER8] = 23,
+ [ASPEED_WDT] = 24,
+ [ASPEED_PWM] = 44,
+ [ASPEED_LPC] = 35,
+ [ASPEED_IBT] = 35, /* LPC */
+ [ASPEED_I2C] = 110, /* 110 -> 125 */
+ [ASPEED_ETH1] = 2,
+ [ASPEED_ETH2] = 3,
+ [ASPEED_ETH3] = 32,
+ [ASPEED_ETH4] = 33,
+
+};
+
+static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl)
+{
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ return qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[ctrl]);
+}
+
+static void aspeed_soc_ast2600_init(Object *obj)
+{
+ AspeedSoCState *s = ASPEED_SOC(obj);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int i;
+ char socname[8];
+ char typename[64];
+
+ if (sscanf(sc->name, "%7s", socname) != 1) {
+ g_assert_not_reached();
+ }
+
+ for (i = 0; i < sc->num_cpus; i++) {
+ object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
+ sizeof(s->cpu[i]), sc->cpu_type,
+ &error_abort, NULL);
+ }
+
+ snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname);
+ sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu),
+ typename);
+ qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
+ sc->silicon_rev);
+ object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
+ "hw-strap1", &error_abort);
+ object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
+ "hw-strap2", &error_abort);
+ object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
+ "hw-prot-key", &error_abort);
+
+ sysbus_init_child_obj(obj, "a7mpcore", &s->a7mpcore,
+ sizeof(s->a7mpcore), TYPE_A15MPCORE_PRIV);
+
+ sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc),
+ TYPE_ASPEED_RTC);
+
+ snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
+ sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
+ sizeof(s->timerctrl), typename);
+ object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
+ OBJECT(&s->scu), &error_abort);
+
+ snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+ sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c),
+ typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
+ sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc),
+ typename);
+ object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs",
+ &error_abort);
+ object_property_add_alias(obj, "dram", OBJECT(&s->fmc), "dram",
+ &error_abort);
+
+ for (i = 0; i < sc->spis_num; i++) {
+ snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname);
+ sysbus_init_child_obj(obj, "spi[*]", OBJECT(&s->spi[i]),
+ sizeof(s->spi[i]), typename);
+ }
+
+ snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
+ sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc),
+ typename);
+ object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
+ "ram-size", &error_abort);
+ object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc),
+ "max-ram-size", &error_abort);
+
+ for (i = 0; i < sc->wdts_num; i++) {
+ snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
+ sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]),
+ sizeof(s->wdt[i]), typename);
+ object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
+ OBJECT(&s->scu), &error_abort);
+ }
+
+ for (i = 0; i < sc->macs_num; i++) {
+ sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
+ sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
+
+ sysbus_init_child_obj(obj, "mii[*]", &s->mii[i], sizeof(s->mii[i]),
+ TYPE_ASPEED_MII);
+ object_property_add_const_link(OBJECT(&s->mii[i]), "nic",
+ OBJECT(&s->ftgmac100[i]),
+ &error_abort);
+ }
+
+ sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
+ TYPE_ASPEED_XDMA);
+
+ snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+ sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio),
+ typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname);
+ sysbus_init_child_obj(obj, "gpio_1_8v", OBJECT(&s->gpio_1_8v),
+ sizeof(s->gpio_1_8v), typename);
+
+ sysbus_init_child_obj(obj, "sdc", OBJECT(&s->sdhci), sizeof(s->sdhci),
+ TYPE_ASPEED_SDHCI);
+
+ /* Init sd card slot class here so that they're under the correct parent */
+ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) {
+ sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(&s->sdhci.slots[i]),
+ sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI);
+ }
+}
+
+/*
+ * ASPEED ast2600 has 0xf as cluster ID
+ *
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0388e/CIHEBGFG.html
+ */
+static uint64_t aspeed_calc_affinity(int cpu)
+{
+ return (0xf << ARM_AFF1_SHIFT) | cpu;
+}
+
+static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
+{
+ int i;
+ AspeedSoCState *s = ASPEED_SOC(dev);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ Error *err = NULL, *local_err = NULL;
+ qemu_irq irq;
+
+ /* IO space */
+ create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_IOMEM],
+ ASPEED_SOC_IOMEM_SIZE);
+
+ /* Video engine stub */
+ create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_VIDEO],
+ 0x1000);
+
+ if (s->num_cpus > sc->num_cpus) {
+ warn_report("%s: invalid number of CPUs %d, using default %d",
+ sc->name, s->num_cpus, sc->num_cpus);
+ s->num_cpus = sc->num_cpus;
+ }
+
+ /* CPU */
+ for (i = 0; i < s->num_cpus; i++) {
+ object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC,
+ "psci-conduit", &error_abort);
+ if (s->num_cpus > 1) {
+ object_property_set_int(OBJECT(&s->cpu[i]),
+ ASPEED_A7MPCORE_ADDR,
+ "reset-cbar", &error_abort);
+ }
+ object_property_set_int(OBJECT(&s->cpu[i]), aspeed_calc_affinity(i),
+ "mp-affinity", &error_abort);
+
+ /*
+ * TODO: the secondary CPUs are started and a boot helper
+ * is needed when using -kernel
+ */
+
+ object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
+
+ /* A7MPCORE */
+ object_property_set_int(OBJECT(&s->a7mpcore), s->num_cpus, "num-cpu",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->a7mpcore),
+ ASPEED_SOC_AST2600_MAX_IRQ + GIC_INTERNAL,
+ "num-irq", &error_abort);
+
+ object_property_set_bool(OBJECT(&s->a7mpcore), true, "realized",
+ &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR);
+
+ for (i = 0; i < s->num_cpus; i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore);
+ DeviceState *d = DEVICE(qemu_get_cpu(i));
+
+ irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
+ sysbus_connect_irq(sbd, i, irq);
+ irq = qdev_get_gpio_in(d, ARM_CPU_FIQ);
+ sysbus_connect_irq(sbd, i + s->num_cpus, irq);
+ irq = qdev_get_gpio_in(d, ARM_CPU_VIRQ);
+ sysbus_connect_irq(sbd, i + 2 * s->num_cpus, irq);
+ irq = qdev_get_gpio_in(d, ARM_CPU_VFIQ);
+ sysbus_connect_irq(sbd, i + 3 * s->num_cpus, irq);
+ }
+
+ /* SRAM */
+ memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
+ sc->sram_size, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(),
+ sc->memmap[ASPEED_SRAM], &s->sram);
+
+ /* SCU */
+ object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]);
+
+ /* RTC */
+ object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_RTC]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
+ aspeed_soc_get_irq(s, ASPEED_RTC));
+
+ /* Timer */
+ object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
+ sc->memmap[ASPEED_TIMER1]);
+ for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
+ qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_TIMER1 + i);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
+ }
+
+ /* UART - attach an 8250 to the IO space as our UART5 */
+ if (serial_hd(0)) {
+ qemu_irq uart5 = aspeed_soc_get_irq(s, ASPEED_UART5);
+ serial_mm_init(get_system_memory(), sc->memmap[ASPEED_UART5], 2,
+ uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+ }
+
+ /* I2C */
+ object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_I2C]);
+ for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+ qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore),
+ sc->irqmap[ASPEED_I2C] + i);
+ /*
+ * The AST2600 SoC has one IRQ per I2C bus. Skip the common
+ * IRQ (AST2400 and AST2500) and connect all bussses.
+ */
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), i + 1, irq);
+ }
+
+ /* FMC, The number of CS is set at the board level */
+ object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM],
+ "sdram-base", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_FMC]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
+ s->fmc.ctrl->flash_window_base);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
+ aspeed_soc_get_irq(s, ASPEED_FMC));
+
+ /* SPI */
+ for (i = 0; i < sc->spis_num; i++) {
+ object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err);
+ object_property_set_bool(OBJECT(&s->spi[i]), true, "realized",
+ &local_err);
+ error_propagate(&err, local_err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
+ sc->memmap[ASPEED_SPI1 + i]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
+ s->spi[i].ctrl->flash_window_base);
+ }
+
+ /* SDMC - SDRAM Memory Controller */
+ object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_SDMC]);
+
+ /* Watch dog */
+ for (i = 0; i < sc->wdts_num; i++) {
+ AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
+
+ object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
+ sc->memmap[ASPEED_WDT] + i * awc->offset);
+ }
+
+ /* Net */
+ for (i = 0; i < nb_nics && i < sc->macs_num; i++) {
+ qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]);
+ object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
+ &err);
+ object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized",
+ &local_err);
+ error_propagate(&err, local_err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
+ sc->memmap[ASPEED_ETH1 + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
+ aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
+
+ object_property_set_bool(OBJECT(&s->mii[i]), true, "realized",
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->mii[i]), 0,
+ sc->memmap[ASPEED_MII1 + i]);
+ }
+
+ /* XDMA */
+ object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
+ sc->memmap[ASPEED_XDMA]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
+ aspeed_soc_get_irq(s, ASPEED_XDMA));
+
+ /* GPIO */
+ object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_GPIO]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+ aspeed_soc_get_irq(s, ASPEED_GPIO));
+
+ object_property_set_bool(OBJECT(&s->gpio_1_8v), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
+ sc->memmap[ASPEED_GPIO_1_8V]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
+ aspeed_soc_get_irq(s, ASPEED_GPIO_1_8V));
+
+ /* SDHCI */
+ object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
+ sc->memmap[ASPEED_SDHCI]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
+ aspeed_soc_get_irq(s, ASPEED_SDHCI));
+}
+
+static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
+
+ dc->realize = aspeed_soc_ast2600_realize;
+
+ sc->name = "ast2600-a0";
+ sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
+ sc->silicon_rev = AST2600_A0_SILICON_REV;
+ sc->sram_size = 0x10000;
+ sc->spis_num = 2;
+ sc->wdts_num = 4;
+ sc->macs_num = 4;
+ sc->irqmap = aspeed_soc_ast2600_irqmap;
+ sc->memmap = aspeed_soc_ast2600_memmap;
+ sc->num_cpus = 2;
+}
+
+static const TypeInfo aspeed_soc_ast2600_type_info = {
+ .name = "ast2600-a0",
+ .parent = TYPE_ASPEED_SOC,
+ .instance_size = sizeof(AspeedSoCState),
+ .instance_init = aspeed_soc_ast2600_init,
+ .class_init = aspeed_soc_ast2600_class_init,
+ .class_size = sizeof(AspeedSoCClass),
+};
+
+static void aspeed_soc_register_types(void)
+{
+ type_register_static(&aspeed_soc_ast2600_type_info);
+};
+
+type_init(aspeed_soc_register_types)
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index cf1d0cf921..f4fe243458 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -34,8 +34,10 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = {
[ASPEED_SDMC] = 0x1E6E0000,
[ASPEED_SCU] = 0x1E6E2000,
[ASPEED_XDMA] = 0x1E6E7000,
+ [ASPEED_VIDEO] = 0x1E700000,
[ASPEED_ADC] = 0x1E6E9000,
[ASPEED_SRAM] = 0x1E720000,
+ [ASPEED_SDHCI] = 0x1E740000,
[ASPEED_GPIO] = 0x1E780000,
[ASPEED_RTC] = 0x1E781000,
[ASPEED_TIMER1] = 0x1E782000,
@@ -62,7 +64,9 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = {
[ASPEED_SCU] = 0x1E6E2000,
[ASPEED_XDMA] = 0x1E6E7000,
[ASPEED_ADC] = 0x1E6E9000,
+ [ASPEED_VIDEO] = 0x1E700000,
[ASPEED_SRAM] = 0x1E720000,
+ [ASPEED_SDHCI] = 0x1E740000,
[ASPEED_GPIO] = 0x1E780000,
[ASPEED_RTC] = 0x1E781000,
[ASPEED_TIMER1] = 0x1E782000,
@@ -108,39 +112,16 @@ static const int aspeed_soc_ast2400_irqmap[] = {
[ASPEED_ETH1] = 2,
[ASPEED_ETH2] = 3,
[ASPEED_XDMA] = 6,
+ [ASPEED_SDHCI] = 26,
};
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
-static const AspeedSoCInfo aspeed_socs[] = {
- {
- .name = "ast2400-a1",
- .cpu_type = ARM_CPU_TYPE_NAME("arm926"),
- .silicon_rev = AST2400_A1_SILICON_REV,
- .sram_size = 0x8000,
- .spis_num = 1,
- .wdts_num = 2,
- .irqmap = aspeed_soc_ast2400_irqmap,
- .memmap = aspeed_soc_ast2400_memmap,
- .num_cpus = 1,
- }, {
- .name = "ast2500-a1",
- .cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
- .silicon_rev = AST2500_A1_SILICON_REV,
- .sram_size = 0x9000,
- .spis_num = 2,
- .wdts_num = 3,
- .irqmap = aspeed_soc_ast2500_irqmap,
- .memmap = aspeed_soc_ast2500_memmap,
- .num_cpus = 1,
- },
-};
-
static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl)
{
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
- return qdev_get_gpio_in(DEVICE(&s->vic), sc->info->irqmap[ctrl]);
+ return qdev_get_gpio_in(DEVICE(&s->vic), sc->irqmap[ctrl]);
}
static void aspeed_soc_init(Object *obj)
@@ -151,13 +132,13 @@ static void aspeed_soc_init(Object *obj)
char socname[8];
char typename[64];
- if (sscanf(sc->info->name, "%7s", socname) != 1) {
+ if (sscanf(sc->name, "%7s", socname) != 1) {
g_assert_not_reached();
}
- for (i = 0; i < sc->info->num_cpus; i++) {
+ for (i = 0; i < sc->num_cpus; i++) {
object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
- sizeof(s->cpu[i]), sc->info->cpu_type,
+ sizeof(s->cpu[i]), sc->cpu_type,
&error_abort, NULL);
}
@@ -165,7 +146,7 @@ static void aspeed_soc_init(Object *obj)
sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu),
typename);
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
- sc->info->silicon_rev);
+ sc->silicon_rev);
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
"hw-strap1", &error_abort);
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
@@ -179,13 +160,15 @@ static void aspeed_soc_init(Object *obj)
sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc),
TYPE_ASPEED_RTC);
+ snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
- sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
+ sizeof(s->timerctrl), typename);
object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
OBJECT(&s->scu), &error_abort);
+ snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c),
- TYPE_ASPEED_I2C);
+ typename);
snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc),
@@ -195,31 +178,29 @@ static void aspeed_soc_init(Object *obj)
object_property_add_alias(obj, "dram", OBJECT(&s->fmc), "dram",
&error_abort);
- for (i = 0; i < sc->info->spis_num; i++) {
+ for (i = 0; i < sc->spis_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname);
sysbus_init_child_obj(obj, "spi[*]", OBJECT(&s->spi[i]),
sizeof(s->spi[i]), typename);
}
+ snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc),
- TYPE_ASPEED_SDMC);
- qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev",
- sc->info->silicon_rev);
+ typename);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size", &error_abort);
object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc),
"max-ram-size", &error_abort);
- for (i = 0; i < sc->info->wdts_num; i++) {
+ for (i = 0; i < sc->wdts_num; i++) {
+ snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]),
- sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
- qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev",
- sc->info->silicon_rev);
+ sizeof(s->wdt[i]), typename);
object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
OBJECT(&s->scu), &error_abort);
}
- for (i = 0; i < ASPEED_MACS_NUM; i++) {
+ for (i = 0; i < sc->macs_num; i++) {
sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
}
@@ -230,6 +211,15 @@ static void aspeed_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio),
typename);
+
+ sysbus_init_child_obj(obj, "sdc", OBJECT(&s->sdhci), sizeof(s->sdhci),
+ TYPE_ASPEED_SDHCI);
+
+ /* Init sd card slot class here so that they're under the correct parent */
+ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) {
+ sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(&s->sdhci.slots[i]),
+ sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI);
+ }
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@@ -240,13 +230,17 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
Error *err = NULL, *local_err = NULL;
/* IO space */
- create_unimplemented_device("aspeed_soc.io", sc->info->memmap[ASPEED_IOMEM],
+ create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
- if (s->num_cpus > sc->info->num_cpus) {
+ /* Video engine stub */
+ create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_VIDEO],
+ 0x1000);
+
+ if (s->num_cpus > sc->num_cpus) {
warn_report("%s: invalid number of CPUs %d, using default %d",
- sc->info->name, s->num_cpus, sc->info->num_cpus);
- s->num_cpus = sc->info->num_cpus;
+ sc->name, s->num_cpus, sc->num_cpus);
+ s->num_cpus = sc->num_cpus;
}
/* CPU */
@@ -260,13 +254,13 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
/* SRAM */
memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
- sc->info->sram_size, &err);
+ sc->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
}
memory_region_add_subregion(get_system_memory(),
- sc->info->memmap[ASPEED_SRAM], &s->sram);
+ sc->memmap[ASPEED_SRAM], &s->sram);
/* SCU */
object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
@@ -274,7 +268,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->info->memmap[ASPEED_SCU]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]);
/* VIC */
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
@@ -282,7 +276,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->info->memmap[ASPEED_VIC]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->memmap[ASPEED_VIC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
@@ -294,7 +288,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->info->memmap[ASPEED_RTC]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_RTC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
aspeed_soc_get_irq(s, ASPEED_RTC));
@@ -305,7 +299,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
- sc->info->memmap[ASPEED_TIMER1]);
+ sc->memmap[ASPEED_TIMER1]);
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_TIMER1 + i);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
@@ -314,7 +308,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
/* UART - attach an 8250 to the IO space as our UART5 */
if (serial_hd(0)) {
qemu_irq uart5 = aspeed_soc_get_irq(s, ASPEED_UART5);
- serial_mm_init(get_system_memory(), sc->info->memmap[ASPEED_UART5], 2,
+ serial_mm_init(get_system_memory(), sc->memmap[ASPEED_UART5], 2,
uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
}
@@ -324,12 +318,12 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->info->memmap[ASPEED_I2C]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_I2C]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
aspeed_soc_get_irq(s, ASPEED_I2C));
/* FMC, The number of CS is set at the board level */
- object_property_set_int(OBJECT(&s->fmc), sc->info->memmap[ASPEED_SDRAM],
+ object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM],
"sdram-base", &err);
if (err) {
error_propagate(errp, err);
@@ -340,14 +334,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->info->memmap[ASPEED_FMC]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_FMC]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
s->fmc.ctrl->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
aspeed_soc_get_irq(s, ASPEED_FMC));
/* SPI */
- for (i = 0; i < sc->info->spis_num; i++) {
+ for (i = 0; i < sc->spis_num; i++) {
object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err);
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized",
&local_err);
@@ -357,7 +351,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
- sc->info->memmap[ASPEED_SPI1 + i]);
+ sc->memmap[ASPEED_SPI1 + i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
s->spi[i].ctrl->flash_window_base);
}
@@ -368,21 +362,23 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->info->memmap[ASPEED_SDMC]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_SDMC]);
/* Watch dog */
- for (i = 0; i < sc->info->wdts_num; i++) {
+ for (i = 0; i < sc->wdts_num; i++) {
+ AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
+
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
- sc->info->memmap[ASPEED_WDT] + i * 0x20);
+ sc->memmap[ASPEED_WDT] + i * awc->offset);
}
/* Net */
- for (i = 0; i < nb_nics; i++) {
+ for (i = 0; i < nb_nics && i < sc->macs_num; i++) {
qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]);
object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
&err);
@@ -394,7 +390,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
- sc->info->memmap[ASPEED_ETH1 + i]);
+ sc->memmap[ASPEED_ETH1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
}
@@ -406,7 +402,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
- sc->info->memmap[ASPEED_XDMA]);
+ sc->memmap[ASPEED_XDMA]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_soc_get_irq(s, ASPEED_XDMA));
@@ -416,9 +412,20 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->info->memmap[ASPEED_GPIO]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_GPIO));
+
+ /* SDHCI */
+ object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
+ sc->memmap[ASPEED_SDHCI]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
+ aspeed_soc_get_irq(s, ASPEED_SDHCI));
}
static Property aspeed_soc_properties[] = {
DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
@@ -428,9 +435,7 @@ static Property aspeed_soc_properties[] = {
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
- sc->info = (AspeedSoCInfo *) data;
dc->realize = aspeed_soc_realize;
/* Reason: Uses serial_hds and nd_table in realize() directly */
dc->user_creatable = false;
@@ -440,26 +445,64 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data)
static const TypeInfo aspeed_soc_type_info = {
.name = TYPE_ASPEED_SOC,
.parent = TYPE_DEVICE,
- .instance_init = aspeed_soc_init,
.instance_size = sizeof(AspeedSoCState),
.class_size = sizeof(AspeedSoCClass),
+ .class_init = aspeed_soc_class_init,
.abstract = true,
};
-static void aspeed_soc_register_types(void)
+static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data)
{
- int i;
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
- type_register_static(&aspeed_soc_type_info);
- for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) {
- TypeInfo ti = {
- .name = aspeed_socs[i].name,
- .parent = TYPE_ASPEED_SOC,
- .class_init = aspeed_soc_class_init,
- .class_data = (void *) &aspeed_socs[i],
- };
- type_register(&ti);
- }
+ sc->name = "ast2400-a1";
+ sc->cpu_type = ARM_CPU_TYPE_NAME("arm926");
+ sc->silicon_rev = AST2400_A1_SILICON_REV;
+ sc->sram_size = 0x8000;
+ sc->spis_num = 1;
+ sc->wdts_num = 2;
+ sc->macs_num = 2;
+ sc->irqmap = aspeed_soc_ast2400_irqmap;
+ sc->memmap = aspeed_soc_ast2400_memmap;
+ sc->num_cpus = 1;
}
+static const TypeInfo aspeed_soc_ast2400_type_info = {
+ .name = "ast2400-a1",
+ .parent = TYPE_ASPEED_SOC,
+ .instance_init = aspeed_soc_init,
+ .instance_size = sizeof(AspeedSoCState),
+ .class_init = aspeed_soc_ast2400_class_init,
+};
+
+static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data)
+{
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
+
+ sc->name = "ast2500-a1";
+ sc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
+ sc->silicon_rev = AST2500_A1_SILICON_REV;
+ sc->sram_size = 0x9000;
+ sc->spis_num = 2;
+ sc->wdts_num = 3;
+ sc->macs_num = 2;
+ sc->irqmap = aspeed_soc_ast2500_irqmap;
+ sc->memmap = aspeed_soc_ast2500_memmap;
+ sc->num_cpus = 1;
+}
+
+static const TypeInfo aspeed_soc_ast2500_type_info = {
+ .name = "ast2500-a1",
+ .parent = TYPE_ASPEED_SOC,
+ .instance_init = aspeed_soc_init,
+ .instance_size = sizeof(AspeedSoCState),
+ .class_init = aspeed_soc_ast2500_class_init,
+};
+static void aspeed_soc_register_types(void)
+{
+ type_register_static(&aspeed_soc_type_info);
+ type_register_static(&aspeed_soc_ast2400_type_info);
+ type_register_static(&aspeed_soc_ast2500_type_info);
+};
+
type_init(aspeed_soc_register_types)
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 8984e2e91f..fdcf616c56 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -22,6 +22,20 @@
/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */
#define BCM2835_SDHC_CAPAREG 0x52134b4
+static void create_unimp(BCM2835PeripheralState *ps,
+ UnimplementedDeviceState *uds,
+ const char *name, hwaddr ofs, hwaddr size)
+{
+ sysbus_init_child_obj(OBJECT(ps), name, uds,
+ sizeof(UnimplementedDeviceState),
+ TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(uds), "name", name);
+ qdev_prop_set_uint64(DEVICE(uds), "size", size);
+ object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal);
+ memory_region_add_subregion_overlap(&ps->peri_mr, ofs,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0), -1000);
+}
+
static void bcm2835_peripherals_init(Object *obj)
{
BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
@@ -165,7 +179,8 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart0), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart0), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
- INTERRUPT_UART));
+ INTERRUPT_UART0));
+
/* AUX / UART1 */
qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hd(1));
@@ -175,7 +190,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
+ memory_region_add_subregion(&s->peri_mr, AUX_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
@@ -268,7 +283,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
+ memory_region_add_subregion(&s->peri_mr, EMMC1_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
@@ -322,6 +337,23 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
+
+ create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
+ create_unimp(s, &s->systmr, "bcm2835-systimer", ST_OFFSET, 0x20);
+ create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
+ create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
+ create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
+ create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
+ create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
+ create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100);
+ create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20);
+ create_unimp(s, &s->i2c[1], "bcm2835-i2c1", BSC1_OFFSET, 0x20);
+ create_unimp(s, &s->i2c[2], "bcm2835-i2c2", BSC2_OFFSET, 0x20);
+ create_unimp(s, &s->otp, "bcm2835-otp", OTP_OFFSET, 0x80);
+ create_unimp(s, &s->dbus, "bcm2835-dbus", DBUS_OFFSET, 0x8000);
+ create_unimp(s, &s->ave0, "bcm2835-ave0", AVE0_OFFSET, 0x8000);
+ create_unimp(s, &s->dwc2, "dwc-usb2", USB_OTG_OFFSET, 0x1000);
+ create_unimp(s, &s->sdramc, "bcm2835-sdramc", SDRAMC_OFFSET, 0x100);
}
static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 493a913f89..723aef6bf5 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -126,7 +126,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
/* set periphbase/CBAR value for CPU-local registers */
object_property_set_int(OBJECT(&s->cpus[n]),
- BCM2836_PERI_BASE + MCORE_OFFSET,
+ BCM2836_PERI_BASE + MSYNC_OFFSET,
"reset-cbar", &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 246cbb1336..f68a399a98 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -843,13 +843,10 @@ static void mv88w8618_timer_tick(void *opaque)
static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
uint32_t freq)
{
- QEMUBH *bh;
-
sysbus_init_irq(dev, &s->irq);
s->freq = freq;
- bh = qemu_bh_new(mv88w8618_timer_tick, s);
- s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->ptimer = ptimer_init(mv88w8618_timer_tick, s, PTIMER_POLICY_DEFAULT);
}
static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
@@ -879,16 +876,19 @@ static void mv88w8618_pit_write(void *opaque, hwaddr offset,
case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
t = &s->timer[offset >> 2];
t->limit = value;
+ ptimer_transaction_begin(t->ptimer);
if (t->limit > 0) {
ptimer_set_limit(t->ptimer, t->limit, 1);
} else {
ptimer_stop(t->ptimer);
}
+ ptimer_transaction_commit(t->ptimer);
break;
case MP_PIT_CONTROL:
for (i = 0; i < 4; i++) {
t = &s->timer[i];
+ ptimer_transaction_begin(t->ptimer);
if (value & 0xf && t->limit > 0) {
ptimer_set_limit(t->ptimer, t->limit, 0);
ptimer_set_freq(t->ptimer, t->freq);
@@ -896,6 +896,7 @@ static void mv88w8618_pit_write(void *opaque, hwaddr offset,
} else {
ptimer_stop(t->ptimer);
}
+ ptimer_transaction_commit(t->ptimer);
value >>= 4;
}
break;
@@ -914,8 +915,11 @@ static void mv88w8618_pit_reset(DeviceState *d)
int i;
for (i = 0; i < 4; i++) {
- ptimer_stop(s->timer[i].ptimer);
- s->timer[i].limit = 0;
+ mv88w8618_timer_state *t = &s->timer[i];
+ ptimer_transaction_begin(t->ptimer);
+ ptimer_stop(t->ptimer);
+ ptimer_transaction_commit(t->ptimer);
+ t->limit = 0;
}
}
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 74c062d05e..615d755879 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -230,7 +230,7 @@ static void raspi2_machine_init(MachineClass *mc)
mc->max_cpus = BCM283X_NCPUS;
mc->min_cpus = BCM283X_NCPUS;
mc->default_cpus = BCM283X_NCPUS;
- mc->default_ram_size = 1024 * 1024 * 1024;
+ mc->default_ram_size = 1 * GiB;
mc->ignore_memory_transaction_failures = true;
};
DEFINE_MACHINE("raspi2", raspi2_machine_init)
@@ -252,7 +252,7 @@ static void raspi3_machine_init(MachineClass *mc)
mc->max_cpus = BCM283X_NCPUS;
mc->min_cpus = BCM283X_NCPUS;
mc->default_cpus = BCM283X_NCPUS;
- mc->default_ram_size = 1024 * 1024 * 1024;
+ mc->default_ram_size = 1 * GiB;
}
DEFINE_MACHINE("raspi3", raspi3_machine_init)
#endif
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 47159de3a4..11ff5b9ad7 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -327,6 +327,7 @@ static const FlashPartInfo known_devices[] = {
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
{ INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) },
+ { INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K) },
};
typedef enum {
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 3f855196e3..a6fc1bf152 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -162,8 +162,9 @@ static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset) {
case AUX_ENABLES:
if (value != 1) {
- qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI "
- "or disable UART\n", __func__);
+ qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI"
+ " or disable UART: 0x%"PRIx64"\n",
+ __func__, value);
}
break;
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index d58e2dfdb0..7239b8227c 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -31,6 +31,16 @@ struct ptimer_state
uint8_t policy_mask;
QEMUBH *bh;
QEMUTimer *timer;
+ ptimer_cb callback;
+ void *callback_opaque;
+ /*
+ * These track whether we're in a transaction block, and if we
+ * need to do a timer reload when the block finishes. They don't
+ * need to be migrated because migration can never happen in the
+ * middle of a transaction block.
+ */
+ bool in_transaction;
+ bool need_reload;
};
/* Use a bottom-half routine to avoid reentrancy issues. */
@@ -39,13 +49,16 @@ static void ptimer_trigger(ptimer_state *s)
if (s->bh) {
replay_bh_schedule_event(s->bh);
}
+ if (s->callback) {
+ s->callback(s->callback_opaque);
+ }
}
static void ptimer_reload(ptimer_state *s, int delta_adjust)
{
- uint32_t period_frac = s->period_frac;
- uint64_t period = s->period;
- uint64_t delta = s->delta;
+ uint32_t period_frac;
+ uint64_t period;
+ uint64_t delta;
bool suppress_trigger = false;
/*
@@ -58,11 +71,20 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
(s->policy_mask & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT)) {
suppress_trigger = true;
}
- if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)
+ if (s->delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)
&& !suppress_trigger) {
ptimer_trigger(s);
}
+ /*
+ * Note that ptimer_trigger() might call the device callback function,
+ * which can then modify timer state, so we must not cache any fields
+ * from ptimer_state until after we have called it.
+ */
+ delta = s->delta;
+ period = s->period;
+ period_frac = s->period_frac;
+
if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) {
delta = s->delta = s->limit;
}
@@ -136,6 +158,15 @@ static void ptimer_tick(void *opaque)
ptimer_state *s = (ptimer_state *)opaque;
bool trigger = true;
+ /*
+ * We perform all the tick actions within a begin/commit block
+ * because the callback function that ptimer_trigger() calls
+ * might make calls into the ptimer APIs that provoke another
+ * trigger, and we want that to cause the callback function
+ * to be called iteratively, not recursively.
+ */
+ ptimer_transaction_begin(s);
+
if (s->enabled == 2) {
s->delta = 0;
s->enabled = 0;
@@ -164,6 +195,8 @@ static void ptimer_tick(void *opaque)
if (trigger) {
ptimer_trigger(s);
}
+
+ ptimer_transaction_commit(s);
}
uint64_t ptimer_get_count(ptimer_state *s)
@@ -263,10 +296,15 @@ uint64_t ptimer_get_count(ptimer_state *s)
void ptimer_set_count(ptimer_state *s, uint64_t count)
{
+ assert(s->in_transaction || !s->callback);
s->delta = count;
if (s->enabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
+ if (!s->callback) {
+ s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ptimer_reload(s, 0);
+ } else {
+ s->need_reload = true;
+ }
}
}
@@ -274,6 +312,8 @@ void ptimer_run(ptimer_state *s, int oneshot)
{
bool was_disabled = !s->enabled;
+ assert(s->in_transaction || !s->callback);
+
if (was_disabled && s->period == 0) {
if (!qtest_enabled()) {
fprintf(stderr, "Timer with period zero, disabling\n");
@@ -282,8 +322,12 @@ void ptimer_run(ptimer_state *s, int oneshot)
}
s->enabled = oneshot ? 2 : 1;
if (was_disabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
+ if (!s->callback) {
+ s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ptimer_reload(s, 0);
+ } else {
+ s->need_reload = true;
+ }
}
}
@@ -291,35 +335,50 @@ void ptimer_run(ptimer_state *s, int oneshot)
is immediately restarted. */
void ptimer_stop(ptimer_state *s)
{
+ assert(s->in_transaction || !s->callback);
+
if (!s->enabled)
return;
s->delta = ptimer_get_count(s);
timer_del(s->timer);
s->enabled = 0;
+ if (s->callback) {
+ s->need_reload = false;
+ }
}
/* Set counter increment interval in nanoseconds. */
void ptimer_set_period(ptimer_state *s, int64_t period)
{
+ assert(s->in_transaction || !s->callback);
s->delta = ptimer_get_count(s);
s->period = period;
s->period_frac = 0;
if (s->enabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
+ if (!s->callback) {
+ s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ptimer_reload(s, 0);
+ } else {
+ s->need_reload = true;
+ }
}
}
/* Set counter frequency in Hz. */
void ptimer_set_freq(ptimer_state *s, uint32_t freq)
{
+ assert(s->in_transaction || !s->callback);
s->delta = ptimer_get_count(s);
s->period = 1000000000ll / freq;
s->period_frac = (1000000000ll << 32) / freq;
if (s->enabled) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
+ if (!s->callback) {
+ s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ptimer_reload(s, 0);
+ } else {
+ s->need_reload = true;
+ }
}
}
@@ -327,12 +386,17 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
count = limit. */
void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
{
+ assert(s->in_transaction || !s->callback);
s->limit = limit;
if (reload)
s->delta = limit;
if (s->enabled && reload) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
+ if (!s->callback) {
+ s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ptimer_reload(s, 0);
+ } else {
+ s->need_reload = true;
+ }
}
}
@@ -341,6 +405,32 @@ uint64_t ptimer_get_limit(ptimer_state *s)
return s->limit;
}
+void ptimer_transaction_begin(ptimer_state *s)
+{
+ assert(!s->in_transaction || !s->callback);
+ s->in_transaction = true;
+ s->need_reload = false;
+}
+
+void ptimer_transaction_commit(ptimer_state *s)
+{
+ assert(s->in_transaction);
+ /*
+ * We must loop here because ptimer_reload() can call the callback
+ * function, which might then update ptimer state in a way that
+ * means we need to do another reload and possibly another callback.
+ * A disabled timer never needs reloading (and if we don't check
+ * this then we loop forever if ptimer_reload() disables the timer).
+ */
+ while (s->need_reload && s->enabled) {
+ s->need_reload = false;
+ s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ptimer_reload(s, 0);
+ }
+ /* Now we've finished reload we can leave the transaction block. */
+ s->in_transaction = false;
+}
+
const VMStateDescription vmstate_ptimer = {
.name = "ptimer",
.version_id = 1,
@@ -358,7 +448,7 @@ const VMStateDescription vmstate_ptimer = {
}
};
-ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask)
+ptimer_state *ptimer_init_with_bh(QEMUBH *bh, uint8_t policy_mask)
{
ptimer_state *s;
@@ -377,9 +467,41 @@ ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask)
return s;
}
+ptimer_state *ptimer_init(ptimer_cb callback, void *callback_opaque,
+ uint8_t policy_mask)
+{
+ ptimer_state *s;
+
+ /*
+ * The callback function is mandatory; so we use it to distinguish
+ * old-style QEMUBH ptimers from new transaction API ptimers.
+ * (ptimer_init_with_bh() allows a NULL bh pointer and at least
+ * one device (digic-timer) passes NULL, so it's not the case
+ * that either s->bh != NULL or s->callback != NULL.)
+ */
+ assert(callback);
+
+ s = g_new0(ptimer_state, 1);
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s);
+ s->policy_mask = policy_mask;
+ s->callback = callback;
+ s->callback_opaque = callback_opaque;
+
+ /*
+ * These two policies are incompatible -- trigger-on-decrement implies
+ * a timer trigger when the count becomes 0, but no-immediate-trigger
+ * implies a trigger when the count stops being 0.
+ */
+ assert(!((policy_mask & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT) &&
+ (policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)));
+ return s;
+}
+
void ptimer_free(ptimer_state *s)
{
- qemu_bh_delete(s->bh);
+ if (s->bh) {
+ qemu_bh_delete(s->bh);
+ }
timer_free(s->timer);
g_free(s);
}
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index 8f856878cd..85aaa54330 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -425,7 +425,7 @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
s->initial_config.base = s->vcram_base + BCM2835_FB_OFFSET;
s->dma_mr = MEMORY_REGION(obj);
- address_space_init(&s->dma_as, s->dma_mr, NULL);
+ address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_FB "-memory");
bcm2835_fb_reset(dev);
diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c
index 192bd377a0..1e458d7fba 100644
--- a/hw/dma/bcm2835_dma.c
+++ b/hw/dma/bcm2835_dma.c
@@ -180,7 +180,7 @@ static uint64_t bcm2835_dma_read(BCM2835DMAState *s, hwaddr offset,
res = ch->debug;
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
__func__, offset);
break;
}
@@ -228,7 +228,7 @@ static void bcm2835_dma_write(BCM2835DMAState *s, hwaddr offset,
ch->debug = value;
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
__func__, offset);
break;
}
@@ -247,7 +247,7 @@ static uint64_t bcm2835_dma0_read(void *opaque, hwaddr offset, unsigned size)
case BCM2708_DMA_ENABLE:
return s->enable;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
__func__, offset);
return 0;
}
@@ -274,7 +274,7 @@ static void bcm2835_dma0_write(void *opaque, hwaddr offset, uint64_t value,
s->enable = (value & 0xffff);
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
__func__, offset);
}
}
@@ -383,7 +383,7 @@ static void bcm2835_dma_realize(DeviceState *dev, Error **errp)
}
s->dma_mr = MEMORY_REGION(obj);
- address_space_init(&s->dma_as, s->dma_mr, NULL);
+ address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_DMA "-memory");
bcm2835_dma_reset(dev);
}
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index a254275b64..e035d1f750 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -552,7 +552,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
st->nr = i;
st->bh = qemu_bh_new(timer_hit, st);
- st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
+ st->ptimer = ptimer_init_with_bh(st->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(st->ptimer, s->freqhz);
}
return;
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 25fbfec3b8..196e47c262 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -169,6 +169,48 @@
#define GPIO_3_6V_MEM_SIZE 0x1F0
#define GPIO_3_6V_REG_ARRAY_SIZE (GPIO_3_6V_MEM_SIZE >> 2)
+/* AST2600 only - 1.8V gpios */
+/*
+ * The AST2600 has same 3.6V gpios as the AST2400 (memory offsets 0x0-0x198)
+ * and addtional 1.8V gpios (memory offsets 0x800-0x9D4).
+ */
+#define GPIO_1_8V_REG_OFFSET 0x800
+#define GPIO_1_8V_ABCD_DATA_VALUE ((0x800 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_DIRECTION ((0x804 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_INT_ENABLE ((0x808 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_INT_SENS_0 ((0x80C - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_INT_SENS_1 ((0x810 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_INT_SENS_2 ((0x814 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_INT_STATUS ((0x818 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_RESET_TOLERANT ((0x81C - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_DATA_VALUE ((0x820 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_DIRECTION ((0x824 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_INT_ENABLE ((0x828 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_INT_SENS_0 ((0x82C - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_INT_SENS_1 ((0x830 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_INT_SENS_2 ((0x834 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_INT_STATUS ((0x838 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_RESET_TOLERANT ((0x83C - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_DEBOUNCE_1 ((0x840 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_DEBOUNCE_2 ((0x844 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_DEBOUNCE_1 ((0x848 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_DEBOUNCE_2 ((0x84C - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_DEBOUNCE_TIME_1 ((0x850 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_DEBOUNCE_TIME_2 ((0x854 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_DEBOUNCE_TIME_3 ((0x858 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_COMMAND_SRC_0 ((0x860 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_COMMAND_SRC_1 ((0x864 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_COMMAND_SRC_0 ((0x868 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_COMMAND_SRC_1 ((0x86C - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_DATA_READ ((0x8C0 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_DATA_READ ((0x8C4 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_ABCD_INPUT_MASK ((0x9D0 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_E_INPUT_MASK ((0x9D4 - GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_1_8V_MEM_SIZE 0x9D8
+#define GPIO_1_8V_REG_ARRAY_SIZE ((GPIO_1_8V_MEM_SIZE - \
+ GPIO_1_8V_REG_OFFSET) >> 2)
+#define GPIO_MAX_MEM_SIZE MAX(GPIO_3_6V_MEM_SIZE, GPIO_1_8V_MEM_SIZE)
+
static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
{
uint32_t falling_edge = 0, rising_edge = 0;
@@ -465,6 +507,39 @@ static const AspeedGPIOReg aspeed_3_6v_gpios[GPIO_3_6V_REG_ARRAY_SIZE] = {
[GPIO_AC_INPUT_MASK] = { 7, gpio_reg_input_mask },
};
+static const AspeedGPIOReg aspeed_1_8v_gpios[GPIO_1_8V_REG_ARRAY_SIZE] = {
+ /* 1.8V Set ABCD */
+ [GPIO_1_8V_ABCD_DATA_VALUE] = {0, gpio_reg_data_value},
+ [GPIO_1_8V_ABCD_DIRECTION] = {0, gpio_reg_direction},
+ [GPIO_1_8V_ABCD_INT_ENABLE] = {0, gpio_reg_int_enable},
+ [GPIO_1_8V_ABCD_INT_SENS_0] = {0, gpio_reg_int_sens_0},
+ [GPIO_1_8V_ABCD_INT_SENS_1] = {0, gpio_reg_int_sens_1},
+ [GPIO_1_8V_ABCD_INT_SENS_2] = {0, gpio_reg_int_sens_2},
+ [GPIO_1_8V_ABCD_INT_STATUS] = {0, gpio_reg_int_status},
+ [GPIO_1_8V_ABCD_RESET_TOLERANT] = {0, gpio_reg_reset_tolerant},
+ [GPIO_1_8V_ABCD_DEBOUNCE_1] = {0, gpio_reg_debounce_1},
+ [GPIO_1_8V_ABCD_DEBOUNCE_2] = {0, gpio_reg_debounce_2},
+ [GPIO_1_8V_ABCD_COMMAND_SRC_0] = {0, gpio_reg_cmd_source_0},
+ [GPIO_1_8V_ABCD_COMMAND_SRC_1] = {0, gpio_reg_cmd_source_1},
+ [GPIO_1_8V_ABCD_DATA_READ] = {0, gpio_reg_data_read},
+ [GPIO_1_8V_ABCD_INPUT_MASK] = {0, gpio_reg_input_mask},
+ /* 1.8V Set E */
+ [GPIO_1_8V_E_DATA_VALUE] = {1, gpio_reg_data_value},
+ [GPIO_1_8V_E_DIRECTION] = {1, gpio_reg_direction},
+ [GPIO_1_8V_E_INT_ENABLE] = {1, gpio_reg_int_enable},
+ [GPIO_1_8V_E_INT_SENS_0] = {1, gpio_reg_int_sens_0},
+ [GPIO_1_8V_E_INT_SENS_1] = {1, gpio_reg_int_sens_1},
+ [GPIO_1_8V_E_INT_SENS_2] = {1, gpio_reg_int_sens_2},
+ [GPIO_1_8V_E_INT_STATUS] = {1, gpio_reg_int_status},
+ [GPIO_1_8V_E_RESET_TOLERANT] = {1, gpio_reg_reset_tolerant},
+ [GPIO_1_8V_E_DEBOUNCE_1] = {1, gpio_reg_debounce_1},
+ [GPIO_1_8V_E_DEBOUNCE_2] = {1, gpio_reg_debounce_2},
+ [GPIO_1_8V_E_COMMAND_SRC_0] = {1, gpio_reg_cmd_source_0},
+ [GPIO_1_8V_E_COMMAND_SRC_1] = {1, gpio_reg_cmd_source_1},
+ [GPIO_1_8V_E_DATA_READ] = {1, gpio_reg_data_read},
+ [GPIO_1_8V_E_INPUT_MASK] = {1, gpio_reg_input_mask},
+};
+
static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
{
AspeedGPIOState *s = ASPEED_GPIO(opaque);
@@ -663,8 +738,11 @@ static void aspeed_gpio_get_pin(Object *obj, Visitor *v, const char *name,
int set_idx, group_idx = 0;
if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) {
- error_setg(errp, "%s: error reading %s", __func__, name);
- return;
+ /* 1.8V gpio */
+ if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) {
+ error_setg(errp, "%s: error reading %s", __func__, name);
+ return;
+ }
}
set_idx = get_set_idx(s, group, &group_idx);
if (set_idx == -1) {
@@ -692,8 +770,11 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
return;
}
if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) {
- error_setg(errp, "%s: error reading %s", __func__, name);
- return;
+ /* 1.8V gpio */
+ if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) {
+ error_setg(errp, "%s: error reading %s", __func__, name);
+ return;
+ }
}
set_idx = get_set_idx(s, group, &group_idx);
if (set_idx == -1) {
@@ -726,6 +807,21 @@ static const GPIOSetProperties ast2500_set_props[] = {
[7] = {0x000000ff, 0x000000ff, {"AC"} },
};
+static GPIOSetProperties ast2600_3_6v_set_props[] = {
+ [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
+ [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
+ [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
+ [3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} },
+ [4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} },
+ [5] = {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} },
+ [6] = {0xffff0000, 0x0fff0000, {"Y", "Z", "", ""} },
+};
+
+static GPIOSetProperties ast2600_1_8v_set_props[] = {
+ [0] = {0xffffffff, 0xffffffff, {"18A", "18B", "18C", "18D"} },
+ [1] = {0x0000000f, 0x0000000f, {"18E"} },
+};
+
static const MemoryRegionOps aspeed_gpio_ops = {
.read = aspeed_gpio_read,
.write = aspeed_gpio_write,
@@ -758,7 +854,7 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp)
}
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
- TYPE_ASPEED_GPIO, GPIO_3_6V_MEM_SIZE);
+ TYPE_ASPEED_GPIO, GPIO_MAX_MEM_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
}
@@ -851,6 +947,26 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
agc->reg_table = aspeed_3_6v_gpios;
}
+static void aspeed_gpio_ast2600_3_6v_class_init(ObjectClass *klass, void *data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
+
+ agc->props = ast2600_3_6v_set_props;
+ agc->nr_gpio_pins = 208;
+ agc->nr_gpio_sets = 7;
+ agc->reg_table = aspeed_3_6v_gpios;
+}
+
+static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
+
+ agc->props = ast2600_1_8v_set_props;
+ agc->nr_gpio_pins = 36;
+ agc->nr_gpio_sets = 2;
+ agc->reg_table = aspeed_1_8v_gpios;
+}
+
static const TypeInfo aspeed_gpio_info = {
.name = TYPE_ASPEED_GPIO,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -874,11 +990,27 @@ static const TypeInfo aspeed_gpio_ast2500_info = {
.instance_init = aspeed_gpio_init,
};
+static const TypeInfo aspeed_gpio_ast2600_3_6v_info = {
+ .name = TYPE_ASPEED_GPIO "-ast2600",
+ .parent = TYPE_ASPEED_GPIO,
+ .class_init = aspeed_gpio_ast2600_3_6v_class_init,
+ .instance_init = aspeed_gpio_init,
+};
+
+static const TypeInfo aspeed_gpio_ast2600_1_8v_info = {
+ .name = TYPE_ASPEED_GPIO "-ast2600-1_8v",
+ .parent = TYPE_ASPEED_GPIO,
+ .class_init = aspeed_gpio_ast2600_1_8v_class_init,
+ .instance_init = aspeed_gpio_init,
+};
+
static void aspeed_gpio_register_types(void)
{
type_register_static(&aspeed_gpio_info);
type_register_static(&aspeed_gpio_ast2400_info);
type_register_static(&aspeed_gpio_ast2500_info);
+ type_register_static(&aspeed_gpio_ast2600_3_6v_info);
+ type_register_static(&aspeed_gpio_ast2600_1_8v_info);
}
type_init(aspeed_gpio_register_types);
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index a956eb3849..06c119f385 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -145,10 +145,12 @@ static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+
bus->intr_status &= bus->intr_ctrl;
if (bus->intr_status) {
bus->controller->intr_status |= 1 << bus->id;
- qemu_irq_raise(bus->controller->irq);
+ qemu_irq_raise(aic->bus_get_irq(bus));
}
}
@@ -273,6 +275,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
AspeedI2CBus *bus = opaque;
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
bool handle_rx;
switch (offset) {
@@ -299,7 +302,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
bus->intr_status &= ~(value & 0x7FFF);
if (!bus->intr_status) {
bus->controller->intr_status &= ~(1 << bus->id);
- qemu_irq_lower(bus->controller->irq);
+ qemu_irq_lower(aic->bus_get_irq(bus));
}
if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) {
aspeed_i2c_handle_rx_cmd(bus);
@@ -408,10 +411,11 @@ static void aspeed_i2c_reset(DeviceState *dev)
{
int i;
AspeedI2CState *s = ASPEED_I2C(dev);
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
s->intr_status = 0;
- for (i = 0; i < ASPEED_I2C_NR_BUSSES; i++) {
+ for (i = 0; i < aic->num_busses; i++) {
s->busses[i].intr_ctrl = 0;
s->busses[i].intr_status = 0;
s->busses[i].cmd = 0;
@@ -421,7 +425,7 @@ static void aspeed_i2c_reset(DeviceState *dev)
}
/*
- * Address Definitions
+ * Address Definitions (AST2400 and AST2500)
*
* 0x000 ... 0x03F: Global Register
* 0x040 ... 0x07F: Device 1
@@ -446,22 +450,26 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
int i;
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedI2CState *s = ASPEED_I2C(dev);
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
"aspeed.i2c", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
- for (i = 0; i < ASPEED_I2C_NR_BUSSES; i++) {
- char name[16];
- int offset = i < 7 ? 1 : 5;
+ for (i = 0; i < aic->num_busses; i++) {
+ char name[32];
+ int offset = i < aic->gap ? 1 : 5;
+
+ sysbus_init_irq(sbd, &s->busses[i].irq);
snprintf(name, sizeof(name), "aspeed.i2c.%d", i);
s->busses[i].controller = s;
s->busses[i].id = i;
s->busses[i].bus = i2c_init_bus(dev, name);
memory_region_init_io(&s->busses[i].mr, OBJECT(dev),
- &aspeed_i2c_bus_ops, &s->busses[i], name, 0x40);
- memory_region_add_subregion(&s->iomem, 0x40 * (i + offset),
+ &aspeed_i2c_bus_ops, &s->busses[i], name,
+ aic->reg_size);
+ memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
&s->busses[i].mr);
}
}
@@ -481,11 +489,88 @@ static const TypeInfo aspeed_i2c_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedI2CState),
.class_init = aspeed_i2c_class_init,
+ .class_size = sizeof(AspeedI2CClass),
+ .abstract = true,
+};
+
+static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
+{
+ return bus->controller->irq;
+}
+
+static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 I2C Controller";
+
+ aic->num_busses = 14;
+ aic->reg_size = 0x40;
+ aic->gap = 7;
+ aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq;
+}
+
+static const TypeInfo aspeed_2400_i2c_info = {
+ .name = TYPE_ASPEED_2400_I2C,
+ .parent = TYPE_ASPEED_I2C,
+ .class_init = aspeed_2400_i2c_class_init,
+};
+
+static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus)
+{
+ return bus->controller->irq;
+}
+
+static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 I2C Controller";
+
+ aic->num_busses = 14;
+ aic->reg_size = 0x40;
+ aic->gap = 7;
+ aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq;
+}
+
+static const TypeInfo aspeed_2500_i2c_info = {
+ .name = TYPE_ASPEED_2500_I2C,
+ .parent = TYPE_ASPEED_I2C,
+ .class_init = aspeed_2500_i2c_class_init,
+};
+
+static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus)
+{
+ return bus->irq;
+}
+
+static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 I2C Controller";
+
+ aic->num_busses = 16;
+ aic->reg_size = 0x80;
+ aic->gap = -1; /* no gap */
+ aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+}
+
+static const TypeInfo aspeed_2600_i2c_info = {
+ .name = TYPE_ASPEED_2600_I2C,
+ .parent = TYPE_ASPEED_I2C,
+ .class_init = aspeed_2600_i2c_class_init,
};
static void aspeed_i2c_register_types(void)
{
type_register_static(&aspeed_i2c_info);
+ type_register_static(&aspeed_2400_i2c_info);
+ type_register_static(&aspeed_2500_i2c_info);
+ type_register_static(&aspeed_2600_i2c_info);
}
type_init(aspeed_i2c_register_types)
@@ -494,9 +579,10 @@ type_init(aspeed_i2c_register_types)
I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr)
{
AspeedI2CState *s = ASPEED_I2C(dev);
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
I2CBus *bus = NULL;
- if (busnr >= 0 && busnr < ASPEED_I2C_NR_BUSSES) {
+ if (busnr >= 0 && busnr < aic->num_busses) {
bus = s->busses[busnr].bus;
}
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index b56fda144f..9deb15e7e6 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -55,7 +55,7 @@ void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level)
* has separate fields in the irq number for type,
* CPU number and interrupt number.
*/
- int kvm_irq, irqtype, cpu;
+ int irqtype, cpu;
if (irq < (num_irq - GIC_INTERNAL)) {
/* External interrupt. The kernel numbers these like the GIC
@@ -72,10 +72,7 @@ void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level)
cpu = irq / GIC_INTERNAL;
irq %= GIC_INTERNAL;
}
- kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
- | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
-
- kvm_set_irq(kvm_state, kvm_irq, !!level);
+ kvm_arm_set_irq(cpu, irqtype, irq, !!level);
}
static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level)
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
index 04229b8a17..61f884ff9e 100644
--- a/hw/intc/bcm2836_control.c
+++ b/hw/intc/bcm2836_control.c
@@ -264,7 +264,7 @@ static uint64_t bcm2836_control_read(void *opaque, hwaddr offset, unsigned size)
} else if (offset >= REG_MBOX0_RDCLR && offset < REG_LIMIT) {
return s->mailboxes[(offset - REG_MBOX0_RDCLR) >> 2];
} else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx"\n",
__func__, offset);
return 0;
}
@@ -293,8 +293,9 @@ static void bcm2836_control_write(void *opaque, hwaddr offset,
} else if (offset >= REG_MBOX0_RDCLR && offset < REG_LIMIT) {
s->mailboxes[(offset - REG_MBOX0_RDCLR) >> 2] &= ~val;
} else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
+ qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx
+ " value 0x%"PRIx64"\n",
+ __func__, offset, val);
return;
}
diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c
index a9c2c95b0d..a49096367c 100644
--- a/hw/m68k/mcf5206.c
+++ b/hw/m68k/mcf5206.c
@@ -141,7 +141,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq)
s = g_new0(m5206_timer_state, 1);
bh = qemu_bh_new(m5206_timer_trigger, s);
- s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
s->irq = irq;
m5206_timer_reset(s);
return s;
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index 60c5802b4e..34d34eba17 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -192,7 +192,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
for (i = 0; i < 2; i++) {
s = g_new0(m5208_timer_state, 1);
bh = qemu_bh_new(m5208_timer_trigger, s);
- s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s,
"m5208-timer", 0x00004000);
memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 620b25c204..717509bc54 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -88,6 +88,36 @@
#define BMC_REV TO_REG(0x19C)
#define BMC_DEV_ID TO_REG(0x1A4)
+#define AST2600_PROT_KEY TO_REG(0x00)
+#define AST2600_SILICON_REV TO_REG(0x04)
+#define AST2600_SILICON_REV2 TO_REG(0x14)
+#define AST2600_SYS_RST_CTRL TO_REG(0x40)
+#define AST2600_SYS_RST_CTRL_CLR TO_REG(0x44)
+#define AST2600_SYS_RST_CTRL2 TO_REG(0x50)
+#define AST2600_SYS_RST_CTRL2_CLR TO_REG(0x54)
+#define AST2600_CLK_STOP_CTRL TO_REG(0x80)
+#define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84)
+#define AST2600_CLK_STOP_CTRL2 TO_REG(0x90)
+#define AST2600_CLK_STOP_CTR2L_CLR TO_REG(0x94)
+#define AST2600_SDRAM_HANDSHAKE TO_REG(0x100)
+#define AST2600_HPLL_PARAM TO_REG(0x200)
+#define AST2600_HPLL_EXT TO_REG(0x204)
+#define AST2600_MPLL_EXT TO_REG(0x224)
+#define AST2600_EPLL_EXT TO_REG(0x244)
+#define AST2600_CLK_SEL TO_REG(0x300)
+#define AST2600_CLK_SEL2 TO_REG(0x304)
+#define AST2600_CLK_SEL3 TO_REG(0x310)
+#define AST2600_HW_STRAP1 TO_REG(0x500)
+#define AST2600_HW_STRAP1_CLR TO_REG(0x504)
+#define AST2600_HW_STRAP1_PROT TO_REG(0x508)
+#define AST2600_HW_STRAP2 TO_REG(0x510)
+#define AST2600_HW_STRAP2_CLR TO_REG(0x514)
+#define AST2600_HW_STRAP2_PROT TO_REG(0x518)
+#define AST2600_RNG_CTRL TO_REG(0x524)
+#define AST2600_RNG_DATA TO_REG(0x540)
+
+#define AST2600_CLK TO_REG(0x40)
+
#define SCU_IO_REGION_SIZE 0x1000
static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
@@ -178,7 +208,7 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
- if (reg >= ARRAY_SIZE(s->regs)) {
+ if (reg >= ASPEED_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@@ -208,7 +238,7 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data,
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
- if (reg >= ARRAY_SIZE(s->regs)) {
+ if (reg >= ASPEED_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@@ -346,7 +376,7 @@ static void aspeed_scu_reset(DeviceState *dev)
AspeedSCUState *s = ASPEED_SCU(dev);
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
- memcpy(s->regs, asc->resets, sizeof(s->regs));
+ memcpy(s->regs, asc->resets, asc->nr_regs * 4);
s->regs[SILICON_REV] = s->silicon_rev;
s->regs[HW_STRAP1] = s->hw_strap1;
s->regs[HW_STRAP2] = s->hw_strap2;
@@ -358,6 +388,7 @@ static uint32_t aspeed_silicon_revs[] = {
AST2400_A1_SILICON_REV,
AST2500_A0_SILICON_REV,
AST2500_A1_SILICON_REV,
+ AST2600_A0_SILICON_REV,
};
bool is_supported_silicon_rev(uint32_t silicon_rev)
@@ -377,6 +408,7 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSCUState *s = ASPEED_SCU(dev);
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
if (!is_supported_silicon_rev(s->silicon_rev)) {
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
@@ -384,7 +416,7 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_scu_ops, s,
+ memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s,
TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
@@ -392,10 +424,10 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_scu = {
.name = "aspeed.scu",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_SCU_NR_REGS),
+ VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS),
VMSTATE_END_OF_LIST()
}
};
@@ -436,6 +468,8 @@ static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data)
asc->resets = ast2400_a0_resets;
asc->calc_hpll = aspeed_2400_scu_calc_hpll;
asc->apb_divider = 2;
+ asc->nr_regs = ASPEED_SCU_NR_REGS;
+ asc->ops = &aspeed_scu_ops;
}
static const TypeInfo aspeed_2400_scu_info = {
@@ -454,6 +488,8 @@ static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data)
asc->resets = ast2500_a1_resets;
asc->calc_hpll = aspeed_2500_scu_calc_hpll;
asc->apb_divider = 4;
+ asc->nr_regs = ASPEED_SCU_NR_REGS;
+ asc->ops = &aspeed_scu_ops;
}
static const TypeInfo aspeed_2500_scu_info = {
@@ -463,11 +499,155 @@ static const TypeInfo aspeed_2500_scu_info = {
.class_init = aspeed_2500_scu_class_init,
};
+static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+
+ if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ case AST2600_HPLL_EXT:
+ case AST2600_EPLL_EXT:
+ case AST2600_MPLL_EXT:
+ /* PLLs are always "locked" */
+ return s->regs[reg] | BIT(31);
+ case AST2600_RNG_DATA:
+ /*
+ * On hardware, RNG_DATA works regardless of the state of the
+ * enable bit in RNG_CTRL
+ *
+ * TODO: Check this is true for ast2600
+ */
+ s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random();
+ break;
+ }
+
+ return s->regs[reg];
+}
+
+static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+
+ if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ if (reg > PROT_KEY && !s->regs[PROT_KEY]) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
+ }
+
+ trace_aspeed_scu_write(offset, size, data);
+
+ switch (reg) {
+ case AST2600_PROT_KEY:
+ s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
+ return;
+ case AST2600_HW_STRAP1:
+ case AST2600_HW_STRAP2:
+ if (s->regs[reg + 2]) {
+ return;
+ }
+ /* fall through */
+ case AST2600_SYS_RST_CTRL:
+ case AST2600_SYS_RST_CTRL2:
+ /* W1S (Write 1 to set) registers */
+ s->regs[reg] |= data;
+ return;
+ case AST2600_SYS_RST_CTRL_CLR:
+ case AST2600_SYS_RST_CTRL2_CLR:
+ case AST2600_HW_STRAP1_CLR:
+ case AST2600_HW_STRAP2_CLR:
+ /* W1C (Write 1 to clear) registers */
+ s->regs[reg] &= ~data;
+ return;
+
+ case AST2600_RNG_DATA:
+ case AST2600_SILICON_REV:
+ case AST2600_SILICON_REV2:
+ /* Add read only registers here */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_ast2600_scu_ops = {
+ .read = aspeed_ast2600_scu_read,
+ .write = aspeed_ast2600_scu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .valid.unaligned = false,
+};
+
+static const uint32_t ast2600_a0_resets[ASPEED_AST2600_SCU_NR_REGS] = {
+ [AST2600_SILICON_REV] = AST2600_SILICON_REV,
+ [AST2600_SILICON_REV2] = AST2600_SILICON_REV,
+ [AST2600_SYS_RST_CTRL] = 0xF7CFFEDC | 0x100,
+ [AST2600_SYS_RST_CTRL2] = 0xFFFFFFFC,
+ [AST2600_CLK_STOP_CTRL] = 0xEFF43E8B,
+ [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0,
+ [AST2600_SDRAM_HANDSHAKE] = 0x00000040, /* SoC completed DRAM init */
+ [AST2600_HPLL_PARAM] = 0x1000405F,
+};
+
+static void aspeed_ast2600_scu_reset(DeviceState *dev)
+{
+ AspeedSCUState *s = ASPEED_SCU(dev);
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
+
+ memcpy(s->regs, asc->resets, asc->nr_regs * 4);
+
+ s->regs[AST2600_SILICON_REV] = s->silicon_rev;
+ s->regs[AST2600_SILICON_REV2] = s->silicon_rev;
+ s->regs[AST2600_HW_STRAP1] = s->hw_strap1;
+ s->regs[AST2600_HW_STRAP2] = s->hw_strap2;
+ s->regs[PROT_KEY] = s->hw_prot_key;
+}
+
+static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 System Control Unit";
+ dc->reset = aspeed_ast2600_scu_reset;
+ asc->resets = ast2600_a0_resets;
+ asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */
+ asc->apb_divider = 4;
+ asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS;
+ asc->ops = &aspeed_ast2600_scu_ops;
+}
+
+static const TypeInfo aspeed_2600_scu_info = {
+ .name = TYPE_ASPEED_2600_SCU,
+ .parent = TYPE_ASPEED_SCU,
+ .instance_size = sizeof(AspeedSCUState),
+ .class_init = aspeed_2600_scu_class_init,
+};
+
static void aspeed_scu_register_types(void)
{
type_register_static(&aspeed_scu_info);
type_register_static(&aspeed_2400_scu_info);
type_register_static(&aspeed_2500_scu_info);
+ type_register_static(&aspeed_2600_scu_info);
}
type_init(aspeed_scu_register_types);
diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index cb13c63ec8..f3a63a2e01 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -28,6 +28,7 @@
/* Control/Status Register #1 (ast2500) */
#define R_STATUS1 (0x60 / 4)
#define PHY_BUSY_STATE BIT(0)
+#define PHY_PLL_LOCK_STATUS BIT(4)
#define R_ECC_TEST_CTRL (0x70 / 4)
#define ECC_TEST_FINISHED BIT(12)
@@ -85,6 +86,11 @@
#define ASPEED_SDMC_AST2500_512MB 0x2
#define ASPEED_SDMC_AST2500_1024MB 0x3
+#define ASPEED_SDMC_AST2600_256MB 0x0
+#define ASPEED_SDMC_AST2600_512MB 0x1
+#define ASPEED_SDMC_AST2600_1024MB 0x2
+#define ASPEED_SDMC_AST2600_2048MB 0x3
+
#define ASPEED_SDMC_AST2500_READONLY_MASK \
(ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE | \
ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT | \
@@ -110,6 +116,7 @@ static void aspeed_sdmc_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
AspeedSDMCState *s = ASPEED_SDMC(opaque);
+ AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
addr >>= 2;
@@ -130,41 +137,7 @@ static void aspeed_sdmc_write(void *opaque, hwaddr addr, uint64_t data,
return;
}
- if (addr == R_CONF) {
- /* Make sure readonly bits are kept */
- switch (s->silicon_rev) {
- case AST2400_A0_SILICON_REV:
- case AST2400_A1_SILICON_REV:
- data &= ~ASPEED_SDMC_READONLY_MASK;
- data |= s->fixed_conf;
- break;
- case AST2500_A0_SILICON_REV:
- case AST2500_A1_SILICON_REV:
- data &= ~ASPEED_SDMC_AST2500_READONLY_MASK;
- data |= s->fixed_conf;
- break;
- default:
- g_assert_not_reached();
- }
- }
- if (s->silicon_rev == AST2500_A0_SILICON_REV ||
- s->silicon_rev == AST2500_A1_SILICON_REV) {
- switch (addr) {
- case R_STATUS1:
- /* Will never return 'busy' */
- data &= ~PHY_BUSY_STATE;
- break;
- case R_ECC_TEST_CTRL:
- /* Always done, always happy */
- data |= ECC_TEST_FINISHED;
- data &= ~ECC_TEST_FAIL;
- break;
- default:
- break;
- }
- }
-
- s->regs[addr] = data;
+ asc->write(s, addr, data);
}
static const MemoryRegionOps aspeed_sdmc_ops = {
@@ -219,47 +192,46 @@ static int ast2500_rambits(AspeedSDMCState *s)
return ASPEED_SDMC_AST2500_512MB;
}
+static int ast2600_rambits(AspeedSDMCState *s)
+{
+ switch (s->ram_size >> 20) {
+ case 256:
+ return ASPEED_SDMC_AST2600_256MB;
+ case 512:
+ return ASPEED_SDMC_AST2600_512MB;
+ case 1024:
+ return ASPEED_SDMC_AST2600_1024MB;
+ case 2048:
+ return ASPEED_SDMC_AST2600_2048MB;
+ default:
+ break;
+ }
+
+ /* use a common default */
+ warn_report("Invalid RAM size 0x%" PRIx64 ". Using default 512M",
+ s->ram_size);
+ s->ram_size = 512 << 20;
+ return ASPEED_SDMC_AST2600_512MB;
+}
+
static void aspeed_sdmc_reset(DeviceState *dev)
{
AspeedSDMCState *s = ASPEED_SDMC(dev);
+ AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
memset(s->regs, 0, sizeof(s->regs));
/* Set ram size bit and defaults values */
- s->regs[R_CONF] = s->fixed_conf;
+ s->regs[R_CONF] = asc->compute_conf(s, 0);
}
static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSDMCState *s = ASPEED_SDMC(dev);
+ AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
- if (!is_supported_silicon_rev(s->silicon_rev)) {
- error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
- s->silicon_rev);
- return;
- }
-
- switch (s->silicon_rev) {
- case AST2400_A0_SILICON_REV:
- case AST2400_A1_SILICON_REV:
- s->ram_bits = ast2400_rambits(s);
- s->max_ram_size = 512 << 20;
- s->fixed_conf = ASPEED_SDMC_VGA_COMPAT |
- ASPEED_SDMC_DRAM_SIZE(s->ram_bits);
- break;
- case AST2500_A0_SILICON_REV:
- case AST2500_A1_SILICON_REV:
- s->ram_bits = ast2500_rambits(s);
- s->max_ram_size = 1024 << 20;
- s->fixed_conf = ASPEED_SDMC_HW_VERSION(1) |
- ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) |
- ASPEED_SDMC_CACHE_INITIAL_DONE |
- ASPEED_SDMC_DRAM_SIZE(s->ram_bits);
- break;
- default:
- g_assert_not_reached();
- }
+ s->max_ram_size = asc->max_ram_size;
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
TYPE_ASPEED_SDMC, 0x1000);
@@ -277,7 +249,6 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
};
static Property aspeed_sdmc_properties[] = {
- DEFINE_PROP_UINT32("silicon-rev", AspeedSDMCState, silicon_rev, 0),
DEFINE_PROP_UINT64("ram-size", AspeedSDMCState, ram_size, 0),
DEFINE_PROP_UINT64("max-ram-size", AspeedSDMCState, max_ram_size, 0),
DEFINE_PROP_END_OF_LIST(),
@@ -298,11 +269,164 @@ static const TypeInfo aspeed_sdmc_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSDMCState),
.class_init = aspeed_sdmc_class_init,
+ .class_size = sizeof(AspeedSDMCClass),
+ .abstract = true,
+};
+
+static uint32_t aspeed_2400_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
+{
+ uint32_t fixed_conf = ASPEED_SDMC_VGA_COMPAT |
+ ASPEED_SDMC_DRAM_SIZE(ast2400_rambits(s));
+
+ /* Make sure readonly bits are kept */
+ data &= ~ASPEED_SDMC_READONLY_MASK;
+
+ return data | fixed_conf;
+}
+
+static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg,
+ uint32_t data)
+{
+ switch (reg) {
+ case R_CONF:
+ data = aspeed_2400_sdmc_compute_conf(s, data);
+ break;
+ default:
+ break;
+ }
+
+ s->regs[reg] = data;
+}
+
+static void aspeed_2400_sdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 SDRAM Memory Controller";
+ asc->max_ram_size = 512 << 20;
+ asc->compute_conf = aspeed_2400_sdmc_compute_conf;
+ asc->write = aspeed_2400_sdmc_write;
+}
+
+static const TypeInfo aspeed_2400_sdmc_info = {
+ .name = TYPE_ASPEED_2400_SDMC,
+ .parent = TYPE_ASPEED_SDMC,
+ .class_init = aspeed_2400_sdmc_class_init,
+};
+
+static uint32_t aspeed_2500_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
+{
+ uint32_t fixed_conf = ASPEED_SDMC_HW_VERSION(1) |
+ ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) |
+ ASPEED_SDMC_CACHE_INITIAL_DONE |
+ ASPEED_SDMC_DRAM_SIZE(ast2500_rambits(s));
+
+ /* Make sure readonly bits are kept */
+ data &= ~ASPEED_SDMC_AST2500_READONLY_MASK;
+
+ return data | fixed_conf;
+}
+
+static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg,
+ uint32_t data)
+{
+ switch (reg) {
+ case R_CONF:
+ data = aspeed_2500_sdmc_compute_conf(s, data);
+ break;
+ case R_STATUS1:
+ /* Will never return 'busy' */
+ data &= ~PHY_BUSY_STATE;
+ break;
+ case R_ECC_TEST_CTRL:
+ /* Always done, always happy */
+ data |= ECC_TEST_FINISHED;
+ data &= ~ECC_TEST_FAIL;
+ break;
+ default:
+ break;
+ }
+
+ s->regs[reg] = data;
+}
+
+static void aspeed_2500_sdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 SDRAM Memory Controller";
+ asc->max_ram_size = 1024 << 20;
+ asc->compute_conf = aspeed_2500_sdmc_compute_conf;
+ asc->write = aspeed_2500_sdmc_write;
+}
+
+static const TypeInfo aspeed_2500_sdmc_info = {
+ .name = TYPE_ASPEED_2500_SDMC,
+ .parent = TYPE_ASPEED_SDMC,
+ .class_init = aspeed_2500_sdmc_class_init,
+};
+
+static uint32_t aspeed_2600_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
+{
+ uint32_t fixed_conf = ASPEED_SDMC_HW_VERSION(3) |
+ ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) |
+ ASPEED_SDMC_DRAM_SIZE(ast2600_rambits(s));
+
+ /* Make sure readonly bits are kept (use ast2500 mask) */
+ data &= ~ASPEED_SDMC_AST2500_READONLY_MASK;
+
+ return data | fixed_conf;
+}
+
+static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
+ uint32_t data)
+{
+ switch (reg) {
+ case R_CONF:
+ data = aspeed_2600_sdmc_compute_conf(s, data);
+ break;
+ case R_STATUS1:
+ /* Will never return 'busy'. 'lock status' is always set */
+ data &= ~PHY_BUSY_STATE;
+ data |= PHY_PLL_LOCK_STATUS;
+ break;
+ case R_ECC_TEST_CTRL:
+ /* Always done, always happy */
+ data |= ECC_TEST_FINISHED;
+ data &= ~ECC_TEST_FAIL;
+ break;
+ default:
+ break;
+ }
+
+ s->regs[reg] = data;
+}
+
+static void aspeed_2600_sdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 SDRAM Memory Controller";
+ asc->max_ram_size = 2048 << 20;
+ asc->compute_conf = aspeed_2600_sdmc_compute_conf;
+ asc->write = aspeed_2600_sdmc_write;
+}
+
+static const TypeInfo aspeed_2600_sdmc_info = {
+ .name = TYPE_ASPEED_2600_SDMC,
+ .parent = TYPE_ASPEED_SDMC,
+ .class_init = aspeed_2600_sdmc_class_init,
};
static void aspeed_sdmc_register_types(void)
{
type_register_static(&aspeed_sdmc_info);
+ type_register_static(&aspeed_2400_sdmc_info);
+ type_register_static(&aspeed_2500_sdmc_info);
+ type_register_static(&aspeed_2600_sdmc_info);
}
type_init(aspeed_sdmc_register_types);
diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c
index 79bad11631..77d2d80706 100644
--- a/hw/misc/bcm2835_mbox.c
+++ b/hw/misc/bcm2835_mbox.c
@@ -15,6 +15,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
#define MAIL0_PEEK 0x90
#define MAIL0_SENDER 0x94
@@ -123,6 +124,7 @@ static void bcm2835_mbox_update(BCM2835MboxState *s)
set = true;
}
}
+ trace_bcm2835_mbox_irq(set);
qemu_set_irq(s->arm_irq, set);
}
@@ -176,10 +178,12 @@ static uint64_t bcm2835_mbox_read(void *opaque, hwaddr offset, unsigned size)
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx"\n",
__func__, offset);
+ trace_bcm2835_mbox_read(size, offset, res);
return 0;
}
+ trace_bcm2835_mbox_read(size, offset, res);
bcm2835_mbox_update(s);
@@ -195,6 +199,7 @@ static void bcm2835_mbox_write(void *opaque, hwaddr offset,
offset &= 0xff;
+ trace_bcm2835_mbox_write(size, offset, value);
switch (offset) {
case MAIL0_SENDER:
break;
@@ -228,8 +233,9 @@ static void bcm2835_mbox_write(void *opaque, hwaddr offset,
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
- __func__, offset);
+ qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx
+ " value 0x%"PRIx64"\n",
+ __func__, offset, value);
return;
}
@@ -310,7 +316,7 @@ static void bcm2835_mbox_realize(DeviceState *dev, Error **errp)
}
s->mbox_mr = MEMORY_REGION(obj);
- address_space_init(&s->mbox_as, s->mbox_mr, NULL);
+ address_space_init(&s->mbox_as, s->mbox_mr, TYPE_BCM2835_MBOX "-memory");
bcm2835_mbox_reset(dev);
}
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index d86d510572..0eea2e20f7 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -13,6 +13,7 @@
#include "sysemu/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
@@ -56,7 +57,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
break;
case 0x00010001: /* Get board model */
qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x get board model NYI\n", tag);
+ "bcm2835_property: 0x%08x get board model NYI\n",
+ tag);
resplen = 4;
break;
case 0x00010002: /* Get board revision */
@@ -69,7 +71,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
break;
case 0x00010004: /* Get board serial */
qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x get board serial NYI\n", tag);
+ "bcm2835_property: 0x%08x get board serial NYI\n",
+ tag);
resplen = 8;
break;
case 0x00010005: /* Get ARM memory */
@@ -104,7 +107,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
case 0x00038001: /* Set clock state */
qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x set clock state NYI\n", tag);
+ "bcm2835_property: 0x%08x set clock state NYI\n",
+ tag);
resplen = 8;
break;
@@ -129,7 +133,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
case 0x00038004: /* Set max clock rate */
case 0x00038007: /* Set min clock rate */
qemu_log_mask(LOG_UNIMP,
- "bcm2835_property: %x set clock rates NYI\n", tag);
+ "bcm2835_property: 0x%08x set clock rate NYI\n",
+ tag);
resplen = 8;
break;
@@ -274,11 +279,12 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "bcm2835_property: unhandled tag %08x\n", tag);
+ qemu_log_mask(LOG_UNIMP,
+ "bcm2835_property: unhandled tag 0x%08x\n", tag);
break;
}
+ trace_bcm2835_mbox_property(tag, bufsize, resplen);
if (tag == 0) {
break;
}
@@ -403,7 +409,7 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp)
}
s->dma_mr = MEMORY_REGION(obj);
- address_space_init(&s->dma_as, s->dma_mr, NULL);
+ address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory");
/* TODO: connect to MAC address of USB NIC device, once we emulate it */
qemu_macaddr_default_if_unset(&s->macaddr);
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 74276225f8..1deb1d08c1 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -143,3 +143,9 @@ armsse_mhu_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU wri
# aspeed_xdma.c
aspeed_xdma_write(uint64_t offset, uint64_t data) "XDMA write: offset 0x%" PRIx64 " data 0x%" PRIx64
+
+# bcm2835_mbox.c
+bcm2835_mbox_write(unsigned int size, uint64_t addr, uint64_t value) "mbox write sz:%u addr:0x%"PRIx64" data:0x%"PRIx64
+bcm2835_mbox_read(unsigned int size, uint64_t addr, uint64_t value) "mbox read sz:%u addr:0x%"PRIx64" data:0x%"PRIx64
+bcm2835_mbox_irq(unsigned level) "mbox irq:ARM level:%u"
+bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu"
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 8451c17fb8..d9b3e8c691 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -393,7 +393,7 @@ static void etsec_realize(DeviceState *dev, Error **errp)
etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
- etsec->ptimer = ptimer_init(etsec->bh, PTIMER_POLICY_DEFAULT);
+ etsec->ptimer = ptimer_init_with_bh(etsec->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(etsec->ptimer, 100);
}
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 04c78e8517..eb8b441461 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -15,6 +15,7 @@
#include "hw/irq.h"
#include "hw/net/ftgmac100.h"
#include "sysemu/dma.h"
+#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "net/checksum.h"
@@ -1087,9 +1088,170 @@ static const TypeInfo ftgmac100_info = {
.class_init = ftgmac100_class_init,
};
+/*
+ * AST2600 MII controller
+ */
+#define ASPEED_MII_PHYCR_FIRE BIT(31)
+#define ASPEED_MII_PHYCR_ST_22 BIT(28)
+#define ASPEED_MII_PHYCR_OP(x) ((x) & (ASPEED_MII_PHYCR_OP_WRITE | \
+ ASPEED_MII_PHYCR_OP_READ))
+#define ASPEED_MII_PHYCR_OP_WRITE BIT(26)
+#define ASPEED_MII_PHYCR_OP_READ BIT(27)
+#define ASPEED_MII_PHYCR_DATA(x) (x & 0xffff)
+#define ASPEED_MII_PHYCR_PHY(x) (((x) >> 21) & 0x1f)
+#define ASPEED_MII_PHYCR_REG(x) (((x) >> 16) & 0x1f)
+
+#define ASPEED_MII_PHYDATA_IDLE BIT(16)
+
+static void aspeed_mii_transition(AspeedMiiState *s, bool fire)
+{
+ if (fire) {
+ s->phycr |= ASPEED_MII_PHYCR_FIRE;
+ s->phydata &= ~ASPEED_MII_PHYDATA_IDLE;
+ } else {
+ s->phycr &= ~ASPEED_MII_PHYCR_FIRE;
+ s->phydata |= ASPEED_MII_PHYDATA_IDLE;
+ }
+}
+
+static void aspeed_mii_do_phy_ctl(AspeedMiiState *s)
+{
+ uint8_t reg;
+ uint16_t data;
+
+ if (!(s->phycr & ASPEED_MII_PHYCR_ST_22)) {
+ aspeed_mii_transition(s, !ASPEED_MII_PHYCR_FIRE);
+ qemu_log_mask(LOG_UNIMP, "%s: unsupported ST code\n", __func__);
+ return;
+ }
+
+ /* Nothing to do */
+ if (!(s->phycr & ASPEED_MII_PHYCR_FIRE)) {
+ return;
+ }
+
+ reg = ASPEED_MII_PHYCR_REG(s->phycr);
+ data = ASPEED_MII_PHYCR_DATA(s->phycr);
+
+ switch (ASPEED_MII_PHYCR_OP(s->phycr)) {
+ case ASPEED_MII_PHYCR_OP_WRITE:
+ do_phy_write(s->nic, reg, data);
+ break;
+ case ASPEED_MII_PHYCR_OP_READ:
+ s->phydata = (s->phydata & ~0xffff) | do_phy_read(s->nic, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid OP code %08x\n",
+ __func__, s->phycr);
+ }
+
+ aspeed_mii_transition(s, !ASPEED_MII_PHYCR_FIRE);
+}
+
+static uint64_t aspeed_mii_read(void *opaque, hwaddr addr, unsigned size)
+{
+ AspeedMiiState *s = ASPEED_MII(opaque);
+
+ switch (addr) {
+ case 0x0:
+ return s->phycr;
+ case 0x4:
+ return s->phydata;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void aspeed_mii_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ AspeedMiiState *s = ASPEED_MII(opaque);
+
+ switch (addr) {
+ case 0x0:
+ s->phycr = value & ~(s->phycr & ASPEED_MII_PHYCR_FIRE);
+ break;
+ case 0x4:
+ s->phydata = value & ~(0xffff | ASPEED_MII_PHYDATA_IDLE);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ aspeed_mii_transition(s, !!(s->phycr & ASPEED_MII_PHYCR_FIRE));
+ aspeed_mii_do_phy_ctl(s);
+}
+
+static const MemoryRegionOps aspeed_mii_ops = {
+ .read = aspeed_mii_read,
+ .write = aspeed_mii_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void aspeed_mii_reset(DeviceState *dev)
+{
+ AspeedMiiState *s = ASPEED_MII(dev);
+
+ s->phycr = 0;
+ s->phydata = 0;
+
+ aspeed_mii_transition(s, !!(s->phycr & ASPEED_MII_PHYCR_FIRE));
+};
+
+static void aspeed_mii_realize(DeviceState *dev, Error **errp)
+{
+ AspeedMiiState *s = ASPEED_MII(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ Object *obj;
+ Error *local_err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "nic", &local_err);
+ if (!obj) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'nic' not found: ");
+ return;
+ }
+
+ s->nic = FTGMAC100(obj);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &aspeed_mii_ops, s,
+ TYPE_ASPEED_MII, 0x8);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription vmstate_aspeed_mii = {
+ .name = TYPE_ASPEED_MII,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(phycr, FTGMAC100State),
+ VMSTATE_UINT32(phydata, FTGMAC100State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+static void aspeed_mii_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_aspeed_mii;
+ dc->reset = aspeed_mii_reset;
+ dc->realize = aspeed_mii_realize;
+ dc->desc = "Aspeed MII controller";
+}
+
+static const TypeInfo aspeed_mii_info = {
+ .name = TYPE_ASPEED_MII,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedMiiState),
+ .class_init = aspeed_mii_class_init,
+};
+
static void ftgmac100_register_types(void)
{
type_register_static(&ftgmac100_info);
+ type_register_static(&aspeed_mii_info);
}
type_init(ftgmac100_register_types)
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 8bba2a8056..ed551f2178 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -21,7 +21,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
/* For crc32 */
#include <zlib.h>
@@ -450,8 +449,10 @@ static void lan9118_reset(DeviceState *d)
s->e2p_data = 0;
s->free_timer_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40;
+ ptimer_transaction_begin(s->timer);
ptimer_stop(s->timer);
ptimer_set_count(s->timer, 0xffff);
+ ptimer_transaction_commit(s->timer);
s->gpt_cfg = 0xffff;
s->mac_cr = MAC_CR_PRMS;
@@ -1100,6 +1101,7 @@ static void lan9118_writel(void *opaque, hwaddr offset,
break;
case CSR_GPT_CFG:
if ((s->gpt_cfg ^ val) & GPT_TIMER_EN) {
+ ptimer_transaction_begin(s->timer);
if (val & GPT_TIMER_EN) {
ptimer_set_count(s->timer, val & 0xffff);
ptimer_run(s->timer, 0);
@@ -1107,6 +1109,7 @@ static void lan9118_writel(void *opaque, hwaddr offset,
ptimer_stop(s->timer);
ptimer_set_count(s->timer, 0xffff);
}
+ ptimer_transaction_commit(s->timer);
}
s->gpt_cfg = val & (GPT_TIMER_EN | 0xffff);
break;
@@ -1328,7 +1331,6 @@ static void lan9118_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
lan9118_state *s = LAN9118(dev);
- QEMUBH *bh;
int i;
const MemoryRegionOps *mem_ops =
s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
@@ -1349,10 +1351,11 @@ static void lan9118_realize(DeviceState *dev, Error **errp)
s->pmt_ctrl = 1;
s->txp = &s->tx_packet;
- bh = qemu_bh_new(lan9118_tick, s);
- s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init(lan9118_tick, s, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(s->timer);
ptimer_set_freq(s->timer, 10000);
ptimer_set_limit(s->timer, 0xffff, 1);
+ ptimer_transaction_commit(s->timer);
}
static Property lan9118_properties[] = {
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs
index 06657279d1..a884c238df 100644
--- a/hw/sd/Makefile.objs
+++ b/hw/sd/Makefile.objs
@@ -8,3 +8,4 @@ obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
obj-$(CONFIG_OMAP) += omap_mmc.o
obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o
obj-$(CONFIG_RASPI) += bcm2835_sdhost.o
+obj-$(CONFIG_ASPEED_SOC) += aspeed_sdhci.o
diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c
new file mode 100644
index 0000000000..cff3eb7dd2
--- /dev/null
+++ b/hw/sd/aspeed_sdhci.c
@@ -0,0 +1,198 @@
+/*
+ * Aspeed SD Host Controller
+ * Eddie James <eajames@linux.ibm.com>
+ *
+ * Copyright (C) 2019 IBM Corp
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/sd/aspeed_sdhci.h"
+#include "qapi/error.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+
+#define ASPEED_SDHCI_INFO 0x00
+#define ASPEED_SDHCI_INFO_RESET 0x00030000
+#define ASPEED_SDHCI_DEBOUNCE 0x04
+#define ASPEED_SDHCI_DEBOUNCE_RESET 0x00000005
+#define ASPEED_SDHCI_BUS 0x08
+#define ASPEED_SDHCI_SDIO_140 0x10
+#define ASPEED_SDHCI_SDIO_148 0x18
+#define ASPEED_SDHCI_SDIO_240 0x20
+#define ASPEED_SDHCI_SDIO_248 0x28
+#define ASPEED_SDHCI_WP_POL 0xec
+#define ASPEED_SDHCI_CARD_DET 0xf0
+#define ASPEED_SDHCI_IRQ_STAT 0xfc
+
+#define TO_REG(addr) ((addr) / sizeof(uint32_t))
+
+static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ uint32_t val = 0;
+ AspeedSDHCIState *sdhci = opaque;
+
+ switch (addr) {
+ case ASPEED_SDHCI_SDIO_140:
+ val = (uint32_t)sdhci->slots[0].capareg;
+ break;
+ case ASPEED_SDHCI_SDIO_148:
+ val = (uint32_t)sdhci->slots[0].maxcurr;
+ break;
+ case ASPEED_SDHCI_SDIO_240:
+ val = (uint32_t)sdhci->slots[1].capareg;
+ break;
+ case ASPEED_SDHCI_SDIO_248:
+ val = (uint32_t)sdhci->slots[1].maxcurr;
+ break;
+ default:
+ if (addr < ASPEED_SDHCI_REG_SIZE) {
+ val = sdhci->regs[TO_REG(addr)];
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ }
+ }
+
+ return (uint64_t)val;
+}
+
+static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int size)
+{
+ AspeedSDHCIState *sdhci = opaque;
+
+ switch (addr) {
+ case ASPEED_SDHCI_SDIO_140:
+ sdhci->slots[0].capareg = (uint64_t)(uint32_t)val;
+ break;
+ case ASPEED_SDHCI_SDIO_148:
+ sdhci->slots[0].maxcurr = (uint64_t)(uint32_t)val;
+ break;
+ case ASPEED_SDHCI_SDIO_240:
+ sdhci->slots[1].capareg = (uint64_t)(uint32_t)val;
+ break;
+ case ASPEED_SDHCI_SDIO_248:
+ sdhci->slots[1].maxcurr = (uint64_t)(uint32_t)val;
+ break;
+ default:
+ if (addr < ASPEED_SDHCI_REG_SIZE) {
+ sdhci->regs[TO_REG(addr)] = (uint32_t)val;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ }
+ }
+}
+
+static const MemoryRegionOps aspeed_sdhci_ops = {
+ .read = aspeed_sdhci_read,
+ .write = aspeed_sdhci_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static void aspeed_sdhci_set_irq(void *opaque, int n, int level)
+{
+ AspeedSDHCIState *sdhci = opaque;
+
+ if (level) {
+ sdhci->regs[TO_REG(ASPEED_SDHCI_IRQ_STAT)] |= BIT(n);
+
+ qemu_irq_raise(sdhci->irq);
+ } else {
+ sdhci->regs[TO_REG(ASPEED_SDHCI_IRQ_STAT)] &= ~BIT(n);
+
+ qemu_irq_lower(sdhci->irq);
+ }
+}
+
+static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
+{
+ Error *err = NULL;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev);
+
+ /* Create input irqs for the slots */
+ qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq,
+ sdhci, NULL, ASPEED_SDHCI_NUM_SLOTS);
+
+ sysbus_init_irq(sbd, &sdhci->irq);
+ memory_region_init_io(&sdhci->iomem, OBJECT(sdhci), &aspeed_sdhci_ops,
+ sdhci, TYPE_ASPEED_SDHCI, 0x1000);
+ sysbus_init_mmio(sbd, &sdhci->iomem);
+
+ for (int i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) {
+ Object *sdhci_slot = OBJECT(&sdhci->slots[i]);
+ SysBusDevice *sbd_slot = SYS_BUS_DEVICE(&sdhci->slots[i]);
+
+ object_property_set_int(sdhci_slot, 2, "sd-spec-version", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_uint(sdhci_slot, ASPEED_SDHCI_CAPABILITIES,
+ "capareg", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(sdhci_slot, true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_connect_irq(sbd_slot, 0, qdev_get_gpio_in(DEVICE(sbd), i));
+ memory_region_add_subregion(&sdhci->iomem, (i + 1) * 0x100,
+ &sdhci->slots[i].iomem);
+ }
+}
+
+static void aspeed_sdhci_reset(DeviceState *dev)
+{
+ AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev);
+
+ memset(sdhci->regs, 0, ASPEED_SDHCI_REG_SIZE);
+ sdhci->regs[TO_REG(ASPEED_SDHCI_INFO)] = ASPEED_SDHCI_INFO_RESET;
+ sdhci->regs[TO_REG(ASPEED_SDHCI_DEBOUNCE)] = ASPEED_SDHCI_DEBOUNCE_RESET;
+}
+
+static const VMStateDescription vmstate_aspeed_sdhci = {
+ .name = TYPE_ASPEED_SDHCI,
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, AspeedSDHCIState, ASPEED_SDHCI_NUM_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static void aspeed_sdhci_class_init(ObjectClass *classp, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(classp);
+
+ dc->realize = aspeed_sdhci_realize;
+ dc->reset = aspeed_sdhci_reset;
+ dc->vmsd = &vmstate_aspeed_sdhci;
+}
+
+static TypeInfo aspeed_sdhci_info = {
+ .name = TYPE_ASPEED_SDHCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedSDHCIState),
+ .class_init = aspeed_sdhci_class_init,
+};
+
+static void aspeed_sdhci_register_types(void)
+{
+ type_register_static(&aspeed_sdhci_info);
+}
+
+type_init(aspeed_sdhci_register_types)
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 9ffc7e0117..f0c7bbbad3 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -30,6 +30,7 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "exec/address-spaces.h"
+#include "qemu/units.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -50,7 +51,7 @@
#define CONF_FLASH_TYPE0 0
#define CONF_FLASH_TYPE_NOR 0x0
#define CONF_FLASH_TYPE_NAND 0x1
-#define CONF_FLASH_TYPE_SPI 0x2
+#define CONF_FLASH_TYPE_SPI 0x2 /* AST2600 is SPI only */
/* CE Control Register */
#define R_CE_CTRL (0x04 / 4)
@@ -71,8 +72,11 @@
/* CEx Control Register */
#define R_CTRL0 (0x10 / 4)
+#define CTRL_IO_QPI (1 << 31)
+#define CTRL_IO_QUAD_DATA (1 << 30)
#define CTRL_IO_DUAL_DATA (1 << 29)
#define CTRL_IO_DUAL_ADDR_DATA (1 << 28) /* Includes dummies */
+#define CTRL_IO_QUAD_ADDR_DATA (1 << 28) /* Includes dummies */
#define CTRL_CMD_SHIFT 16
#define CTRL_CMD_MASK 0xff
#define CTRL_DUMMY_HIGH_SHIFT 14
@@ -136,7 +140,7 @@
/* Misc Control Register #2 */
#define R_TIMINGS (0x94 / 4)
-/* SPI controller registers and bits */
+/* SPI controller registers and bits (AST2400) */
#define R_SPI_CONF (0x00 / 4)
#define SPI_CONF_ENABLE_W0 0
#define R_SPI_CTRL0 (0x4 / 4)
@@ -211,6 +215,39 @@ static const AspeedSegments aspeed_segments_ast2500_spi2[] = {
{ 0x38000000, 32 * 1024 * 1024 }, /* start address is readonly */
{ 0x3A000000, 96 * 1024 * 1024 }, /* end address is readonly */
};
+static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s,
+ const AspeedSegments *seg);
+static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg,
+ AspeedSegments *seg);
+
+/*
+ * AST2600 definitions
+ */
+#define ASPEED26_SOC_FMC_FLASH_BASE 0x20000000
+#define ASPEED26_SOC_SPI_FLASH_BASE 0x30000000
+#define ASPEED26_SOC_SPI2_FLASH_BASE 0x50000000
+
+static const AspeedSegments aspeed_segments_ast2600_fmc[] = {
+ { 0x0, 128 * MiB }, /* start address is readonly */
+ { 0x0, 0 }, /* disabled */
+ { 0x0, 0 }, /* disabled */
+};
+
+static const AspeedSegments aspeed_segments_ast2600_spi1[] = {
+ { 0x0, 128 * MiB }, /* start address is readonly */
+ { 0x0, 0 }, /* disabled */
+};
+
+static const AspeedSegments aspeed_segments_ast2600_spi2[] = {
+ { 0x0, 128 * MiB }, /* start address is readonly */
+ { 0x0, 0 }, /* disabled */
+ { 0x0, 0 }, /* disabled */
+};
+
+static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s,
+ const AspeedSegments *seg);
+static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s,
+ uint32_t reg, AspeedSegments *seg);
static const AspeedSMCController controllers[] = {
{
@@ -226,6 +263,8 @@ static const AspeedSMCController controllers[] = {
.flash_window_size = 0x6000000,
.has_dma = false,
.nregs = ASPEED_SMC_R_SMC_MAX,
+ .segment_to_reg = aspeed_smc_segment_to_reg,
+ .reg_to_segment = aspeed_smc_reg_to_segment,
}, {
.name = "aspeed.fmc-ast2400",
.r_conf = R_CONF,
@@ -241,6 +280,8 @@ static const AspeedSMCController controllers[] = {
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x1FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_smc_segment_to_reg,
+ .reg_to_segment = aspeed_smc_reg_to_segment,
}, {
.name = "aspeed.spi1-ast2400",
.r_conf = R_SPI_CONF,
@@ -254,6 +295,8 @@ static const AspeedSMCController controllers[] = {
.flash_window_size = 0x10000000,
.has_dma = false,
.nregs = ASPEED_SMC_R_SPI_MAX,
+ .segment_to_reg = aspeed_smc_segment_to_reg,
+ .reg_to_segment = aspeed_smc_reg_to_segment,
}, {
.name = "aspeed.fmc-ast2500",
.r_conf = R_CONF,
@@ -269,6 +312,8 @@ static const AspeedSMCController controllers[] = {
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_smc_segment_to_reg,
+ .reg_to_segment = aspeed_smc_reg_to_segment,
}, {
.name = "aspeed.spi1-ast2500",
.r_conf = R_CONF,
@@ -282,6 +327,8 @@ static const AspeedSMCController controllers[] = {
.flash_window_size = 0x8000000,
.has_dma = false,
.nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_smc_segment_to_reg,
+ .reg_to_segment = aspeed_smc_reg_to_segment,
}, {
.name = "aspeed.spi2-ast2500",
.r_conf = R_CONF,
@@ -295,19 +342,64 @@ static const AspeedSMCController controllers[] = {
.flash_window_size = 0x8000000,
.has_dma = false,
.nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_smc_segment_to_reg,
+ .reg_to_segment = aspeed_smc_reg_to_segment,
+ }, {
+ .name = "aspeed.fmc-ast2600",
+ .r_conf = R_CONF,
+ .r_ce_ctrl = R_CE_CTRL,
+ .r_ctrl0 = R_CTRL0,
+ .r_timings = R_TIMINGS,
+ .conf_enable_w0 = CONF_ENABLE_W0,
+ .max_slaves = 3,
+ .segments = aspeed_segments_ast2600_fmc,
+ .flash_window_base = ASPEED26_SOC_FMC_FLASH_BASE,
+ .flash_window_size = 0x10000000,
+ .has_dma = true,
+ .nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_2600_smc_segment_to_reg,
+ .reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ }, {
+ .name = "aspeed.spi1-ast2600",
+ .r_conf = R_CONF,
+ .r_ce_ctrl = R_CE_CTRL,
+ .r_ctrl0 = R_CTRL0,
+ .r_timings = R_TIMINGS,
+ .conf_enable_w0 = CONF_ENABLE_W0,
+ .max_slaves = 2,
+ .segments = aspeed_segments_ast2600_spi1,
+ .flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE,
+ .flash_window_size = 0x10000000,
+ .has_dma = false,
+ .nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_2600_smc_segment_to_reg,
+ .reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ }, {
+ .name = "aspeed.spi2-ast2600",
+ .r_conf = R_CONF,
+ .r_ce_ctrl = R_CE_CTRL,
+ .r_ctrl0 = R_CTRL0,
+ .r_timings = R_TIMINGS,
+ .conf_enable_w0 = CONF_ENABLE_W0,
+ .max_slaves = 3,
+ .segments = aspeed_segments_ast2600_spi2,
+ .flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE,
+ .flash_window_size = 0x10000000,
+ .has_dma = false,
+ .nregs = ASPEED_SMC_R_MAX,
+ .segment_to_reg = aspeed_2600_smc_segment_to_reg,
+ .reg_to_segment = aspeed_2600_smc_reg_to_segment,
},
};
/*
- * The Segment Register uses a 8MB unit to encode the start address
- * and the end address of the mapping window of a flash SPI slave :
- *
- * | byte 1 | byte 2 | byte 3 | byte 4 |
- * +--------+--------+--------+--------+
- * | end | start | 0 | 0 |
- *
+ * The Segment Registers of the AST2400 and AST2500 have a 8MB
+ * unit. The address range of a flash SPI slave is encoded with
+ * absolute addresses which should be part of the overall controller
+ * window.
*/
-static inline uint32_t aspeed_smc_segment_to_reg(const AspeedSegments *seg)
+static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s,
+ const AspeedSegments *seg)
{
uint32_t reg = 0;
reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT;
@@ -315,12 +407,47 @@ static inline uint32_t aspeed_smc_segment_to_reg(const AspeedSegments *seg)
return reg;
}
-static inline void aspeed_smc_reg_to_segment(uint32_t reg, AspeedSegments *seg)
+static void aspeed_smc_reg_to_segment(const AspeedSMCState *s,
+ uint32_t reg, AspeedSegments *seg)
{
seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23;
seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr;
}
+/*
+ * The Segment Registers of the AST2600 have a 1MB unit. The address
+ * range of a flash SPI slave is encoded with offsets in the overall
+ * controller window. The previous SoC AST2400 and AST2500 used
+ * absolute addresses. Only bits [27:20] are relevant and the end
+ * address is an upper bound limit.
+ */
+#define AST2600_SEG_ADDR_MASK 0x0ff00000
+
+static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s,
+ const AspeedSegments *seg)
+{
+ uint32_t reg = 0;
+
+ /* Disabled segments have a nil register */
+ if (!seg->size) {
+ return 0;
+ }
+
+ reg |= (seg->addr & AST2600_SEG_ADDR_MASK) >> 16; /* start offset */
+ reg |= (seg->addr + seg->size - 1) & AST2600_SEG_ADDR_MASK; /* end offset */
+ return reg;
+}
+
+static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s,
+ uint32_t reg, AspeedSegments *seg)
+{
+ uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK;
+ uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK;
+
+ seg->addr = s->ctrl->flash_window_base + start_offset;
+ seg->size = end_offset + MiB - start_offset;
+}
+
static bool aspeed_smc_flash_overlap(const AspeedSMCState *s,
const AspeedSegments *new,
int cs)
@@ -333,7 +460,7 @@ static bool aspeed_smc_flash_overlap(const AspeedSMCState *s,
continue;
}
- aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + i], &seg);
+ s->ctrl->reg_to_segment(s, s->regs[R_SEG_ADDR0 + i], &seg);
if (new->addr + new->size > seg.addr &&
new->addr < seg.addr + seg.size) {
@@ -354,7 +481,7 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
AspeedSMCFlash *fl = &s->flashes[cs];
AspeedSegments seg;
- aspeed_smc_reg_to_segment(new, &seg);
+ s->ctrl->reg_to_segment(s, new, &seg);
/* The start address of CS0 is read-only */
if (cs == 0 && seg.addr != s->ctrl->flash_window_base) {
@@ -362,7 +489,7 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
"%s: Tried to change CS0 start address to 0x%"
HWADDR_PRIx "\n", s->ctrl->name, seg.addr);
seg.addr = s->ctrl->flash_window_base;
- new = aspeed_smc_segment_to_reg(&seg);
+ new = s->ctrl->segment_to_reg(s, &seg);
}
/*
@@ -379,7 +506,7 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr + seg.size);
seg.size = s->ctrl->segments[cs].addr + s->ctrl->segments[cs].size -
seg.addr;
- new = aspeed_smc_segment_to_reg(&seg);
+ new = s->ctrl->segment_to_reg(s, &seg);
}
/* Keep the segment in the overall flash window */
@@ -455,8 +582,12 @@ static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl)
const AspeedSMCState *s = fl->controller;
int cmd = (s->regs[s->r_ctrl0 + fl->id] >> CTRL_CMD_SHIFT) & CTRL_CMD_MASK;
- /* In read mode, the default SPI command is READ (0x3). In other
- * modes, the command should necessarily be defined */
+ /*
+ * In read mode, the default SPI command is READ (0x3). In other
+ * modes, the command should necessarily be defined
+ *
+ * TODO: add support for READ4 (0x13) on AST2600
+ */
if (aspeed_smc_flash_mode(fl) == CTRL_READMODE) {
cmd = SPI_OP_READ;
}
@@ -509,7 +640,7 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl,
const AspeedSMCState *s = fl->controller;
AspeedSegments seg;
- aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + fl->id], &seg);
+ s->ctrl->reg_to_segment(s, s->regs[R_SEG_ADDR0 + fl->id], &seg);
if ((addr % seg.size) != addr) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid address 0x%08x for CS%d segment : "
@@ -769,7 +900,15 @@ static void aspeed_smc_reset(DeviceState *d)
/* setup default segment register values for all */
for (i = 0; i < s->ctrl->max_slaves; ++i) {
s->regs[R_SEG_ADDR0 + i] =
- aspeed_smc_segment_to_reg(&s->ctrl->segments[i]);
+ s->ctrl->segment_to_reg(s, &s->ctrl->segments[i]);
+ }
+
+ /* HW strapping flash type for the AST2600 controllers */
+ if (s->ctrl->segments == aspeed_segments_ast2600_fmc) {
+ /* flash type is fixed to SPI for all */
+ s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0);
+ s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1);
+ s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE2);
}
/* HW strapping flash type for FMC controllers */
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
index ca5a905059..aae880f5b3 100644
--- a/hw/timer/allwinner-a10-pit.c
+++ b/hw/timer/allwinner-a10-pit.c
@@ -22,7 +22,6 @@
#include "hw/timer/allwinner-a10-pit.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
static void a10_pit_update_irq(AwA10PITState *s)
@@ -80,6 +79,7 @@ static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
return 0;
}
+/* Must be called inside a ptimer transaction block for s->timer[index] */
static void a10_pit_set_freq(AwA10PITState *s, int index)
{
uint32_t prescaler, source, source_freq;
@@ -118,6 +118,7 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset & 0x0f) {
case AW_A10_PIT_TIMER_CONTROL:
s->control[index] = value;
+ ptimer_transaction_begin(s->timer[index]);
a10_pit_set_freq(s, index);
if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
ptimer_set_count(s->timer[index], s->interval[index]);
@@ -131,10 +132,13 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
} else {
ptimer_stop(s->timer[index]);
}
+ ptimer_transaction_commit(s->timer[index]);
break;
case AW_A10_PIT_TIMER_INTERVAL:
s->interval[index] = value;
+ ptimer_transaction_begin(s->timer[index]);
ptimer_set_limit(s->timer[index], s->interval[index], 1);
+ ptimer_transaction_commit(s->timer[index]);
break;
case AW_A10_PIT_TIMER_COUNT:
s->count[index] = value;
@@ -225,8 +229,10 @@ static void a10_pit_reset(DeviceState *dev)
s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
s->interval[i] = 0;
s->count[i] = 0;
+ ptimer_transaction_begin(s->timer[i]);
ptimer_stop(s->timer[i]);
a10_pit_set_freq(s, i);
+ ptimer_transaction_commit(s->timer[i]);
}
s->watch_dog_mode = 0;
s->watch_dog_control = 0;
@@ -255,7 +261,6 @@ static void a10_pit_init(Object *obj)
{
AwA10PITState *s = AW_A10_PIT(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- QEMUBH * bh[AW_A10_PIT_TIMER_NR];
uint8_t i;
for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
@@ -270,8 +275,7 @@ static void a10_pit_init(Object *obj)
tc->container = s;
tc->index = i;
- bh[i] = qemu_bh_new(a10_pit_timer_cb, tc);
- s->timer[i] = ptimer_init(bh[i], PTIMER_POLICY_DEFAULT);
+ s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, PTIMER_POLICY_DEFAULT);
}
}
diff --git a/hw/timer/altera_timer.c b/hw/timer/altera_timer.c
index 936b31311d..ee32e0ec1f 100644
--- a/hw/timer/altera_timer.c
+++ b/hw/timer/altera_timer.c
@@ -184,7 +184,7 @@ static void altera_timer_realize(DeviceState *dev, Error **errp)
}
t->bh = qemu_bh_new(timer_hit, t);
- t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT);
+ t->ptimer = ptimer_init_with_bh(t->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(t->ptimer, t->freq_hz);
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index 9f63abef10..fdf97d1800 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -27,7 +27,6 @@
#include "hw/timer/arm_mptimer.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/core/cpu.h"
@@ -65,6 +64,7 @@ static inline uint32_t timerblock_scale(uint32_t control)
return (((control >> 8) & 0xff) + 1) * 10;
}
+/* Must be called within a ptimer transaction block */
static inline void timerblock_set_count(struct ptimer_state *timer,
uint32_t control, uint64_t *count)
{
@@ -77,6 +77,7 @@ static inline void timerblock_set_count(struct ptimer_state *timer,
ptimer_set_count(timer, *count);
}
+/* Must be called within a ptimer transaction block */
static inline void timerblock_run(struct ptimer_state *timer,
uint32_t control, uint32_t load)
{
@@ -124,6 +125,7 @@ static void timerblock_write(void *opaque, hwaddr addr,
uint32_t control = tb->control;
switch (addr) {
case 0: /* Load */
+ ptimer_transaction_begin(tb->timer);
/* Setting load to 0 stops the timer without doing the tick if
* prescaler = 0.
*/
@@ -132,8 +134,10 @@ static void timerblock_write(void *opaque, hwaddr addr,
}
ptimer_set_limit(tb->timer, value, 1);
timerblock_run(tb->timer, control, value);
+ ptimer_transaction_commit(tb->timer);
break;
case 4: /* Counter. */
+ ptimer_transaction_begin(tb->timer);
/* Setting counter to 0 stops the one-shot timer, or periodic with
* load = 0, without doing the tick if prescaler = 0.
*/
@@ -143,8 +147,10 @@ static void timerblock_write(void *opaque, hwaddr addr,
}
timerblock_set_count(tb->timer, control, &value);
timerblock_run(tb->timer, control, value);
+ ptimer_transaction_commit(tb->timer);
break;
case 8: /* Control. */
+ ptimer_transaction_begin(tb->timer);
if ((control & 3) != (value & 3)) {
ptimer_stop(tb->timer);
}
@@ -160,6 +166,7 @@ static void timerblock_write(void *opaque, hwaddr addr,
timerblock_run(tb->timer, value, count);
}
tb->control = value;
+ ptimer_transaction_commit(tb->timer);
break;
case 12: /* Interrupt status. */
tb->status &= ~value;
@@ -212,9 +219,11 @@ static void timerblock_reset(TimerBlock *tb)
tb->control = 0;
tb->status = 0;
if (tb->timer) {
+ ptimer_transaction_begin(tb->timer);
ptimer_stop(tb->timer);
ptimer_set_limit(tb->timer, 0, 1);
ptimer_set_period(tb->timer, timerblock_scale(0));
+ ptimer_transaction_commit(tb->timer);
}
}
@@ -228,7 +237,7 @@ static void arm_mptimer_reset(DeviceState *dev)
}
}
-static void arm_mptimer_init(Object *obj)
+static void arm_mptimer_init_with_bh(Object *obj)
{
ARMMPTimerState *s = ARM_MPTIMER(obj);
@@ -260,8 +269,7 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp)
*/
for (i = 0; i < s->num_cpu; i++) {
TimerBlock *tb = &s->timerblock[i];
- QEMUBH *bh = qemu_bh_new(timerblock_tick, tb);
- tb->timer = ptimer_init(bh, PTIMER_POLICY);
+ tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY);
sysbus_init_irq(sbd, &tb->irq);
memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
"arm_mptimer_timerblock", 0x20);
@@ -311,7 +319,7 @@ static const TypeInfo arm_mptimer_info = {
.name = TYPE_ARM_MPTIMER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ARMMPTimerState),
- .instance_init = arm_mptimer_init,
+ .instance_init = arm_mptimer_init_with_bh,
.class_init = arm_mptimer_class_init,
};
diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
index c2e6211188..af524fabf7 100644
--- a/hw/timer/arm_timer.c
+++ b/hw/timer/arm_timer.c
@@ -14,7 +14,6 @@
#include "hw/irq.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/log.h"
@@ -75,7 +74,10 @@ static uint32_t arm_timer_read(void *opaque, hwaddr offset)
}
}
-/* Reset the timer limit after settings have changed. */
+/*
+ * Reset the timer limit after settings have changed.
+ * May only be called from inside a ptimer transaction block.
+ */
static void arm_timer_recalibrate(arm_timer_state *s, int reload)
{
uint32_t limit;
@@ -102,13 +104,16 @@ static void arm_timer_write(void *opaque, hwaddr offset,
switch (offset >> 2) {
case 0: /* TimerLoad */
s->limit = value;
+ ptimer_transaction_begin(s->timer);
arm_timer_recalibrate(s, 1);
+ ptimer_transaction_commit(s->timer);
break;
case 1: /* TimerValue */
/* ??? Linux seems to want to write to this readonly register.
Ignore it. */
break;
case 2: /* TimerControl */
+ ptimer_transaction_begin(s->timer);
if (s->control & TIMER_CTRL_ENABLE) {
/* Pause the timer if it is running. This may cause some
inaccuracy dure to rounding, but avoids a whole lot of other
@@ -128,13 +133,16 @@ static void arm_timer_write(void *opaque, hwaddr offset,
/* Restart the timer if still enabled. */
ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
}
+ ptimer_transaction_commit(s->timer);
break;
case 3: /* TimerIntClr */
s->int_level = 0;
break;
case 6: /* TimerBGLoad */
s->limit = value;
+ ptimer_transaction_begin(s->timer);
arm_timer_recalibrate(s, 0);
+ ptimer_transaction_commit(s->timer);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
@@ -166,14 +174,12 @@ static const VMStateDescription vmstate_arm_timer = {
static arm_timer_state *arm_timer_init(uint32_t freq)
{
arm_timer_state *s;
- QEMUBH *bh;
s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
s->freq = freq;
s->control = TIMER_CTRL_IE;
- bh = qemu_bh_new(arm_timer_tick, s);
- s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT);
vmstate_register(NULL, -1, &vmstate_arm_timer, s);
return s;
}
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 2bda826882..bcce2192a9 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -160,7 +160,9 @@ static uint64_t calculate_next(struct AspeedTimer *t)
timer_del(&t->timer);
if (timer_overflow_interrupt(t)) {
+ AspeedTimerCtrlState *s = timer_to_ctrl(t);
t->level = !t->level;
+ s->irq_sts |= BIT(t->id);
qemu_set_irq(t->irq, t->level);
}
@@ -199,7 +201,9 @@ static void aspeed_timer_expire(void *opaque)
}
if (interrupt) {
+ AspeedTimerCtrlState *s = timer_to_ctrl(t);
t->level = !t->level;
+ s->irq_sts |= BIT(t->id);
qemu_set_irq(t->irq, t->level);
}
@@ -244,22 +248,14 @@ static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
case 0x30: /* Control Register */
value = s->ctrl;
break;
- case 0x34: /* Control Register 2 */
- value = s->ctrl2;
- break;
case 0x00 ... 0x2c: /* Timers 1 - 4 */
value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg);
break;
case 0x40 ... 0x8c: /* Timers 5 - 8 */
value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
break;
- /* Illegal */
- case 0x38:
- case 0x3C:
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- value = 0;
+ value = ASPEED_TIMER_GET_CLASS(s)->read(s, offset);
break;
}
trace_aspeed_timer_read(offset, size, value);
@@ -443,9 +439,6 @@ static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
case 0x30:
aspeed_timer_set_ctrl(s, tv);
break;
- case 0x34:
- aspeed_timer_set_ctrl2(s, tv);
- break;
/* Timer Registers */
case 0x00 ... 0x2c:
aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv);
@@ -453,12 +446,8 @@ static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
case 0x40 ... 0x8c:
aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
break;
- /* Illegal */
- case 0x38:
- case 0x3C:
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
+ ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value);
break;
}
}
@@ -472,6 +461,135 @@ static const MemoryRegionOps aspeed_timer_ops = {
.valid.unaligned = false,
};
+static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
+{
+ uint64_t value;
+
+ switch (offset) {
+ case 0x34:
+ value = s->ctrl2;
+ break;
+ case 0x38:
+ case 0x3C:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
+ uint64_t value)
+{
+ const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
+
+ switch (offset) {
+ case 0x34:
+ aspeed_timer_set_ctrl2(s, tv);
+ break;
+ case 0x38:
+ case 0x3C:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+}
+
+static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
+{
+ uint64_t value;
+
+ switch (offset) {
+ case 0x34:
+ value = s->ctrl2;
+ break;
+ case 0x38:
+ value = s->ctrl3 & BIT(0);
+ break;
+ case 0x3C:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
+ uint64_t value)
+{
+ const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
+ uint8_t command;
+
+ switch (offset) {
+ case 0x34:
+ aspeed_timer_set_ctrl2(s, tv);
+ break;
+ case 0x38:
+ command = (value >> 1) & 0xFF;
+ if (command == 0xAE) {
+ s->ctrl3 = 0x1;
+ } else if (command == 0xEA) {
+ s->ctrl3 = 0x0;
+ }
+ break;
+ case 0x3C:
+ if (s->ctrl3 & BIT(0)) {
+ aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
+ }
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+}
+
+static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
+{
+ uint64_t value;
+
+ switch (offset) {
+ case 0x34:
+ value = s->irq_sts;
+ break;
+ case 0x38:
+ case 0x3C:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
+ uint64_t value)
+{
+ const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
+
+ switch (offset) {
+ case 0x34:
+ s->irq_sts &= tv;
+ break;
+ case 0x3C:
+ aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
+ break;
+
+ case 0x38:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+}
+
static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
{
AspeedTimer *t = &s->timers[id];
@@ -525,6 +643,8 @@ static void aspeed_timer_reset(DeviceState *dev)
}
s->ctrl = 0;
s->ctrl2 = 0;
+ s->ctrl3 = 0;
+ s->irq_sts = 0;
}
static const VMStateDescription vmstate_aspeed_timer = {
@@ -543,11 +663,13 @@ static const VMStateDescription vmstate_aspeed_timer = {
static const VMStateDescription vmstate_aspeed_timer_state = {
.name = "aspeed.timerctrl",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
+ VMSTATE_UINT32(ctrl3, AspeedTimerCtrlState),
+ VMSTATE_UINT32(irq_sts, AspeedTimerCtrlState),
VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
AspeedTimer),
@@ -570,11 +692,64 @@ static const TypeInfo aspeed_timer_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedTimerCtrlState),
.class_init = timer_class_init,
+ .class_size = sizeof(AspeedTimerClass),
+ .abstract = true,
+};
+
+static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 Timer";
+ awc->read = aspeed_2400_timer_read;
+ awc->write = aspeed_2400_timer_write;
+}
+
+static const TypeInfo aspeed_2400_timer_info = {
+ .name = TYPE_ASPEED_2400_TIMER,
+ .parent = TYPE_ASPEED_TIMER,
+ .class_init = aspeed_2400_timer_class_init,
+};
+
+static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 Timer";
+ awc->read = aspeed_2500_timer_read;
+ awc->write = aspeed_2500_timer_write;
+}
+
+static const TypeInfo aspeed_2500_timer_info = {
+ .name = TYPE_ASPEED_2500_TIMER,
+ .parent = TYPE_ASPEED_TIMER,
+ .class_init = aspeed_2500_timer_class_init,
+};
+
+static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 Timer";
+ awc->read = aspeed_2600_timer_read;
+ awc->write = aspeed_2600_timer_write;
+}
+
+static const TypeInfo aspeed_2600_timer_info = {
+ .name = TYPE_ASPEED_2600_TIMER,
+ .parent = TYPE_ASPEED_TIMER,
+ .class_init = aspeed_2600_timer_class_init,
};
static void aspeed_timer_register_types(void)
{
type_register_static(&aspeed_timer_info);
+ type_register_static(&aspeed_2400_timer_info);
+ type_register_static(&aspeed_2500_timer_info);
+ type_register_static(&aspeed_2600_timer_info);
}
type_init(aspeed_timer_register_types)
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
index 5e2352dd32..e28ba9c90a 100644
--- a/hw/timer/cmsdk-apb-dualtimer.c
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -20,7 +20,6 @@
#include "qemu/log.h"
#include "trace.h"
#include "qapi/error.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
@@ -112,6 +111,8 @@ static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
/* Handle a write to the CONTROL register */
uint32_t changed;
+ ptimer_transaction_begin(m->timer);
+
newctrl &= R_CONTROL_VALID_MASK;
changed = m->control ^ newctrl;
@@ -213,6 +214,8 @@ static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
}
m->control = newctrl;
+
+ ptimer_transaction_commit(m->timer);
}
static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
@@ -330,6 +333,7 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
if (!(m->control & R_CONTROL_SIZE_MASK)) {
value &= 0xffff;
}
+ ptimer_transaction_begin(m->timer);
if (!(m->control & R_CONTROL_MODE_MASK)) {
/*
* In free-running mode this won't set the limit but will
@@ -346,6 +350,7 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
ptimer_run(m->timer, 1);
}
}
+ ptimer_transaction_commit(m->timer);
break;
case A_TIMER1BGLOAD:
/* Set the limit, but not the current count */
@@ -357,7 +362,9 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
if (!(m->control & R_CONTROL_SIZE_MASK)) {
value &= 0xffff;
}
+ ptimer_transaction_begin(m->timer);
ptimer_set_limit(m->timer, value, 0);
+ ptimer_transaction_commit(m->timer);
break;
case A_TIMER1CONTROL:
cmsdk_dualtimermod_write_control(m, value);
@@ -398,6 +405,7 @@ static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
m->intstatus = 0;
m->load = 0;
m->value = 0xffffffff;
+ ptimer_transaction_begin(m->timer);
ptimer_stop(m->timer);
/*
* We start in free-running mode, with VALUE at 0xffffffff, and
@@ -406,6 +414,7 @@ static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
*/
ptimer_set_limit(m->timer, 0xffff, 1);
ptimer_set_freq(m->timer, m->parent->pclk_frq);
+ ptimer_transaction_commit(m->timer);
}
static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
@@ -450,10 +459,9 @@ static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
CMSDKAPBDualTimerModule *m = &s->timermod[i];
- QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m);
m->parent = s;
- m->timer = ptimer_init(bh,
+ m->timer = ptimer_init(cmsdk_dualtimermod_tick, m,
PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
index c83e26566a..40728e85e2 100644
--- a/hw/timer/cmsdk-apb-timer.c
+++ b/hw/timer/cmsdk-apb-timer.c
@@ -29,7 +29,6 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qapi/error.h"
#include "trace.h"
@@ -121,14 +120,17 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value,
"CMSDK APB timer: EXTIN input not supported\n");
}
s->ctrl = value & 0xf;
+ ptimer_transaction_begin(s->timer);
if (s->ctrl & R_CTRL_EN_MASK) {
ptimer_run(s->timer, ptimer_get_limit(s->timer) == 0);
} else {
ptimer_stop(s->timer);
}
+ ptimer_transaction_commit(s->timer);
break;
case A_RELOAD:
/* Writing to reload also sets the current timer value */
+ ptimer_transaction_begin(s->timer);
if (!value) {
ptimer_stop(s->timer);
}
@@ -140,8 +142,10 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value,
*/
ptimer_run(s->timer, 0);
}
+ ptimer_transaction_commit(s->timer);
break;
case A_VALUE:
+ ptimer_transaction_begin(s->timer);
if (!value && !ptimer_get_limit(s->timer)) {
ptimer_stop(s->timer);
}
@@ -149,6 +153,7 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value,
if (value && (s->ctrl & R_CTRL_EN_MASK)) {
ptimer_run(s->timer, ptimer_get_limit(s->timer) == 0);
}
+ ptimer_transaction_commit(s->timer);
break;
case A_INTSTATUS:
/* Just one bit, which is W1C. */
@@ -191,9 +196,11 @@ static void cmsdk_apb_timer_reset(DeviceState *dev)
trace_cmsdk_apb_timer_reset();
s->ctrl = 0;
s->intstatus = 0;
+ ptimer_transaction_begin(s->timer);
ptimer_stop(s->timer);
/* Set the limit and the count */
ptimer_set_limit(s->timer, 0, 1);
+ ptimer_transaction_commit(s->timer);
}
static void cmsdk_apb_timer_init(Object *obj)
@@ -210,21 +217,21 @@ static void cmsdk_apb_timer_init(Object *obj)
static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp)
{
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(dev);
- QEMUBH *bh;
if (s->pclk_frq == 0) {
error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
return;
}
- bh = qemu_bh_new(cmsdk_apb_timer_tick, s);
- s->timer = ptimer_init(bh,
+ s->timer = ptimer_init(cmsdk_apb_timer_tick, s,
PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+ ptimer_transaction_begin(s->timer);
ptimer_set_freq(s->timer, s->pclk_frq);
+ ptimer_transaction_commit(s->timer);
}
static const VMStateDescription cmsdk_apb_timer_vmstate = {
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
index 021c4ef714..32612228da 100644
--- a/hw/timer/digic-timer.c
+++ b/hw/timer/digic-timer.c
@@ -29,7 +29,6 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/ptimer.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/log.h"
@@ -52,7 +51,9 @@ static void digic_timer_reset(DeviceState *dev)
{
DigicTimerState *s = DIGIC_TIMER(dev);
+ ptimer_transaction_begin(s->ptimer);
ptimer_stop(s->ptimer);
+ ptimer_transaction_commit(s->ptimer);
s->control = 0;
s->relvalue = 0;
}
@@ -93,16 +94,20 @@ static void digic_timer_write(void *opaque, hwaddr offset,
break;
}
+ ptimer_transaction_begin(s->ptimer);
if (value & DIGIC_TIMER_CONTROL_EN) {
ptimer_run(s->ptimer, 0);
}
s->control = (uint32_t)value;
+ ptimer_transaction_commit(s->ptimer);
break;
case DIGIC_TIMER_RELVALUE:
s->relvalue = extract32(value, 0, 16);
+ ptimer_transaction_begin(s->ptimer);
ptimer_set_limit(s->ptimer, s->relvalue, 1);
+ ptimer_transaction_commit(s->ptimer);
break;
case DIGIC_TIMER_VALUE:
@@ -125,17 +130,24 @@ static const MemoryRegionOps digic_timer_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
+static void digic_timer_tick(void *opaque)
+{
+ /* Nothing to do on timer rollover */
+}
+
static void digic_timer_init(Object *obj)
{
DigicTimerState *s = DIGIC_TIMER(obj);
- s->ptimer = ptimer_init(NULL, PTIMER_POLICY_DEFAULT);
+ s->ptimer = ptimer_init(digic_timer_tick, NULL, PTIMER_POLICY_DEFAULT);
/*
* FIXME: there is no documentation on Digic timer
* frequency setup so let it always run at 1 MHz
*/
+ ptimer_transaction_begin(s->ptimer);
ptimer_set_freq(s->ptimer, 1 * 1000 * 1000);
+ ptimer_transaction_commit(s->ptimer);
memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s,
TYPE_DIGIC_TIMER, 0x100);
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
index d62025b879..ab27fe1895 100644
--- a/hw/timer/etraxfs_timer.c
+++ b/hw/timer/etraxfs_timer.c
@@ -328,9 +328,9 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp)
t->bh_t0 = qemu_bh_new(timer0_hit, t);
t->bh_t1 = qemu_bh_new(timer1_hit, t);
t->bh_wd = qemu_bh_new(watchdog_hit, t);
- t->ptimer_t0 = ptimer_init(t->bh_t0, PTIMER_POLICY_DEFAULT);
- t->ptimer_t1 = ptimer_init(t->bh_t1, PTIMER_POLICY_DEFAULT);
- t->ptimer_wd = ptimer_init(t->bh_wd, PTIMER_POLICY_DEFAULT);
+ t->ptimer_t0 = ptimer_init_with_bh(t->bh_t0, PTIMER_POLICY_DEFAULT);
+ t->ptimer_t1 = ptimer_init_with_bh(t->bh_t1, PTIMER_POLICY_DEFAULT);
+ t->ptimer_wd = ptimer_init_with_bh(t->bh_wd, PTIMER_POLICY_DEFAULT);
sysbus_init_irq(sbd, &t->irq);
sysbus_init_irq(sbd, &t->nmi);
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
index 77b9af05f4..7225758414 100644
--- a/hw/timer/exynos4210_mct.c
+++ b/hw/timer/exynos4210_mct.c
@@ -58,7 +58,6 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/timer.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/ptimer.h"
@@ -364,6 +363,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s);
/*
* Set counter of FRC global timer.
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
{
@@ -385,6 +385,7 @@ static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
/*
* Stop global FRC timer
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
{
@@ -395,6 +396,7 @@ static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
/*
* Start global FRC timer
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
{
@@ -404,6 +406,21 @@ static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
}
/*
+ * Start ptimer transaction for global FRC timer; this is just for
+ * consistency with the way we wrap operations like stop and run.
+ */
+static void exynos4210_gfrc_tx_begin(Exynos4210MCTGT *s)
+{
+ ptimer_transaction_begin(s->ptimer_frc);
+}
+
+/* Commit ptimer transaction for global FRC timer. */
+static void exynos4210_gfrc_tx_commit(Exynos4210MCTGT *s)
+{
+ ptimer_transaction_commit(s->ptimer_frc);
+}
+
+/*
* Find next nearest Comparator. If current Comparator value equals to other
* Comparator value, skip them both
*/
@@ -492,6 +509,7 @@ static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
/*
* Restart global FRC timer
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
{
@@ -589,6 +607,7 @@ static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
/*
* Set counter of FRC local timer.
+ * Must be called from within exynos4210_lfrc_tx_begin/commit block.
*/
static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
{
@@ -601,6 +620,7 @@ static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
/*
* Start local FRC timer
+ * Must be called from within exynos4210_lfrc_tx_begin/commit block.
*/
static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
{
@@ -609,12 +629,25 @@ static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
/*
* Stop local FRC timer
+ * Must be called from within exynos4210_lfrc_tx_begin/commit block.
*/
static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
{
ptimer_stop(s->ptimer_frc);
}
+/* Start ptimer transaction for local FRC timer */
+static void exynos4210_lfrc_tx_begin(Exynos4210MCTLT *s)
+{
+ ptimer_transaction_begin(s->ptimer_frc);
+}
+
+/* Commit ptimer transaction for local FRC timer */
+static void exynos4210_lfrc_tx_commit(Exynos4210MCTLT *s)
+{
+ ptimer_transaction_commit(s->ptimer_frc);
+}
+
/*
* Local timer free running counter tick handler
*/
@@ -701,6 +734,7 @@ static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
/*
* Start local tick cnt timer.
+ * Must be called within exynos4210_ltick_tx_begin/commit block.
*/
static void exynos4210_ltick_cnt_start(struct tick_timer *s)
{
@@ -716,6 +750,7 @@ static void exynos4210_ltick_cnt_start(struct tick_timer *s)
/*
* Stop local tick cnt timer.
+ * Must be called within exynos4210_ltick_tx_begin/commit block.
*/
static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
{
@@ -733,6 +768,18 @@ static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
}
}
+/* Start ptimer transaction for local tick timer */
+static void exynos4210_ltick_tx_begin(struct tick_timer *s)
+{
+ ptimer_transaction_begin(s->ptimer_tick);
+}
+
+/* Commit ptimer transaction for local tick timer */
+static void exynos4210_ltick_tx_commit(struct tick_timer *s)
+{
+ ptimer_transaction_commit(s->ptimer_tick);
+}
+
/*
* Get counter for CNT timer
*/
@@ -778,6 +825,7 @@ static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
/*
* Set new values of counters for CNT and INT timers
+ * Must be called within exynos4210_ltick_tx_begin/commit block.
*/
static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
uint32_t new_int)
@@ -851,7 +899,9 @@ static void exynos4210_ltick_recalc_count(struct tick_timer *s)
static void exynos4210_ltick_timer_init(struct tick_timer *s)
{
exynos4210_ltick_int_stop(s);
+ exynos4210_ltick_tx_begin(s);
exynos4210_ltick_cnt_stop(s);
+ exynos4210_ltick_tx_commit(s);
s->count = 0;
s->distance = 0;
@@ -933,6 +983,19 @@ static void exynos4210_ltick_event(void *opaque)
exynos4210_ltick_int_start(&s->tick_timer);
}
+static void tx_ptimer_set_freq(ptimer_state *s, uint32_t freq)
+{
+ /*
+ * callers of exynos4210_mct_update_freq() never do anything
+ * else that needs to be in the same ptimer transaction, so
+ * to avoid a lot of repetition we have a convenience function
+ * for begin/set_freq/commit.
+ */
+ ptimer_transaction_begin(s);
+ ptimer_set_freq(s, freq);
+ ptimer_transaction_commit(s);
+}
+
/* update timer frequency */
static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
{
@@ -945,13 +1008,13 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
DPRINTF("freq=%dHz\n", s->freq);
/* global timer */
- ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
+ tx_ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
/* local timer */
- ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
- ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
- ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
- ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
+ tx_ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
+ tx_ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
+ tx_ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
+ tx_ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
}
}
@@ -965,7 +1028,9 @@ static void exynos4210_mct_reset(DeviceState *d)
/* global timer */
memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
+ exynos4210_gfrc_tx_begin(&s->g_timer);
exynos4210_gfrc_stop(&s->g_timer);
+ exynos4210_gfrc_tx_commit(&s->g_timer);
/* local timer */
memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
@@ -978,7 +1043,9 @@ static void exynos4210_mct_reset(DeviceState *d)
s->l_timer[i].tick_timer.count = 0;
s->l_timer[i].tick_timer.distance = 0;
s->l_timer[i].tick_timer.progress = 0;
+ exynos4210_lfrc_tx_begin(&s->l_timer[i]);
ptimer_stop(s->l_timer[i].ptimer_frc);
+ exynos4210_lfrc_tx_commit(&s->l_timer[i]);
exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
}
@@ -1144,7 +1211,9 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
}
s->g_timer.reg.cnt = new_frc;
+ exynos4210_gfrc_tx_begin(&s->g_timer);
exynos4210_gfrc_restart(s);
+ exynos4210_gfrc_tx_commit(&s->g_timer);
break;
case G_CNT_WSTAT:
@@ -1168,7 +1237,9 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
}
+ exynos4210_gfrc_tx_begin(&s->g_timer);
exynos4210_gfrc_restart(s);
+ exynos4210_gfrc_tx_commit(&s->g_timer);
break;
case G_TCON:
@@ -1178,6 +1249,8 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
DPRINTF("global timer write to reg.g_tcon %llx\n", value);
+ exynos4210_gfrc_tx_begin(&s->g_timer);
+
/* Start FRC if transition from disabled to enabled */
if ((value & G_TCON_TIMER_ENABLE) > (old_val &
G_TCON_TIMER_ENABLE)) {
@@ -1195,6 +1268,8 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
exynos4210_gfrc_restart(s);
}
}
+
+ exynos4210_gfrc_tx_commit(&s->g_timer);
break;
case G_INT_CSTAT:
@@ -1245,6 +1320,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
s->l_timer[lt_i].reg.tcon = value;
+ exynos4210_ltick_tx_begin(&s->l_timer[lt_i].tick_timer);
/* Stop local CNT */
if ((value & L_TCON_TICK_START) <
(old_val & L_TCON_TICK_START)) {
@@ -1272,8 +1348,10 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
DPRINTF("local timer[%d] start int\n", lt_i);
exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
}
+ exynos4210_ltick_tx_commit(&s->l_timer[lt_i].tick_timer);
/* Start or Stop local FRC if TCON changed */
+ exynos4210_lfrc_tx_begin(&s->l_timer[lt_i]);
if ((value & L_TCON_FRC_START) >
(s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
DPRINTF("local timer[%d] start frc\n", lt_i);
@@ -1284,6 +1362,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
DPRINTF("local timer[%d] stop frc\n", lt_i);
exynos4210_lfrc_stop(&s->l_timer[lt_i]);
}
+ exynos4210_lfrc_tx_commit(&s->l_timer[lt_i]);
break;
case L0_TCNTB: case L1_TCNTB:
@@ -1295,8 +1374,10 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
* Due to this we should reload timer to nearest moment when CNT is
* expired and then in event handler update tcntb to new TCNTB value.
*/
+ exynos4210_ltick_tx_begin(&s->l_timer[lt_i].tick_timer);
exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
s->l_timer[lt_i].tick_timer.icntb);
+ exynos4210_ltick_tx_commit(&s->l_timer[lt_i].tick_timer);
s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
@@ -1425,20 +1506,20 @@ static void exynos4210_mct_init(Object *obj)
int i;
Exynos4210MCTState *s = EXYNOS4210_MCT(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- QEMUBH *bh[2];
/* Global timer */
- bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
- s->g_timer.ptimer_frc = ptimer_init(bh[0], PTIMER_POLICY_DEFAULT);
+ s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s,
+ PTIMER_POLICY_DEFAULT);
memset(&s->g_timer.reg, 0, sizeof(struct gregs));
/* Local timers */
for (i = 0; i < 2; i++) {
- bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
- bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
s->l_timer[i].tick_timer.ptimer_tick =
- ptimer_init(bh[0], PTIMER_POLICY_DEFAULT);
- s->l_timer[i].ptimer_frc = ptimer_init(bh[1], PTIMER_POLICY_DEFAULT);
+ ptimer_init(exynos4210_ltick_event, &s->l_timer[i],
+ PTIMER_POLICY_DEFAULT);
+ s->l_timer[i].ptimer_frc =
+ ptimer_init(exynos4210_lfrc_event, &s->l_timer[i],
+ PTIMER_POLICY_DEFAULT);
s->l_timer[i].id = i;
}
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
index b7fad2ad44..59a8c08db0 100644
--- a/hw/timer/exynos4210_pwm.c
+++ b/hw/timer/exynos4210_pwm.c
@@ -25,7 +25,6 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/timer.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/ptimer.h"
@@ -150,7 +149,9 @@ static const VMStateDescription vmstate_exynos4210_pwm_state = {
};
/*
- * PWM update frequency
+ * PWM update frequency.
+ * Must be called within a ptimer_transaction_begin/commit block
+ * for s->timer[id].ptimer.
*/
static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id)
{
@@ -281,12 +282,15 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset,
/* update timers frequencies */
for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+ ptimer_transaction_begin(s->timer[i].ptimer);
exynos4210_pwm_update_freq(s, s->timer[i].id);
+ ptimer_transaction_commit(s->timer[i].ptimer);
}
break;
case TCON:
for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+ ptimer_transaction_begin(s->timer[i].ptimer);
if ((value & TCON_TIMER_MANUAL_UPD(i)) >
(s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) {
/*
@@ -315,6 +319,7 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset,
ptimer_stop(s->timer[i].ptimer);
DPRINTF("stop timer %d\n", i);
}
+ ptimer_transaction_commit(s->timer[i].ptimer);
}
s->reg_tcon = value;
break;
@@ -369,8 +374,10 @@ static void exynos4210_pwm_reset(DeviceState *d)
s->timer[i].reg_tcmpb = 0;
s->timer[i].reg_tcntb = 0;
+ ptimer_transaction_begin(s->timer[i].ptimer);
exynos4210_pwm_update_freq(s, s->timer[i].id);
ptimer_stop(s->timer[i].ptimer);
+ ptimer_transaction_commit(s->timer[i].ptimer);
}
}
@@ -388,12 +395,12 @@ static void exynos4210_pwm_init(Object *obj)
Exynos4210PWMState *s = EXYNOS4210_PWM(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
int i;
- QEMUBH *bh;
for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]);
sysbus_init_irq(dev, &s->timer[i].irq);
- s->timer[i].ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer[i].ptimer = ptimer_init(exynos4210_pwm_tick,
+ &s->timer[i],
+ PTIMER_POLICY_DEFAULT);
s->timer[i].id = i;
s->timer[i].parent = s;
}
diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c
index ea68904229..f85483a07f 100644
--- a/hw/timer/exynos4210_rtc.c
+++ b/hw/timer/exynos4210_rtc.c
@@ -28,7 +28,6 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
@@ -195,6 +194,7 @@ static void check_alarm_raise(Exynos4210RTCState *s)
* RTC update frequency
* Parameters:
* reg_value - current RTCCON register or his new value
+ * Must be called within a ptimer_transaction_begin/commit block for s->ptimer.
*/
static void exynos4210_rtc_update_freq(Exynos4210RTCState *s,
uint32_t reg_value)
@@ -401,6 +401,8 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset,
}
break;
case RTCCON:
+ ptimer_transaction_begin(s->ptimer_1Hz);
+ ptimer_transaction_begin(s->ptimer);
if (value & RTC_ENABLE) {
exynos4210_rtc_update_freq(s, value);
}
@@ -430,6 +432,8 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset,
ptimer_stop(s->ptimer);
}
}
+ ptimer_transaction_commit(s->ptimer_1Hz);
+ ptimer_transaction_commit(s->ptimer);
s->reg_rtccon = value;
break;
case TICCNT:
@@ -537,9 +541,13 @@ static void exynos4210_rtc_reset(DeviceState *d)
s->reg_curticcnt = 0;
+ ptimer_transaction_begin(s->ptimer);
exynos4210_rtc_update_freq(s, s->reg_rtccon);
ptimer_stop(s->ptimer);
+ ptimer_transaction_commit(s->ptimer);
+ ptimer_transaction_begin(s->ptimer_1Hz);
ptimer_stop(s->ptimer_1Hz);
+ ptimer_transaction_commit(s->ptimer_1Hz);
}
static const MemoryRegionOps exynos4210_rtc_ops = {
@@ -555,16 +563,18 @@ static void exynos4210_rtc_init(Object *obj)
{
Exynos4210RTCState *s = EXYNOS4210_RTC(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- QEMUBH *bh;
- bh = qemu_bh_new(exynos4210_rtc_tick, s);
- s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->ptimer = ptimer_init(exynos4210_rtc_tick, s, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(s->ptimer);
ptimer_set_freq(s->ptimer, RTC_BASE_FREQ);
exynos4210_rtc_update_freq(s, 0);
+ ptimer_transaction_commit(s->ptimer);
- bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
- s->ptimer_1Hz = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->ptimer_1Hz = ptimer_init(exynos4210_rtc_1Hz_tick,
+ s, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(s->ptimer_1Hz);
ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
+ ptimer_transaction_commit(s->ptimer_1Hz);
sysbus_init_irq(dev, &s->alm_irq);
sysbus_init_irq(dev, &s->tick_irq);
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index 32dbf870d4..bb09268ea1 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -366,7 +366,7 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
timer->unit = unit;
timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
- timer->ptimer = ptimer_init(timer->bh, PTIMER_POLICY_DEFAULT);
+ timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT);
timer->id = i;
/* One IRQ line for each timer */
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index f54e059910..baf6338e1a 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -17,7 +17,6 @@
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "hw/misc/imx_ccm.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/log.h"
@@ -74,6 +73,10 @@ static void imx_epit_update_int(IMXEPITState *s)
}
}
+/*
+ * Must be called from within a ptimer_transaction_begin/commit block
+ * for both s->timer_cmp and s->timer_reload.
+ */
static void imx_epit_set_freq(IMXEPITState *s)
{
uint32_t clksrc;
@@ -105,6 +108,8 @@ static void imx_epit_reset(DeviceState *dev)
s->lr = EPIT_TIMER_MAX;
s->cmp = 0;
s->cnt = 0;
+ ptimer_transaction_begin(s->timer_cmp);
+ ptimer_transaction_begin(s->timer_reload);
/* stop both timers */
ptimer_stop(s->timer_cmp);
ptimer_stop(s->timer_reload);
@@ -117,6 +122,8 @@ static void imx_epit_reset(DeviceState *dev)
/* if the timer is still enabled, restart it */
ptimer_run(s->timer_reload, 0);
}
+ ptimer_transaction_commit(s->timer_cmp);
+ ptimer_transaction_commit(s->timer_reload);
}
static uint32_t imx_epit_update_count(IMXEPITState *s)
@@ -164,6 +171,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
return reg_value;
}
+/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */
static void imx_epit_reload_compare_timer(IMXEPITState *s)
{
if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) {
@@ -191,6 +199,8 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset >> 2) {
case 0: /* CR */
+ ptimer_transaction_begin(s->timer_cmp);
+ ptimer_transaction_begin(s->timer_reload);
oldcr = s->cr;
s->cr = value & 0x03ffffff;
@@ -231,6 +241,9 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
} else {
ptimer_stop(s->timer_cmp);
}
+
+ ptimer_transaction_commit(s->timer_cmp);
+ ptimer_transaction_commit(s->timer_reload);
break;
case 1: /* SR - ACK*/
@@ -244,6 +257,8 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
case 2: /* LR - set ticks */
s->lr = value;
+ ptimer_transaction_begin(s->timer_cmp);
+ ptimer_transaction_begin(s->timer_reload);
if (s->cr & CR_RLD) {
/* Also set the limit if the LRD bit is set */
/* If IOVW bit is set then set the timer value */
@@ -255,12 +270,16 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
}
imx_epit_reload_compare_timer(s);
+ ptimer_transaction_commit(s->timer_cmp);
+ ptimer_transaction_commit(s->timer_reload);
break;
case 3: /* CMP */
s->cmp = value;
+ ptimer_transaction_begin(s->timer_cmp);
imx_epit_reload_compare_timer(s);
+ ptimer_transaction_commit(s->timer_cmp);
break;
@@ -281,6 +300,11 @@ static void imx_epit_cmp(void *opaque)
imx_epit_update_int(s);
}
+static void imx_epit_reload(void *opaque)
+{
+ /* No action required on rollover of timer_reload */
+}
+
static const MemoryRegionOps imx_epit_ops = {
.read = imx_epit_read,
.write = imx_epit_write,
@@ -308,7 +332,6 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
{
IMXEPITState *s = IMX_EPIT(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- QEMUBH *bh;
DPRINTF("\n");
@@ -317,10 +340,9 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
0x00001000);
sysbus_init_mmio(sbd, &s->iomem);
- s->timer_reload = ptimer_init(NULL, PTIMER_POLICY_DEFAULT);
+ s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_DEFAULT);
- bh = qemu_bh_new(imx_epit_cmp, s);
- s->timer_cmp = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_DEFAULT);
}
static void imx_epit_class_init(ObjectClass *klass, void *data)
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 49a441f451..5c0d9a269c 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -16,7 +16,6 @@
#include "hw/irq.h"
#include "hw/timer/imx_gpt.h"
#include "migration/vmstate.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/log.h"
@@ -127,6 +126,7 @@ static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 111 not defined */
};
+/* Must be called from within ptimer_transaction_begin/commit block */
static void imx_gpt_set_freq(IMXGPTState *s)
{
uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3);
@@ -167,6 +167,7 @@ static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg,
return timeout;
}
+/* Must be called from within ptimer_transaction_begin/commit block */
static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
{
uint32_t timeout = GPT_TIMER_MAX;
@@ -313,6 +314,7 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size)
static void imx_gpt_reset_common(IMXGPTState *s, bool is_soft_reset)
{
+ ptimer_transaction_begin(s->timer);
/* stop timer */
ptimer_stop(s->timer);
@@ -350,6 +352,7 @@ static void imx_gpt_reset_common(IMXGPTState *s, bool is_soft_reset)
if (s->freq && (s->cr & GPT_CR_EN)) {
ptimer_run(s->timer, 1);
}
+ ptimer_transaction_commit(s->timer);
}
static void imx_gpt_soft_reset(DeviceState *dev)
@@ -382,6 +385,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
imx_gpt_soft_reset(DEVICE(s));
} else {
/* set our freq, as the source might have changed */
+ ptimer_transaction_begin(s->timer);
imx_gpt_set_freq(s);
if ((oldreg ^ s->cr) & GPT_CR_EN) {
@@ -397,12 +401,15 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
ptimer_stop(s->timer);
}
}
+ ptimer_transaction_commit(s->timer);
}
break;
case 1: /* Prescaler */
s->pr = value & 0xfff;
+ ptimer_transaction_begin(s->timer);
imx_gpt_set_freq(s);
+ ptimer_transaction_commit(s->timer);
break;
case 2: /* SR */
@@ -414,13 +421,16 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
s->ir = value & 0x3f;
imx_gpt_update_int(s);
+ ptimer_transaction_begin(s->timer);
imx_gpt_compute_next_timeout(s, false);
+ ptimer_transaction_commit(s->timer);
break;
case 4: /* OCR1 -- output compare register */
s->ocr1 = value;
+ ptimer_transaction_begin(s->timer);
/* In non-freerun mode, reset count when this register is written */
if (!(s->cr & GPT_CR_FRR)) {
s->next_timeout = GPT_TIMER_MAX;
@@ -429,6 +439,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
/* compute the new timeout */
imx_gpt_compute_next_timeout(s, false);
+ ptimer_transaction_commit(s->timer);
break;
@@ -436,7 +447,9 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
s->ocr2 = value;
/* compute the new timeout */
+ ptimer_transaction_begin(s->timer);
imx_gpt_compute_next_timeout(s, false);
+ ptimer_transaction_commit(s->timer);
break;
@@ -444,7 +457,9 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
s->ocr3 = value;
/* compute the new timeout */
+ ptimer_transaction_begin(s->timer);
imx_gpt_compute_next_timeout(s, false);
+ ptimer_transaction_commit(s->timer);
break;
@@ -484,15 +499,13 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp)
{
IMXGPTState *s = IMX_GPT(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- QEMUBH *bh;
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT,
0x00001000);
sysbus_init_mmio(sbd, &s->iomem);
- bh = qemu_bh_new(imx_gpt_timeout, s);
- s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_DEFAULT);
}
static void imx_gpt_class_init(ObjectClass *klass, void *data)
diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c
index cf316edb7f..fabde760b2 100644
--- a/hw/timer/lm32_timer.c
+++ b/hw/timer/lm32_timer.c
@@ -196,7 +196,7 @@ static void lm32_timer_realize(DeviceState *dev, Error **errp)
LM32TimerState *s = LM32_TIMER(dev);
s->bh = qemu_bh_new(timer_hit, s);
- s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT);
+ s->ptimer = ptimer_init_with_bh(s->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(s->ptimer, s->freq_hz);
}
diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c
index 6aedc11bef..5193c03850 100644
--- a/hw/timer/milkymist-sysctl.c
+++ b/hw/timer/milkymist-sysctl.c
@@ -294,8 +294,8 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp)
s->bh0 = qemu_bh_new(timer0_hit, s);
s->bh1 = qemu_bh_new(timer1_hit, s);
- s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT);
- s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT);
+ s->ptimer0 = ptimer_init_with_bh(s->bh0, PTIMER_POLICY_DEFAULT);
+ s->ptimer1 = ptimer_init_with_bh(s->bh1, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(s->ptimer0, s->freq_hz);
ptimer_set_freq(s->ptimer1, s->freq_hz);
diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c
index 45f1cf42f9..b1c9a80501 100644
--- a/hw/timer/mss-timer.c
+++ b/hw/timer/mss-timer.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/log.h"
#include "hw/irq.h"
@@ -67,6 +66,7 @@ static void timer_update_irq(struct Msf2Timer *st)
qemu_set_irq(st->irq, (ier && isr));
}
+/* Must be called from within a ptimer_transaction_begin/commit block */
static void timer_update(struct Msf2Timer *st)
{
uint64_t count;
@@ -159,7 +159,9 @@ timer_write(void *opaque, hwaddr offset,
switch (addr) {
case R_TIM_CTRL:
st->regs[R_TIM_CTRL] = value;
+ ptimer_transaction_begin(st->ptimer);
timer_update(st);
+ ptimer_transaction_commit(st->ptimer);
break;
case R_TIM_RIS:
@@ -171,7 +173,9 @@ timer_write(void *opaque, hwaddr offset,
case R_TIM_LOADVAL:
st->regs[R_TIM_LOADVAL] = value;
if (st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL) {
+ ptimer_transaction_begin(st->ptimer);
timer_update(st);
+ ptimer_transaction_commit(st->ptimer);
}
break;
@@ -228,9 +232,10 @@ static void mss_timer_init(Object *obj)
for (i = 0; i < NUM_TIMERS; i++) {
struct Msf2Timer *st = &t->timers[i];
- st->bh = qemu_bh_new(timer_hit, st);
- st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
+ st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(st->ptimer);
ptimer_set_freq(st->ptimer, t->freq_hz);
+ ptimer_transaction_commit(st->ptimer);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &st->irq);
}
diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c
index 6fe370049b..0898da5ce9 100644
--- a/hw/timer/puv3_ost.c
+++ b/hw/timer/puv3_ost.c
@@ -129,7 +129,7 @@ static void puv3_ost_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq);
s->bh = qemu_bh_new(puv3_ost_tick, s);
- s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT);
+ s->ptimer = ptimer_init_with_bh(s->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost",
diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c
index adcc0c138e..48a81b4dc7 100644
--- a/hw/timer/sh_timer.c
+++ b/hw/timer/sh_timer.c
@@ -204,7 +204,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
s->irq = irq;
bh = qemu_bh_new(sh_timer_tick, s);
- s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index 38fd32b62a..692d213897 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -393,7 +393,7 @@ static void slavio_timer_init(Object *obj)
tc->timer_index = i;
bh = qemu_bh_new(slavio_timer_irq, tc);
- s->cputimer[i].timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c
index 355518232c..92dbff304d 100644
--- a/hw/timer/xilinx_timer.c
+++ b/hw/timer/xilinx_timer.c
@@ -221,7 +221,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp)
xt->parent = t;
xt->nr = i;
xt->bh = qemu_bh_new(timer_hit, xt);
- xt->ptimer = ptimer_init(xt->bh, PTIMER_POLICY_DEFAULT);
+ xt->ptimer = ptimer_init_with_bh(xt->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(xt->ptimer, t->freq_hz);
}
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
index 6bf43f943f..e6f3b93c44 100644
--- a/hw/watchdog/cmsdk-apb-watchdog.c
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
@@ -24,7 +24,6 @@
#include "qemu/log.h"
#include "trace.h"
#include "qapi/error.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "sysemu/watchdog.h"
#include "hw/sysbus.h"
@@ -200,8 +199,10 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
* Reset the load value and the current count, and make sure
* we're counting.
*/
+ ptimer_transaction_begin(s->timer);
ptimer_set_limit(s->timer, value, 1);
ptimer_run(s->timer, 0);
+ ptimer_transaction_commit(s->timer);
break;
case A_WDOGCONTROL:
if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
@@ -217,7 +218,9 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
break;
case A_WDOGINTCLR:
s->intstatus = 0;
+ ptimer_transaction_begin(s->timer);
ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
+ ptimer_transaction_commit(s->timer);
cmsdk_apb_watchdog_update(s);
break;
case A_WDOGLOCK:
@@ -299,8 +302,10 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
s->itop = 0;
s->resetstatus = 0;
/* Set the limit and the count */
+ ptimer_transaction_begin(s->timer);
ptimer_set_limit(s->timer, 0xffffffff, 1);
ptimer_run(s->timer, 0);
+ ptimer_transaction_commit(s->timer);
}
static void cmsdk_apb_watchdog_init(Object *obj)
@@ -320,7 +325,6 @@ static void cmsdk_apb_watchdog_init(Object *obj)
static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
{
CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
- QEMUBH *bh;
if (s->wdogclk_frq == 0) {
error_setg(errp,
@@ -328,14 +332,15 @@ static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
return;
}
- bh = qemu_bh_new(cmsdk_apb_watchdog_tick, s);
- s->timer = ptimer_init(bh,
+ s->timer = ptimer_init(cmsdk_apb_watchdog_tick, s,
PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+ ptimer_transaction_begin(s->timer);
ptimer_set_freq(s->timer, s->wdogclk_frq);
+ ptimer_transaction_commit(s->timer);
}
static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
index 9b93213417..145be6f99c 100644
--- a/hw/watchdog/wdt_aspeed.c
+++ b/hw/watchdog/wdt_aspeed.c
@@ -40,12 +40,14 @@
#define WDT_DRIVE_TYPE_MASK (0xFF << 24)
#define WDT_PUSH_PULL_MAGIC (0xA8 << 24)
#define WDT_OPEN_DRAIN_MAGIC (0x8A << 24)
+#define WDT_RESET_MASK1 (0x1c / 4)
#define WDT_TIMEOUT_STATUS (0x10 / 4)
#define WDT_TIMEOUT_CLEAR (0x14 / 4)
#define WDT_RESTART_MAGIC 0x4755
+#define AST2600_SCU_RESET_CONTROL1 (0x40 / 4)
#define SCU_RESET_CONTROL1 (0x04 / 4)
#define SCU_RESET_SDRAM BIT(0)
@@ -54,21 +56,6 @@ static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
}
-static bool is_ast2500(const AspeedWDTState *s)
-{
- switch (s->silicon_rev) {
- case AST2500_A0_SILICON_REV:
- case AST2500_A1_SILICON_REV:
- return true;
- case AST2400_A0_SILICON_REV:
- case AST2400_A1_SILICON_REV:
- default:
- break;
- }
-
- return false;
-}
-
static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedWDTState *s = ASPEED_WDT(opaque);
@@ -89,6 +76,8 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
return s->regs[WDT_CTRL];
case WDT_RESET_WIDTH:
return s->regs[WDT_RESET_WIDTH];
+ case WDT_RESET_MASK1:
+ return s->regs[WDT_RESET_MASK1];
case WDT_TIMEOUT_STATUS:
case WDT_TIMEOUT_CLEAR:
qemu_log_mask(LOG_UNIMP,
@@ -124,6 +113,7 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
AspeedWDTState *s = ASPEED_WDT(opaque);
+ AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s);
bool enable = data & WDT_CTRL_ENABLE;
offset >>= 2;
@@ -140,7 +130,7 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
case WDT_RESTART:
if ((data & 0xFFFF) == WDT_RESTART_MAGIC) {
s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE];
- aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
+ aspeed_wdt_reload(s, !(s->regs[WDT_CTRL] & WDT_CTRL_1MHZ_CLK));
}
break;
case WDT_CTRL:
@@ -153,24 +143,18 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
}
break;
case WDT_RESET_WIDTH:
- {
- uint32_t property = data & WDT_POLARITY_MASK;
-
- if (property && is_ast2500(s)) {
- if (property == WDT_ACTIVE_HIGH_MAGIC) {
- s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH;
- } else if (property == WDT_ACTIVE_LOW_MAGIC) {
- s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH;
- } else if (property == WDT_PUSH_PULL_MAGIC) {
- s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL;
- } else if (property == WDT_OPEN_DRAIN_MAGIC) {
- s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL;
- }
+ if (awc->reset_pulse) {
+ awc->reset_pulse(s, data & WDT_POLARITY_MASK);
}
- s->regs[WDT_RESET_WIDTH] &= ~s->ext_pulse_width_mask;
- s->regs[WDT_RESET_WIDTH] |= data & s->ext_pulse_width_mask;
+ s->regs[WDT_RESET_WIDTH] &= ~awc->ext_pulse_width_mask;
+ s->regs[WDT_RESET_WIDTH] |= data & awc->ext_pulse_width_mask;
break;
- }
+
+ case WDT_RESET_MASK1:
+ /* TODO: implement */
+ s->regs[WDT_RESET_MASK1] = data;
+ break;
+
case WDT_TIMEOUT_STATUS:
case WDT_TIMEOUT_CLEAR:
qemu_log_mask(LOG_UNIMP,
@@ -226,9 +210,10 @@ static void aspeed_wdt_reset(DeviceState *dev)
static void aspeed_wdt_timer_expired(void *dev)
{
AspeedWDTState *s = ASPEED_WDT(dev);
+ uint32_t reset_ctrl_reg = ASPEED_WDT_GET_CLASS(s)->reset_ctrl_reg;
/* Do not reset on SDRAM controller reset */
- if (s->scu->regs[SCU_RESET_CONTROL1] & SCU_RESET_SDRAM) {
+ if (s->scu->regs[reset_ctrl_reg] & SCU_RESET_SDRAM) {
timer_del(s->timer);
s->regs[WDT_CTRL] = 0;
return;
@@ -256,25 +241,6 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
}
s->scu = ASPEED_SCU(obj);
- if (!is_supported_silicon_rev(s->silicon_rev)) {
- error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
- s->silicon_rev);
- return;
- }
-
- switch (s->silicon_rev) {
- case AST2400_A0_SILICON_REV:
- case AST2400_A1_SILICON_REV:
- s->ext_pulse_width_mask = 0xff;
- break;
- case AST2500_A0_SILICON_REV:
- case AST2500_A1_SILICON_REV:
- s->ext_pulse_width_mask = 0xfffff;
- break;
- default:
- g_assert_not_reached();
- }
-
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
/* FIXME: This setting should be derived from the SCU hw strapping
@@ -287,20 +253,15 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property aspeed_wdt_properties[] = {
- DEFINE_PROP_UINT32("silicon-rev", AspeedWDTState, silicon_rev, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->desc = "ASPEED Watchdog Controller";
dc->realize = aspeed_wdt_realize;
dc->reset = aspeed_wdt_reset;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->vmsd = &vmstate_aspeed_wdt;
- dc->props = aspeed_wdt_properties;
}
static const TypeInfo aspeed_wdt_info = {
@@ -308,12 +269,88 @@ static const TypeInfo aspeed_wdt_info = {
.name = TYPE_ASPEED_WDT,
.instance_size = sizeof(AspeedWDTState),
.class_init = aspeed_wdt_class_init,
+ .class_size = sizeof(AspeedWDTClass),
+ .abstract = true,
+};
+
+static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 Watchdog Controller";
+ awc->offset = 0x20;
+ awc->ext_pulse_width_mask = 0xff;
+ awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
+}
+
+static const TypeInfo aspeed_2400_wdt_info = {
+ .name = TYPE_ASPEED_2400_WDT,
+ .parent = TYPE_ASPEED_WDT,
+ .instance_size = sizeof(AspeedWDTState),
+ .class_init = aspeed_2400_wdt_class_init,
+};
+
+static void aspeed_2500_wdt_reset_pulse(AspeedWDTState *s, uint32_t property)
+{
+ if (property) {
+ if (property == WDT_ACTIVE_HIGH_MAGIC) {
+ s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH;
+ } else if (property == WDT_ACTIVE_LOW_MAGIC) {
+ s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH;
+ } else if (property == WDT_PUSH_PULL_MAGIC) {
+ s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL;
+ } else if (property == WDT_OPEN_DRAIN_MAGIC) {
+ s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL;
+ }
+ }
+}
+
+static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 Watchdog Controller";
+ awc->offset = 0x20;
+ awc->ext_pulse_width_mask = 0xfffff;
+ awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
+ awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
+}
+
+static const TypeInfo aspeed_2500_wdt_info = {
+ .name = TYPE_ASPEED_2500_WDT,
+ .parent = TYPE_ASPEED_WDT,
+ .instance_size = sizeof(AspeedWDTState),
+ .class_init = aspeed_2500_wdt_class_init,
+};
+
+static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 Watchdog Controller";
+ awc->offset = 0x40;
+ awc->ext_pulse_width_mask = 0xfffff; /* TODO */
+ awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1;
+ awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
+}
+
+static const TypeInfo aspeed_2600_wdt_info = {
+ .name = TYPE_ASPEED_2600_WDT,
+ .parent = TYPE_ASPEED_WDT,
+ .instance_size = sizeof(AspeedWDTState),
+ .class_init = aspeed_2600_wdt_class_init,
};
static void wdt_aspeed_register_types(void)
{
watchdog_add_model(&model);
type_register_static(&aspeed_wdt_info);
+ type_register_static(&aspeed_2400_wdt_info);
+ type_register_static(&aspeed_2500_wdt_info);
+ type_register_static(&aspeed_2600_wdt_info);
}
type_init(wdt_aspeed_register_types)
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index ab5052b12c..cccb684a19 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -12,6 +12,7 @@
#ifndef ASPEED_SOC_H
#define ASPEED_SOC_H
+#include "hw/cpu/a15mpcore.h"
#include "hw/intc/aspeed_vic.h"
#include "hw/misc/aspeed_scu.h"
#include "hw/misc/aspeed_sdmc.h"
@@ -24,11 +25,12 @@
#include "hw/net/ftgmac100.h"
#include "target/arm/cpu.h"
#include "hw/gpio/aspeed_gpio.h"
+#include "hw/sd/aspeed_sdhci.h"
#define ASPEED_SPIS_NUM 2
-#define ASPEED_WDTS_NUM 3
+#define ASPEED_WDTS_NUM 4
#define ASPEED_CPUS_NUM 2
-#define ASPEED_MACS_NUM 2
+#define ASPEED_MACS_NUM 4
typedef struct AspeedSoCState {
/*< private >*/
@@ -37,6 +39,7 @@ typedef struct AspeedSoCState {
/*< public >*/
ARMCPU cpu[ASPEED_CPUS_NUM];
uint32_t num_cpus;
+ A15MPPrivState a7mpcore;
MemoryRegion sram;
AspeedVICState vic;
AspeedRtcState rtc;
@@ -49,27 +52,28 @@ typedef struct AspeedSoCState {
AspeedSDMCState sdmc;
AspeedWDTState wdt[ASPEED_WDTS_NUM];
FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
+ AspeedMiiState mii[ASPEED_MACS_NUM];
AspeedGPIOState gpio;
+ AspeedGPIOState gpio_1_8v;
+ AspeedSDHCIState sdhci;
} AspeedSoCState;
#define TYPE_ASPEED_SOC "aspeed-soc"
#define ASPEED_SOC(obj) OBJECT_CHECK(AspeedSoCState, (obj), TYPE_ASPEED_SOC)
-typedef struct AspeedSoCInfo {
+typedef struct AspeedSoCClass {
+ DeviceClass parent_class;
+
const char *name;
const char *cpu_type;
uint32_t silicon_rev;
uint64_t sram_size;
int spis_num;
int wdts_num;
+ int macs_num;
const int *irqmap;
const hwaddr *memmap;
uint32_t num_cpus;
-} AspeedSoCInfo;
-
-typedef struct AspeedSoCClass {
- DeviceClass parent_class;
- AspeedSoCInfo *info;
} AspeedSoCClass;
#define ASPEED_SOC_CLASS(klass) \
@@ -92,8 +96,11 @@ enum {
ASPEED_SDMC,
ASPEED_SCU,
ASPEED_ADC,
+ ASPEED_VIDEO,
ASPEED_SRAM,
+ ASPEED_SDHCI,
ASPEED_GPIO,
+ ASPEED_GPIO_1_8V,
ASPEED_RTC,
ASPEED_TIMER1,
ASPEED_TIMER2,
@@ -110,6 +117,12 @@ enum {
ASPEED_I2C,
ASPEED_ETH1,
ASPEED_ETH2,
+ ASPEED_ETH3,
+ ASPEED_ETH4,
+ ASPEED_MII1,
+ ASPEED_MII2,
+ ASPEED_MII3,
+ ASPEED_MII4,
ASPEED_SDRAM,
ASPEED_XDMA,
};
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index 6b17f6a382..62a4c7b559 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -23,6 +23,7 @@
#include "hw/sd/sdhci.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "hw/gpio/bcm2835_gpio.h"
+#include "hw/misc/unimp.h"
#define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals"
#define BCM2835_PERIPHERALS(obj) \
@@ -37,6 +38,10 @@ typedef struct BCM2835PeripheralState {
MemoryRegion ram_alias[4];
qemu_irq irq, fiq;
+ UnimplementedDeviceState systmr;
+ UnimplementedDeviceState armtmr;
+ UnimplementedDeviceState cprman;
+ UnimplementedDeviceState a2w;
PL011State uart0;
BCM2835AuxState aux;
BCM2835FBState fb;
@@ -48,6 +53,16 @@ typedef struct BCM2835PeripheralState {
SDHCIState sdhci;
BCM2835SDHostState sdhost;
BCM2835GpioState gpio;
+ UnimplementedDeviceState i2s;
+ UnimplementedDeviceState spi[1];
+ UnimplementedDeviceState i2c[3];
+ UnimplementedDeviceState otp;
+ UnimplementedDeviceState dbus;
+ UnimplementedDeviceState ave0;
+ UnimplementedDeviceState bscsl;
+ UnimplementedDeviceState smi;
+ UnimplementedDeviceState dwc2;
+ UnimplementedDeviceState sdramc;
} BCM2835PeripheralState;
#endif /* BCM2835_PERIPHERALS_H */
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
index 10083d33df..cdcbca943f 100644
--- a/include/hw/arm/raspi_platform.h
+++ b/include/hw/arm/raspi_platform.h
@@ -25,8 +25,7 @@
#ifndef HW_ARM_RASPI_PLATFORM_H
#define HW_ARM_RASPI_PLATFORM_H
-#define MCORE_OFFSET 0x0000 /* Fake frame buffer device
- * (the multicore sync block) */
+#define MSYNC_OFFSET 0x0000 /* Multicore Sync Block */
#define IC0_OFFSET 0x2000
#define ST_OFFSET 0x3000 /* System Timer */
#define MPHI_OFFSET 0x6000 /* Message-based Parallel Host Intf. */
@@ -37,9 +36,10 @@
#define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 */
#define ARMCTRL_0_SBM_OFFSET (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores
* Doorbells & Mailboxes */
-#define PM_OFFSET 0x100000 /* Power Management, Reset controller
- * and Watchdog registers */
-#define PCM_CLOCK_OFFSET 0x101098
+#define CPRMAN_OFFSET 0x100000 /* Power Management, Watchdog */
+#define CM_OFFSET 0x101000 /* Clock Management */
+#define A2W_OFFSET 0x102000 /* Reset controller */
+#define AVS_OFFSET 0x103000 /* Audio Video Standard */
#define RNG_OFFSET 0x104000
#define GPIO_OFFSET 0x200000
#define UART0_OFFSET 0x201000
@@ -47,11 +47,17 @@
#define I2S_OFFSET 0x203000
#define SPI0_OFFSET 0x204000
#define BSC0_OFFSET 0x205000 /* BSC0 I2C/TWI */
-#define UART1_OFFSET 0x215000
-#define EMMC_OFFSET 0x300000
+#define OTP_OFFSET 0x20f000
+#define BSC_SL_OFFSET 0x214000 /* SPI slave */
+#define AUX_OFFSET 0x215000 /* AUX: UART1/SPI1/SPI2 */
+#define EMMC1_OFFSET 0x300000
#define SMI_OFFSET 0x600000
#define BSC1_OFFSET 0x804000 /* BSC1 I2C/TWI */
-#define USB_OFFSET 0x980000 /* DTC_OTG USB controller */
+#define BSC2_OFFSET 0x805000 /* BSC2 I2C/TWI */
+#define DBUS_OFFSET 0x900000
+#define AVE0_OFFSET 0x910000
+#define USB_OTG_OFFSET 0x980000 /* DTC_OTG USB controller */
+#define SDRAMC_OFFSET 0xe00000
#define DMA15_OFFSET 0xE05000 /* DMA controller, channel 15 */
/* GPU interrupts */
@@ -112,7 +118,7 @@
#define INTERRUPT_SPI 54
#define INTERRUPT_I2SPCM 55
#define INTERRUPT_SDIO 56
-#define INTERRUPT_UART 57
+#define INTERRUPT_UART0 57
#define INTERRUPT_SLIMBUS 58
#define INTERRUPT_VEC 59
#define INTERRUPT_CPG 60
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index a2753f0bbb..13e0105918 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -25,10 +25,13 @@
#include "hw/sysbus.h"
#define TYPE_ASPEED_I2C "aspeed.i2c"
+#define TYPE_ASPEED_2400_I2C TYPE_ASPEED_I2C "-ast2400"
+#define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500"
+#define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600"
#define ASPEED_I2C(obj) \
OBJECT_CHECK(AspeedI2CState, (obj), TYPE_ASPEED_I2C)
-#define ASPEED_I2C_NR_BUSSES 14
+#define ASPEED_I2C_NR_BUSSES 16
struct AspeedI2CState;
@@ -39,6 +42,7 @@ typedef struct AspeedI2CBus {
I2CBus *bus;
uint8_t id;
+ qemu_irq irq;
uint32_t ctrl;
uint32_t timing[2];
@@ -59,6 +63,20 @@ typedef struct AspeedI2CState {
AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES];
} AspeedI2CState;
+#define ASPEED_I2C_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AspeedI2CClass, (klass), TYPE_ASPEED_I2C)
+#define ASPEED_I2C_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AspeedI2CClass, (obj), TYPE_ASPEED_I2C)
+
+typedef struct AspeedI2CClass {
+ SysBusDeviceClass parent_class;
+
+ uint8_t num_busses;
+ uint8_t reg_size;
+ uint8_t gap;
+ qemu_irq (*bus_get_irq)(AspeedI2CBus *);
+} AspeedI2CClass;
+
I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr);
#endif /* ASPEED_I2C_H */
diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h
index 239e94fe2c..1d7f7ffc15 100644
--- a/include/hw/misc/aspeed_scu.h
+++ b/include/hw/misc/aspeed_scu.h
@@ -17,8 +17,10 @@
#define ASPEED_SCU(obj) OBJECT_CHECK(AspeedSCUState, (obj), TYPE_ASPEED_SCU)
#define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400"
#define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500"
+#define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600"
#define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
+#define ASPEED_AST2600_SCU_NR_REGS (0xE20 >> 2)
typedef struct AspeedSCUState {
/*< private >*/
@@ -27,7 +29,7 @@ typedef struct AspeedSCUState {
/*< public >*/
MemoryRegion iomem;
- uint32_t regs[ASPEED_SCU_NR_REGS];
+ uint32_t regs[ASPEED_AST2600_SCU_NR_REGS];
uint32_t silicon_rev;
uint32_t hw_strap1;
uint32_t hw_strap2;
@@ -38,6 +40,7 @@ typedef struct AspeedSCUState {
#define AST2400_A1_SILICON_REV 0x02010303U
#define AST2500_A0_SILICON_REV 0x04000303U
#define AST2500_A1_SILICON_REV 0x04010303U
+#define AST2600_A0_SILICON_REV 0x05000303U
#define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04)
@@ -54,6 +57,8 @@ typedef struct AspeedSCUClass {
const uint32_t *resets;
uint32_t (*calc_hpll)(AspeedSCUState *s, uint32_t hpll_reg);
uint32_t apb_divider;
+ uint32_t nr_regs;
+ const MemoryRegionOps *ops;
} AspeedSCUClass;
#define ASPEED_SCU_PROT_KEY 0x1688A8A8
diff --git a/include/hw/misc/aspeed_sdmc.h b/include/hw/misc/aspeed_sdmc.h
index b3c926acae..5dbde59fe7 100644
--- a/include/hw/misc/aspeed_sdmc.h
+++ b/include/hw/misc/aspeed_sdmc.h
@@ -13,6 +13,9 @@
#define TYPE_ASPEED_SDMC "aspeed.sdmc"
#define ASPEED_SDMC(obj) OBJECT_CHECK(AspeedSDMCState, (obj), TYPE_ASPEED_SDMC)
+#define TYPE_ASPEED_2400_SDMC TYPE_ASPEED_SDMC "-ast2400"
+#define TYPE_ASPEED_2500_SDMC TYPE_ASPEED_SDMC "-ast2500"
+#define TYPE_ASPEED_2600_SDMC TYPE_ASPEED_SDMC "-ast2600"
#define ASPEED_SDMC_NR_REGS (0x174 >> 2)
@@ -24,12 +27,21 @@ typedef struct AspeedSDMCState {
MemoryRegion iomem;
uint32_t regs[ASPEED_SDMC_NR_REGS];
- uint32_t silicon_rev;
- uint32_t ram_bits;
uint64_t ram_size;
uint64_t max_ram_size;
- uint32_t fixed_conf;
-
} AspeedSDMCState;
+#define ASPEED_SDMC_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AspeedSDMCClass, (klass), TYPE_ASPEED_SDMC)
+#define ASPEED_SDMC_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AspeedSDMCClass, (obj), TYPE_ASPEED_SDMC)
+
+typedef struct AspeedSDMCClass {
+ SysBusDeviceClass parent_class;
+
+ uint64_t max_ram_size;
+ uint32_t (*compute_conf)(AspeedSDMCState *s, uint32_t data);
+ void (*write)(AspeedSDMCState *s, uint32_t reg, uint32_t data);
+} AspeedSDMCClass;
+
#endif /* ASPEED_SDMC_H */
diff --git a/include/hw/net/ftgmac100.h b/include/hw/net/ftgmac100.h
index 94cfe05332..ab37e7b2b8 100644
--- a/include/hw/net/ftgmac100.h
+++ b/include/hw/net/ftgmac100.h
@@ -66,4 +66,21 @@ typedef struct FTGMAC100State {
uint32_t rxdes0_edorr;
} FTGMAC100State;
+#define TYPE_ASPEED_MII "aspeed-mmi"
+#define ASPEED_MII(obj) OBJECT_CHECK(AspeedMiiState, (obj), TYPE_ASPEED_MII)
+
+/*
+ * AST2600 MII controller
+ */
+typedef struct AspeedMiiState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ FTGMAC100State *nic;
+
+ MemoryRegion iomem;
+ uint32_t phycr;
+ uint32_t phydata;
+} AspeedMiiState;
+
#endif
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 9c77055229..4c321f65dc 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -72,7 +72,7 @@
* ptimer_set_count() or ptimer_set_limit() will not trigger the timer
* (though it will cause a reload). Only a counter decrement to "0"
* will cause a trigger. Not compatible with NO_IMMEDIATE_TRIGGER;
- * ptimer_init() will assert() that you don't set both.
+ * ptimer_init_with_bh() will assert() that you don't set both.
*/
#define PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT (1 << 5)
@@ -81,7 +81,7 @@ typedef struct ptimer_state ptimer_state;
typedef void (*ptimer_cb)(void *opaque);
/**
- * ptimer_init - Allocate and return a new ptimer
+ * ptimer_init_with_bh - Allocate and return a new ptimer
* @bh: QEMU bottom half which is run on timer expiry
* @policy: PTIMER_POLICY_* bits specifying behaviour
*
@@ -89,18 +89,72 @@ typedef void (*ptimer_cb)(void *opaque);
* The ptimer takes ownership of @bh and will delete it
* when the ptimer is eventually freed.
*/
-ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask);
+ptimer_state *ptimer_init_with_bh(QEMUBH *bh, uint8_t policy_mask);
+
+/**
+ * ptimer_init - Allocate and return a new ptimer
+ * @callback: function to call on ptimer expiry
+ * @callback_opaque: opaque pointer passed to @callback
+ * @policy: PTIMER_POLICY_* bits specifying behaviour
+ *
+ * The ptimer returned must be freed using ptimer_free().
+ *
+ * If a ptimer is created using this API then will use the
+ * transaction-based API for modifying ptimer state: all calls
+ * to functions which modify ptimer state:
+ * - ptimer_set_period()
+ * - ptimer_set_freq()
+ * - ptimer_set_limit()
+ * - ptimer_set_count()
+ * - ptimer_run()
+ * - ptimer_stop()
+ * must be between matched calls to ptimer_transaction_begin()
+ * and ptimer_transaction_commit(). When ptimer_transaction_commit()
+ * is called it will evaluate the state of the timer after all the
+ * changes in the transaction, and call the callback if necessary.
+ *
+ * The callback function is always called from within a transaction
+ * begin/commit block, so the callback should not call the
+ * ptimer_transaction_begin() function itself. If the callback changes
+ * the ptimer state such that another ptimer expiry is triggered, then
+ * the callback will be called a second time after the first call returns.
+ */
+ptimer_state *ptimer_init(ptimer_cb callback,
+ void *callback_opaque,
+ uint8_t policy_mask);
/**
* ptimer_free - Free a ptimer
* @s: timer to free
*
- * Free a ptimer created using ptimer_init() (including
+ * Free a ptimer created using ptimer_init_with_bh() (including
* deleting the bottom half which it is using).
*/
void ptimer_free(ptimer_state *s);
/**
+ * ptimer_transaction_begin() - Start a ptimer modification transaction
+ *
+ * This function must be called before making any calls to functions
+ * which modify the ptimer's state (see the ptimer_init() documentation
+ * for a list of these), and must always have a matched call to
+ * ptimer_transaction_commit().
+ * It is an error to call this function for a BH-based ptimer;
+ * attempting to do this will trigger an assert.
+ */
+void ptimer_transaction_begin(ptimer_state *s);
+
+/**
+ * ptimer_transaction_commit() - Commit a ptimer modification transaction
+ *
+ * This function must be called after calls to functions which modify
+ * the ptimer's state, and completes the update of the ptimer. If the
+ * ptimer state now means that we should trigger the timer expiry
+ * callback, it will be called directly.
+ */
+void ptimer_transaction_commit(ptimer_state *s);
+
+/**
* ptimer_set_period - Set counter increment interval in nanoseconds
* @s: ptimer to configure
* @period: period of the counter in nanoseconds
@@ -108,6 +162,9 @@ void ptimer_free(ptimer_state *s);
* Note that if your counter behaviour is specified as having a
* particular frequency rather than a period then ptimer_set_freq()
* may be more appropriate.
+ *
+ * This function will assert if it is called outside a
+ * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer.
*/
void ptimer_set_period(ptimer_state *s, int64_t period);
@@ -121,6 +178,9 @@ void ptimer_set_period(ptimer_state *s, int64_t period);
* as setting the frequency then this function is more appropriate,
* because it allows specifying an effective period which is
* precise to fractions of a nanosecond, avoiding rounding errors.
+ *
+ * This function will assert if it is called outside a
+ * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer.
*/
void ptimer_set_freq(ptimer_state *s, uint32_t freq);
@@ -148,6 +208,9 @@ uint64_t ptimer_get_limit(ptimer_state *s);
* Set the limit value of the down-counter. The @reload flag can
* be used to emulate the behaviour of timers which immediately
* reload the counter when their reload register is written to.
+ *
+ * This function will assert if it is called outside a
+ * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer.
*/
void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload);
@@ -169,6 +232,9 @@ uint64_t ptimer_get_count(ptimer_state *s);
* Set the value of the down-counter. If the counter is currently
* enabled this will arrange for a timer callback at the appropriate
* point in the future.
+ *
+ * This function will assert if it is called outside a
+ * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer.
*/
void ptimer_set_count(ptimer_state *s, uint64_t count);
@@ -178,10 +244,14 @@ void ptimer_set_count(ptimer_state *s, uint64_t count);
* @oneshot: non-zero if this timer should only count down once
*
* Start a ptimer counting down; when it reaches zero the bottom half
- * passed to ptimer_init() will be invoked. If the @oneshot argument is zero,
+ * passed to ptimer_init_with_bh() will be invoked.
+ * If the @oneshot argument is zero,
* the counter value will then be reloaded from the limit and it will
* start counting down again. If @oneshot is non-zero, then the counter
* will disable itself when it reaches zero.
+ *
+ * This function will assert if it is called outside a
+ * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer.
*/
void ptimer_run(ptimer_state *s, int oneshot);
@@ -194,6 +264,9 @@ void ptimer_run(ptimer_state *s, int oneshot);
*
* Note that this can cause it to "lose" time, even if it is immediately
* restarted.
+ *
+ * This function will assert if it is called outside a
+ * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer.
*/
void ptimer_stop(ptimer_state *s);
diff --git a/include/hw/sd/aspeed_sdhci.h b/include/hw/sd/aspeed_sdhci.h
new file mode 100644
index 0000000000..dfdab43790
--- /dev/null
+++ b/include/hw/sd/aspeed_sdhci.h
@@ -0,0 +1,34 @@
+/*
+ * Aspeed SD Host Controller
+ * Eddie James <eajames@linux.ibm.com>
+ *
+ * Copyright (C) 2019 IBM Corp
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ */
+
+#ifndef ASPEED_SDHCI_H
+#define ASPEED_SDHCI_H
+
+#include "hw/sd/sdhci.h"
+
+#define TYPE_ASPEED_SDHCI "aspeed.sdhci"
+#define ASPEED_SDHCI(obj) OBJECT_CHECK(AspeedSDHCIState, (obj), \
+ TYPE_ASPEED_SDHCI)
+
+#define ASPEED_SDHCI_CAPABILITIES 0x01E80080
+#define ASPEED_SDHCI_NUM_SLOTS 2
+#define ASPEED_SDHCI_NUM_REGS (ASPEED_SDHCI_REG_SIZE / sizeof(uint32_t))
+#define ASPEED_SDHCI_REG_SIZE 0x100
+
+typedef struct AspeedSDHCIState {
+ SysBusDevice parent;
+
+ SDHCIState slots[ASPEED_SDHCI_NUM_SLOTS];
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ uint32_t regs[ASPEED_SDHCI_NUM_REGS];
+} AspeedSDHCIState;
+
+#endif /* ASPEED_SDHCI_H */
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 5176ff6bf9..684d16e336 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -49,6 +49,10 @@ typedef struct AspeedSMCController {
hwaddr dma_flash_mask;
hwaddr dma_dram_mask;
uint32_t nregs;
+ uint32_t (*segment_to_reg)(const struct AspeedSMCState *s,
+ const AspeedSegments *seg);
+ void (*reg_to_segment)(const struct AspeedSMCState *s, uint32_t reg,
+ AspeedSegments *seg);
} AspeedSMCController;
typedef struct AspeedSMCFlash {
diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_timer.h
index 1fb949e167..948329893c 100644
--- a/include/hw/timer/aspeed_timer.h
+++ b/include/hw/timer/aspeed_timer.h
@@ -28,6 +28,10 @@
#define ASPEED_TIMER(obj) \
OBJECT_CHECK(AspeedTimerCtrlState, (obj), TYPE_ASPEED_TIMER);
#define TYPE_ASPEED_TIMER "aspeed.timer"
+#define TYPE_ASPEED_2400_TIMER TYPE_ASPEED_TIMER "-ast2400"
+#define TYPE_ASPEED_2500_TIMER TYPE_ASPEED_TIMER "-ast2500"
+#define TYPE_ASPEED_2600_TIMER TYPE_ASPEED_TIMER "-ast2600"
+
#define ASPEED_TIMER_NR_TIMERS 8
typedef struct AspeedTimer {
@@ -55,9 +59,23 @@ typedef struct AspeedTimerCtrlState {
uint32_t ctrl;
uint32_t ctrl2;
+ uint32_t ctrl3;
+ uint32_t irq_sts;
AspeedTimer timers[ASPEED_TIMER_NR_TIMERS];
AspeedSCUState *scu;
} AspeedTimerCtrlState;
+#define ASPEED_TIMER_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AspeedTimerClass, (klass), TYPE_ASPEED_TIMER)
+#define ASPEED_TIMER_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AspeedTimerClass, (obj), TYPE_ASPEED_TIMER)
+
+typedef struct AspeedTimerClass {
+ SysBusDeviceClass parent_class;
+
+ uint64_t (*read)(AspeedTimerCtrlState *s, hwaddr offset);
+ void (*write)(AspeedTimerCtrlState *s, hwaddr offset, uint64_t value);
+} AspeedTimerClass;
+
#endif /* ASPEED_TIMER_H */
diff --git a/include/hw/timer/mss-timer.h b/include/hw/timer/mss-timer.h
index d15d1732f8..e5a784b27e 100644
--- a/include/hw/timer/mss-timer.h
+++ b/include/hw/timer/mss-timer.h
@@ -46,7 +46,6 @@
#define R_TIM1_MAX 6
struct Msf2Timer {
- QEMUBH *bh;
ptimer_state *ptimer;
uint32_t regs[R_TIM1_MAX];
diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h
index 8c5691ce20..dfedd7662d 100644
--- a/include/hw/watchdog/wdt_aspeed.h
+++ b/include/hw/watchdog/wdt_aspeed.h
@@ -16,6 +16,9 @@
#define TYPE_ASPEED_WDT "aspeed.wdt"
#define ASPEED_WDT(obj) \
OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
+#define TYPE_ASPEED_2400_WDT TYPE_ASPEED_WDT "-ast2400"
+#define TYPE_ASPEED_2500_WDT TYPE_ASPEED_WDT "-ast2500"
+#define TYPE_ASPEED_2600_WDT TYPE_ASPEED_WDT "-ast2600"
#define ASPEED_WDT_REGS_MAX (0x20 / 4)
@@ -30,8 +33,20 @@ typedef struct AspeedWDTState {
AspeedSCUState *scu;
uint32_t pclk_freq;
- uint32_t silicon_rev;
- uint32_t ext_pulse_width_mask;
} AspeedWDTState;
+#define ASPEED_WDT_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AspeedWDTClass, (klass), TYPE_ASPEED_WDT)
+#define ASPEED_WDT_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AspeedWDTClass, (obj), TYPE_ASPEED_WDT)
+
+typedef struct AspeedWDTClass {
+ SysBusDeviceClass parent_class;
+
+ uint32_t offset;
+ uint32_t ext_pulse_width_mask;
+ uint32_t reset_ctrl_reg;
+ void (*reset_pulse)(AspeedWDTState *s, uint32_t property);
+} AspeedWDTClass;
+
#endif /* WDT_ASPEED_H */
diff --git a/include/standard-headers/asm-x86/bootparam.h b/include/standard-headers/asm-x86/bootparam.h
index 67d4f0119f..a6f7cf535e 100644
--- a/include/standard-headers/asm-x86/bootparam.h
+++ b/include/standard-headers/asm-x86/bootparam.h
@@ -29,6 +29,8 @@
#define XLF_EFI_HANDOVER_32 (1<<2)
#define XLF_EFI_HANDOVER_64 (1<<3)
#define XLF_EFI_KEXEC (1<<4)
+#define XLF_5LEVEL (1<<5)
+#define XLF_5LEVEL_ENABLED (1<<6)
#endif /* _ASM_X86_BOOTPARAM_H */
diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h
index e1715143fd..90604a8fb7 100644
--- a/include/standard-headers/asm-x86/kvm_para.h
+++ b/include/standard-headers/asm-x86/kvm_para.h
@@ -30,6 +30,7 @@
#define KVM_FEATURE_ASYNC_PF_VMEXIT 10
#define KVM_FEATURE_PV_SEND_IPI 11
#define KVM_FEATURE_POLL_CONTROL 12
+#define KVM_FEATURE_PV_SCHED_YIELD 13
#define KVM_HINTS_REALTIME 0
diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h
index 9b9919a8f6..4ff422b635 100644
--- a/include/standard-headers/linux/ethtool.h
+++ b/include/standard-headers/linux/ethtool.h
@@ -259,10 +259,32 @@ struct ethtool_tunable {
#define ETHTOOL_PHY_FAST_LINK_DOWN_ON 0
#define ETHTOOL_PHY_FAST_LINK_DOWN_OFF 0xff
+/* Energy Detect Power Down (EDPD) is a feature supported by some PHYs, where
+ * the PHY's RX & TX blocks are put into a low-power mode when there is no
+ * link detected (typically cable is un-plugged). For RX, only a minimal
+ * link-detection is available, and for TX the PHY wakes up to send link pulses
+ * to avoid any lock-ups in case the peer PHY may also be running in EDPD mode.
+ *
+ * Some PHYs may support configuration of the wake-up interval for TX pulses,
+ * and some PHYs may support only disabling TX pulses entirely. For the latter
+ * a special value is required (ETHTOOL_PHY_EDPD_NO_TX) so that this can be
+ * configured from userspace (should the user want it).
+ *
+ * The interval units for TX wake-up are in milliseconds, since this should
+ * cover a reasonable range of intervals:
+ * - from 1 millisecond, which does not sound like much of a power-saver
+ * - to ~65 seconds which is quite a lot to wait for a link to come up when
+ * plugging a cable
+ */
+#define ETHTOOL_PHY_EDPD_DFLT_TX_MSECS 0xffff
+#define ETHTOOL_PHY_EDPD_NO_TX 0xfffe
+#define ETHTOOL_PHY_EDPD_DISABLE 0
+
enum phy_tunable_id {
ETHTOOL_PHY_ID_UNSPEC,
ETHTOOL_PHY_DOWNSHIFT,
ETHTOOL_PHY_FAST_LINK_DOWN,
+ ETHTOOL_PHY_EDPD,
/*
* Add your fresh new phy tunable attribute above and remember to update
* phy_tunable_strings[] in net/core/ethtool.c
@@ -1483,6 +1505,8 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64,
ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT = 65,
ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66,
+ ETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67,
+ ETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68,
/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS
diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index 27164769d1..29d6e93fd1 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -528,6 +528,7 @@
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
#define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */
+#define PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
@@ -556,6 +557,7 @@
#define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002 /* Current Link Speed 5.0GT/s */
#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
#define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */
+#define PCI_EXP_LNKSTA_CLS_32_0GB 0x0005 /* Current Link Speed 32.0GT/s */
#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */
#define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */
#define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */
@@ -589,6 +591,7 @@
#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */
#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */
#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */
+#define PCI_EXP_SLTCTL_ATTN_IND_SHIFT 6 /* Attention Indicator shift */
#define PCI_EXP_SLTCTL_ATTN_IND_ON 0x0040 /* Attention Indicator on */
#define PCI_EXP_SLTCTL_ATTN_IND_BLINK 0x0080 /* Attention Indicator blinking */
#define PCI_EXP_SLTCTL_ATTN_IND_OFF 0x00c0 /* Attention Indicator off */
@@ -661,6 +664,7 @@
#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5GT/s */
#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */
#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */
+#define PCI_EXP_LNKCAP2_SLS_32_0GB 0x00000020 /* Supported Speed 32GT/s */
#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */
#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
#define PCI_EXP_LNKCTL2_TLS 0x000f
@@ -668,6 +672,7 @@
#define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */
#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */
#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */
+#define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */
#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */
#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */
#define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */
@@ -709,7 +714,9 @@
#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */
#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */
#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
-#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM
+#define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */
+#define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */
+#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT
#define PCI_EXT_CAP_DSN_SIZEOF 12
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
@@ -1049,4 +1056,14 @@
#define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */
#define PCI_L1SS_CTL2 0x0c /* Control 2 Register */
+/* Data Link Feature */
+#define PCI_DLF_CAP 0x04 /* Capabilities Register */
+#define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */
+
+/* Physical Layer 16.0 GT/s */
+#define PCI_PL_16GT_LE_CTRL 0x20 /* Lane Equalization Control Register */
+#define PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK 0x0000000F
+#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0
+#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4
+
#endif /* LINUX_PCI_REGS_H */
diff --git a/include/standard-headers/linux/virtio_fs.h b/include/standard-headers/linux/virtio_fs.h
new file mode 100644
index 0000000000..9d88817a6b
--- /dev/null
+++ b/include/standard-headers/linux/virtio_fs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+
+#ifndef _LINUX_VIRTIO_FS_H
+#define _LINUX_VIRTIO_FS_H
+
+#include "standard-headers/linux/types.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_config.h"
+#include "standard-headers/linux/virtio_types.h"
+
+struct virtio_fs_config {
+ /* Filesystem name (UTF-8, not NUL-terminated, padded with NULs) */
+ uint8_t tag[36];
+
+ /* Number of request queues */
+ uint32_t num_request_queues;
+} QEMU_PACKED;
+
+#endif /* _LINUX_VIRTIO_FS_H */
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
index 32b2f94d1f..585e07b273 100644
--- a/include/standard-headers/linux/virtio_ids.h
+++ b/include/standard-headers/linux/virtio_ids.h
@@ -43,6 +43,8 @@
#define VIRTIO_ID_INPUT 18 /* virtio input */
#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
+#define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */
+#define VIRTIO_ID_FS 26 /* virtio filesystem */
#define VIRTIO_ID_PMEM 27 /* virtio pmem */
#endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/standard-headers/linux/virtio_iommu.h b/include/standard-headers/linux/virtio_iommu.h
new file mode 100644
index 0000000000..b9443b83a1
--- /dev/null
+++ b/include/standard-headers/linux/virtio_iommu.h
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Virtio-iommu definition v0.12
+ *
+ * Copyright (C) 2019 Arm Ltd.
+ */
+#ifndef _LINUX_VIRTIO_IOMMU_H
+#define _LINUX_VIRTIO_IOMMU_H
+
+#include "standard-headers/linux/types.h"
+
+/* Feature bits */
+#define VIRTIO_IOMMU_F_INPUT_RANGE 0
+#define VIRTIO_IOMMU_F_DOMAIN_RANGE 1
+#define VIRTIO_IOMMU_F_MAP_UNMAP 2
+#define VIRTIO_IOMMU_F_BYPASS 3
+#define VIRTIO_IOMMU_F_PROBE 4
+#define VIRTIO_IOMMU_F_MMIO 5
+
+struct virtio_iommu_range_64 {
+ uint64_t start;
+ uint64_t end;
+};
+
+struct virtio_iommu_range_32 {
+ uint32_t start;
+ uint32_t end;
+};
+
+struct virtio_iommu_config {
+ /* Supported page sizes */
+ uint64_t page_size_mask;
+ /* Supported IOVA range */
+ struct virtio_iommu_range_64 input_range;
+ /* Max domain ID size */
+ struct virtio_iommu_range_32 domain_range;
+ /* Probe buffer size */
+ uint32_t probe_size;
+};
+
+/* Request types */
+#define VIRTIO_IOMMU_T_ATTACH 0x01
+#define VIRTIO_IOMMU_T_DETACH 0x02
+#define VIRTIO_IOMMU_T_MAP 0x03
+#define VIRTIO_IOMMU_T_UNMAP 0x04
+#define VIRTIO_IOMMU_T_PROBE 0x05
+
+/* Status types */
+#define VIRTIO_IOMMU_S_OK 0x00
+#define VIRTIO_IOMMU_S_IOERR 0x01
+#define VIRTIO_IOMMU_S_UNSUPP 0x02
+#define VIRTIO_IOMMU_S_DEVERR 0x03
+#define VIRTIO_IOMMU_S_INVAL 0x04
+#define VIRTIO_IOMMU_S_RANGE 0x05
+#define VIRTIO_IOMMU_S_NOENT 0x06
+#define VIRTIO_IOMMU_S_FAULT 0x07
+#define VIRTIO_IOMMU_S_NOMEM 0x08
+
+struct virtio_iommu_req_head {
+ uint8_t type;
+ uint8_t reserved[3];
+};
+
+struct virtio_iommu_req_tail {
+ uint8_t status;
+ uint8_t reserved[3];
+};
+
+struct virtio_iommu_req_attach {
+ struct virtio_iommu_req_head head;
+ uint32_t domain;
+ uint32_t endpoint;
+ uint8_t reserved[8];
+ struct virtio_iommu_req_tail tail;
+};
+
+struct virtio_iommu_req_detach {
+ struct virtio_iommu_req_head head;
+ uint32_t domain;
+ uint32_t endpoint;
+ uint8_t reserved[8];
+ struct virtio_iommu_req_tail tail;
+};
+
+#define VIRTIO_IOMMU_MAP_F_READ (1 << 0)
+#define VIRTIO_IOMMU_MAP_F_WRITE (1 << 1)
+#define VIRTIO_IOMMU_MAP_F_MMIO (1 << 2)
+
+#define VIRTIO_IOMMU_MAP_F_MASK (VIRTIO_IOMMU_MAP_F_READ | \
+ VIRTIO_IOMMU_MAP_F_WRITE | \
+ VIRTIO_IOMMU_MAP_F_MMIO)
+
+struct virtio_iommu_req_map {
+ struct virtio_iommu_req_head head;
+ uint32_t domain;
+ uint64_t virt_start;
+ uint64_t virt_end;
+ uint64_t phys_start;
+ uint32_t flags;
+ struct virtio_iommu_req_tail tail;
+};
+
+struct virtio_iommu_req_unmap {
+ struct virtio_iommu_req_head head;
+ uint32_t domain;
+ uint64_t virt_start;
+ uint64_t virt_end;
+ uint8_t reserved[4];
+ struct virtio_iommu_req_tail tail;
+};
+
+#define VIRTIO_IOMMU_PROBE_T_NONE 0
+#define VIRTIO_IOMMU_PROBE_T_RESV_MEM 1
+
+#define VIRTIO_IOMMU_PROBE_T_MASK 0xfff
+
+struct virtio_iommu_probe_property {
+ uint16_t type;
+ uint16_t length;
+};
+
+#define VIRTIO_IOMMU_RESV_MEM_T_RESERVED 0
+#define VIRTIO_IOMMU_RESV_MEM_T_MSI 1
+
+struct virtio_iommu_probe_resv_mem {
+ struct virtio_iommu_probe_property head;
+ uint8_t subtype;
+ uint8_t reserved[3];
+ uint64_t start;
+ uint64_t end;
+};
+
+struct virtio_iommu_req_probe {
+ struct virtio_iommu_req_head head;
+ uint32_t endpoint;
+ uint8_t reserved[64];
+
+ uint8_t properties[];
+
+ /*
+ * Tail follows the variable-length properties array. No padding,
+ * property lengths are all aligned on 8 bytes.
+ */
+};
+
+/* Fault types */
+#define VIRTIO_IOMMU_FAULT_R_UNKNOWN 0
+#define VIRTIO_IOMMU_FAULT_R_DOMAIN 1
+#define VIRTIO_IOMMU_FAULT_R_MAPPING 2
+
+#define VIRTIO_IOMMU_FAULT_F_READ (1 << 0)
+#define VIRTIO_IOMMU_FAULT_F_WRITE (1 << 1)
+#define VIRTIO_IOMMU_FAULT_F_EXEC (1 << 2)
+#define VIRTIO_IOMMU_FAULT_F_ADDRESS (1 << 8)
+
+struct virtio_iommu_fault {
+ uint8_t reason;
+ uint8_t reserved[3];
+ uint32_t flags;
+ uint32_t endpoint;
+ uint8_t reserved2[4];
+ uint64_t address;
+};
+
+#endif
diff --git a/include/standard-headers/linux/virtio_pmem.h b/include/standard-headers/linux/virtio_pmem.h
index 7e3d43b121..fc029de798 100644
--- a/include/standard-headers/linux/virtio_pmem.h
+++ b/include/standard-headers/linux/virtio_pmem.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause */
/*
* Definitions for virtio-pmem devices.
*
@@ -7,8 +7,8 @@
* Author(s): Pankaj Gupta <pagupta@redhat.com>
*/
-#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
-#define _UAPI_LINUX_VIRTIO_PMEM_H
+#ifndef _LINUX_VIRTIO_PMEM_H
+#define _LINUX_VIRTIO_PMEM_H
#include "standard-headers/linux/types.h"
#include "standard-headers/linux/virtio_ids.h"
diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index e1f8b74558..9d379d3372 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -214,6 +214,18 @@ struct kvm_vcpu_events {
#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \
KVM_REG_ARM_FW | ((r) & 0xffff))
#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 KVM_REG_ARM_FW_REG(1)
+ /* Higher values mean better protection. */
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL 0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL 1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED 2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 KVM_REG_ARM_FW_REG(2)
+ /* Higher values mean better protection. */
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL 0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN 1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL 2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4)
/* Device Control API: ARM VGIC */
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
@@ -254,8 +266,10 @@ struct kvm_vcpu_events {
#define KVM_DEV_ARM_ITS_CTRL_RESET 4
/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_VCPU2_SHIFT 28
+#define KVM_ARM_IRQ_VCPU2_MASK 0xf
#define KVM_ARM_IRQ_TYPE_SHIFT 24
-#define KVM_ARM_IRQ_TYPE_MASK 0xff
+#define KVM_ARM_IRQ_TYPE_MASK 0xf
#define KVM_ARM_IRQ_VCPU_SHIFT 16
#define KVM_ARM_IRQ_VCPU_MASK 0xff
#define KVM_ARM_IRQ_NUM_SHIFT 0
diff --git a/linux-headers/asm-arm/unistd-common.h b/linux-headers/asm-arm/unistd-common.h
index 27a9b6da27..eb5d361b11 100644
--- a/linux-headers/asm-arm/unistd-common.h
+++ b/linux-headers/asm-arm/unistd-common.h
@@ -388,5 +388,7 @@
#define __NR_fsconfig (__NR_SYSCALL_BASE + 431)
#define __NR_fsmount (__NR_SYSCALL_BASE + 432)
#define __NR_fspick (__NR_SYSCALL_BASE + 433)
+#define __NR_pidfd_open (__NR_SYSCALL_BASE + 434)
+#define __NR_clone3 (__NR_SYSCALL_BASE + 435)
#endif /* _ASM_ARM_UNISTD_COMMON_H */
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 2431ec35a9..0ce6e49f3a 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -229,6 +229,16 @@ struct kvm_vcpu_events {
#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
KVM_REG_ARM_FW | ((r) & 0xffff))
#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 KVM_REG_ARM_FW_REG(1)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL 0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL 1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED 2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 KVM_REG_ARM_FW_REG(2)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL 0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN 1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL 2
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4)
/* SVE registers */
#define KVM_REG_ARM64_SVE (0x15 << KVM_REG_ARM_COPROC_SHIFT)
@@ -260,6 +270,13 @@ struct kvm_vcpu_events {
KVM_REG_SIZE_U256 | \
((i) & (KVM_ARM64_SVE_MAX_SLICES - 1)))
+/*
+ * Register values for KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() and
+ * KVM_REG_ARM64_SVE_FFR() are represented in memory in an endianness-
+ * invariant layout which differs from the layout used for the FPSIMD
+ * V-registers on big-endian systems: see sigcontext.h for more explanation.
+ */
+
#define KVM_ARM64_SVE_VQ_MIN __SVE_VQ_MIN
#define KVM_ARM64_SVE_VQ_MAX __SVE_VQ_MAX
@@ -308,8 +325,10 @@ struct kvm_vcpu_events {
#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_VCPU2_SHIFT 28
+#define KVM_ARM_IRQ_VCPU2_MASK 0xf
#define KVM_ARM_IRQ_TYPE_SHIFT 24
-#define KVM_ARM_IRQ_TYPE_MASK 0xff
+#define KVM_ARM_IRQ_TYPE_MASK 0xf
#define KVM_ARM_IRQ_VCPU_SHIFT 16
#define KVM_ARM_IRQ_VCPU_MASK 0xff
#define KVM_ARM_IRQ_NUM_SHIFT 0
diff --git a/linux-headers/asm-generic/mman-common.h b/linux-headers/asm-generic/mman-common.h
index abd238d0f7..c160a5354e 100644
--- a/linux-headers/asm-generic/mman-common.h
+++ b/linux-headers/asm-generic/mman-common.h
@@ -19,15 +19,18 @@
#define MAP_TYPE 0x0f /* Mask for type of mapping */
#define MAP_FIXED 0x10 /* Interpret addr exactly */
#define MAP_ANONYMOUS 0x20 /* don't use a file */
-#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
-# define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */
-#else
-# define MAP_UNINITIALIZED 0x0 /* Don't support this flag */
-#endif
-/* 0x0100 - 0x80000 flags are defined in asm-generic/mman.h */
+/* 0x0100 - 0x4000 flags are defined in asm-generic/mman.h */
+#define MAP_POPULATE 0x008000 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x010000 /* do not block on IO */
+#define MAP_STACK 0x020000 /* give out an address that is best suited for process/thread stacks */
+#define MAP_HUGETLB 0x040000 /* create a huge page mapping */
+#define MAP_SYNC 0x080000 /* perform synchronous page faults for the mapping */
#define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED which doesn't unmap underlying mapping */
+#define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be
+ * uninitialized */
+
/*
* Flags for mlock
*/
@@ -64,6 +67,9 @@
#define MADV_WIPEONFORK 18 /* Zero memory on fork, child only */
#define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK */
+#define MADV_COLD 20 /* deactivate these pages */
+#define MADV_PAGEOUT 21 /* reclaim these pages */
+
/* compatibility flags */
#define MAP_FILE 0
diff --git a/linux-headers/asm-generic/mman.h b/linux-headers/asm-generic/mman.h
index 653687d977..57e8195d0b 100644
--- a/linux-headers/asm-generic/mman.h
+++ b/linux-headers/asm-generic/mman.h
@@ -9,13 +9,11 @@
#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
#define MAP_LOCKED 0x2000 /* pages are locked */
#define MAP_NORESERVE 0x4000 /* don't check for reservations */
-#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
-#define MAP_NONBLOCK 0x10000 /* do not block on IO */
-#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */
-#define MAP_HUGETLB 0x40000 /* create a huge page mapping */
-#define MAP_SYNC 0x80000 /* perform synchronous page faults for the mapping */
-/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */
+/*
+ * Bits [26:31] are reserved, see asm-generic/hugetlb_encode.h
+ * for MAP_HUGETLB usage
+ */
#define MCL_CURRENT 1 /* lock all current mappings */
#define MCL_FUTURE 2 /* lock all future mappings */
diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h
index a87904daf1..1fc8faa6e9 100644
--- a/linux-headers/asm-generic/unistd.h
+++ b/linux-headers/asm-generic/unistd.h
@@ -569,7 +569,7 @@ __SYSCALL(__NR_semget, sys_semget)
__SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl)
#if defined(__ARCH_WANT_TIME32_SYSCALLS) || __BITS_PER_LONG != 32
#define __NR_semtimedop 192
-__SC_COMP(__NR_semtimedop, sys_semtimedop, sys_semtimedop_time32)
+__SC_3264(__NR_semtimedop, sys_semtimedop_time32, sys_semtimedop)
#endif
#define __NR_semop 193
__SYSCALL(__NR_semop, sys_semop)
@@ -844,9 +844,15 @@ __SYSCALL(__NR_fsconfig, sys_fsconfig)
__SYSCALL(__NR_fsmount, sys_fsmount)
#define __NR_fspick 433
__SYSCALL(__NR_fspick, sys_fspick)
+#define __NR_pidfd_open 434
+__SYSCALL(__NR_pidfd_open, sys_pidfd_open)
+#ifdef __ARCH_WANT_SYS_CLONE3
+#define __NR_clone3 435
+__SYSCALL(__NR_clone3, sys_clone3)
+#endif
#undef __NR_syscalls
-#define __NR_syscalls 434
+#define __NR_syscalls 436
/*
* 32 bit systems traditionally used different
diff --git a/linux-headers/asm-mips/mman.h b/linux-headers/asm-mips/mman.h
index c2b40969eb..57dc2ac4f8 100644
--- a/linux-headers/asm-mips/mman.h
+++ b/linux-headers/asm-mips/mman.h
@@ -95,6 +95,9 @@
#define MADV_WIPEONFORK 18 /* Zero memory on fork, child only */
#define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK */
+#define MADV_COLD 20 /* deactivate these pages */
+#define MADV_PAGEOUT 21 /* reclaim these pages */
+
/* compatibility flags */
#define MAP_FILE 0
diff --git a/linux-headers/asm-mips/unistd_n32.h b/linux-headers/asm-mips/unistd_n32.h
index fb988de900..7dffe8e34e 100644
--- a/linux-headers/asm-mips/unistd_n32.h
+++ b/linux-headers/asm-mips/unistd_n32.h
@@ -363,6 +363,7 @@
#define __NR_fsconfig (__NR_Linux + 431)
#define __NR_fsmount (__NR_Linux + 432)
#define __NR_fspick (__NR_Linux + 433)
+#define __NR_pidfd_open (__NR_Linux + 434)
#endif /* _ASM_MIPS_UNISTD_N32_H */
diff --git a/linux-headers/asm-mips/unistd_n64.h b/linux-headers/asm-mips/unistd_n64.h
index 17359163c9..f4592d6fc5 100644
--- a/linux-headers/asm-mips/unistd_n64.h
+++ b/linux-headers/asm-mips/unistd_n64.h
@@ -339,6 +339,7 @@
#define __NR_fsconfig (__NR_Linux + 431)
#define __NR_fsmount (__NR_Linux + 432)
#define __NR_fspick (__NR_Linux + 433)
+#define __NR_pidfd_open (__NR_Linux + 434)
#endif /* _ASM_MIPS_UNISTD_N64_H */
diff --git a/linux-headers/asm-mips/unistd_o32.h b/linux-headers/asm-mips/unistd_o32.h
index 83c8d8fb83..04c6728352 100644
--- a/linux-headers/asm-mips/unistd_o32.h
+++ b/linux-headers/asm-mips/unistd_o32.h
@@ -409,6 +409,7 @@
#define __NR_fsconfig (__NR_Linux + 431)
#define __NR_fsmount (__NR_Linux + 432)
#define __NR_fspick (__NR_Linux + 433)
+#define __NR_pidfd_open (__NR_Linux + 434)
#endif /* _ASM_MIPS_UNISTD_O32_H */
diff --git a/linux-headers/asm-powerpc/mman.h b/linux-headers/asm-powerpc/mman.h
index 1c2b3fca05..8db7c2a3be 100644
--- a/linux-headers/asm-powerpc/mman.h
+++ b/linux-headers/asm-powerpc/mman.h
@@ -21,15 +21,11 @@
#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
+
#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */
#define MCL_FUTURE 0x4000 /* lock all additions to address space */
#define MCL_ONFAULT 0x8000 /* lock all pages that are faulted in */
-#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
-#define MAP_NONBLOCK 0x10000 /* do not block on IO */
-#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */
-#define MAP_HUGETLB 0x40000 /* create a huge page mapping */
-
/* Override any generic PKEY permission defines */
#define PKEY_DISABLE_EXECUTE 0x4
#undef PKEY_ACCESS_MASK
diff --git a/linux-headers/asm-powerpc/unistd_32.h b/linux-headers/asm-powerpc/unistd_32.h
index 04cb2d3e61..5584cc1b4f 100644
--- a/linux-headers/asm-powerpc/unistd_32.h
+++ b/linux-headers/asm-powerpc/unistd_32.h
@@ -416,6 +416,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#endif /* _ASM_POWERPC_UNISTD_32_H */
diff --git a/linux-headers/asm-powerpc/unistd_64.h b/linux-headers/asm-powerpc/unistd_64.h
index b1e6921490..251bcff77e 100644
--- a/linux-headers/asm-powerpc/unistd_64.h
+++ b/linux-headers/asm-powerpc/unistd_64.h
@@ -388,6 +388,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#endif /* _ASM_POWERPC_UNISTD_64_H */
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 03ab5968c7..0138ccb0d8 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -231,6 +231,12 @@ struct kvm_guest_debug_arch {
#define KVM_SYNC_GSCB (1UL << 9)
#define KVM_SYNC_BPBC (1UL << 10)
#define KVM_SYNC_ETOKEN (1UL << 11)
+
+#define KVM_SYNC_S390_VALID_FIELDS \
+ (KVM_SYNC_PREFIX | KVM_SYNC_GPRS | KVM_SYNC_ACRS | KVM_SYNC_CRS | \
+ KVM_SYNC_ARCH0 | KVM_SYNC_PFAULT | KVM_SYNC_VRS | KVM_SYNC_RICCB | \
+ KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN)
+
/* length and alignment of the sdnx as a power of two */
#define SDNXC 8
#define SDNXL (1UL << SDNXC)
diff --git a/linux-headers/asm-s390/unistd_32.h b/linux-headers/asm-s390/unistd_32.h
index 941853f3e9..7cce3ee296 100644
--- a/linux-headers/asm-s390/unistd_32.h
+++ b/linux-headers/asm-s390/unistd_32.h
@@ -406,5 +406,7 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#endif /* _ASM_S390_UNISTD_32_H */
diff --git a/linux-headers/asm-s390/unistd_64.h b/linux-headers/asm-s390/unistd_64.h
index 90271d7f82..2371ff1e7a 100644
--- a/linux-headers/asm-s390/unistd_64.h
+++ b/linux-headers/asm-s390/unistd_64.h
@@ -354,5 +354,7 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#endif /* _ASM_S390_UNISTD_64_H */
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 6e7dd792e4..503d3f42da 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -378,23 +378,24 @@ struct kvm_sync_regs {
struct kvm_vcpu_events events;
};
-#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0)
-#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1)
-#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2)
-#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3)
+#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0)
+#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1)
+#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2)
+#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3)
+#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4)
#define KVM_STATE_NESTED_FORMAT_VMX 0
-#define KVM_STATE_NESTED_FORMAT_SVM 1
+#define KVM_STATE_NESTED_FORMAT_SVM 1 /* unused */
#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
#define KVM_STATE_NESTED_EVMCS 0x00000004
-#define KVM_STATE_NESTED_VMX_VMCS_SIZE 0x1000
-
#define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
#define KVM_STATE_NESTED_SMM_VMXON 0x00000002
+#define KVM_STATE_NESTED_VMX_VMCS_SIZE 0x1000
+
struct kvm_vmx_nested_state_data {
__u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
__u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
@@ -432,4 +433,17 @@ struct kvm_nested_state {
} data;
};
+/* for KVM_CAP_PMU_EVENT_FILTER */
+struct kvm_pmu_event_filter {
+ __u32 action;
+ __u32 nevents;
+ __u32 fixed_counter_bitmap;
+ __u32 flags;
+ __u32 pad[4];
+ __u64 events[0];
+};
+
+#define KVM_PMU_EVENT_ALLOW 0
+#define KVM_PMU_EVENT_DENY 1
+
#endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/asm-x86/unistd.h b/linux-headers/asm-x86/unistd.h
index c04f638154..498d1515c6 100644
--- a/linux-headers/asm-x86/unistd.h
+++ b/linux-headers/asm-x86/unistd.h
@@ -3,7 +3,7 @@
#define _ASM_X86_UNISTD_H
/* x32 syscall flag bit */
-#define __X32_SYSCALL_BIT 0x40000000
+#define __X32_SYSCALL_BIT 0x40000000UL
# ifdef __i386__
# include <asm/unistd_32.h>
diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h
index 57bb48854c..e8ebec1cdc 100644
--- a/linux-headers/asm-x86/unistd_32.h
+++ b/linux-headers/asm-x86/unistd_32.h
@@ -424,5 +424,7 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#endif /* _ASM_X86_UNISTD_32_H */
diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h
index fe6aa0688a..a2f863d549 100644
--- a/linux-headers/asm-x86/unistd_64.h
+++ b/linux-headers/asm-x86/unistd_64.h
@@ -346,5 +346,7 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#endif /* _ASM_X86_UNISTD_64_H */
diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h
index 09cca49ba7..4cdc67d848 100644
--- a/linux-headers/asm-x86/unistd_x32.h
+++ b/linux-headers/asm-x86/unistd_x32.h
@@ -299,6 +299,8 @@
#define __NR_fsconfig (__X32_SYSCALL_BIT + 431)
#define __NR_fsmount (__X32_SYSCALL_BIT + 432)
#define __NR_fspick (__X32_SYSCALL_BIT + 433)
+#define __NR_pidfd_open (__X32_SYSCALL_BIT + 434)
+#define __NR_clone3 (__X32_SYSCALL_BIT + 435)
#define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512)
#define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513)
#define __NR_ioctl (__X32_SYSCALL_BIT + 514)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 18892d6541..3d9b18f7f8 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -116,7 +116,7 @@ struct kvm_irq_level {
* ACPI gsi notion of irq.
* For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
* For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
- * For ARM: See Documentation/virtual/kvm/api.txt
+ * For ARM: See Documentation/virt/kvm/api.txt
*/
union {
__u32 irq;
@@ -243,6 +243,8 @@ struct kvm_hyperv_exit {
#define KVM_INTERNAL_ERROR_SIMUL_EX 2
/* Encounter unexpected vm-exit due to delivery event. */
#define KVM_INTERNAL_ERROR_DELIVERY_EV 3
+/* Encounter unexpected vm-exit reason */
+#define KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON 4
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
@@ -995,6 +997,9 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_SVE 170
#define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
#define KVM_CAP_ARM_PTRAUTH_GENERIC 172
+#define KVM_CAP_PMU_EVENT_FILTER 173
+#define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174
+#define KVM_CAP_HYPERV_DIRECT_TLBFLUSH 175
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1085,7 +1090,7 @@ struct kvm_xen_hvm_config {
*
* KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
* the irqfd to operate in resampling mode for level triggered interrupt
- * emulation. See Documentation/virtual/kvm/api.txt.
+ * emulation. See Documentation/virt/kvm/api.txt.
*/
#define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
@@ -1141,6 +1146,7 @@ struct kvm_dirty_tlb {
#define KVM_REG_S390 0x5000000000000000ULL
#define KVM_REG_ARM64 0x6000000000000000ULL
#define KVM_REG_MIPS 0x7000000000000000ULL
+#define KVM_REG_RISCV 0x8000000000000000ULL
#define KVM_REG_SIZE_SHIFT 52
#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
@@ -1329,6 +1335,8 @@ struct kvm_s390_ucas_mapping {
#define KVM_PPC_GET_RMMU_INFO _IOW(KVMIO, 0xb0, struct kvm_ppc_rmmu_info)
/* Available with KVM_CAP_PPC_GET_CPU_CHAR */
#define KVM_PPC_GET_CPU_CHAR _IOR(KVMIO, 0xb1, struct kvm_ppc_cpu_char)
+/* Available with KVM_CAP_PMU_EVENT_FILTER */
+#define KVM_SET_PMU_EVENT_FILTER _IOW(KVMIO, 0xb2, struct kvm_pmu_event_filter)
/* ioctl for vm fd */
#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)
diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h
index 36bbe17d8f..34c39690c0 100644
--- a/linux-headers/linux/psp-sev.h
+++ b/linux-headers/linux/psp-sev.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Userspace interface for AMD Secure Encrypted Virtualization (SEV)
* platform management commands.
@@ -7,10 +8,6 @@
* Author: Brijesh Singh <brijesh.singh@amd.com>
*
* SEV API specification is available at: https://developer.amd.com/sev/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef __PSP_SEV_USER_H__
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 24f505199f..fb10370d29 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -295,15 +295,38 @@ struct vfio_region_info_cap_type {
__u32 subtype; /* type specific */
};
+/*
+ * List of region types, global per bus driver.
+ * If you introduce a new type, please add it here.
+ */
+
+/* PCI region type containing a PCI vendor part */
#define VFIO_REGION_TYPE_PCI_VENDOR_TYPE (1 << 31)
#define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff)
+#define VFIO_REGION_TYPE_GFX (1)
+#define VFIO_REGION_TYPE_CCW (2)
+
+/* sub-types for VFIO_REGION_TYPE_PCI_* */
-/* 8086 Vendor sub-types */
+/* 8086 vendor PCI sub-types */
#define VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION (1)
#define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2)
#define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3)
-#define VFIO_REGION_TYPE_GFX (1)
+/* 10de vendor PCI sub-types */
+/*
+ * NVIDIA GPU NVlink2 RAM is coherent RAM mapped onto the host address space.
+ */
+#define VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM (1)
+
+/* 1014 vendor PCI sub-types */
+/*
+ * IBM NPU NVlink2 ATSD (Address Translation Shootdown) register of NPU
+ * to do TLB invalidation on a GPU.
+ */
+#define VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD (1)
+
+/* sub-types for VFIO_REGION_TYPE_GFX */
#define VFIO_REGION_SUBTYPE_GFX_EDID (1)
/**
@@ -353,26 +376,10 @@ struct vfio_region_gfx_edid {
#define VFIO_DEVICE_GFX_LINK_STATE_DOWN 2
};
-#define VFIO_REGION_TYPE_CCW (2)
-/* ccw sub-types */
+/* sub-types for VFIO_REGION_TYPE_CCW */
#define VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD (1)
/*
- * 10de vendor sub-type
- *
- * NVIDIA GPU NVlink2 RAM is coherent RAM mapped onto the host address space.
- */
-#define VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM (1)
-
-/*
- * 1014 vendor sub-type
- *
- * IBM NPU NVlink2 ATSD (Address Translation Shootdown) register of NPU
- * to do TLB invalidation on a GPU.
- */
-#define VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD (1)
-
-/*
* The MSIX mappable capability informs that MSIX data of a BAR can be mmapped
* which allows direct access to non-MSIX registers which happened to be within
* the same system page.
@@ -714,7 +721,31 @@ struct vfio_iommu_type1_info {
__u32 argsz;
__u32 flags;
#define VFIO_IOMMU_INFO_PGSIZES (1 << 0) /* supported page sizes info */
- __u64 iova_pgsizes; /* Bitmap of supported page sizes */
+#define VFIO_IOMMU_INFO_CAPS (1 << 1) /* Info supports caps */
+ __u64 iova_pgsizes; /* Bitmap of supported page sizes */
+ __u32 cap_offset; /* Offset within info struct of first cap */
+};
+
+/*
+ * The IOVA capability allows to report the valid IOVA range(s)
+ * excluding any non-relaxable reserved regions exposed by
+ * devices attached to the container. Any DMA map attempt
+ * outside the valid iova range will return error.
+ *
+ * The structures below define version 1 of this capability.
+ */
+#define VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE 1
+
+struct vfio_iova_range {
+ __u64 start;
+ __u64 end;
+};
+
+struct vfio_iommu_type1_info_cap_iova_range {
+ struct vfio_info_cap_header header;
+ __u32 nr_iovas;
+ __u32 reserved;
+ struct vfio_iova_range iova_ranges[];
};
#define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c
index 90423a35de..6f7b6d801b 100644
--- a/target/arm/arm-semi.c
+++ b/target/arm/arm-semi.c
@@ -59,6 +59,7 @@
#define TARGET_SYS_HEAPINFO 0x16
#define TARGET_SYS_EXIT 0x18
#define TARGET_SYS_SYNCCACHE 0x19
+#define TARGET_SYS_EXIT_EXTENDED 0x20
/* ADP_Stopped_ApplicationExit is used for exit(0),
* anything else is implemented as exit(1) */
@@ -106,43 +107,169 @@ static int open_modeflags[12] = {
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
-#ifdef CONFIG_USER_ONLY
-static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
+typedef enum GuestFDType {
+ GuestFDUnused = 0,
+ GuestFDHost = 1,
+ GuestFDGDB = 2,
+ GuestFDFeatureFile = 3,
+} GuestFDType;
+
+/*
+ * Guest file descriptors are integer indexes into an array of
+ * these structures (we will dynamically resize as necessary).
+ */
+typedef struct GuestFD {
+ GuestFDType type;
+ union {
+ int hostfd;
+ target_ulong featurefile_offset;
+ };
+} GuestFD;
+
+static GArray *guestfd_array;
+
+/*
+ * Allocate a new guest file descriptor and return it; if we
+ * couldn't allocate a new fd then return -1.
+ * This is a fairly simplistic implementation because we don't
+ * expect that most semihosting guest programs will make very
+ * heavy use of opening and closing fds.
+ */
+static int alloc_guestfd(void)
{
- if (code == (uint32_t)-1)
- ts->swi_errno = errno;
- return code;
+ guint i;
+
+ if (!guestfd_array) {
+ /* New entries zero-initialized, i.e. type GuestFDUnused */
+ guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
+ }
+
+ for (i = 0; i < guestfd_array->len; i++) {
+ GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
+
+ if (gf->type == GuestFDUnused) {
+ return i;
+ }
+ }
+
+ /* All elements already in use: expand the array */
+ g_array_set_size(guestfd_array, i + 1);
+ return i;
}
-#else
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+
+/*
+ * Look up the guestfd in the data structure; return NULL
+ * for out of bounds, but don't check whether the slot is unused.
+ * This is used internally by the other guestfd functions.
+ */
+static GuestFD *do_get_guestfd(int guestfd)
{
- return code;
+ if (!guestfd_array) {
+ return NULL;
+ }
+
+ if (guestfd < 0 || guestfd >= guestfd_array->len) {
+ return NULL;
+ }
+
+ return &g_array_index(guestfd_array, GuestFD, guestfd);
+}
+
+/*
+ * Associate the specified guest fd (which must have been
+ * allocated via alloc_fd() and not previously used) with
+ * the specified host/gdb fd.
+ */
+static void associate_guestfd(int guestfd, int hostfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
+ gf->hostfd = hostfd;
+}
+
+/*
+ * Deallocate the specified guest file descriptor. This doesn't
+ * close the host fd, it merely undoes the work of alloc_fd().
+ */
+static void dealloc_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = GuestFDUnused;
+}
+
+/*
+ * Given a guest file descriptor, get the associated struct.
+ * If the fd is not valid, return NULL. This is the function
+ * used by the various semihosting calls to validate a handle
+ * from the guest.
+ * Note: calling alloc_guestfd() or dealloc_guestfd() will
+ * invalidate any GuestFD* obtained by calling this function.
+ */
+static GuestFD *get_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ if (!gf || gf->type == GuestFDUnused) {
+ return NULL;
+ }
+ return gf;
}
+/*
+ * The semihosting API has no concept of its errno being thread-safe,
+ * as the API design predates SMP CPUs and was intended as a simple
+ * real-hardware set of debug functionality. For QEMU, we make the
+ * errno be per-thread in linux-user mode; in softmmu it is a simple
+ * global, and we assume that the guest takes care of avoiding any races.
+ */
+#ifndef CONFIG_USER_ONLY
+static target_ulong syscall_err;
+
#include "exec/softmmu-semi.h"
#endif
-static target_ulong arm_semi_syscall_len;
+static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+{
+ if (code == (uint32_t)-1) {
+#ifdef CONFIG_USER_ONLY
+ CPUState *cs = env_cpu(env);
+ TaskState *ts = cs->opaque;
-#if !defined(CONFIG_USER_ONLY)
-static target_ulong syscall_err;
+ ts->swi_errno = errno;
+#else
+ syscall_err = errno;
#endif
+ }
+ return code;
+}
-static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static inline uint32_t get_swi_errno(CPUARMState *env)
{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
#ifdef CONFIG_USER_ONLY
+ CPUState *cs = env_cpu(env);
TaskState *ts = cs->opaque;
+
+ return ts->swi_errno;
+#else
+ return syscall_err;
#endif
+}
+
+static target_ulong arm_semi_syscall_len;
+
+static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
if (ret == (target_ulong)-1) {
-#ifdef CONFIG_USER_ONLY
- ts->swi_errno = err;
-#else
- syscall_err = err;
-#endif
+ errno = err;
+ set_swi_errno(env, -1);
reg0 = ret;
} else {
/* Fixup syscalls that use nonstardard return conventions. */
@@ -199,11 +326,30 @@ static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
} else {
env->regs[0] = size;
}
-#ifdef CONFIG_USER_ONLY
- ((TaskState *)cs->opaque)->swi_errno = err;
-#else
- syscall_err = err;
-#endif
+ errno = err;
+ set_swi_errno(env, -1);
+}
+
+static int arm_semi_open_guestfd;
+
+static void arm_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ if (ret == (target_ulong)-1) {
+ errno = err;
+ set_swi_errno(env, -1);
+ dealloc_guestfd(arm_semi_open_guestfd);
+ } else {
+ associate_guestfd(arm_semi_open_guestfd, ret);
+ ret = arm_semi_open_guestfd;
+ }
+
+ if (is_a64(env)) {
+ env->xregs[0] = ret;
+ } else {
+ env->regs[0] = ret;
+ }
}
static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
@@ -216,26 +362,289 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
gdb_do_syscallv(cb, fmt, va);
va_end(va);
- /* FIXME: we are implicitly relying on the syscall completing
- * before this point, which is not guaranteed. We should
- * put in an explicit synchronization between this and
- * the callback function.
+ /*
+ * FIXME: in softmmu mode, the gdbstub will schedule our callback
+ * to occur, but will not actually call it to complete the syscall
+ * until after this function has returned and we are back in the
+ * CPU main loop. Therefore callers to this function must not
+ * do anything with its return value, because it is not necessarily
+ * the result of the syscall, but could just be the old value of X0.
+ * The only thing safe to do with this is that the callers of
+ * do_arm_semihosting() will write it straight back into X0.
+ * (In linux-user mode, the callback will have happened before
+ * gdb_do_syscallv() returns.)
+ *
+ * We should tidy this up so neither this function nor
+ * do_arm_semihosting() return a value, so the mistake of
+ * doing something with the return value is not possible to make.
*/
return is_a64(env) ? env->xregs[0] : env->regs[0];
}
+/*
+ * Types for functions implementing various semihosting calls
+ * for specific types of guest file descriptor. These must all
+ * do the work and return the required return value for the guest,
+ * setting the guest errno if appropriate.
+ */
+typedef uint32_t sys_closefn(ARMCPU *cpu, GuestFD *gf);
+typedef uint32_t sys_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len);
+typedef uint32_t sys_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len);
+typedef uint32_t sys_isattyfn(ARMCPU *cpu, GuestFD *gf);
+typedef uint32_t sys_seekfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong offset);
+typedef uint32_t sys_flenfn(ARMCPU *cpu, GuestFD *gf);
+
+static uint32_t host_closefn(ARMCPU *cpu, GuestFD *gf)
+{
+ CPUARMState *env = &cpu->env;
+
+ return set_swi_errno(env, close(gf->hostfd));
+}
+
+static uint32_t host_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ uint32_t ret;
+ CPUARMState *env = &cpu->env;
+ char *s = lock_user(VERIFY_READ, buf, len, 1);
+ if (!s) {
+ /* Return bytes not written on error */
+ return len;
+ }
+ ret = set_swi_errno(env, write(gf->hostfd, s, len));
+ unlock_user(s, buf, 0);
+ if (ret == (uint32_t)-1) {
+ ret = 0;
+ }
+ /* Return bytes not written */
+ return len - ret;
+}
+
+static uint32_t host_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ uint32_t ret;
+ CPUARMState *env = &cpu->env;
+ char *s = lock_user(VERIFY_WRITE, buf, len, 0);
+ if (!s) {
+ /* return bytes not read */
+ return len;
+ }
+ do {
+ ret = set_swi_errno(env, read(gf->hostfd, s, len));
+ } while (ret == -1 && errno == EINTR);
+ unlock_user(s, buf, len);
+ if (ret == (uint32_t)-1) {
+ ret = 0;
+ }
+ /* Return bytes not read */
+ return len - ret;
+}
+
+static uint32_t host_isattyfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return isatty(gf->hostfd);
+}
+
+static uint32_t host_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
+{
+ CPUARMState *env = &cpu->env;
+ uint32_t ret = set_swi_errno(env, lseek(gf->hostfd, offset, SEEK_SET));
+ if (ret == (uint32_t)-1) {
+ return -1;
+ }
+ return 0;
+}
+
+static uint32_t host_flenfn(ARMCPU *cpu, GuestFD *gf)
+{
+ CPUARMState *env = &cpu->env;
+ struct stat buf;
+ uint32_t ret = set_swi_errno(env, fstat(gf->hostfd, &buf));
+ if (ret == (uint32_t)-1) {
+ return -1;
+ }
+ return buf.st_size;
+}
+
+static uint32_t gdb_closefn(ARMCPU *cpu, GuestFD *gf)
+{
+ return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd);
+}
+
+static uint32_t gdb_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ arm_semi_syscall_len = len;
+ return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
+ gf->hostfd, buf, len);
+}
+
+static uint32_t gdb_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ arm_semi_syscall_len = len;
+ return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
+ gf->hostfd, buf, len);
+}
+
+static uint32_t gdb_isattyfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", gf->hostfd);
+}
+
+static uint32_t gdb_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
+{
+ return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
+ gf->hostfd, offset);
+}
+
+static uint32_t gdb_flenfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
+ gf->hostfd, arm_flen_buf(cpu));
+}
+
+#define SHFB_MAGIC_0 0x53
+#define SHFB_MAGIC_1 0x48
+#define SHFB_MAGIC_2 0x46
+#define SHFB_MAGIC_3 0x42
+
+/* Feature bits reportable in feature byte 0 */
+#define SH_EXT_EXIT_EXTENDED (1 << 0)
+#define SH_EXT_STDOUT_STDERR (1 << 1)
+
+static const uint8_t featurefile_data[] = {
+ SHFB_MAGIC_0,
+ SHFB_MAGIC_1,
+ SHFB_MAGIC_2,
+ SHFB_MAGIC_3,
+ SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
+};
+
+static void init_featurefile_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = GuestFDFeatureFile;
+ gf->featurefile_offset = 0;
+}
+
+static uint32_t featurefile_closefn(ARMCPU *cpu, GuestFD *gf)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+static uint32_t featurefile_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ /* This fd can never be open for writing */
+ CPUARMState *env = &cpu->env;
+
+ errno = EBADF;
+ return set_swi_errno(env, -1);
+}
+
+static uint32_t featurefile_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ uint32_t i;
+#ifndef CONFIG_USER_ONLY
+ CPUARMState *env = &cpu->env;
+#endif
+ char *s;
+
+ s = lock_user(VERIFY_WRITE, buf, len, 0);
+ if (!s) {
+ return len;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (gf->featurefile_offset >= sizeof(featurefile_data)) {
+ break;
+ }
+ s[i] = featurefile_data[gf->featurefile_offset];
+ gf->featurefile_offset++;
+ }
+
+ unlock_user(s, buf, len);
+
+ /* Return number of bytes not read */
+ return len - i;
+}
+
+static uint32_t featurefile_isattyfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return 0;
+}
+
+static uint32_t featurefile_seekfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong offset)
+{
+ gf->featurefile_offset = offset;
+ return 0;
+}
+
+static uint32_t featurefile_flenfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return sizeof(featurefile_data);
+}
+
+typedef struct GuestFDFunctions {
+ sys_closefn *closefn;
+ sys_writefn *writefn;
+ sys_readfn *readfn;
+ sys_isattyfn *isattyfn;
+ sys_seekfn *seekfn;
+ sys_flenfn *flenfn;
+} GuestFDFunctions;
+
+static const GuestFDFunctions guestfd_fns[] = {
+ [GuestFDHost] = {
+ .closefn = host_closefn,
+ .writefn = host_writefn,
+ .readfn = host_readfn,
+ .isattyfn = host_isattyfn,
+ .seekfn = host_seekfn,
+ .flenfn = host_flenfn,
+ },
+ [GuestFDGDB] = {
+ .closefn = gdb_closefn,
+ .writefn = gdb_writefn,
+ .readfn = gdb_readfn,
+ .isattyfn = gdb_isattyfn,
+ .seekfn = gdb_seekfn,
+ .flenfn = gdb_flenfn,
+ },
+ [GuestFDFeatureFile] = {
+ .closefn = featurefile_closefn,
+ .writefn = featurefile_writefn,
+ .readfn = featurefile_readfn,
+ .isattyfn = featurefile_isattyfn,
+ .seekfn = featurefile_seekfn,
+ .flenfn = featurefile_flenfn,
+ },
+};
+
/* Read the input value from the argument block; fail the semihosting
* call if the memory read fails.
*/
#define GET_ARG(n) do { \
if (is_a64(env)) { \
if (get_user_u64(arg ## n, args + (n) * 8)) { \
- return -1; \
+ errno = EFAULT; \
+ return set_swi_errno(env, -1); \
} \
} else { \
if (get_user_u32(arg ## n, args + (n) * 4)) { \
- return -1; \
+ errno = EFAULT; \
+ return set_swi_errno(env, -1); \
} \
} \
} while (0)
@@ -264,11 +673,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
int nr;
uint32_t ret;
uint32_t len;
-#ifdef CONFIG_USER_ONLY
- TaskState *ts = cs->opaque;
-#else
- CPUARMState *ts = env;
-#endif
+ GuestFD *gf;
if (is_a64(env)) {
/* Note that the syscall number is in W0, not X0 */
@@ -281,38 +686,90 @@ target_ulong do_arm_semihosting(CPUARMState *env)
switch (nr) {
case TARGET_SYS_OPEN:
+ {
+ int guestfd;
+
GET_ARG(0);
GET_ARG(1);
GET_ARG(2);
s = lock_user_string(arg0);
if (!s) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
if (arg1 >= 12) {
unlock_user(s, arg0, 0);
- return (uint32_t)-1;
+ errno = EINVAL;
+ return set_swi_errno(env, -1);
+ }
+
+ guestfd = alloc_guestfd();
+ if (guestfd < 0) {
+ unlock_user(s, arg0, 0);
+ errno = EMFILE;
+ return set_swi_errno(env, -1);
}
+
if (strcmp(s, ":tt") == 0) {
- int result_fileno = arg1 < 4 ? STDIN_FILENO : STDOUT_FILENO;
+ int result_fileno;
+
+ /*
+ * We implement SH_EXT_STDOUT_STDERR, so:
+ * open for read == stdin
+ * open for write == stdout
+ * open for append == stderr
+ */
+ if (arg1 < 4) {
+ result_fileno = STDIN_FILENO;
+ } else if (arg1 < 8) {
+ result_fileno = STDOUT_FILENO;
+ } else {
+ result_fileno = STDERR_FILENO;
+ }
+ associate_guestfd(guestfd, result_fileno);
unlock_user(s, arg0, 0);
- return result_fileno;
+ return guestfd;
}
+ if (strcmp(s, ":semihosting-features") == 0) {
+ unlock_user(s, arg0, 0);
+ /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
+ if (arg1 != 0 && arg1 != 1) {
+ dealloc_guestfd(guestfd);
+ errno = EACCES;
+ return set_swi_errno(env, -1);
+ }
+ init_featurefile_guestfd(guestfd);
+ return guestfd;
+ }
+
if (use_gdb_syscalls()) {
- ret = arm_gdb_syscall(cpu, arm_semi_cb, "open,%s,%x,1a4", arg0,
+ arm_semi_open_guestfd = guestfd;
+ ret = arm_gdb_syscall(cpu, arm_semi_open_cb, "open,%s,%x,1a4", arg0,
(int)arg2+1, gdb_open_modeflags[arg1]);
} else {
- ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
+ ret = set_swi_errno(env, open(s, open_modeflags[arg1], 0644));
+ if (ret == (uint32_t)-1) {
+ dealloc_guestfd(guestfd);
+ } else {
+ associate_guestfd(guestfd, ret);
+ ret = guestfd;
+ }
}
unlock_user(s, arg0, 0);
return ret;
+ }
case TARGET_SYS_CLOSE:
GET_ARG(0);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", arg0);
- } else {
- return set_swi_errno(ts, close(arg0));
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ ret = guestfd_fns[gf->type].closefn(cpu, gf);
+ dealloc_guestfd(arg0);
+ return ret;
case TARGET_SYS_WRITEC:
qemu_semihosting_console_outc(env, args);
return 0xdeadbeef;
@@ -323,83 +780,61 @@ target_ulong do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
GET_ARG(2);
len = arg2;
- if (use_gdb_syscalls()) {
- arm_semi_syscall_len = len;
- return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
- arg0, arg1, len);
- } else {
- s = lock_user(VERIFY_READ, arg1, len, 1);
- if (!s) {
- /* Return bytes not written on error */
- return len;
- }
- ret = set_swi_errno(ts, write(arg0, s, len));
- unlock_user(s, arg1, 0);
- if (ret == (uint32_t)-1) {
- ret = 0;
- }
- /* Return bytes not written */
- return len - ret;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].writefn(cpu, gf, arg1, len);
case TARGET_SYS_READ:
GET_ARG(0);
GET_ARG(1);
GET_ARG(2);
len = arg2;
- if (use_gdb_syscalls()) {
- arm_semi_syscall_len = len;
- return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
- arg0, arg1, len);
- } else {
- s = lock_user(VERIFY_WRITE, arg1, len, 0);
- if (!s) {
- /* return bytes not read */
- return len;
- }
- do {
- ret = set_swi_errno(ts, read(arg0, s, len));
- } while (ret == -1 && errno == EINTR);
- unlock_user(s, arg1, len);
- if (ret == (uint32_t)-1) {
- ret = 0;
- }
- /* Return bytes not read */
- return len - ret;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].readfn(cpu, gf, arg1, len);
case TARGET_SYS_READC:
qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
return 0;
case TARGET_SYS_ISTTY:
GET_ARG(0);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", arg0);
- } else {
- return isatty(arg0);
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].isattyfn(cpu, gf);
case TARGET_SYS_SEEK:
GET_ARG(0);
GET_ARG(1);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
- arg0, arg1);
- } else {
- ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET));
- if (ret == (uint32_t)-1)
- return -1;
- return 0;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].seekfn(cpu, gf, arg1);
case TARGET_SYS_FLEN:
GET_ARG(0);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
- arg0, arm_flen_buf(cpu));
- } else {
- struct stat buf;
- ret = set_swi_errno(ts, fstat(arg0, &buf));
- if (ret == (uint32_t)-1)
- return -1;
- return buf.st_size;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].flenfn(cpu, gf);
case TARGET_SYS_TMPNAM:
qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
return -1;
@@ -412,10 +847,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} else {
s = lock_user_string(arg0);
if (!s) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
- ret = set_swi_errno(ts, remove(s));
+ ret = set_swi_errno(env, remove(s));
unlock_user(s, arg0, 0);
}
return ret;
@@ -431,11 +866,12 @@ target_ulong do_arm_semihosting(CPUARMState *env)
char *s2;
s = lock_user_string(arg0);
s2 = lock_user_string(arg2);
- if (!s || !s2)
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- ret = (uint32_t)-1;
- else
- ret = set_swi_errno(ts, rename(s, s2));
+ if (!s || !s2) {
+ errno = EFAULT;
+ ret = set_swi_errno(env, -1);
+ } else {
+ ret = set_swi_errno(env, rename(s, s2));
+ }
if (s2)
unlock_user(s2, arg2, 0);
if (s)
@@ -445,7 +881,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
case TARGET_SYS_CLOCK:
return clock() / (CLOCKS_PER_SEC / 100);
case TARGET_SYS_TIME:
- return set_swi_errno(ts, time(NULL));
+ return set_swi_errno(env, time(NULL));
case TARGET_SYS_SYSTEM:
GET_ARG(0);
GET_ARG(1);
@@ -455,19 +891,15 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} else {
s = lock_user_string(arg0);
if (!s) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
- ret = set_swi_errno(ts, system(s));
+ ret = set_swi_errno(env, system(s));
unlock_user(s, arg0, 0);
return ret;
}
case TARGET_SYS_ERRNO:
-#ifdef CONFIG_USER_ONLY
- return ts->swi_errno;
-#else
- return syscall_err;
-#endif
+ return get_swi_errno(env);
case TARGET_SYS_GET_CMDLINE:
{
/* Build a command-line from the original argv.
@@ -490,6 +922,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
int status = 0;
#if !defined(CONFIG_USER_ONLY)
const char *cmdline;
+#else
+ TaskState *ts = cs->opaque;
#endif
GET_ARG(0);
GET_ARG(1);
@@ -516,19 +950,22 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (output_size > input_size) {
/* Not enough space to store command-line arguments. */
- return -1;
+ errno = E2BIG;
+ return set_swi_errno(env, -1);
}
/* Adjust the command-line length. */
if (SET_ARG(1, output_size - 1)) {
/* Couldn't write back to argument block */
- return -1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
/* Lock the buffer on the ARM side. */
output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
if (!output_buffer) {
- return -1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
/* Copy the command-line arguments. */
@@ -543,7 +980,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (copy_from_user(output_buffer, ts->info->arg_start,
output_size)) {
- status = -1;
+ errno = EFAULT;
+ status = set_swi_errno(env, -1);
goto out;
}
@@ -565,6 +1003,9 @@ target_ulong do_arm_semihosting(CPUARMState *env)
target_ulong retvals[4];
target_ulong limit;
int i;
+#ifdef CONFIG_USER_ONLY
+ TaskState *ts = cs->opaque;
+#endif
GET_ARG(0);
@@ -613,17 +1054,21 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (fail) {
/* Couldn't write back to argument block */
- return -1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
}
return 0;
}
case TARGET_SYS_EXIT:
- if (is_a64(env)) {
+ case TARGET_SYS_EXIT_EXTENDED:
+ if (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(env)) {
/*
- * The A64 version of this call takes a parameter block,
+ * The A64 version of SYS_EXIT takes a parameter block,
* so the application-exit type can return a subcode which
* is the exit status code from the application.
+ * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
+ * which allows A32/T32 guests to also provide a status code.
*/
GET_ARG(0);
GET_ARG(1);
@@ -635,8 +1080,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
}
} else {
/*
- * ARM specifies only Stopped_ApplicationExit as normal
- * exit, everything else is considered an error
+ * The A32/T32 version of SYS_EXIT specifies only
+ * Stopped_ApplicationExit as normal exit, but does not
+ * allow the guest to specify the exit status code.
+ * Everything else is considered an error.
*/
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2399c14471..13813fb213 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -576,16 +576,16 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
uint32_t linestate_bit;
+ int irq_id;
switch (irq) {
case ARM_CPU_IRQ:
- kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
+ irq_id = KVM_ARM_IRQ_CPU_IRQ;
linestate_bit = CPU_INTERRUPT_HARD;
break;
case ARM_CPU_FIQ:
- kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
+ irq_id = KVM_ARM_IRQ_CPU_FIQ;
linestate_bit = CPU_INTERRUPT_FIQ;
break;
default:
@@ -597,9 +597,7 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
} else {
env->irq_line_state &= ~linestate_bit;
}
-
- kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
- kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
+ kvm_arm_set_irq(cs->cpu_index, KVM_ARM_IRQ_TYPE_CPU, irq_id, !!level);
#endif
}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b2eaa50b8d..b473c63edb 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -182,6 +182,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
+ int ret = 0;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -195,7 +196,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
- return 0;
+ if (ms->smp.cpus > 256 &&
+ !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
+ error_report("Using more than 256 vcpus requires a host kernel "
+ "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
+ ret = -EINVAL;
+ }
+
+ return ret;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
@@ -744,6 +752,18 @@ int kvm_arm_vgic_probe(void)
}
}
+int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level)
+{
+ int kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT) | irq;
+ int cpu_idx1 = cpu % 256;
+ int cpu_idx2 = cpu / 256;
+
+ kvm_irq |= (cpu_idx1 << KVM_ARM_IRQ_VCPU_SHIFT) |
+ (cpu_idx2 << KVM_ARM_IRQ_VCPU2_SHIFT);
+
+ return kvm_set_irq(kvm_state, kvm_irq, !!level);
+}
+
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint64_t address, uint32_t data, PCIDevice *dev)
{
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index b3106c8600..b4e19457a0 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -253,6 +253,7 @@ int kvm_arm_vgic_probe(void);
void kvm_arm_pmu_set_irq(CPUState *cs, int irq);
void kvm_arm_pmu_init(CPUState *cs);
+int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level);
#else
diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index 5b20e91599..e16c30ce57 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -67,12 +67,13 @@ static void qemu_clock_step(uint64_t ns)
static void check_set_count(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 1000);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 1000);
g_assert_false(triggered);
ptimer_free(ptimer);
@@ -81,17 +82,20 @@ static void check_set_count(gconstpointer arg)
static void check_set_limit(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_limit(ptimer, 1000, 0);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 1000);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_limit(ptimer, 2000, 1);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 2000);
g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 2000);
g_assert_false(triggered);
@@ -101,22 +105,25 @@ static void check_set_limit(gconstpointer arg)
static void check_oneshot(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_set_count(ptimer, 10);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 2 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_stop(ptimer);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
g_assert_false(triggered);
@@ -126,7 +133,9 @@ static void check_oneshot(gconstpointer arg)
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 7 + 1);
@@ -157,28 +166,36 @@ static void check_oneshot(gconstpointer arg)
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 10);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(20000000 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_limit(ptimer, 9, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(20000000 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 20);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 19 + 1);
@@ -190,7 +207,9 @@ static void check_oneshot(gconstpointer arg)
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
g_assert_true(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_stop(ptimer);
+ ptimer_transaction_commit(ptimer);
triggered = false;
@@ -204,8 +223,7 @@ static void check_oneshot(gconstpointer arg)
static void check_periodic(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
bool no_immediate_reload = (*policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
@@ -214,9 +232,11 @@ static void check_periodic(gconstpointer arg)
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_set_limit(ptimer, 10, 1);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
g_assert_false(triggered);
@@ -245,7 +265,9 @@ static void check_periodic(gconstpointer arg)
(no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 20);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 20);
g_assert_false(triggered);
@@ -268,7 +290,9 @@ static void check_periodic(gconstpointer arg)
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 3);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
g_assert_false(triggered);
@@ -284,7 +308,9 @@ static void check_periodic(gconstpointer arg)
(no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
g_assert_true(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_stop(ptimer);
+ ptimer_transaction_commit(ptimer);
triggered = false;
qemu_clock_step(2000000);
@@ -293,8 +319,10 @@ static void check_periodic(gconstpointer arg)
(no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 3);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 3 + 1);
@@ -310,7 +338,9 @@ static void check_periodic(gconstpointer arg)
(no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==,
no_immediate_reload ? 0 : 10);
@@ -348,7 +378,9 @@ static void check_periodic(gconstpointer arg)
(no_round_down ? 8 : 7) + (wrap_policy ? 1 : 0));
g_assert_true(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_stop(ptimer);
+ ptimer_transaction_commit(ptimer);
triggered = false;
@@ -358,8 +390,13 @@ static void check_periodic(gconstpointer arg)
(no_round_down ? 8 : 7) + (wrap_policy ? 1 : 0));
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
+
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 + 1);
@@ -372,23 +409,26 @@ static void check_periodic(gconstpointer arg)
static void check_on_the_fly_mode_change(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_set_limit(ptimer, 10, 1);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 9 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
g_assert_false(triggered);
@@ -403,7 +443,9 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
qemu_clock_step(2000000 * 9);
+ ptimer_transaction_begin(ptimer);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==,
(no_round_down ? 1 : 0) + (wrap_policy ? 1 : 0));
@@ -419,22 +461,25 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
static void check_on_the_fly_period_change(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_set_limit(ptimer, 8, 1);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 4 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 4000000);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
qemu_clock_step(4000000 * 2 + 1);
@@ -452,22 +497,25 @@ static void check_on_the_fly_period_change(gconstpointer arg)
static void check_on_the_fly_freq_change(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_freq(ptimer, 500);
ptimer_set_limit(ptimer, 8, 1);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 4 + 1);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
g_assert_false(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_set_freq(ptimer, 250);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
qemu_clock_step(2000000 * 4 + 1);
@@ -485,13 +533,14 @@ static void check_on_the_fly_freq_change(gconstpointer arg)
static void check_run_with_period_0(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 99);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(10 * NANOSECONDS_PER_SECOND);
@@ -503,8 +552,7 @@ static void check_run_with_period_0(gconstpointer arg)
static void check_run_with_delta_0(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
bool no_immediate_reload = (*policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
@@ -513,9 +561,11 @@ static void check_run_with_delta_0(gconstpointer arg)
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_set_limit(ptimer, 99, 0);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==,
no_immediate_reload ? 0 : 99);
@@ -541,8 +591,10 @@ static void check_run_with_delta_0(gconstpointer arg)
g_assert_false(triggered);
}
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 99);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
}
qemu_clock_step(2000000 + 1);
@@ -562,8 +614,10 @@ static void check_run_with_delta_0(gconstpointer arg)
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 0);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==,
no_immediate_reload ? 0 : 99);
@@ -602,23 +656,26 @@ static void check_run_with_delta_0(gconstpointer arg)
wrap_policy ? 0 : (no_round_down ? 99 : 98));
g_assert_true(triggered);
+ ptimer_transaction_begin(ptimer);
ptimer_stop(ptimer);
+ ptimer_transaction_commit(ptimer);
ptimer_free(ptimer);
}
static void check_periodic_with_load_0(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool continuous_trigger = (*policy & PTIMER_POLICY_CONTINUOUS_TRIGGER);
bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
bool trig_only_on_dec = (*policy & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
@@ -642,8 +699,10 @@ static void check_periodic_with_load_0(gconstpointer arg)
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_count(ptimer, 10);
ptimer_run(ptimer, 0);
+ ptimer_transaction_commit(ptimer);
qemu_clock_step(2000000 * 10 + 1);
@@ -662,22 +721,25 @@ static void check_periodic_with_load_0(gconstpointer arg)
g_assert_false(triggered);
}
+ ptimer_transaction_begin(ptimer);
ptimer_stop(ptimer);
+ ptimer_transaction_commit(ptimer);
ptimer_free(ptimer);
}
static void check_oneshot_with_load_0(gconstpointer arg)
{
const uint8_t *policy = arg;
- QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
- ptimer_state *ptimer = ptimer_init(bh, *policy);
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
bool trig_only_on_dec = (*policy & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
triggered = false;
+ ptimer_transaction_begin(ptimer);
ptimer_set_period(ptimer, 2000000);
ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);