diff options
Diffstat (limited to 'hw')
99 files changed, 1699 insertions, 878 deletions
diff --git a/hw/Kconfig b/hw/Kconfig index b45db3c813..4b53fee4d0 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -27,6 +27,7 @@ source pci-host/Kconfig source pcmcia/Kconfig source pci/Kconfig source rdma/Kconfig +source rtc/Kconfig source scsi/Kconfig source sd/Kconfig source semihosting/Kconfig diff --git a/hw/Makefile.objs b/hw/Makefile.objs index ece6cc3755..fd9750e5f2 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -26,6 +26,7 @@ devices-dirs-y += nvram/ devices-dirs-y += pci/ devices-dirs-$(CONFIG_PCI) += pci-bridge/ pci-host/ devices-dirs-y += pcmcia/ +devices-dirs-y += rtc/ devices-dirs-$(CONFIG_SCSI) += scsi/ devices-dirs-y += sd/ devices-dirs-y += ssi/ diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 51feee8558..51b3cf7a61 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -14,7 +14,7 @@ #include "alpha_sys.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/ide.h" #include "hw/timer/i8254.h" #include "hw/isa/superio.h" diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 52993f84b4..028191ff36 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -88,6 +88,10 @@ struct AspeedBoardState { /* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */ #define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 +/* AST2600 evb hardware value */ +#define AST2600_EVB_HW_STRAP1 0x000000C0 +#define AST2600_EVB_HW_STRAP2 0x00000003 + /* * The max ram region is for firmwares that scan the address space * with load/store to guess how much RAM the SoC has. @@ -187,6 +191,8 @@ static void aspeed_board_init(MachineState *machine, &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", &error_abort); + object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap2, "hw-strap2", + &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs", &error_abort); object_property_set_int(OBJECT(&bmc->soc), machine->smp.cpus, "num-cpus", @@ -308,6 +314,12 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); } +static void ast2600_evb_i2c_init(AspeedBoardState *bmc) +{ + /* Start with some devices on our I2C busses */ + ast2500_evb_i2c_init(bmc); +} + static void romulus_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -455,6 +467,17 @@ static const AspeedBoardConfig aspeed_boards[] = { .num_cs = 2, .i2c_init = witherspoon_bmc_i2c_init, .ram = 512 * MiB, + }, { + .name = MACHINE_TYPE_NAME("ast2600-evb"), + .desc = "Aspeed AST2600 EVB (Cortex A7)", + .soc_name = "ast2600-a0", + .hw_strap1 = AST2600_EVB_HW_STRAP1, + .hw_strap2 = AST2600_EVB_HW_STRAP2, + .fmc_model = "w25q512jv", + .spi_model = "mx66u51235f", + .num_cs = 1, + .i2c_init = ast2600_evb_i2c_init, + .ram = 1 * GiB, }, }; diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index fdcf616c56..17207ae07e 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -58,6 +58,10 @@ static void bcm2835_peripherals_init(Object *obj) /* Interrupt Controller */ sysbus_init_child_obj(obj, "ic", &s->ic, sizeof(s->ic), TYPE_BCM2835_IC); + /* SYS Timer */ + sysbus_init_child_obj(obj, "systimer", &s->systmr, sizeof(s->systmr), + TYPE_BCM2835_SYSTIMER); + /* UART0 */ sysbus_init_child_obj(obj, "uart0", &s->uart0, sizeof(s->uart0), TYPE_PL011); @@ -111,6 +115,10 @@ static void bcm2835_peripherals_init(Object *obj) object_property_add_const_link(OBJECT(&s->dma), "dma-mr", OBJECT(&s->gpu_bus_mr), &error_abort); + /* Thermal */ + sysbus_init_child_obj(obj, "thermal", &s->thermal, sizeof(s->thermal), + TYPE_BCM2835_THERMAL); + /* GPIO */ sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), TYPE_BCM2835_GPIO); @@ -167,6 +175,18 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0)); sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); + /* Sys Timer */ + object_property_set_bool(OBJECT(&s->systmr), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(&s->peri_mr, ST_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systmr), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ, + INTERRUPT_ARM_TIMER)); + /* UART0 */ qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0)); object_property_set_bool(OBJECT(&s->uart0), true, "realized", &err); @@ -321,6 +341,15 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_DMA0 + n)); } + /* THERMAL */ + object_property_set_bool(OBJECT(&s->thermal), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(&s->peri_mr, THERMAL_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0)); + /* GPIO */ object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); if (err) { @@ -339,7 +368,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } 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); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 723aef6bf5..221ff06895 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -16,15 +16,11 @@ #include "hw/arm/raspi_platform.h" #include "hw/sysbus.h" -/* Peripheral base address seen by the CPU */ -#define BCM2836_PERI_BASE 0x3F000000 - -/* "QA7" (Pi2) interrupt controller and mailboxes etc. */ -#define BCM2836_CONTROL_BASE 0x40000000 - struct BCM283XInfo { const char *name; const char *cpu_type; + hwaddr peri_base; /* Peripheral base address seen by the CPU */ + hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */ int clusterid; }; @@ -32,12 +28,16 @@ static const BCM283XInfo bcm283x_socs[] = { { .name = TYPE_BCM2836, .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"), + .peri_base = 0x3f000000, + .ctrl_base = 0x40000000, .clusterid = 0xf, }, #ifdef TARGET_AARCH64 { .name = TYPE_BCM2837, .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"), + .peri_base = 0x3f000000, + .ctrl_base = 0x40000000, .clusterid = 0x0, }, #endif @@ -51,8 +51,9 @@ static void bcm2836_init(Object *obj) int n; for (n = 0; n < BCM283X_NCPUS; n++) { - object_initialize_child(obj, "cpu[*]", &s->cpus[n], sizeof(s->cpus[n]), - info->cpu_type, &error_abort, NULL); + object_initialize_child(obj, "cpu[*]", &s->cpu[n].core, + sizeof(s->cpu[n].core), info->cpu_type, + &error_abort, NULL); } sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control), @@ -104,7 +105,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, - BCM2836_PERI_BASE, 1); + info->peri_base, 1); /* bcm2836 interrupt controller (and mailboxes, etc.) */ object_property_set_bool(OBJECT(&s->control), true, "realized", &err); @@ -113,7 +114,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); @@ -122,11 +123,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) for (n = 0; n < BCM283X_NCPUS; n++) { /* TODO: this should be converted to a property of ARM_CPU */ - s->cpus[n].mp_affinity = (info->clusterid << 8) | n; + s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n; /* set periphbase/CBAR value for CPU-local registers */ - object_property_set_int(OBJECT(&s->cpus[n]), - BCM2836_PERI_BASE + MSYNC_OFFSET, + object_property_set_int(OBJECT(&s->cpu[n].core), + info->peri_base, "reset-cbar", &err); if (err) { error_propagate(errp, err); @@ -134,14 +135,15 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) } /* start powered off if not enabled */ - object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus, + object_property_set_bool(OBJECT(&s->cpu[n].core), n >= s->enabled_cpus, "start-powered-off", &err); if (err) { error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err); + object_property_set_bool(OBJECT(&s->cpu[n].core), true, + "realized", &err); if (err) { error_propagate(errp, err); return; @@ -149,18 +151,18 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) /* Connect irq/fiq outputs from the interrupt controller. */ qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, - qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ)); + qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ)); qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, - qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ)); + qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ)); /* Connect timers from the CPU to the interrupt controller */ - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS, + qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS, qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n)); - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT, + qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT, qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP, + qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP, qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n)); - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC, + qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC, qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); } } diff --git a/hw/arm/collie.c b/hw/arm/collie.c index b1288ccea8..970a4405cc 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -27,9 +27,13 @@ static void collie_init(MachineState *machine) { StrongARMState *s; DriveInfo *dinfo; - MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *sdram = g_new(MemoryRegion, 1); - s = sa1110_init(sysmem, collie_binfo.ram_size, machine->cpu_type); + s = sa1110_init(machine->cpu_type); + + memory_region_allocate_system_memory(sdram, NULL, "strongarm.sdram", + collie_binfo.ram_size); + memory_region_add_subregion(get_system_memory(), SA_SDCS0, sdram); dinfo = drive_get(IF_PFLASH, 0, 0); pflash_cfi01_register(SA_CS0, "collie.fl1", 0x02000000, diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index 304e4d1a29..ef3fc2b6a5 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -53,12 +53,6 @@ typedef struct DigicBoard { const char *rom1_def_filename; } DigicBoard; -static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size) -{ - memory_region_allocate_system_memory(&s->ram, NULL, "ram", ram_size); - memory_region_add_subregion(get_system_memory(), 0, &s->ram); -} - static void digic4_board_init(DigicBoard *board) { Error *err = NULL; @@ -72,7 +66,8 @@ static void digic4_board_init(DigicBoard *board) exit(1); } - digic4_board_setup_ram(s, board->ram_size); + memory_region_allocate_system_memory(&s->ram, NULL, "ram", board->ram_size); + memory_region_add_subregion(get_system_memory(), 0, &s->ram); if (board->add_rom0) { board->add_rom0(s, DIGIC4_ROM0_BASE, board->rom0_def_filename); diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index a9f8a5c868..77fbe1baab 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -405,7 +405,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) * public datasheet which is very similar (implementing * MMC Specification Version 4.0 being the only difference noted) */ - dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); + dev = qdev_create(NULL, TYPE_S3C_SDHCI); qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); qdev_init_nofail(dev); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index f1724d6929..518d935fdf 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -78,7 +78,8 @@ static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) for (n = 0; n < ARRAY_SIZE(smpboot); n++) { smpboot[n] = tswap32(smpboot[n]); } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); + rom_add_blob_fixed_as("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR, + arm_boot_address_space(cpu, info)); } static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 6b24aaacde..f8b620bcc6 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -38,6 +38,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/arm/boot.h" @@ -458,7 +459,7 @@ static void mps2tz_common_init(MachineState *machine) * call the 16MB our "system memory", as it's the largest lump. */ memory_region_allocate_system_memory(&mms->psram, - NULL, "mps.ram", 0x01000000); + NULL, "mps.ram", 16 * MiB); memory_region_add_subregion(system_memory, 0x80000000, &mms->psram); /* The overflow IRQs for all UARTs are ORed together. diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 10efff36b2..d002b126d3 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/arm/boot.h" @@ -146,7 +147,7 @@ static void mps2_common_init(MachineState *machine) * zbt_boot_ctrl is always zero). */ memory_region_allocate_system_memory(&mms->psram, - NULL, "mps.ram", 0x1000000); + NULL, "mps.ram", 16 * MiB); memory_region_add_subregion(system_memory, 0x21000000, &mms->psram); switch (mmc->fpga_type) { diff --git a/hw/arm/musca.c b/hw/arm/musca.c index 68db4b5b38..ba99dd1941 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -32,7 +32,7 @@ #include "hw/misc/tz-mpc.h" #include "hw/misc/tz-ppc.h" #include "hw/misc/unimp.h" -#include "hw/timer/pl031.h" +#include "hw/rtc/pl031.h" #define MUSCA_NUMIRQ_MAX 96 #define MUSCA_PPC_MAX 3 diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index a36971d39a..7e361936a9 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -47,6 +47,7 @@ /* Nokia N8x0 support */ struct n800_s { + MemoryRegion sdram; struct omap_mpu_state_s *mpu; struct rfbi_chip_s blizzard; @@ -1311,11 +1312,14 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p) static void n8x0_init(MachineState *machine, struct arm_boot_info *binfo, int model) { - MemoryRegion *sysmem = get_system_memory(); struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); - int sdram_size = binfo->ram_size; + uint64_t sdram_size = binfo->ram_size; - s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_type); + memory_region_allocate_system_memory(&s->sdram, NULL, "omap2.dram", + sdram_size); + memory_region_add_subregion(get_system_memory(), OMAP2_Q2_BASE, &s->sdram); + + s->mpu = omap2420_mpu_init(&s->sdram, machine->cpu_type); /* Setup peripherals * diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 0400593805..6ce038a453 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -23,6 +23,7 @@ #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" +#include "exec/address-spaces.h" #include "hw/boards.h" #include "hw/hw.h" #include "hw/irq.h" @@ -3858,8 +3859,7 @@ static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr); } -struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, - unsigned long sdram_size, +struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, const char *cpu_type) { int i; @@ -3867,11 +3867,12 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, qemu_irq dma_irqs[6]; DriveInfo *dinfo; SysBusDevice *busdev; + MemoryRegion *system_memory = get_system_memory(); /* Core */ s->mpu_model = omap310; s->cpu = ARM_CPU(cpu_create(cpu_type)); - s->sdram_size = sdram_size; + s->sdram_size = memory_region_size(dram); s->sram_size = OMAP15XX_SRAM_SIZE; s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0); @@ -3880,9 +3881,6 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, omap_clk_init(s); /* Memory-mapped stuff */ - memory_region_allocate_system_memory(&s->emiff_ram, NULL, "omap1.dram", - s->sdram_size); - memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram); memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size, &error_fatal); memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram); @@ -3925,7 +3923,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; /* Register SDRAM and SRAM DMA ports for fast transfers. */ - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram), + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(dram), OMAP_EMIFF_BASE, s->sdram_size); soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram), OMAP_IMIF_BASE, s->sram_size); diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index bd7ddff983..457f152bac 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -22,6 +22,7 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "cpu.h" +#include "exec/address-spaces.h" #include "sysemu/blockdev.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" @@ -2276,8 +2277,7 @@ static const struct dma_irq_map omap2_dma_irq_map[] = { { 0, OMAP_INT_24XX_SDMA_IRQ3 }, }; -struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, - unsigned long sdram_size, +struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, const char *cpu_type) { struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1); @@ -2286,11 +2286,11 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, int i; SysBusDevice *busdev; struct omap_target_agent_s *ta; + MemoryRegion *sysmem = get_system_memory(); /* Core */ s->mpu_model = omap2420; s->cpu = ARM_CPU(cpu_create(cpu_type)); - s->sdram_size = sdram_size; s->sram_size = OMAP242X_SRAM_SIZE; s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0); @@ -2299,9 +2299,6 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, omap_clk_init(s); /* Memory-mapped stuff */ - memory_region_allocate_system_memory(&s->sdram, NULL, "omap2.dram", - s->sdram_size); - memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram); memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size, &error_fatal); memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram); @@ -2338,8 +2335,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, s->port->addr_valid = omap2_validate_addr; /* Register SDRAM and SRAM ports for fast DMA transfers. */ - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sdram), - OMAP2_Q2_BASE, s->sdram_size); + soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(sdram), + OMAP2_Q2_BASE, memory_region_size(sdram)); soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram), OMAP2_SRAM_BASE, s->sram_size); diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index c071197be7..be245714db 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -103,6 +103,7 @@ static void sx1_init(MachineState *machine, const int version) { struct omap_mpu_state_s *mpu; MemoryRegion *address_space = get_system_memory(); + MemoryRegion *dram = g_new(MemoryRegion, 1); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *cs = g_new(MemoryRegion, 4); static uint32_t cs0val = 0x00213090; @@ -118,8 +119,11 @@ static void sx1_init(MachineState *machine, const int version) flash_size = flash2_size; } - mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, - machine->cpu_type); + memory_region_allocate_system_memory(dram, NULL, "omap1.dram", + sx1_binfo.ram_size); + memory_region_add_subregion(address_space, OMAP_EMIFF_BASE, dram); + + mpu = omap310_mpu_init(dram, machine->cpu_type); /* External Flash (EMIFS) */ memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size, diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 02a3a82b9b..72eca8cc55 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -190,16 +190,20 @@ static void palmte_init(MachineState *machine) MemoryRegion *address_space_mem = get_system_memory(); struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; - int sdram_size = palmte_binfo.ram_size; static uint32_t cs0val = 0xffffffff; static uint32_t cs1val = 0x0000e1a0; static uint32_t cs2val = 0x0000e1a0; static uint32_t cs3val = 0xe1a0e1a0; int rom_size, rom_loaded = 0; + MemoryRegion *dram = g_new(MemoryRegion, 1); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *cs = g_new(MemoryRegion, 4); - mpu = omap310_mpu_init(address_space_mem, sdram_size, machine->cpu_type); + memory_region_allocate_system_memory(dram, NULL, "omap1.dram", + palmte_binfo.ram_size); + memory_region_add_subregion(address_space_mem, OMAP_EMIFF_BASE, dram); + + mpu = omap310_mpu_init(dram, machine->cpu_type); /* External Flash (EMIFS) */ memory_region_init_ram(flash, NULL, "palmte.flash", flash_size, diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 615d755879..6a510aafc1 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -60,12 +60,14 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0 || (BOARDSETUP_ADDR >> 4) >= 0x100); - rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); + rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start, + arm_boot_address_space(cpu, info)); } static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info) { + AddressSpace *as = arm_boot_address_space(cpu, info); /* Unlike the AArch32 version we don't need to call the board setup hook. * The mechanism for doing the spin-table is also entirely different. * We must have four 64-bit fields at absolute addresses @@ -92,10 +94,10 @@ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info) 0, 0, 0, 0 }; - rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); - rom_add_blob_fixed("raspi_spintables", spintables, sizeof(spintables), - SPINTABLE_ADDR); + rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start, as); + rom_add_blob_fixed_as("raspi_spintables", spintables, sizeof(spintables), + SPINTABLE_ADDR, as); } static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index dc65d88a65..6bee034914 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -1586,8 +1586,7 @@ static const TypeInfo strongarm_ssp_info = { }; /* Main CPU functions */ -StrongARMState *sa1110_init(MemoryRegion *sysmem, - unsigned int sdram_size, const char *cpu_type) +StrongARMState *sa1110_init(const char *cpu_type) { StrongARMState *s; int i; @@ -1601,10 +1600,6 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, s->cpu = ARM_CPU(cpu_create(cpu_type)); - memory_region_allocate_system_memory(&s->sdram, NULL, "strongarm.sdram", - sdram_size); - memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram); - s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ), qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ), diff --git a/hw/arm/strongarm.h b/hw/arm/strongarm.h index e98840b461..192821f6aa 100644 --- a/hw/arm/strongarm.h +++ b/hw/arm/strongarm.h @@ -55,7 +55,6 @@ enum { typedef struct { ARMCPU *cpu; - MemoryRegion sdram; DeviceState *pic; DeviceState *gpio; DeviceState *ppc; @@ -63,7 +62,6 @@ typedef struct { SSIBus *ssp_bus; } StrongARMState; -StrongARMState *sa1110_init(MemoryRegion *sysmem, - unsigned int sdram_size, const char *rev); +StrongARMState *sa1110_init(const char *cpu_type); #endif diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index c14774e542..3a0fa5b23f 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -16,6 +16,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "cpu.h" #include "hw/sysbus.h" @@ -194,7 +195,7 @@ static void zynq_init(MachineState *machine) memory_region_add_subregion(address_space_mem, 0, ext_ram); /* 256K of on-chip memory */ - memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10, + memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 * KiB, &error_fatal); memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index ed2ddebd2b..14e9f85b8b 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1207,6 +1207,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); + blk_drain(s->blk); virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; qemu_del_vm_change_state_handler(s->change); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index e035d1f750..fb3a978e28 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -31,7 +31,6 @@ #include "hw/ptimer.h" #include "hw/qdev-properties.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/stream.h" @@ -104,7 +103,6 @@ enum { }; struct Stream { - QEMUBH *bh; ptimer_state *ptimer; qemu_irq irq; @@ -242,6 +240,7 @@ static void stream_complete(struct Stream *s) unsigned int comp_delay; /* Start the delayed timer. */ + ptimer_transaction_begin(s->ptimer); comp_delay = s->regs[R_DMACR] >> 24; if (comp_delay) { ptimer_stop(s->ptimer); @@ -255,6 +254,7 @@ static void stream_complete(struct Stream *s) s->regs[R_DMASR] |= DMASR_IOC_IRQ; stream_reload_complete_cnt(s); } + ptimer_transaction_commit(s->ptimer); } static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, @@ -551,9 +551,10 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) struct Stream *st = &s->streams[i]; st->nr = i; - st->bh = qemu_bh_new(timer_hit, st); - st->ptimer = ptimer_init_with_bh(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, s->freqhz); + ptimer_transaction_commit(st->ptimer); } return; diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 196e47c262..7acc5fa8e2 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -733,13 +733,13 @@ static void aspeed_gpio_get_pin(Object *obj, Visitor *v, const char *name, { int pin = 0xfff; bool level = true; - char group[3]; + char group[4]; AspeedGPIOState *s = ASPEED_GPIO(obj); int set_idx, group_idx = 0; if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) { /* 1.8V gpio */ - if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) { + if (sscanf(name, "gpio%3[18A-E]%1d", group, &pin) != 2) { error_setg(errp, "%s: error reading %s", __func__, name); return; } @@ -760,7 +760,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; bool level; int pin = 0xfff; - char group[3]; + char group[4]; AspeedGPIOState *s = ASPEED_GPIO(obj); int set_idx, group_idx = 0; @@ -771,7 +771,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name, } if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) { /* 1.8V gpio */ - if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) { + if (sscanf(name, "gpio%3[18A-E]%1d", group, &pin) != 2) { error_setg(errp, "%s: error reading %s", __func__, name); return; } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 7e23675429..b30aba6d54 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -12,7 +12,7 @@ #include "qemu/error-report.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/ide.h" #include "hw/timer/i8254.h" #include "hw/char/serial.h" @@ -161,9 +161,8 @@ static void machine_hppa_init(MachineState *machine) g_free(firmware_filename); rom_region = g_new(MemoryRegion, 1); - memory_region_allocate_system_memory(rom_region, OBJECT(machine), - "firmware", - (FIRMWARE_END - FIRMWARE_START)); + memory_region_init_ram(rom_region, NULL, "firmware", + (FIRMWARE_END - FIRMWARE_START), &error_fatal); memory_region_add_subregion(addr_space, FIRMWARE_START, rom_region); /* Load kernel */ diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index bc0256e1e0..9dd3dbb16c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -45,7 +45,7 @@ #include "hw/acpi/vmgenid.h" #include "hw/boards.h" #include "sysemu/tpm_backend.h" -#include "hw/timer/mc146818rtc_regs.h" +#include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" #include "hw/mem/memory-device.h" #include "sysemu/numa.h" diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 20d2189ea8..8aacd6c8d1 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -35,7 +35,7 @@ #include "hw/i386/pc.h" #include "target/i386/cpu.h" #include "hw/timer/i8254.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/char/serial.h" #include "hw/i386/topology.h" #include "hw/i386/e820_memory_layout.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 5fce60c856..b8f02c6f3f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -43,7 +43,7 @@ #include "elf.h" #include "migration/vmstate.h" #include "multiboot.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/dma/i8257.h" #include "hw/timer/i8254.h" #include "hw/input/i8042.h" diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index def3bc2d7b..d8b4c48021 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -33,7 +33,7 @@ #include "hw/loader.h" #include "sysemu/arch_init.h" #include "hw/i2c/smbus_eeprom.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/xen/xen.h" #include "sysemu/kvm.h" #include "hw/kvm/clock.h" diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 8e93e51e81..e8c74f9eba 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2251,7 +2251,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return MEMTX_OK; + goto exit_ok; case 0x200 ... 0x23f: /* NVIC Set pend */ /* the special logic in armv7m_nvic_set_pending() * is not needed since IRQs are never escalated @@ -2269,9 +2269,9 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return MEMTX_OK; + goto exit_ok; case 0x300 ... 0x33f: /* NVIC Active */ - return MEMTX_OK; /* R/O */ + goto exit_ok; /* R/O */ case 0x400 ... 0x5ef: /* NVIC Priority */ startvec = (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */ @@ -2281,10 +2281,10 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return MEMTX_OK; + goto exit_ok; case 0xd18 ... 0xd1b: /* System Handler Priority (SHPR1) */ if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) { - return MEMTX_OK; + goto exit_ok; } /* fall through */ case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */ @@ -2299,10 +2299,10 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, set_prio(s, hdlidx, sbank, newprio); } nvic_irq_update(s); - return MEMTX_OK; + goto exit_ok; case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) { - return MEMTX_OK; + goto exit_ok; } /* All bits are W1C, so construct 32 bit value with 0s in * the parts not written by the access size @@ -2322,15 +2322,19 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, */ s->cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK); } - return MEMTX_OK; + goto exit_ok; } if (size == 4) { nvic_writel(s, offset, value, attrs); - return MEMTX_OK; + goto exit_ok; } qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad write of size %d at offset 0x%x\n", size, offset); /* This is UNPREDICTABLE; treat as RAZ/WI */ + + exit_ok: + /* Ensure any changes made are reflected in the cached hflags. */ + arm_rebuild_hflags(&s->cpu->env); return MEMTX_OK; } diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index ed6e9d71bb..348f2fdd26 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -385,7 +385,7 @@ static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx, PnvXive *xive = PNV_XIVE(xrtr); if (pnv_xive_get_ic(blk) != xive) { - xive_error(xive, "VST: EAS %x is remote !?", XIVE_SRCNO(blk, idx)); + xive_error(xive, "VST: EAS %x is remote !?", XIVE_EAS(blk, idx)); return -1; } @@ -431,7 +431,7 @@ static void pnv_xive_notify(XiveNotifier *xn, uint32_t srcno) PnvXive *xive = PNV_XIVE(xn); uint8_t blk = xive->chip->chip_id; - xive_router_notify(xn, XIVE_SRCNO(blk, srcno)); + xive_router_notify(xn, XIVE_EAS(blk, srcno)); } /* @@ -1225,12 +1225,24 @@ static const MemoryRegionOps pnv_xive_ic_reg_ops = { static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val) { + uint8_t blk; + uint32_t idx; + + if (val & XIVE_TRIGGER_END) { + xive_error(xive, "IC: END trigger at @0x%"HWADDR_PRIx" data 0x%"PRIx64, + addr, val); + return; + } + /* * Forward the source event notification directly to the Router. * The source interrupt number should already be correctly encoded * with the chip block id by the sending device (PHB, PSI). */ - xive_router_notify(XIVE_NOTIFIER(xive), val); + blk = XIVE_EAS_BLOCK(val); + idx = XIVE_EAS_INDEX(val); + + xive_router_notify(XIVE_NOTIFIER(xive), XIVE_EAS(blk, idx)); } static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t val, @@ -1566,7 +1578,7 @@ void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon) { XiveRouter *xrtr = XIVE_ROUTER(xive); uint8_t blk = xive->chip->chip_id; - uint32_t srcno0 = XIVE_SRCNO(blk, 0); + uint32_t srcno0 = XIVE_EAS(blk, 0); uint32_t nr_ipis = pnv_xive_nr_ipis(xive); uint32_t nr_ends = pnv_xive_nr_ends(xive); XiveEAS eas; diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 04879abf2e..d8e1291905 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -205,23 +205,6 @@ void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable) memory_region_set_enabled(&xive->end_source.esb_mmio, false); } -/* - * When a Virtual Processor is scheduled to run on a HW thread, the - * hypervisor pushes its identifier in the OS CAM line. Emulate the - * same behavior under QEMU. - */ -void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx) -{ - uint8_t nvt_blk; - uint32_t nvt_idx; - uint32_t nvt_cam; - - spapr_xive_cpu_to_nvt(POWERPC_CPU(tctx->cs), &nvt_blk, &nvt_idx); - - nvt_cam = cpu_to_be32(TM_QW1W2_VO | xive_nvt_cam_line(nvt_blk, nvt_idx)); - memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &nvt_cam, 4); -} - static void spapr_xive_end_reset(XiveEND *end) { memset(end, 0, sizeof(*end)); @@ -462,10 +445,10 @@ static int vmstate_spapr_xive_pre_save(void *opaque) * Called by the sPAPR IRQ backend 'post_load' method at the machine * level. */ -int spapr_xive_post_load(SpaprXive *xive, int version_id) +static int spapr_xive_post_load(SpaprInterruptController *intc, int version_id) { if (kvm_irqchip_in_kernel()) { - return kvmppc_xive_post_load(xive, version_id); + return kvmppc_xive_post_load(SPAPR_XIVE(intc), version_id); } return 0; @@ -487,6 +470,42 @@ static const VMStateDescription vmstate_spapr_xive = { }, }; +static int spapr_xive_claim_irq(SpaprInterruptController *intc, int lisn, + bool lsi, Error **errp) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + XiveSource *xsrc = &xive->source; + + assert(lisn < xive->nr_irqs); + + if (xive_eas_is_valid(&xive->eat[lisn])) { + error_setg(errp, "IRQ %d is not free", lisn); + return -EBUSY; + } + + /* + * Set default values when allocating an IRQ number + */ + xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED); + if (lsi) { + xive_source_irq_set_lsi(xsrc, lisn); + } + + if (kvm_irqchip_in_kernel()) { + return kvmppc_xive_source_reset_one(xsrc, lisn, errp); + } + + return 0; +} + +static void spapr_xive_free_irq(SpaprInterruptController *intc, int lisn) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + assert(lisn < xive->nr_irqs); + + xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID); +} + static Property spapr_xive_properties[] = { DEFINE_PROP_UINT32("nr-irqs", SpaprXive, nr_irqs, 0), DEFINE_PROP_UINT32("nr-ends", SpaprXive, nr_ends, 0), @@ -495,10 +514,167 @@ static Property spapr_xive_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static int spapr_xive_cpu_intc_create(SpaprInterruptController *intc, + PowerPCCPU *cpu, Error **errp) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + Object *obj; + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + + obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(xive), errp); + if (!obj) { + return -1; + } + + spapr_cpu->tctx = XIVE_TCTX(obj); + return 0; +} + +static void xive_tctx_set_os_cam(XiveTCTX *tctx, uint32_t os_cam) +{ + uint32_t qw1w2 = cpu_to_be32(TM_QW1W2_VO | os_cam); + memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4); +} + +static void spapr_xive_cpu_intc_reset(SpaprInterruptController *intc, + PowerPCCPU *cpu) +{ + XiveTCTX *tctx = spapr_cpu_state(cpu)->tctx; + uint8_t nvt_blk; + uint32_t nvt_idx; + + xive_tctx_reset(tctx); + + /* + * When a Virtual Processor is scheduled to run on a HW thread, + * the hypervisor pushes its identifier in the OS CAM line. + * Emulate the same behavior under QEMU. + */ + spapr_xive_cpu_to_nvt(cpu, &nvt_blk, &nvt_idx); + + xive_tctx_set_os_cam(tctx, xive_nvt_cam_line(nvt_blk, nvt_idx)); +} + +static void spapr_xive_set_irq(SpaprInterruptController *intc, int irq, int val) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + + if (kvm_irqchip_in_kernel()) { + kvmppc_xive_source_set_irq(&xive->source, irq, val); + } else { + xive_source_set_irq(&xive->source, irq, val); + } +} + +static void spapr_xive_print_info(SpaprInterruptController *intc, Monitor *mon) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + + xive_tctx_pic_print_info(spapr_cpu_state(cpu)->tctx, mon); + } + + spapr_xive_pic_print_info(xive, mon); +} + +static void spapr_xive_dt(SpaprInterruptController *intc, uint32_t nr_servers, + void *fdt, uint32_t phandle) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + int node; + uint64_t timas[2 * 2]; + /* Interrupt number ranges for the IPIs */ + uint32_t lisn_ranges[] = { + cpu_to_be32(0), + cpu_to_be32(nr_servers), + }; + /* + * EQ size - the sizes of pages supported by the system 4K, 64K, + * 2M, 16M. We only advertise 64K for the moment. + */ + uint32_t eq_sizes[] = { + cpu_to_be32(16), /* 64K */ + }; + /* + * The following array is in sync with the reserved priorities + * defined by the 'spapr_xive_priority_is_reserved' routine. + */ + uint32_t plat_res_int_priorities[] = { + cpu_to_be32(7), /* start */ + cpu_to_be32(0xf8), /* count */ + }; + + /* Thread Interrupt Management Area : User (ring 3) and OS (ring 2) */ + timas[0] = cpu_to_be64(xive->tm_base + + XIVE_TM_USER_PAGE * (1ull << TM_SHIFT)); + timas[1] = cpu_to_be64(1ull << TM_SHIFT); + timas[2] = cpu_to_be64(xive->tm_base + + XIVE_TM_OS_PAGE * (1ull << TM_SHIFT)); + timas[3] = cpu_to_be64(1ull << TM_SHIFT); + + _FDT(node = fdt_add_subnode(fdt, 0, xive->nodename)); + + _FDT(fdt_setprop_string(fdt, node, "device_type", "power-ivpe")); + _FDT(fdt_setprop(fdt, node, "reg", timas, sizeof(timas))); + + _FDT(fdt_setprop_string(fdt, node, "compatible", "ibm,power-ivpe")); + _FDT(fdt_setprop(fdt, node, "ibm,xive-eq-sizes", eq_sizes, + sizeof(eq_sizes))); + _FDT(fdt_setprop(fdt, node, "ibm,xive-lisn-ranges", lisn_ranges, + sizeof(lisn_ranges))); + + /* For Linux to link the LSIs to the interrupt controller. */ + _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); + _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); + + /* For SLOF */ + _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); + _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); + + /* + * The "ibm,plat-res-int-priorities" property defines the priority + * ranges reserved by the hypervisor + */ + _FDT(fdt_setprop(fdt, 0, "ibm,plat-res-int-priorities", + plat_res_int_priorities, sizeof(plat_res_int_priorities))); +} + +static int spapr_xive_activate(SpaprInterruptController *intc, Error **errp) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + + if (kvm_enabled()) { + int rc = spapr_irq_init_kvm(kvmppc_xive_connect, intc, errp); + if (rc < 0) { + return rc; + } + } + + /* Activate the XIVE MMIOs */ + spapr_xive_mmio_set_enabled(xive, true); + + return 0; +} + +static void spapr_xive_deactivate(SpaprInterruptController *intc) +{ + SpaprXive *xive = SPAPR_XIVE(intc); + + spapr_xive_mmio_set_enabled(xive, false); + + if (kvm_irqchip_in_kernel()) { + kvmppc_xive_disconnect(intc); + } +} + static void spapr_xive_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass); + SpaprInterruptControllerClass *sicc = SPAPR_INTC_CLASS(klass); dc->desc = "sPAPR XIVE Interrupt Controller"; dc->props = spapr_xive_properties; @@ -511,6 +687,17 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data) xrc->get_nvt = spapr_xive_get_nvt; xrc->write_nvt = spapr_xive_write_nvt; xrc->get_tctx = spapr_xive_get_tctx; + + sicc->activate = spapr_xive_activate; + sicc->deactivate = spapr_xive_deactivate; + sicc->cpu_intc_create = spapr_xive_cpu_intc_create; + sicc->cpu_intc_reset = spapr_xive_cpu_intc_reset; + sicc->claim_irq = spapr_xive_claim_irq; + sicc->free_irq = spapr_xive_free_irq; + sicc->set_irq = spapr_xive_set_irq; + sicc->print_info = spapr_xive_print_info; + sicc->dt = spapr_xive_dt; + sicc->post_load = spapr_xive_post_load; } static const TypeInfo spapr_xive_info = { @@ -519,6 +706,10 @@ static const TypeInfo spapr_xive_info = { .instance_init = spapr_xive_instance_init, .instance_size = sizeof(SpaprXive), .class_init = spapr_xive_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_SPAPR_INTC }, + { } + }, }; static void spapr_xive_register_types(void) @@ -528,39 +719,6 @@ static void spapr_xive_register_types(void) type_init(spapr_xive_register_types) -int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp) -{ - XiveSource *xsrc = &xive->source; - - assert(lisn < xive->nr_irqs); - - if (xive_eas_is_valid(&xive->eat[lisn])) { - error_setg(errp, "IRQ %d is not free", lisn); - return -EBUSY; - } - - /* - * Set default values when allocating an IRQ number - */ - xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED); - if (lsi) { - xive_source_irq_set_lsi(xsrc, lisn); - } - - if (kvm_irqchip_in_kernel()) { - return kvmppc_xive_source_reset_one(xsrc, lisn, errp); - } - - return 0; -} - -void spapr_xive_irq_free(SpaprXive *xive, int lisn) -{ - assert(lisn < xive->nr_irqs); - - xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID); -} - /* * XIVE hcalls * @@ -1540,65 +1698,3 @@ void spapr_xive_hcall_init(SpaprMachineState *spapr) spapr_register_hypercall(H_INT_SYNC, h_int_sync); spapr_register_hypercall(H_INT_RESET, h_int_reset); } - -void spapr_dt_xive(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, - uint32_t phandle) -{ - SpaprXive *xive = spapr->xive; - int node; - uint64_t timas[2 * 2]; - /* Interrupt number ranges for the IPIs */ - uint32_t lisn_ranges[] = { - cpu_to_be32(0), - cpu_to_be32(nr_servers), - }; - /* - * EQ size - the sizes of pages supported by the system 4K, 64K, - * 2M, 16M. We only advertise 64K for the moment. - */ - uint32_t eq_sizes[] = { - cpu_to_be32(16), /* 64K */ - }; - /* - * The following array is in sync with the reserved priorities - * defined by the 'spapr_xive_priority_is_reserved' routine. - */ - uint32_t plat_res_int_priorities[] = { - cpu_to_be32(7), /* start */ - cpu_to_be32(0xf8), /* count */ - }; - - /* Thread Interrupt Management Area : User (ring 3) and OS (ring 2) */ - timas[0] = cpu_to_be64(xive->tm_base + - XIVE_TM_USER_PAGE * (1ull << TM_SHIFT)); - timas[1] = cpu_to_be64(1ull << TM_SHIFT); - timas[2] = cpu_to_be64(xive->tm_base + - XIVE_TM_OS_PAGE * (1ull << TM_SHIFT)); - timas[3] = cpu_to_be64(1ull << TM_SHIFT); - - _FDT(node = fdt_add_subnode(fdt, 0, xive->nodename)); - - _FDT(fdt_setprop_string(fdt, node, "device_type", "power-ivpe")); - _FDT(fdt_setprop(fdt, node, "reg", timas, sizeof(timas))); - - _FDT(fdt_setprop_string(fdt, node, "compatible", "ibm,power-ivpe")); - _FDT(fdt_setprop(fdt, node, "ibm,xive-eq-sizes", eq_sizes, - sizeof(eq_sizes))); - _FDT(fdt_setprop(fdt, node, "ibm,xive-lisn-ranges", lisn_ranges, - sizeof(lisn_ranges))); - - /* For Linux to link the LSIs to the interrupt controller. */ - _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); - _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); - - /* For SLOF */ - _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); - _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); - - /* - * The "ibm,plat-res-int-priorities" property defines the priority - * ranges reserved by the hypervisor - */ - _FDT(fdt_setprop(fdt, 0, "ibm,plat-res-int-priorities", - plat_res_int_priorities, sizeof(plat_res_int_priorities))); -} diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 51b334b676..08012ac7cd 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -740,8 +740,9 @@ static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len, * All the XIVE memory regions are now backed by mappings from the KVM * XIVE device. */ -void kvmppc_xive_connect(SpaprXive *xive, Error **errp) +int kvmppc_xive_connect(SpaprInterruptController *intc, Error **errp) { + SpaprXive *xive = SPAPR_XIVE(intc); XiveSource *xsrc = &xive->source; Error *local_err = NULL; size_t esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs; @@ -753,19 +754,19 @@ void kvmppc_xive_connect(SpaprXive *xive, Error **errp) * rebooting under the XIVE-only interrupt mode. */ if (xive->fd != -1) { - return; + return 0; } if (!kvmppc_has_cap_xive()) { error_setg(errp, "IRQ_XIVE capability must be present for KVM"); - return; + return -1; } /* First, create the KVM XIVE device */ xive->fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false); if (xive->fd < 0) { error_setg_errno(errp, -xive->fd, "XIVE: error creating KVM device"); - return; + return -1; } /* @@ -821,15 +822,17 @@ void kvmppc_xive_connect(SpaprXive *xive, Error **errp) kvm_kernel_irqchip = true; kvm_msi_via_irqfd_allowed = true; kvm_gsi_direct_mapping = true; - return; + return 0; fail: error_propagate(errp, local_err); - kvmppc_xive_disconnect(xive, NULL); + kvmppc_xive_disconnect(intc); + return -1; } -void kvmppc_xive_disconnect(SpaprXive *xive, Error **errp) +void kvmppc_xive_disconnect(SpaprInterruptController *intc) { + SpaprXive *xive = SPAPR_XIVE(intc); XiveSource *xsrc; size_t esb_len; @@ -838,11 +841,6 @@ void kvmppc_xive_disconnect(SpaprXive *xive, Error **errp) return; } - if (!kvmppc_has_cap_xive()) { - error_setg(errp, "IRQ_XIVE capability must be present for KVM"); - return; - } - /* Clear the KVM mapping */ xsrc = &xive->source; esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs; diff --git a/hw/intc/xics.c b/hw/intc/xics.c index dfe7dbd254..6da05763f9 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -274,10 +274,8 @@ static const VMStateDescription vmstate_icp_server = { }, }; -static void icp_reset_handler(void *dev) +void icp_reset(ICPState *icp) { - ICPState *icp = ICP(dev); - icp->xirr = 0; icp->pending_priority = 0xff; icp->mfrr = 0xff; @@ -288,7 +286,7 @@ static void icp_reset_handler(void *dev) if (kvm_irqchip_in_kernel()) { Error *local_err = NULL; - icp_set_kvm_state(ICP(dev), &local_err); + icp_set_kvm_state(icp, &local_err); if (local_err) { error_report_err(local_err); } @@ -351,7 +349,6 @@ static void icp_realize(DeviceState *dev, Error **errp) } } - qemu_register_reset(icp_reset_handler, dev); vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp); } @@ -360,7 +357,6 @@ static void icp_unrealize(DeviceState *dev, Error **errp) ICPState *icp = ICP(dev); vmstate_unregister(NULL, &vmstate_icp_server, icp); - qemu_unregister_reset(icp_reset_handler, dev); } static void icp_class_init(ObjectClass *klass, void *data) @@ -369,6 +365,11 @@ static void icp_class_init(ObjectClass *klass, void *data) dc->realize = icp_realize; dc->unrealize = icp_unrealize; + /* + * Reason: part of XICS interrupt controller, needs to be wired up + * by icp_create(). + */ + dc->user_creatable = false; } static const TypeInfo icp_info = { @@ -689,6 +690,11 @@ static void ics_class_init(ObjectClass *klass, void *data) dc->props = ics_properties; dc->reset = ics_reset; dc->vmsd = &vmstate_ics; + /* + * Reason: part of XICS interrupt controller, needs to be wired up, + * e.g. by spapr_irq_init(). + */ + dc->user_creatable = false; } static const TypeInfo ics_info = { diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index ba90d6dc96..954c424b36 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -342,8 +342,9 @@ void ics_kvm_set_irq(ICSState *ics, int srcno, int val) } } -int xics_kvm_connect(SpaprMachineState *spapr, Error **errp) +int xics_kvm_connect(SpaprInterruptController *intc, Error **errp) { + ICSState *ics = ICS_SPAPR(intc); int rc; CPUState *cs; Error *local_err = NULL; @@ -413,7 +414,7 @@ int xics_kvm_connect(SpaprMachineState *spapr, Error **errp) } /* Update the KVM sources */ - ics_set_kvm_state(spapr->ics, &local_err); + ics_set_kvm_state(ics, &local_err); if (local_err) { goto fail; } @@ -431,11 +432,11 @@ int xics_kvm_connect(SpaprMachineState *spapr, Error **errp) fail: error_propagate(errp, local_err); - xics_kvm_disconnect(spapr, NULL); + xics_kvm_disconnect(intc); return -1; } -void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp) +void xics_kvm_disconnect(SpaprInterruptController *intc) { /* * Only on P9 using the XICS-on XIVE KVM device: diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 6e5eb24b3c..7418fb9f37 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -308,8 +308,8 @@ static void ics_spapr_realize(DeviceState *dev, Error **errp) spapr_register_hypercall(H_IPOLL, h_ipoll); } -void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, - uint32_t phandle) +static void xics_spapr_dt(SpaprInterruptController *intc, uint32_t nr_servers, + void *fdt, uint32_t phandle) { uint32_t interrupt_server_ranges_prop[] = { 0, cpu_to_be32(nr_servers), @@ -330,19 +330,132 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); } +static int xics_spapr_cpu_intc_create(SpaprInterruptController *intc, + PowerPCCPU *cpu, Error **errp) +{ + ICSState *ics = ICS_SPAPR(intc); + Object *obj; + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + + obj = icp_create(OBJECT(cpu), TYPE_ICP, ics->xics, errp); + if (!obj) { + return -1; + } + + spapr_cpu->icp = ICP(obj); + return 0; +} + +static void xics_spapr_cpu_intc_reset(SpaprInterruptController *intc, + PowerPCCPU *cpu) +{ + icp_reset(spapr_cpu_state(cpu)->icp); +} + +static int xics_spapr_claim_irq(SpaprInterruptController *intc, int irq, + bool lsi, Error **errp) +{ + ICSState *ics = ICS_SPAPR(intc); + + assert(ics); + assert(ics_valid_irq(ics, irq)); + + if (!ics_irq_free(ics, irq - ics->offset)) { + error_setg(errp, "IRQ %d is not free", irq); + return -EBUSY; + } + + ics_set_irq_type(ics, irq - ics->offset, lsi); + return 0; +} + +static void xics_spapr_free_irq(SpaprInterruptController *intc, int irq) +{ + ICSState *ics = ICS_SPAPR(intc); + uint32_t srcno = irq - ics->offset; + + assert(ics_valid_irq(ics, irq)); + + memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); +} + +static void xics_spapr_set_irq(SpaprInterruptController *intc, int irq, int val) +{ + ICSState *ics = ICS_SPAPR(intc); + uint32_t srcno = irq - ics->offset; + + ics_set_irq(ics, srcno, val); +} + +static void xics_spapr_print_info(SpaprInterruptController *intc, Monitor *mon) +{ + ICSState *ics = ICS_SPAPR(intc); + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + + icp_pic_print_info(spapr_cpu_state(cpu)->icp, mon); + } + + ics_pic_print_info(ics, mon); +} + +static int xics_spapr_post_load(SpaprInterruptController *intc, int version_id) +{ + if (!kvm_irqchip_in_kernel()) { + CPUState *cs; + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + icp_resend(spapr_cpu_state(cpu)->icp); + } + } + return 0; +} + +static int xics_spapr_activate(SpaprInterruptController *intc, Error **errp) +{ + if (kvm_enabled()) { + return spapr_irq_init_kvm(xics_kvm_connect, intc, errp); + } + return 0; +} + +static void xics_spapr_deactivate(SpaprInterruptController *intc) +{ + if (kvm_irqchip_in_kernel()) { + xics_kvm_disconnect(intc); + } +} + static void ics_spapr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ICSStateClass *isc = ICS_CLASS(klass); + SpaprInterruptControllerClass *sicc = SPAPR_INTC_CLASS(klass); device_class_set_parent_realize(dc, ics_spapr_realize, &isc->parent_realize); + sicc->activate = xics_spapr_activate; + sicc->deactivate = xics_spapr_deactivate; + sicc->cpu_intc_create = xics_spapr_cpu_intc_create; + sicc->cpu_intc_reset = xics_spapr_cpu_intc_reset; + sicc->claim_irq = xics_spapr_claim_irq; + sicc->free_irq = xics_spapr_free_irq; + sicc->set_irq = xics_spapr_set_irq; + sicc->print_info = xics_spapr_print_info; + sicc->dt = xics_spapr_dt; + sicc->post_load = xics_spapr_post_load; } static const TypeInfo ics_spapr_info = { .name = TYPE_ICS_SPAPR, .parent = TYPE_ICS, .class_init = ics_spapr_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_SPAPR_INTC }, + { } + }, }; static void xics_spapr_register_types(void) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 29df06df11..f066be5eb5 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -547,10 +547,8 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon) } } -static void xive_tctx_reset(void *dev) +void xive_tctx_reset(XiveTCTX *tctx) { - XiveTCTX *tctx = XIVE_TCTX(dev); - memset(tctx->regs, 0, sizeof(tctx->regs)); /* Set some defaults */ @@ -607,13 +605,6 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) return; } } - - qemu_register_reset(xive_tctx_reset, dev); -} - -static void xive_tctx_unrealize(DeviceState *dev, Error **errp) -{ - qemu_unregister_reset(xive_tctx_reset, dev); } static int vmstate_xive_tctx_pre_save(void *opaque) @@ -668,8 +659,12 @@ static void xive_tctx_class_init(ObjectClass *klass, void *data) dc->desc = "XIVE Interrupt Thread Context"; dc->realize = xive_tctx_realize; - dc->unrealize = xive_tctx_unrealize; dc->vmsd = &vmstate_xive_tctx; + /* + * Reason: part of XIVE interrupt controller, needs to be wired up + * by xive_tctx_create(). + */ + dc->user_creatable = false; } static const TypeInfo xive_tctx_info = { @@ -1118,6 +1113,11 @@ static void xive_source_class_init(ObjectClass *klass, void *data) dc->props = xive_source_properties; dc->realize = xive_source_realize; dc->vmsd = &vmstate_xive_source; + /* + * Reason: part of XIVE interrupt controller, needs to be wired up, + * e.g. by spapr_xive_instance_init(). + */ + dc->user_creatable = false; } static const TypeInfo xive_source_info = { @@ -1648,8 +1648,8 @@ do_escalation: void xive_router_notify(XiveNotifier *xn, uint32_t lisn) { XiveRouter *xrtr = XIVE_ROUTER(xn); - uint8_t eas_blk = XIVE_SRCNO_BLOCK(lisn); - uint32_t eas_idx = XIVE_SRCNO_INDEX(lisn); + uint8_t eas_blk = XIVE_EAS_BLOCK(lisn); + uint32_t eas_idx = XIVE_EAS_INDEX(lisn); XiveEAS eas; /* EAS cache lookup */ @@ -1853,6 +1853,11 @@ static void xive_end_source_class_init(ObjectClass *klass, void *data) dc->desc = "XIVE END Source"; dc->props = xive_end_source_properties; dc->realize = xive_end_source_realize; + /* + * Reason: part of XIVE interrupt controller, needs to be wired up, + * e.g. by spapr_xive_instance_init(). + */ + dc->user_creatable = false; } static const TypeInfo xive_end_source_info = { diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index a49096367c..b155dd8170 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -8,7 +8,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "hw/hw.h" #include "hw/irq.h" @@ -57,10 +56,12 @@ static void m5206_timer_recalibrate(m5206_timer_state *s) int prescale; int mode; + ptimer_transaction_begin(s->timer); ptimer_stop(s->timer); - if ((s->tmr & TMR_RST) == 0) - return; + if ((s->tmr & TMR_RST) == 0) { + goto exit; + } prescale = (s->tmr >> 8) + 1; mode = (s->tmr >> 1) & 3; @@ -78,6 +79,8 @@ static void m5206_timer_recalibrate(m5206_timer_state *s) ptimer_set_limit(s->timer, s->trr, 0); ptimer_run(s->timer, 0); +exit: + ptimer_transaction_commit(s->timer); } static void m5206_timer_trigger(void *opaque) @@ -123,7 +126,9 @@ static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) s->tcr = val; break; case 0xc: + ptimer_transaction_begin(s->timer); ptimer_set_count(s->timer, val); + ptimer_transaction_commit(s->timer); break; case 0x11: s->ter &= ~val; @@ -137,11 +142,9 @@ static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) static m5206_timer_state *m5206_timer_init(qemu_irq irq) { m5206_timer_state *s; - QEMUBH *bh; s = g_new0(m5206_timer_state, 1); - bh = qemu_bh_new(m5206_timer_trigger, s); - s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(m5206_timer_trigger, s, 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 34d34eba17..158c5e4be7 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/error-report.h" -#include "qemu/main-loop.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -79,6 +78,7 @@ static void m5208_timer_write(void *opaque, hwaddr offset, return; } + ptimer_transaction_begin(s->timer); if (s->pcsr & PCSR_EN) ptimer_stop(s->timer); @@ -94,8 +94,10 @@ static void m5208_timer_write(void *opaque, hwaddr offset, if (s->pcsr & PCSR_EN) ptimer_run(s->timer, 0); + ptimer_transaction_commit(s->timer); break; case 2: + ptimer_transaction_begin(s->timer); s->pmr = value; s->pcsr &= ~PCSR_PIF; if ((s->pcsr & PCSR_RLD) == 0) { @@ -104,6 +106,7 @@ static void m5208_timer_write(void *opaque, hwaddr offset, } else { ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); } + ptimer_transaction_commit(s->timer); break; case 4: break; @@ -182,7 +185,6 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) { MemoryRegion *iomem = g_new(MemoryRegion, 1); m5208_timer_state *s; - QEMUBH *bh; int i; /* SDRAMC. */ @@ -191,8 +193,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) /* Timers. */ 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_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(m5208_timer_trigger, s, 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/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index cf537dd7e6..03a27e1767 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -39,7 +39,7 @@ #include "hw/ide.h" #include "elf.h" #include "hw/isa/vt82c686.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 8d010a0b6e..d978bb64a0 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -39,7 +39,7 @@ #include "hw/scsi/esp.h" #include "hw/mips/bios.h" #include "hw/loader.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "hw/display/vga.h" #include "hw/audio/pcspk.h" diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 4d9c64b36a..c1c8810e71 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -45,7 +45,7 @@ #include "hw/irq.h" #include "hw/loader.h" #include "elf.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "exec/address-spaces.h" #include "hw/sysbus.h" /* SysBusDevice */ diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index bc0be26544..70024235ae 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -28,7 +28,7 @@ #include "hw/ide.h" #include "hw/loader.h" #include "elf.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/input/i8042.h" #include "hw/timer/i8254.h" #include "exec/address-spaces.h" diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index a150680966..c89f3816a5 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -53,6 +53,7 @@ common-obj-$(CONFIG_OMAP) += omap_tap.o common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o common-obj-$(CONFIG_RASPI) += bcm2835_property.o common-obj-$(CONFIG_RASPI) += bcm2835_rng.o +common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o common-obj-$(CONFIG_SLAVIO) += slavio_misc.o common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o diff --git a/hw/misc/bcm2835_thermal.c b/hw/misc/bcm2835_thermal.c new file mode 100644 index 0000000000..c6f3b1ad60 --- /dev/null +++ b/hw/misc/bcm2835_thermal.c @@ -0,0 +1,135 @@ +/* + * BCM2835 dummy thermal sensor + * + * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "hw/misc/bcm2835_thermal.h" +#include "hw/registerfields.h" +#include "migration/vmstate.h" + +REG32(CTL, 0) +FIELD(CTL, POWER_DOWN, 0, 1) +FIELD(CTL, RESET, 1, 1) +FIELD(CTL, BANDGAP_CTRL, 2, 3) +FIELD(CTL, INTERRUPT_ENABLE, 5, 1) +FIELD(CTL, DIRECT, 6, 1) +FIELD(CTL, INTERRUPT_CLEAR, 7, 1) +FIELD(CTL, HOLD, 8, 10) +FIELD(CTL, RESET_DELAY, 18, 8) +FIELD(CTL, REGULATOR_ENABLE, 26, 1) + +REG32(STAT, 4) +FIELD(STAT, DATA, 0, 10) +FIELD(STAT, VALID, 10, 1) +FIELD(STAT, INTERRUPT, 11, 1) + +#define THERMAL_OFFSET_C 412 +#define THERMAL_COEFF (-0.538f) + +static uint16_t bcm2835_thermal_temp2adc(int temp_C) +{ + return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF; +} + +static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size) +{ + Bcm2835ThermalState *s = BCM2835_THERMAL(opaque); + uint32_t val = 0; + + switch (addr) { + case A_CTL: + val = s->ctl; + break; + case A_STAT: + /* Temperature is constantly 25°C. */ + val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true); + break; + default: + /* MemoryRegionOps are aligned, so this can not happen. */ + g_assert_not_reached(); + } + return val; +} + +static void bcm2835_thermal_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + Bcm2835ThermalState *s = BCM2835_THERMAL(opaque); + + switch (addr) { + case A_CTL: + s->ctl = value; + break; + case A_STAT: + qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64 + " to 0x%" HWADDR_PRIx "\n", + __func__, value, addr); + break; + default: + /* MemoryRegionOps are aligned, so this can not happen. */ + g_assert_not_reached(); + } +} + +static const MemoryRegionOps bcm2835_thermal_ops = { + .read = bcm2835_thermal_read, + .write = bcm2835_thermal_write, + .impl.max_access_size = 4, + .valid.min_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void bcm2835_thermal_reset(DeviceState *dev) +{ + Bcm2835ThermalState *s = BCM2835_THERMAL(dev); + + s->ctl = 0; +} + +static void bcm2835_thermal_realize(DeviceState *dev, Error **errp) +{ + Bcm2835ThermalState *s = BCM2835_THERMAL(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops, + s, TYPE_BCM2835_THERMAL, 8); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); +} + +static const VMStateDescription bcm2835_thermal_vmstate = { + .name = "bcm2835_thermal", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ctl, Bcm2835ThermalState), + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_thermal_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_thermal_realize; + dc->reset = bcm2835_thermal_reset; + dc->vmsd = &bcm2835_thermal_vmstate; +} + +static const TypeInfo bcm2835_thermal_info = { + .name = TYPE_BCM2835_THERMAL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Bcm2835ThermalState), + .class_init = bcm2835_thermal_class_init, +}; + +static void bcm2835_thermal_register_types(void) +{ + type_register_static(&bcm2835_thermal_info); +} + +type_init(bcm2835_thermal_register_types) diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index d9b3e8c691..717de76569 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -34,7 +34,6 @@ #include "etsec.h" #include "registers.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" /* #define HEX_DUMP */ @@ -195,9 +194,11 @@ static void write_dmactrl(eTSEC *etsec, if (!(value & DMACTRL_WOP)) { /* Start polling */ + ptimer_transaction_begin(etsec->ptimer); ptimer_stop(etsec->ptimer); ptimer_set_count(etsec->ptimer, 1); ptimer_run(etsec->ptimer, 1); + ptimer_transaction_commit(etsec->ptimer); } } @@ -391,10 +392,10 @@ static void etsec_realize(DeviceState *dev, Error **errp) object_get_typename(OBJECT(dev)), dev->id, etsec); qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a); - - etsec->bh = qemu_bh_new(etsec_timer_hit, etsec); - etsec->ptimer = ptimer_init_with_bh(etsec->bh, PTIMER_POLICY_DEFAULT); + etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(etsec->ptimer); ptimer_set_freq(etsec->ptimer, 100); + ptimer_transaction_commit(etsec->ptimer); } static void etsec_instance_init(Object *obj) diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h index 09d05c2133..7951c3ad65 100644 --- a/hw/net/fsl_etsec/etsec.h +++ b/hw/net/fsl_etsec/etsec.h @@ -141,7 +141,6 @@ typedef struct eTSEC { uint16_t phy_control; /* Polling */ - QEMUBH *bh; struct ptimer_state *ptimer; /* Whether we should flush the rx queue when buffer becomes available. */ diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 715b9a4fe6..97967d12eb 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -311,7 +311,7 @@ void pci_bridge_reset(DeviceState *qdev) /* * the default values for base/limit registers aren't specified - * in the PCI-to-PCI-bridge spec. So we don't thouch them here. + * in the PCI-to-PCI-bridge spec. So we don't touch them here. * Each implementation can override it. * typical implementation does * zero base/limit registers or diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 7cf64b6d25..60632720ef 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -48,7 +48,7 @@ #include "hw/isa/isa.h" #include "hw/boards.h" #include "hw/char/serial.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include <libfdt.h> @@ -778,6 +778,13 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, pnv_cpu->intc = obj; } +static void pnv_chip_power8_intc_reset(PnvChip *chip, PowerPCCPU *cpu) +{ + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + icp_reset(ICP(pnv_cpu->intc)); +} + /* * 0:48 Reserved - Read as zeroes * 49:52 Node ID @@ -815,6 +822,13 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, pnv_cpu->intc = obj; } +static void pnv_chip_power9_intc_reset(PnvChip *chip, PowerPCCPU *cpu) +{ + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + xive_tctx_reset(XIVE_TCTX(pnv_cpu->intc)); +} + /* * Allowed core identifiers on a POWER8 Processor Chip : * @@ -984,6 +998,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER8E_CORE_MASK; k->core_pir = pnv_chip_core_pir_p8; k->intc_create = pnv_chip_power8_intc_create; + k->intc_reset = pnv_chip_power8_intc_reset; k->isa_create = pnv_chip_power8_isa_create; k->dt_populate = pnv_chip_power8_dt_populate; k->pic_print_info = pnv_chip_power8_pic_print_info; @@ -1003,6 +1018,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER8_CORE_MASK; k->core_pir = pnv_chip_core_pir_p8; k->intc_create = pnv_chip_power8_intc_create; + k->intc_reset = pnv_chip_power8_intc_reset; k->isa_create = pnv_chip_power8_isa_create; k->dt_populate = pnv_chip_power8_dt_populate; k->pic_print_info = pnv_chip_power8_pic_print_info; @@ -1022,6 +1038,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER8_CORE_MASK; k->core_pir = pnv_chip_core_pir_p8; k->intc_create = pnv_chip_power8_intc_create; + k->intc_reset = pnv_chip_power8_intc_reset; k->isa_create = pnv_chip_power8nvl_isa_create; k->dt_populate = pnv_chip_power8_dt_populate; k->pic_print_info = pnv_chip_power8_pic_print_info; @@ -1191,6 +1208,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER9_CORE_MASK; k->core_pir = pnv_chip_core_pir_p9; k->intc_create = pnv_chip_power9_intc_create; + k->intc_reset = pnv_chip_power9_intc_reset; k->isa_create = pnv_chip_power9_isa_create; k->dt_populate = pnv_chip_power9_dt_populate; k->pic_print_info = pnv_chip_power9_pic_print_info; diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index b1a7489e7a..e81cd3a3e0 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -40,11 +40,11 @@ static const char *pnv_core_cpu_typename(PnvCore *pc) return cpu_type; } -static void pnv_cpu_reset(void *opaque) +static void pnv_core_cpu_reset(PowerPCCPU *cpu, PnvChip *chip) { - PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); cpu_reset(cs); @@ -55,6 +55,8 @@ static void pnv_cpu_reset(void *opaque) env->gpr[3] = PNV_FDT_ADDR; env->nip = 0x10; env->msr |= MSR_HVB; /* Hypervisor mode */ + + pcc->intc_reset(chip, cpu); } /* @@ -160,7 +162,7 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) +static void pnv_core_cpu_realize(PowerPCCPU *cpu, PnvChip *chip, Error **errp) { CPUPPCState *env = &cpu->env; int core_pir; @@ -192,8 +194,17 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ); +} + +static void pnv_core_reset(void *dev) +{ + CPUCore *cc = CPU_CORE(dev); + PnvCore *pc = PNV_CORE(dev); + int i; - qemu_register_reset(pnv_cpu_reset, cpu); + for (i = 0; i < cc->nr_threads; i++) { + pnv_core_cpu_reset(pc->threads[i], pc->chip); + } } static void pnv_core_realize(DeviceState *dev, Error **errp) @@ -214,6 +225,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) "required link 'chip' not found: "); return; } + pc->chip = PNV_CHIP(chip); pc->threads = g_new(PowerPCCPU *, cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { @@ -235,7 +247,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) } for (j = 0; j < cc->nr_threads; j++) { - pnv_realize_vcpu(pc->threads[j], PNV_CHIP(chip), &local_err); + pnv_core_cpu_realize(pc->threads[j], pc->chip, &local_err); if (local_err) { goto err; } @@ -244,6 +256,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id); pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops, pc, name, PNV_XSCOM_EX_SIZE); + + qemu_register_reset(pnv_core_reset, pc); return; err: @@ -255,11 +269,10 @@ err: error_propagate(errp, local_err); } -static void pnv_unrealize_vcpu(PowerPCCPU *cpu) +static void pnv_core_cpu_unrealize(PowerPCCPU *cpu) { PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); - qemu_unregister_reset(pnv_cpu_reset, cpu); object_unparent(OBJECT(pnv_cpu_state(cpu)->intc)); cpu_remove_sync(CPU(cpu)); cpu->machine_data = NULL; @@ -273,8 +286,10 @@ static void pnv_core_unrealize(DeviceState *dev, Error **errp) CPUCore *cc = CPU_CORE(dev); int i; + qemu_unregister_reset(pnv_core_reset, pc); + for (i = 0; i < cc->nr_threads; i++) { - pnv_unrealize_vcpu(pc->threads[i]); + pnv_core_cpu_unrealize(pc->threads[i]); } g_free(pc->threads); } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index a997f16bb4..68d0dfacfe 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -660,10 +660,19 @@ static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno) uint32_t offset = (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT); - uint64_t lisn = cpu_to_be64(offset + srcno); + uint64_t data = XIVE_TRIGGER_PQ | offset | srcno; + MemTxResult result; - if (valid) { - cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn)); + if (!valid) { + return; + } + + address_space_stq_be(&address_space_memory, notify_addr, data, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: trigger failed @%" + HWADDR_PRIx "\n", __func__, notif_port); + return; } } diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 388cae0b43..1f721feed6 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -29,7 +29,7 @@ #include "cpu.h" #include "hw/ppc/ppc.h" #include "ppc405.h" -#include "hw/timer/m48t59.h" +#include "hw/rtc/m48t59.h" #include "hw/block/flash.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 4f3c6bf190..862345c2ac 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hw/timer/m48t59.h" +#include "hw/rtc/m48t59.h" #include "hw/char/serial.h" #include "hw/block/fdc.h" #include "net/net.h" @@ -40,7 +40,7 @@ #include "hw/ide.h" #include "hw/irq.h" #include "hw/loader.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/isa/pc87312.h" #include "hw/net/ne2000-isa.h" #include "sysemu/arch_init.h" diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c index df7c0006fc..66b14db5fa 100644 --- a/hw/ppc/rs6000_mc.c +++ b/hw/ppc/rs6000_mc.c @@ -144,6 +144,7 @@ static void rs6000mc_realize(DeviceState *dev, Error **errp) RS6000MCState *s = RS6000MC_DEVICE(dev); int socket = 0; unsigned int ram_size = s->ram_size / MiB; + Error *local_err = NULL; while (socket < 6) { if (ram_size >= 64) { @@ -165,19 +166,21 @@ static void rs6000mc_realize(DeviceState *dev, Error **errp) if (s->simm_size[socket]) { char name[] = "simm.?"; name[5] = socket + '0'; - memory_region_allocate_system_memory(&s->simm[socket], OBJECT(dev), - name, - s->simm_size[socket] * MiB); + memory_region_init_ram(&s->simm[socket], OBJECT(dev), name, + s->simm_size[socket] * MiB, &local_err); + if (local_err) { + goto out; + } memory_region_add_subregion_overlap(get_system_memory(), 0, &s->simm[socket], socket); } } if (ram_size) { /* unable to push all requested RAM in SIMMs */ - error_setg(errp, "RAM size incompatible with this board. " + error_setg(&local_err, "RAM size incompatible with this board. " "Try again with something else, like %" PRId64 " MB", s->ram_size / MiB - ram_size); - return; + goto out; } if (s->autoconfigure) { @@ -193,6 +196,8 @@ static void rs6000mc_realize(DeviceState *dev, Error **errp) isa_register_portio_list(ISA_DEVICE(dev), &s->portio, 0x0, rs6000mc_port_list, s, "rs6000mc"); +out: + error_propagate(errp, local_err); } static const VMStateDescription vmstate_rs6000mc = { diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4eb97d3a9b..94f9d27096 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1247,8 +1247,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr) _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2)); /* /interrupt controller */ - spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt, - PHANDLE_INTC); + spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC); ret = spapr_populate_memory(spapr, fdt); if (ret < 0) { @@ -1268,7 +1267,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr) } QLIST_FOREACH(phb, &spapr->phbs, list) { - ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, NULL); + ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL); if (ret < 0) { error_report("couldn't setup PCI devices in fdt"); exit(1); @@ -2496,6 +2495,7 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) { MachineState *ms = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); Error *local_err = NULL; bool vsmt_user = !!spapr->vsmt; int kvm_smt = kvmppc_smt_threads(); @@ -2522,7 +2522,7 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) goto out; } /* In this case, spapr->vsmt has been set by the command line */ - } else { + } else if (!smc->smp_threads_vsmt) { /* * Default VSMT value is tricky, because we need it to be as * consistent as possible (for migration), but this requires @@ -2531,6 +2531,8 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) * overwhelmingly common case in production systems. */ spapr->vsmt = MAX(8, smp_threads); + } else { + spapr->vsmt = smp_threads; } /* KVM: If necessary, set the SMT mode: */ @@ -3739,9 +3741,10 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, spapr_vcpu_id(spapr, cc->core_id)); g_assert(drc); - spapr_drc_detach(drc); - - spapr_hotplug_req_remove_by_index(drc); + if (!spapr_drc_unplug_requested(drc)) { + spapr_drc_detach(drc); + spapr_hotplug_req_remove_by_index(drc); + } } int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, @@ -3903,8 +3906,7 @@ int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, return -1; } - if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis, - fdt_start_offset)) { + if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) { error_setg(errp, "unable to create FDT node for PHB %d", sphb->index); return -1; } @@ -4263,7 +4265,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, { SpaprMachineState *spapr = SPAPR_MACHINE(obj); - spapr->irq->print_info(spapr, mon); + spapr_irq_print_info(spapr, mon); monitor_printf(mon, "irqchip: %s\n", kvm_irqchip_in_kernel() ? "in-kernel" : "emulated"); } @@ -4438,6 +4440,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->irq = &spapr_irq_dual; smc->dr_phb_enabled = true; smc->linux_pci_probe = true; + smc->smp_threads_vsmt = true; + smc->nr_xirqs = SPAPR_NR_XIRQS; } static const TypeInfo spapr_machine_info = { @@ -4505,6 +4509,7 @@ static void spapr_machine_4_1_class_options(MachineClass *mc) spapr_machine_4_2_class_options(mc); smc->linux_pci_probe = false; + smc->smp_threads_vsmt = false; compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } @@ -4573,6 +4578,7 @@ static void spapr_machine_3_0_class_options(MachineClass *mc) compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len); smc->legacy_irq_allocation = true; + smc->nr_xirqs = 0x400; smc->irq = &spapr_irq_xics_legacy; } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 1d93de8161..ef7b27a66d 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -25,14 +25,14 @@ #include "sysemu/hw_accel.h" #include "qemu/error-report.h" -static void spapr_cpu_reset(void *opaque) +static void spapr_reset_vcpu(PowerPCCPU *cpu) { - PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); target_ulong lpcr; + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); cpu_reset(cs); @@ -77,9 +77,11 @@ static void spapr_cpu_reset(void *opaque) spapr_cpu->dtl_addr = 0; spapr_cpu->dtl_size = 0; - spapr_caps_cpu_apply(SPAPR_MACHINE(qdev_get_machine()), cpu); + spapr_caps_cpu_apply(spapr, cpu); kvm_check_mmu(cpu, &error_fatal); + + spapr_irq_cpu_intc_reset(spapr, cpu); } void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3) @@ -193,7 +195,6 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc) if (!sc->pre_3_0_migration) { vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data); } - qemu_unregister_reset(spapr_cpu_reset, cpu); if (spapr_cpu_state(cpu)->icp) { object_unparent(OBJECT(spapr_cpu_state(cpu)->icp)); } @@ -204,12 +205,36 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc) object_unparent(OBJECT(cpu)); } +/* + * Called when CPUs are hot-plugged. + */ +static void spapr_cpu_core_reset(DeviceState *dev) +{ + CPUCore *cc = CPU_CORE(dev); + SpaprCpuCore *sc = SPAPR_CPU_CORE(dev); + int i; + + for (i = 0; i < cc->nr_threads; i++) { + spapr_reset_vcpu(sc->threads[i]); + } +} + +/* + * Called by the machine reset. + */ +static void spapr_cpu_core_reset_handler(void *opaque) +{ + spapr_cpu_core_reset(opaque); +} + static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp) { SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); int i; + qemu_unregister_reset(spapr_cpu_core_reset_handler, sc); + for (i = 0; i < cc->nr_threads; i++) { spapr_unrealize_vcpu(sc->threads[i], sc); } @@ -234,12 +259,8 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); kvmppc_set_papr(cpu); - qemu_register_reset(spapr_cpu_reset, cpu); - spapr_cpu_reset(cpu); - - spapr->irq->cpu_intc_create(spapr, cpu, &local_err); - if (local_err) { - goto error_unregister; + if (spapr_irq_cpu_intc_create(spapr, cpu, &local_err) < 0) { + goto error_intc_create; } if (!sc->pre_3_0_migration) { @@ -249,8 +270,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, return; -error_unregister: - qemu_unregister_reset(spapr_cpu_reset, cpu); +error_intc_create: cpu_remove_sync(CPU(cpu)); error: error_propagate(errp, local_err); @@ -337,6 +357,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) goto err_unrealize; } } + + qemu_register_reset(spapr_cpu_core_reset_handler, sc); return; err_unrealize: @@ -365,6 +387,7 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) dc->realize = spapr_cpu_core_realize; dc->unrealize = spapr_cpu_core_unrealize; + dc->reset = spapr_cpu_core_reset; dc->props = spapr_cpu_core_properties; scc->cpu_type = data; } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 457eabe24c..b941608b69 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -23,9 +23,20 @@ #include "trace.h" -void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis) +static const TypeInfo spapr_intc_info = { + .name = TYPE_SPAPR_INTC, + .parent = TYPE_INTERFACE, + .class_size = sizeof(SpaprInterruptControllerClass), +}; + +static void spapr_irq_msi_init(SpaprMachineState *spapr) { - spapr->irq_map_nr = nr_msis; + if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { + /* Legacy mode doesn't use this allocator */ + return; + } + + spapr->irq_map_nr = spapr_irq_nr_msis(spapr); spapr->irq_map = bitmap_new(spapr->irq_map_nr); } @@ -59,262 +70,53 @@ void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num) bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num); } -static void spapr_irq_init_kvm(SpaprMachineState *spapr, - SpaprIrq *irq, Error **errp) +int spapr_irq_init_kvm(int (*fn)(SpaprInterruptController *, Error **), + SpaprInterruptController *intc, + Error **errp) { - MachineState *machine = MACHINE(spapr); + MachineState *machine = MACHINE(qdev_get_machine()); Error *local_err = NULL; if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { - irq->init_kvm(spapr, &local_err); - if (local_err && machine_kernel_irqchip_required(machine)) { - error_prepend(&local_err, - "kernel_irqchip requested but unavailable: "); - error_propagate(errp, local_err); - return; - } + if (fn(intc, &local_err) < 0) { + if (machine_kernel_irqchip_required(machine)) { + error_prepend(&local_err, + "kernel_irqchip requested but unavailable: "); + error_propagate(errp, local_err); + return -1; + } - if (!local_err) { - return; + /* + * We failed to initialize the KVM device, fallback to + * emulated mode + */ + error_prepend(&local_err, + "kernel_irqchip allowed but unavailable: "); + error_append_hint(&local_err, + "Falling back to kernel-irqchip=off\n"); + warn_report_err(local_err); } - - /* - * We failed to initialize the KVM device, fallback to - * emulated mode - */ - error_prepend(&local_err, "kernel_irqchip allowed but unavailable: "); - error_append_hint(&local_err, "Falling back to kernel-irqchip=off\n"); - warn_report_err(local_err); } + + return 0; } /* * XICS IRQ backend. */ -static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, - Error **errp) -{ - ICSState *ics = spapr->ics; - - assert(ics); - assert(ics_valid_irq(ics, irq)); - - if (!ics_irq_free(ics, irq - ics->offset)) { - error_setg(errp, "IRQ %d is not free", irq); - return -1; - } - - ics_set_irq_type(ics, irq - ics->offset, lsi); - return 0; -} - -static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq) -{ - ICSState *ics = spapr->ics; - uint32_t srcno = irq - ics->offset; - - assert(ics_valid_irq(ics, irq)); - - memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); -} - -static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - - icp_pic_print_info(spapr_cpu_state(cpu)->icp, mon); - } - - ics_pic_print_info(spapr->ics, mon); -} - -static void spapr_irq_cpu_intc_create_xics(SpaprMachineState *spapr, - PowerPCCPU *cpu, Error **errp) -{ - Error *local_err = NULL; - Object *obj; - SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - - obj = icp_create(OBJECT(cpu), TYPE_ICP, XICS_FABRIC(spapr), - &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_cpu->icp = ICP(obj); -} - -static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id) -{ - if (!kvm_irqchip_in_kernel()) { - CPUState *cs; - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - icp_resend(spapr_cpu_state(cpu)->icp); - } - } - return 0; -} - -static void spapr_irq_set_irq_xics(void *opaque, int irq, int val) -{ - SpaprMachineState *spapr = opaque; - uint32_t srcno = irq - spapr->ics->offset; - - ics_set_irq(spapr->ics, srcno, val); -} - -static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_init_kvm(spapr, &spapr_irq_xics, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - -static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) -{ - if (kvm_enabled()) { - xics_kvm_connect(spapr, errp); - } -} - SpaprIrq spapr_irq_xics = { - .nr_xirqs = SPAPR_NR_XIRQS, - .nr_msis = SPAPR_NR_MSIS, .xics = true, .xive = false, - - .claim = spapr_irq_claim_xics, - .free = spapr_irq_free_xics, - .print_info = spapr_irq_print_info_xics, - .dt_populate = spapr_dt_xics, - .cpu_intc_create = spapr_irq_cpu_intc_create_xics, - .post_load = spapr_irq_post_load_xics, - .reset = spapr_irq_reset_xics, - .set_irq = spapr_irq_set_irq_xics, - .init_kvm = spapr_irq_init_kvm_xics, }; /* * XIVE IRQ backend. */ -static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, - Error **errp) -{ - return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp); -} - -static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq) -{ - spapr_xive_irq_free(spapr->xive, irq); -} - -static void spapr_irq_print_info_xive(SpaprMachineState *spapr, - Monitor *mon) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - - xive_tctx_pic_print_info(spapr_cpu_state(cpu)->tctx, mon); - } - - spapr_xive_pic_print_info(spapr->xive, mon); -} - -static void spapr_irq_cpu_intc_create_xive(SpaprMachineState *spapr, - PowerPCCPU *cpu, Error **errp) -{ - Error *local_err = NULL; - Object *obj; - SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - - obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_cpu->tctx = XIVE_TCTX(obj); - - /* - * (TCG) Early setting the OS CAM line for hotplugged CPUs as they - * don't beneficiate from the reset of the XIVE IRQ backend - */ - spapr_xive_set_tctx_os_cam(spapr_cpu->tctx); -} - -static int spapr_irq_post_load_xive(SpaprMachineState *spapr, int version_id) -{ - return spapr_xive_post_load(spapr->xive, version_id); -} - -static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp) -{ - CPUState *cs; - Error *local_err = NULL; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - - /* (TCG) Set the OS CAM line of the thread interrupt context. */ - spapr_xive_set_tctx_os_cam(spapr_cpu_state(cpu)->tctx); - } - - spapr_irq_init_kvm(spapr, &spapr_irq_xive, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - /* Activate the XIVE MMIOs */ - spapr_xive_mmio_set_enabled(spapr->xive, true); -} - -static void spapr_irq_set_irq_xive(void *opaque, int irq, int val) -{ - SpaprMachineState *spapr = opaque; - - if (kvm_irqchip_in_kernel()) { - kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val); - } else { - xive_source_set_irq(&spapr->xive->source, irq, val); - } -} - -static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) -{ - if (kvm_enabled()) { - kvmppc_xive_connect(spapr->xive, errp); - } -} - SpaprIrq spapr_irq_xive = { - .nr_xirqs = SPAPR_NR_XIRQS, - .nr_msis = SPAPR_NR_MSIS, .xics = false, .xive = true, - - .claim = spapr_irq_claim_xive, - .free = spapr_irq_free_xive, - .print_info = spapr_irq_print_info_xive, - .dt_populate = spapr_dt_xive, - .cpu_intc_create = spapr_irq_cpu_intc_create_xive, - .post_load = spapr_irq_post_load_xive, - .reset = spapr_irq_reset_xive, - .set_irq = spapr_irq_set_irq_xive, - .init_kvm = spapr_irq_init_kvm_xive, }; /* @@ -327,138 +129,11 @@ SpaprIrq spapr_irq_xive = { */ /* - * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the - * default. - */ -static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) -{ - return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ? - &spapr_irq_xive : &spapr_irq_xics; -} - -static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, - Error **errp) -{ - Error *local_err = NULL; - int ret; - - ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return ret; - } - - ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return ret; - } - - return ret; -} - -static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq) -{ - spapr_irq_xics.free(spapr, irq); - spapr_irq_xive.free(spapr, irq); -} - -static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) -{ - spapr_irq_current(spapr)->print_info(spapr, mon); -} - -static void spapr_irq_dt_populate_dual(SpaprMachineState *spapr, - uint32_t nr_servers, void *fdt, - uint32_t phandle) -{ - spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle); -} - -static void spapr_irq_cpu_intc_create_dual(SpaprMachineState *spapr, - PowerPCCPU *cpu, Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_irq_xics.cpu_intc_create(spapr, cpu, errp); -} - -static int spapr_irq_post_load_dual(SpaprMachineState *spapr, int version_id) -{ - /* - * Force a reset of the XIVE backend after migration. The machine - * defaults to XICS at startup. - */ - if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { - if (kvm_irqchip_in_kernel()) { - xics_kvm_disconnect(spapr, &error_fatal); - } - spapr_irq_xive.reset(spapr, &error_fatal); - } - - return spapr_irq_current(spapr)->post_load(spapr, version_id); -} - -static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) -{ - Error *local_err = NULL; - - /* - * Deactivate the XIVE MMIOs. The XIVE backend will reenable them - * if selected. - */ - spapr_xive_mmio_set_enabled(spapr->xive, false); - - /* Destroy all KVM devices */ - if (kvm_irqchip_in_kernel()) { - xics_kvm_disconnect(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "KVM XICS disconnect failed: "); - return; - } - kvmppc_xive_disconnect(spapr->xive, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "KVM XIVE disconnect failed: "); - return; - } - } - - spapr_irq_current(spapr)->reset(spapr, errp); -} - -static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) -{ - SpaprMachineState *spapr = opaque; - - spapr_irq_current(spapr)->set_irq(spapr, irq, val); -} - -/* * Define values in sync with the XIVE and XICS backend */ SpaprIrq spapr_irq_dual = { - .nr_xirqs = SPAPR_NR_XIRQS, - .nr_msis = SPAPR_NR_MSIS, .xics = true, .xive = true, - - .claim = spapr_irq_claim_dual, - .free = spapr_irq_free_dual, - .print_info = spapr_irq_print_info_dual, - .dt_populate = spapr_irq_dt_populate_dual, - .cpu_intc_create = spapr_irq_cpu_intc_create_dual, - .post_load = spapr_irq_post_load_dual, - .reset = spapr_irq_reset_dual, - .set_irq = spapr_irq_set_irq_dual, - .init_kvm = NULL, /* should not be used */ }; @@ -521,9 +196,85 @@ static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) /* * sPAPR IRQ frontend routines for devices */ +#define ALL_INTCS(spapr_) \ + { SPAPR_INTC((spapr_)->ics), SPAPR_INTC((spapr_)->xive), } + +int spapr_irq_cpu_intc_create(SpaprMachineState *spapr, + PowerPCCPU *cpu, Error **errp) +{ + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i; + int rc; + + for (i = 0; i < ARRAY_SIZE(intcs); i++) { + SpaprInterruptController *intc = intcs[i]; + if (intc) { + SpaprInterruptControllerClass *sicc = SPAPR_INTC_GET_CLASS(intc); + rc = sicc->cpu_intc_create(intc, cpu, errp); + if (rc < 0) { + return rc; + } + } + } + + return 0; +} + +void spapr_irq_cpu_intc_reset(SpaprMachineState *spapr, PowerPCCPU *cpu) +{ + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i; + + for (i = 0; i < ARRAY_SIZE(intcs); i++) { + SpaprInterruptController *intc = intcs[i]; + if (intc) { + SpaprInterruptControllerClass *sicc = SPAPR_INTC_GET_CLASS(intc); + sicc->cpu_intc_reset(intc, cpu); + } + } +} + +static void spapr_set_irq(void *opaque, int irq, int level) +{ + SpaprMachineState *spapr = SPAPR_MACHINE(opaque); + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->active_intc); + + sicc->set_irq(spapr->active_intc, irq, level); +} + +void spapr_irq_print_info(SpaprMachineState *spapr, Monitor *mon) +{ + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->active_intc); + + sicc->print_info(spapr->active_intc, mon); +} + +void spapr_irq_dt(SpaprMachineState *spapr, uint32_t nr_servers, + void *fdt, uint32_t phandle) +{ + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->active_intc); + + sicc->dt(spapr->active_intc, nr_servers, fdt, phandle); +} + +uint32_t spapr_irq_nr_msis(SpaprMachineState *spapr) +{ + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + + if (smc->legacy_irq_allocation) { + return smc->nr_xirqs; + } else { + return SPAPR_XIRQ_BASE + smc->nr_xirqs - SPAPR_IRQ_MSI; + } +} + void spapr_irq_init(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); if (machine_kernel_irqchip_split(machine)) { error_setg(errp, "kernel_irqchip split mode not supported on pseries"); @@ -541,9 +292,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) } /* Initialize the MSI IRQ allocator. */ - if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { - spapr_irq_msi_init(spapr, spapr->irq->nr_msis); - } + spapr_irq_msi_init(spapr); if (spapr->irq->xics) { Error *local_err = NULL; @@ -563,8 +312,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) return; } - object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs", - &local_err); + object_property_set_int(obj, smc->nr_xirqs, "nr-irqs", &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -585,8 +333,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) int i; dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", - spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_XIRQ_BASE); /* * 8 XIVE END structures per CPU. One for each available * priority @@ -598,8 +345,11 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) /* Enable the CPU IPIs */ for (i = 0; i < nr_servers; ++i) { - if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, - false, errp) < 0) { + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->xive); + + if (sicc->claim_irq(SPAPR_INTC(spapr->xive), SPAPR_IRQ_IPI + i, + false, errp) < 0) { return; } } @@ -607,32 +357,60 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_xive_hcall_init(spapr); } - spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, - spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + spapr->qirqs = qemu_allocate_irqs(spapr_set_irq, spapr, + smc->nr_xirqs + SPAPR_XIRQ_BASE); } int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i; + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + int rc; + assert(irq >= SPAPR_XIRQ_BASE); - assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + assert(irq < (smc->nr_xirqs + SPAPR_XIRQ_BASE)); + + for (i = 0; i < ARRAY_SIZE(intcs); i++) { + SpaprInterruptController *intc = intcs[i]; + if (intc) { + SpaprInterruptControllerClass *sicc = SPAPR_INTC_GET_CLASS(intc); + rc = sicc->claim_irq(intc, irq, lsi, errp); + if (rc < 0) { + return rc; + } + } + } - return spapr->irq->claim(spapr, irq, lsi, errp); + return 0; } void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) { - int i; + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i, j; + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); assert(irq >= SPAPR_XIRQ_BASE); - assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + assert((irq + num) <= (smc->nr_xirqs + SPAPR_XIRQ_BASE)); for (i = irq; i < (irq + num); i++) { - spapr->irq->free(spapr, i); + for (j = 0; j < ARRAY_SIZE(intcs); j++) { + SpaprInterruptController *intc = intcs[j]; + + if (intc) { + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(intc); + sicc->free_irq(intc, i); + } + } } } qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) { + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + /* * This interface is basically for VIO and PHB devices to find the * right qemu_irq to manipulate, so we only allow access to the @@ -641,7 +419,7 @@ qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) * interfaces, we can change this if we need to in future. */ assert(irq >= SPAPR_XIRQ_BASE); - assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + assert(irq < (smc->nr_xirqs + SPAPR_XIRQ_BASE)); if (spapr->ics) { assert(ics_valid_irq(spapr->ics, irq)); @@ -656,16 +434,18 @@ qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) { - return spapr->irq->post_load(spapr, version_id); + SpaprInterruptControllerClass *sicc; + + spapr_irq_update_active_intc(spapr); + sicc = SPAPR_INTC_GET_CLASS(spapr->active_intc); + return sicc->post_load(spapr->active_intc, version_id); } void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) { assert(!spapr->irq_map || bitmap_empty(spapr->irq_map, spapr->irq_map_nr)); - if (spapr->irq->reset) { - spapr->irq->reset(spapr, errp); - } + spapr_irq_update_active_intc(spapr); } int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) @@ -689,6 +469,54 @@ int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) return phandle; } +static void set_active_intc(SpaprMachineState *spapr, + SpaprInterruptController *new_intc) +{ + SpaprInterruptControllerClass *sicc; + + assert(new_intc); + + if (new_intc == spapr->active_intc) { + /* Nothing to do */ + return; + } + + if (spapr->active_intc) { + sicc = SPAPR_INTC_GET_CLASS(spapr->active_intc); + if (sicc->deactivate) { + sicc->deactivate(spapr->active_intc); + } + } + + sicc = SPAPR_INTC_GET_CLASS(new_intc); + if (sicc->activate) { + sicc->activate(new_intc, &error_fatal); + } + + spapr->active_intc = new_intc; +} + +void spapr_irq_update_active_intc(SpaprMachineState *spapr) +{ + SpaprInterruptController *new_intc; + + if (!spapr->ics) { + /* + * XXX before we run CAS, ov5_cas is initialized empty, which + * indicates XICS, even if we have ic-mode=xive. TODO: clean + * up the CAS path so that we have a clearer way of handling + * this. + */ + new_intc = SPAPR_INTC(spapr->xive); + } else if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + new_intc = SPAPR_INTC(spapr->xive); + } else { + new_intc = SPAPR_INTC(spapr->ics); + } + + set_active_intc(spapr, new_intc); +} + /* * XICS legacy routines - to deprecate one day */ @@ -744,21 +572,14 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) return first + ics->offset; } -#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400 - SpaprIrq spapr_irq_xics_legacy = { - .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, - .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, .xics = true, .xive = false, - - .claim = spapr_irq_claim_xics, - .free = spapr_irq_free_xics, - .print_info = spapr_irq_print_info_xics, - .dt_populate = spapr_dt_xics, - .cpu_intc_create = spapr_irq_cpu_intc_create_xics, - .post_load = spapr_irq_post_load_xics, - .reset = spapr_irq_reset_xics, - .set_irq = spapr_irq_set_irq_xics, - .init_kvm = spapr_irq_init_kvm_xics, }; + +static void spapr_irq_register_types(void) +{ + type_register_static(&spapr_intc_info); +} + +type_init(spapr_irq_register_types) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 01ff41d4c4..cc0e7829b6 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2277,8 +2277,8 @@ static void spapr_phb_pci_enumerate(SpaprPhbState *phb) } -int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, - uint32_t nr_msis, int *node_offset) +int spapr_dt_phb(SpaprMachineState *spapr, SpaprPhbState *phb, + uint32_t intc_phandle, void *fdt, int *node_offset) { int bus_off, i, j, ret; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; @@ -2343,7 +2343,8 @@ int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges)); _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); - _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", nr_msis)); + _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", + spapr_irq_nr_msis(spapr))); /* Dynamic DMA window */ if (phb->ddw_enabled) { diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig new file mode 100644 index 0000000000..45daa8d655 --- /dev/null +++ b/hw/rtc/Kconfig @@ -0,0 +1,23 @@ +config DS1338 + bool + depends on I2C + +config M41T80 + bool + depends on I2C + +config M48T59 + bool + +config PL031 + bool + +config TWL92230 + bool + depends on I2C + +config MC146818RTC + bool + +config SUN4V_RTC + bool diff --git a/hw/rtc/Makefile.objs b/hw/rtc/Makefile.objs new file mode 100644 index 0000000000..8dc9fcd3a9 --- /dev/null +++ b/hw/rtc/Makefile.objs @@ -0,0 +1,13 @@ +common-obj-$(CONFIG_DS1338) += ds1338.o +common-obj-$(CONFIG_M41T80) += m41t80.o +common-obj-$(CONFIG_M48T59) += m48t59.o +ifeq ($(CONFIG_ISA_BUS),y) +common-obj-$(CONFIG_M48T59) += m48t59-isa.o +endif +common-obj-$(CONFIG_PL031) += pl031.o +common-obj-$(CONFIG_TWL92230) += twl92230.o +common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o +common-obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o +obj-$(CONFIG_MC146818RTC) += mc146818rtc.o +common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o +common-obj-$(CONFIG_ASPEED_SOC) += aspeed_rtc.o diff --git a/hw/timer/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c index 5313017353..3ca1183558 100644 --- a/hw/timer/aspeed_rtc.c +++ b/hw/rtc/aspeed_rtc.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "hw/timer/aspeed_rtc.h" +#include "hw/rtc/aspeed_rtc.h" #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/timer.h" diff --git a/hw/timer/ds1338.c b/hw/rtc/ds1338.c index 588a9ba9be..588a9ba9be 100644 --- a/hw/timer/ds1338.c +++ b/hw/rtc/ds1338.c diff --git a/hw/timer/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c index f85483a07f..f85483a07f 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/rtc/exynos4210_rtc.c diff --git a/hw/timer/m41t80.c b/hw/rtc/m41t80.c index 914ecac8f4..914ecac8f4 100644 --- a/hw/timer/m41t80.c +++ b/hw/rtc/m41t80.c diff --git a/hw/timer/m48t59-internal.h b/hw/rtc/m48t59-internal.h index 4d4f2a6fed..4d4f2a6fed 100644 --- a/hw/timer/m48t59-internal.h +++ b/hw/rtc/m48t59-internal.h diff --git a/hw/timer/m48t59-isa.c b/hw/rtc/m48t59-isa.c index 5e5432abfd..7fde854c0f 100644 --- a/hw/timer/m48t59-isa.c +++ b/hw/rtc/m48t59-isa.c @@ -1,5 +1,5 @@ /* - * QEMU M48T59 and M48T08 NVRAM emulation (ISA bus interface + * QEMU M48T59 and M48T08 NVRAM emulation (ISA bus interface) * * Copyright (c) 2003-2005, 2007 Jocelyn Mayer * Copyright (c) 2013 Hervé Poussineau @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" -#include "hw/timer/m48t59.h" +#include "hw/rtc/m48t59.h" #include "m48t59-internal.h" #include "qemu/module.h" diff --git a/hw/timer/m48t59.c b/hw/rtc/m48t59.c index a9fc2f981a..fc592b9fb1 100644 --- a/hw/timer/m48t59.c +++ b/hw/rtc/m48t59.c @@ -27,7 +27,7 @@ #include "qemu-common.h" #include "hw/irq.h" #include "hw/qdev-properties.h" -#include "hw/timer/m48t59.h" +#include "hw/rtc/m48t59.h" #include "qemu/timer.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" diff --git a/hw/timer/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 0d7784b104..ee6bf82b40 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -34,13 +34,14 @@ #include "sysemu/replay.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" +#include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" #include "qapi/error.h" #include "qapi/qapi-events-misc-target.h" #include "qapi/visitor.h" #include "exec/address-spaces.h" -#include "hw/timer/mc146818rtc_regs.h" +#include "hw/rtc/mc146818rtc_regs.h" #ifdef TARGET_I386 #include "qapi/qapi-commands-misc-target.h" diff --git a/hw/timer/pl031.c b/hw/rtc/pl031.c index 2b3e261006..3a982752a2 100644 --- a/hw/timer/pl031.c +++ b/hw/rtc/pl031.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "hw/timer/pl031.h" +#include "hw/rtc/pl031.h" #include "migration/vmstate.h" #include "hw/irq.h" #include "hw/qdev-properties.h" diff --git a/hw/timer/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c index 54272a822f..ada01b5774 100644 --- a/hw/timer/sun4v-rtc.c +++ b/hw/rtc/sun4v-rtc.c @@ -13,7 +13,7 @@ #include "hw/sysbus.h" #include "qemu/module.h" #include "qemu/timer.h" -#include "hw/timer/sun4v-rtc.h" +#include "hw/rtc/sun4v-rtc.h" #include "trace.h" diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events new file mode 100644 index 0000000000..d6749f4616 --- /dev/null +++ b/hw/rtc/trace-events @@ -0,0 +1,19 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# sun4v-rtc.c +sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64 +sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64 + +# xlnx-zynqmp-rtc.c +xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d" + +# pl031.c +pl031_irq_state(int level) "irq state %d" +pl031_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl031_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl031_alarm_raised(void) "alarm raised" +pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks" + +# aspeed-rtc.c +aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 +aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 diff --git a/hw/timer/twl92230.c b/hw/rtc/twl92230.c index 63bd13d2ca..63bd13d2ca 100644 --- a/hw/timer/twl92230.c +++ b/hw/rtc/twl92230.c diff --git a/hw/timer/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c index 5692db98c2..2bcd14d779 100644 --- a/hw/timer/xlnx-zynqmp-rtc.c +++ b/hw/rtc/xlnx-zynqmp-rtc.c @@ -32,11 +32,10 @@ #include "qemu/log.h" #include "qemu/module.h" #include "hw/irq.h" -#include "hw/ptimer.h" #include "qemu/cutils.h" #include "sysemu/sysemu.h" #include "trace.h" -#include "hw/timer/xlnx-zynqmp-rtc.h" +#include "hw/rtc/xlnx-zynqmp-rtc.h" #include "migration/vmstate.h" #ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index e08ec3e398..88404d0e9d 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1532,6 +1532,8 @@ static const TypeInfo sdhci_bus_info = { .class_init = sdhci_bus_class_init, }; +/* --- qdev i.MX eSDHC --- */ + static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) { SDHCIState *s = SYSBUS_SDHCI(opaque); @@ -1734,7 +1736,6 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) } } - static const MemoryRegionOps usdhc_mmio_ops = { .read = usdhc_read, .write = usdhc_write, @@ -1760,11 +1761,76 @@ static const TypeInfo imx_usdhc_info = { .instance_init = imx_usdhc_init, }; +/* --- qdev Samsung s3c --- */ + +#define S3C_SDHCI_CONTROL2 0x80 +#define S3C_SDHCI_CONTROL3 0x84 +#define S3C_SDHCI_CONTROL4 0x8c + +static uint64_t sdhci_s3c_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t ret; + + switch (offset) { + case S3C_SDHCI_CONTROL2: + case S3C_SDHCI_CONTROL3: + case S3C_SDHCI_CONTROL4: + /* ignore */ + ret = 0; + break; + default: + ret = sdhci_read(opaque, offset, size); + break; + } + + return ret; +} + +static void sdhci_s3c_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + switch (offset) { + case S3C_SDHCI_CONTROL2: + case S3C_SDHCI_CONTROL3: + case S3C_SDHCI_CONTROL4: + /* ignore */ + break; + default: + sdhci_write(opaque, offset, val, size); + break; + } +} + +static const MemoryRegionOps sdhci_s3c_mmio_ops = { + .read = sdhci_s3c_read, + .write = sdhci_s3c_write, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void sdhci_s3c_init(Object *obj) +{ + SDHCIState *s = SYSBUS_SDHCI(obj); + + s->io_ops = &sdhci_s3c_mmio_ops; +} + +static const TypeInfo sdhci_s3c_info = { + .name = TYPE_S3C_SDHCI , + .parent = TYPE_SYSBUS_SDHCI, + .instance_init = sdhci_s3c_init, +}; + static void sdhci_register_types(void) { type_register_static(&sdhci_sysbus_info); type_register_static(&sdhci_bus_info); type_register_static(&imx_usdhc_info); + type_register_static(&sdhci_s3c_info); } type_init(sdhci_register_types) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 6c5a17a020..2aaa5bf1ae 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -31,7 +31,7 @@ #include "qemu/error-report.h" #include "qemu/timer.h" #include "hw/sparc/sun4m_iommu.h" -#include "hw/timer/m48t59.h" +#include "hw/rtc/m48t59.h" #include "migration/vmstate.h" #include "hw/sparc/sparc32_dma.h" #include "hw/block/fdc.h" diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index 167143bffe..5eb2d097b9 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -30,12 +30,13 @@ #include "hw/misc/unimp.h" #include "hw/loader.h" #include "hw/sparc/sparc64.h" -#include "hw/timer/sun4v-rtc.h" +#include "hw/rtc/sun4v-rtc.h" #include "exec/address-spaces.h" #include "sysemu/block-backend.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "sysemu/sysemu.h" +#include "qapi/error.h" typedef struct NiagaraBoardState { MemoryRegion hv_ram; @@ -106,8 +107,8 @@ static void niagara_init(MachineState *machine) /* init CPUs */ sparc64_cpu_devinit(machine->cpu_type, NIAGARA_PROM_BASE); /* set up devices */ - memory_region_allocate_system_memory(&s->hv_ram, NULL, "sun4v-hv.ram", - NIAGARA_HV_RAM_SIZE); + memory_region_init_ram(&s->hv_ram, NULL, "sun4v-hv.ram", + NIAGARA_HV_RAM_SIZE, &error_fatal); memory_region_add_subregion(sysmem, NIAGARA_HV_RAM_BASE, &s->hv_ram); memory_region_allocate_system_memory(&s->partition_ram, NULL, @@ -116,17 +117,17 @@ static void niagara_init(MachineState *machine) memory_region_add_subregion(sysmem, NIAGARA_PARTITION_RAM_BASE, &s->partition_ram); - memory_region_allocate_system_memory(&s->nvram, NULL, - "sun4v.nvram", NIAGARA_NVRAM_SIZE); + memory_region_init_ram(&s->nvram, NULL, "sun4v.nvram", NIAGARA_NVRAM_SIZE, + &error_fatal); memory_region_add_subregion(sysmem, NIAGARA_NVRAM_BASE, &s->nvram); - memory_region_allocate_system_memory(&s->md_rom, NULL, - "sun4v-md.rom", NIAGARA_MD_ROM_SIZE); + memory_region_init_ram(&s->md_rom, NULL, "sun4v-md.rom", + NIAGARA_MD_ROM_SIZE, &error_fatal); memory_region_add_subregion(sysmem, NIAGARA_MD_ROM_BASE, &s->md_rom); - memory_region_allocate_system_memory(&s->hv_rom, NULL, - "sun4v-hv.rom", NIAGARA_HV_ROM_SIZE); + memory_region_init_ram(&s->hv_rom, NULL, "sun4v-hv.rom", + NIAGARA_HV_ROM_SIZE, &error_fatal); memory_region_add_subregion(sysmem, NIAGARA_HV_ROM_BASE, &s->hv_rom); - memory_region_allocate_system_memory(&s->prom, NULL, - "sun4v.prom", PROM_SIZE_MAX); + memory_region_init_ram(&s->prom, NULL, "sun4v.prom", PROM_SIZE_MAX, + &error_fatal); memory_region_add_subregion(sysmem, NIAGARA_PROM_BASE, &s->prom); add_rom_or_fail("nvram1", NIAGARA_NVRAM_BASE); @@ -143,8 +144,8 @@ static void niagara_init(MachineState *machine) BlockBackend *blk = blk_by_legacy_dinfo(dinfo); int size = blk_getlength(blk); if (size > 0) { - memory_region_allocate_system_memory(&s->vdisk_ram, NULL, - "sun4v_vdisk.ram", size); + memory_region_init_ram(&s->vdisk_ram, NULL, "sun4v_vdisk.ram", size, + &error_fatal); memory_region_add_subregion(get_system_memory(), NIAGARA_VDISK_BASE, &s->vdisk_ram); dinfo->is_default = 1; diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 1ded2a4c9a..955082773b 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -36,7 +36,7 @@ #include "hw/pci-host/sabre.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" -#include "hw/timer/m48t59.h" +#include "hw/rtc/m48t59.h" #include "migration/vmstate.h" #include "hw/input/i8042.h" #include "hw/block/fdc.h" diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index eefc95f35e..a990f9fe35 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -9,10 +9,6 @@ config ARM_MPTIMER config A9_GTIMER bool -config DS1338 - bool - depends on I2C - config HPET bool default y if PC @@ -20,27 +16,10 @@ config HPET config I8254 bool -config M41T80 - bool - depends on I2C - -config M48T59 - bool - -config PL031 - bool - -config TWL92230 - bool - depends on I2C - config ALTERA_TIMER bool select PTIMER -config MC146818RTC - bool - config ALLWINNER_A10_PIT bool select PTIMER @@ -48,9 +27,6 @@ config ALLWINNER_A10_PIT config STM32F2XX_TIMER bool -config SUN4V_RTC - bool - config CMSDK_APB_TIMER bool select PTIMER diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 123d92c969..dece235fd7 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -3,17 +3,9 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o common-obj-$(CONFIG_CADENCE) += cadence_ttc.o -common-obj-$(CONFIG_DS1338) += ds1338.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o -common-obj-$(CONFIG_M41T80) += m41t80.o -common-obj-$(CONFIG_M48T59) += m48t59.o -ifeq ($(CONFIG_ISA_BUS),y) -common-obj-$(CONFIG_M48T59) += m48t59-isa.o -endif -common-obj-$(CONFIG_PL031) += pl031.o common-obj-$(CONFIG_PUV3) += puv3_ost.o -common-obj-$(CONFIG_TWL92230) += twl92230.o common-obj-$(CONFIG_XILINX) += xilinx_timer.o common-obj-$(CONFIG_SLAVIO) += slavio_timer.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o @@ -22,28 +14,24 @@ common-obj-$(CONFIG_IMX) += imx_epit.o common-obj-$(CONFIG_IMX) += imx_gpt.o common-obj-$(CONFIG_LM32) += lm32_timer.o common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o -common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o common-obj-$(CONFIG_NRF51_SOC) += nrf51_timer.o -obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o -obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o -obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o -obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o -obj-$(CONFIG_OMAP) += omap_gptimer.o -obj-$(CONFIG_OMAP) += omap_synctimer.o -obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o -obj-$(CONFIG_SH4) += sh_timer.o -obj-$(CONFIG_DIGIC) += digic-timer.o -obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o +common-obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o +common-obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o +common-obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o +common-obj-$(CONFIG_OMAP) += omap_gptimer.o +common-obj-$(CONFIG_OMAP) += omap_synctimer.o +common-obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o +common-obj-$(CONFIG_SH4) += sh_timer.o +common-obj-$(CONFIG_DIGIC) += digic-timer.o +common-obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o -obj-$(CONFIG_MC146818RTC) += mc146818rtc.o - -obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o +common-obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o -common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o aspeed_rtc.o +common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o -common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o common-obj-$(CONFIG_MSF2) += mss-timer.o +common-obj-$(CONFIG_RASPI) += bcm2835_systmr.o diff --git a/hw/timer/altera_timer.c b/hw/timer/altera_timer.c index ee32e0ec1f..79fc381252 100644 --- a/hw/timer/altera_timer.c +++ b/hw/timer/altera_timer.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qapi/error.h" @@ -53,7 +52,6 @@ typedef struct AlteraTimer { MemoryRegion mmio; qemu_irq irq; uint32_t freq_hz; - QEMUBH *bh; ptimer_state *ptimer; uint32_t regs[R_MAX]; } AlteraTimer; @@ -105,6 +103,7 @@ static void timer_write(void *opaque, hwaddr addr, break; case R_CONTROL: + ptimer_transaction_begin(t->ptimer); t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT); if ((value & CONTROL_START) && !(t->regs[R_STATUS] & STATUS_RUN)) { @@ -115,10 +114,12 @@ static void timer_write(void *opaque, hwaddr addr, ptimer_stop(t->ptimer); t->regs[R_STATUS] &= ~STATUS_RUN; } + ptimer_transaction_commit(t->ptimer); break; case R_PERIODL: case R_PERIODH: + ptimer_transaction_begin(t->ptimer); t->regs[addr] = value & 0xFFFF; if (t->regs[R_STATUS] & STATUS_RUN) { ptimer_stop(t->ptimer); @@ -126,6 +127,7 @@ static void timer_write(void *opaque, hwaddr addr, } tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL]; ptimer_set_limit(t->ptimer, tvalue + 1, 1); + ptimer_transaction_commit(t->ptimer); break; case R_SNAPL: @@ -183,9 +185,10 @@ static void altera_timer_realize(DeviceState *dev, Error **errp) return; } - t->bh = qemu_bh_new(timer_hit, t); - t->ptimer = ptimer_init_with_bh(t->bh, PTIMER_POLICY_DEFAULT); + t->ptimer = ptimer_init(timer_hit, t, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(t->ptimer); ptimer_set_freq(t->ptimer, t->freq_hz); + ptimer_transaction_commit(t->ptimer); memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t)); @@ -204,8 +207,10 @@ static void altera_timer_reset(DeviceState *dev) { AlteraTimer *t = ALTERA_TIMER(dev); + ptimer_transaction_begin(t->ptimer); ptimer_stop(t->ptimer); ptimer_set_limit(t->ptimer, 0xffffffff, 1); + ptimer_transaction_commit(t->ptimer); memset(t->regs, 0, sizeof(t->regs)); } diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index fdf97d1800..2bf11f788c 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -237,7 +237,7 @@ static void arm_mptimer_reset(DeviceState *dev) } } -static void arm_mptimer_init_with_bh(Object *obj) +static void arm_mptimer_init(Object *obj) { ARMMPTimerState *s = ARM_MPTIMER(obj); @@ -319,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_with_bh, + .instance_init = arm_mptimer_init, .class_init = arm_mptimer_class_init, }; diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c new file mode 100644 index 0000000000..3387a6214a --- /dev/null +++ b/hw/timer/bcm2835_systmr.c @@ -0,0 +1,163 @@ +/* + * BCM2835 SYS timer emulation + * + * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org> + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Datasheet: BCM2835 ARM Peripherals (C6357-M-1398) + * https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf + * + * Only the free running 64-bit counter is implemented. + * The 4 COMPARE registers and the interruption are not implemented. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "hw/timer/bcm2835_systmr.h" +#include "hw/registerfields.h" +#include "migration/vmstate.h" +#include "trace.h" + +REG32(CTRL_STATUS, 0x00) +REG32(COUNTER_LOW, 0x04) +REG32(COUNTER_HIGH, 0x08) +REG32(COMPARE0, 0x0c) +REG32(COMPARE1, 0x10) +REG32(COMPARE2, 0x14) +REG32(COMPARE3, 0x18) + +static void bcm2835_systmr_update_irq(BCM2835SystemTimerState *s) +{ + bool enable = !!s->reg.status; + + trace_bcm2835_systmr_irq(enable); + qemu_set_irq(s->irq, enable); +} + +static void bcm2835_systmr_update_compare(BCM2835SystemTimerState *s, + unsigned timer_index) +{ + /* TODO fow now, since neither Linux nor U-boot use these timers. */ + qemu_log_mask(LOG_UNIMP, "COMPARE register %u not implemented\n", + timer_index); +} + +static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque); + uint64_t r = 0; + + switch (offset) { + case A_CTRL_STATUS: + r = s->reg.status; + break; + case A_COMPARE0 ... A_COMPARE3: + r = s->reg.compare[(offset - A_COMPARE0) >> 2]; + break; + case A_COUNTER_LOW: + case A_COUNTER_HIGH: + /* Free running counter at 1MHz */ + r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL); + r >>= 8 * (offset - A_COUNTER_LOW); + r &= UINT32_MAX; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } + trace_bcm2835_systmr_read(offset, r); + + return r; +} + +static void bcm2835_systmr_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque); + + trace_bcm2835_systmr_write(offset, value); + switch (offset) { + case A_CTRL_STATUS: + s->reg.status &= ~value; /* Ack */ + bcm2835_systmr_update_irq(s); + break; + case A_COMPARE0 ... A_COMPARE3: + s->reg.compare[(offset - A_COMPARE0) >> 2] = value; + bcm2835_systmr_update_compare(s, (offset - A_COMPARE0) >> 2); + break; + case A_COUNTER_LOW: + case A_COUNTER_HIGH: + qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } +} + +static const MemoryRegionOps bcm2835_systmr_ops = { + .read = bcm2835_systmr_read, + .write = bcm2835_systmr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void bcm2835_systmr_reset(DeviceState *dev) +{ + BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev); + + memset(&s->reg, 0, sizeof(s->reg)); +} + +static void bcm2835_systmr_realize(DeviceState *dev, Error **errp) +{ + BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev); + + memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops, + s, "bcm2835-sys-timer", 0x20); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); +} + +static const VMStateDescription bcm2835_systmr_vmstate = { + .name = "bcm2835_sys_timer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(reg.status, BCM2835SystemTimerState), + VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState, 4), + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_systmr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_systmr_realize; + dc->reset = bcm2835_systmr_reset; + dc->vmsd = &bcm2835_systmr_vmstate; +} + +static const TypeInfo bcm2835_systmr_info = { + .name = TYPE_BCM2835_SYSTIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835SystemTimerState), + .class_init = bcm2835_systmr_class_init, +}; + +static void bcm2835_systmr_register_types(void) +{ + type_register_static(&bcm2835_systmr_info); +} + +type_init(bcm2835_systmr_register_types); diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index ab27fe1895..afe3d30a8e 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -26,7 +26,6 @@ #include "hw/sysbus.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/timer.h" #include "hw/irq.h" @@ -59,9 +58,6 @@ typedef struct ETRAXTimerState { qemu_irq irq; qemu_irq nmi; - QEMUBH *bh_t0; - QEMUBH *bh_t1; - QEMUBH *bh_wd; ptimer_state *ptimer_t0; ptimer_state *ptimer_t1; ptimer_state *ptimer_wd; @@ -155,6 +151,7 @@ static void update_ctrl(ETRAXTimerState *t, int tnum) } D(printf ("freq_hz=%d div=%d\n", freq_hz, div)); + ptimer_transaction_begin(timer); ptimer_set_freq(timer, freq_hz); ptimer_set_limit(timer, div, 0); @@ -176,6 +173,7 @@ static void update_ctrl(ETRAXTimerState *t, int tnum) abort(); break; } + ptimer_transaction_commit(timer); } static void timer_update_irq(ETRAXTimerState *t) @@ -240,6 +238,7 @@ static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value) t->wd_hits = 0; + ptimer_transaction_begin(t->ptimer_wd); ptimer_set_freq(t->ptimer_wd, 760); if (wd_cnt == 0) wd_cnt = 256; @@ -250,6 +249,7 @@ static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value) ptimer_stop(t->ptimer_wd); t->rw_wd_ctrl = value; + ptimer_transaction_commit(t->ptimer_wd); } static void @@ -311,9 +311,15 @@ static void etraxfs_timer_reset(void *opaque) { ETRAXTimerState *t = opaque; + ptimer_transaction_begin(t->ptimer_t0); ptimer_stop(t->ptimer_t0); + ptimer_transaction_commit(t->ptimer_t0); + ptimer_transaction_begin(t->ptimer_t1); ptimer_stop(t->ptimer_t1); + ptimer_transaction_commit(t->ptimer_t1); + ptimer_transaction_begin(t->ptimer_wd); ptimer_stop(t->ptimer_wd); + ptimer_transaction_commit(t->ptimer_wd); t->rw_wd_ctrl = 0; t->r_intr = 0; t->rw_intr_mask = 0; @@ -325,12 +331,9 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp) ETRAXTimerState *t = ETRAX_TIMER(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - 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_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); + t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_DEFAULT); + t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_DEFAULT); + t->ptimer_wd = ptimer_init(watchdog_hit, t, 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 7225758414..944120aea5 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1254,7 +1254,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, /* Start FRC if transition from disabled to enabled */ if ((value & G_TCON_TIMER_ENABLE) > (old_val & G_TCON_TIMER_ENABLE)) { - exynos4210_gfrc_start(&s->g_timer); + exynos4210_gfrc_restart(s); } if ((value & G_TCON_TIMER_ENABLE) < (old_val & G_TCON_TIMER_ENABLE)) { diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index bb09268ea1..7a9371c0e3 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -29,7 +29,6 @@ #include "hw/irq.h" #include "hw/ptimer.h" #include "hw/qdev-properties.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "trace.h" @@ -63,7 +62,6 @@ typedef struct GPTimer GPTimer; typedef struct GPTimerUnit GPTimerUnit; struct GPTimer { - QEMUBH *bh; struct ptimer_state *ptimer; qemu_irq irq; @@ -93,6 +91,17 @@ struct GPTimerUnit { uint32_t config; }; +static void grlib_gptimer_tx_begin(GPTimer *timer) +{ + ptimer_transaction_begin(timer->ptimer); +} + +static void grlib_gptimer_tx_commit(GPTimer *timer) +{ + ptimer_transaction_commit(timer->ptimer); +} + +/* Must be called within grlib_gptimer_tx_begin/commit block */ static void grlib_gptimer_enable(GPTimer *timer) { assert(timer != NULL); @@ -115,6 +124,7 @@ static void grlib_gptimer_enable(GPTimer *timer) ptimer_run(timer->ptimer, 1); } +/* Must be called within grlib_gptimer_tx_begin/commit block */ static void grlib_gptimer_restart(GPTimer *timer) { assert(timer != NULL); @@ -141,7 +151,9 @@ static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler) trace_grlib_gptimer_set_scaler(scaler, value); for (i = 0; i < unit->nr_timers; i++) { + ptimer_transaction_begin(unit->timers[i].ptimer); ptimer_set_freq(unit->timers[i].ptimer, value); + ptimer_transaction_commit(unit->timers[i].ptimer); } } @@ -266,8 +278,10 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr, switch (timer_addr) { case COUNTER_OFFSET: trace_grlib_gptimer_writel(id, addr, value); + grlib_gptimer_tx_begin(&unit->timers[id]); unit->timers[id].counter = value; grlib_gptimer_enable(&unit->timers[id]); + grlib_gptimer_tx_commit(&unit->timers[id]); return; case COUNTER_RELOAD_OFFSET: @@ -291,6 +305,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr, /* gptimer_restart calls gptimer_enable, so if "enable" and "load" bits are present, we just have to call restart. */ + grlib_gptimer_tx_begin(&unit->timers[id]); if (value & GPTIMER_LOAD) { grlib_gptimer_restart(&unit->timers[id]); } else if (value & GPTIMER_ENABLE) { @@ -301,6 +316,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr, value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT); unit->timers[id].config = value; + grlib_gptimer_tx_commit(&unit->timers[id]); return; default: @@ -344,9 +360,11 @@ static void grlib_gptimer_reset(DeviceState *d) timer->counter = 0; timer->reload = 0; timer->config = 0; + ptimer_transaction_begin(timer->ptimer); ptimer_stop(timer->ptimer); ptimer_set_count(timer->ptimer, 0); ptimer_set_freq(timer->ptimer, unit->freq_hz); + ptimer_transaction_commit(timer->ptimer); } } @@ -365,14 +383,16 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp) GPTimer *timer = &unit->timers[i]; timer->unit = unit; - timer->bh = qemu_bh_new(grlib_gptimer_hit, timer); - timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT); + timer->ptimer = ptimer_init(grlib_gptimer_hit, timer, + PTIMER_POLICY_DEFAULT); timer->id = i; /* One IRQ line for each timer */ sysbus_init_irq(sbd, &timer->irq); + ptimer_transaction_begin(timer->ptimer); ptimer_set_freq(timer->ptimer, unit->freq_hz); + ptimer_transaction_commit(timer->ptimer); } memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops, diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index 1ddae4e7d7..9f17aaa278 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -33,7 +33,8 @@ #include "qemu/timer.h" #include "hw/timer/hpet.h" #include "hw/sysbus.h" -#include "hw/timer/mc146818rtc.h" +#include "hw/rtc/mc146818rtc.h" +#include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" #include "hw/timer/i8254.h" diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index fabde760b2..3fdecd09fe 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -30,7 +30,6 @@ #include "hw/ptimer.h" #include "hw/qdev-properties.h" #include "qemu/error-report.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #define DEFAULT_FREQUENCY (50*1000000) @@ -63,7 +62,6 @@ struct LM32TimerState { MemoryRegion iomem; - QEMUBH *bh; ptimer_state *ptimer; qemu_irq irq; @@ -119,6 +117,7 @@ static void timer_write(void *opaque, hwaddr addr, s->regs[R_SR] &= ~SR_TO; break; case R_CR: + ptimer_transaction_begin(s->ptimer); s->regs[R_CR] = value; if (s->regs[R_CR] & CR_START) { ptimer_run(s->ptimer, 1); @@ -126,10 +125,13 @@ static void timer_write(void *opaque, hwaddr addr, if (s->regs[R_CR] & CR_STOP) { ptimer_stop(s->ptimer); } + ptimer_transaction_commit(s->ptimer); break; case R_PERIOD: s->regs[R_PERIOD] = value; + ptimer_transaction_begin(s->ptimer); ptimer_set_count(s->ptimer, value); + ptimer_transaction_commit(s->ptimer); break; case R_SNAPSHOT: error_report("lm32_timer: write access to read only register 0x" @@ -176,7 +178,9 @@ static void timer_reset(DeviceState *d) for (i = 0; i < R_MAX; i++) { s->regs[i] = 0; } + ptimer_transaction_begin(s->ptimer); ptimer_stop(s->ptimer); + ptimer_transaction_commit(s->ptimer); } static void lm32_timer_init(Object *obj) @@ -195,10 +199,11 @@ 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_with_bh(s->bh, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(timer_hit, s, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(s->ptimer); ptimer_set_freq(s->ptimer, s->freq_hz); + ptimer_transaction_commit(s->ptimer); } static const VMStateDescription vmstate_lm32_timer = { diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 5193c03850..7a62e212c3 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -31,7 +31,6 @@ #include "hw/ptimer.h" #include "hw/qdev-properties.h" #include "qemu/error-report.h" -#include "qemu/main-loop.h" #include "qemu/module.h" enum { @@ -71,8 +70,6 @@ struct MilkymistSysctlState { MemoryRegion regs_region; - QEMUBH *bh0; - QEMUBH *bh1; ptimer_state *ptimer0; ptimer_state *ptimer1; @@ -161,14 +158,19 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value, s->regs[addr] = value; break; case R_TIMER0_COMPARE: + ptimer_transaction_begin(s->ptimer0); ptimer_set_limit(s->ptimer0, value, 0); s->regs[addr] = value; + ptimer_transaction_commit(s->ptimer0); break; case R_TIMER1_COMPARE: + ptimer_transaction_begin(s->ptimer1); ptimer_set_limit(s->ptimer1, value, 0); s->regs[addr] = value; + ptimer_transaction_commit(s->ptimer1); break; case R_TIMER0_CONTROL: + ptimer_transaction_begin(s->ptimer0); s->regs[addr] = value; if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) { trace_milkymist_sysctl_start_timer0(); @@ -179,8 +181,10 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value, trace_milkymist_sysctl_stop_timer0(); ptimer_stop(s->ptimer0); } + ptimer_transaction_commit(s->ptimer0); break; case R_TIMER1_CONTROL: + ptimer_transaction_begin(s->ptimer1); s->regs[addr] = value; if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) { trace_milkymist_sysctl_start_timer1(); @@ -191,6 +195,7 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value, trace_milkymist_sysctl_stop_timer1(); ptimer_stop(s->ptimer1); } + ptimer_transaction_commit(s->ptimer1); break; case R_ICAP: sysctl_icap_write(s, value); @@ -263,8 +268,12 @@ static void milkymist_sysctl_reset(DeviceState *d) s->regs[i] = 0; } + ptimer_transaction_begin(s->ptimer0); ptimer_stop(s->ptimer0); + ptimer_transaction_commit(s->ptimer0); + ptimer_transaction_begin(s->ptimer1); ptimer_stop(s->ptimer1); + ptimer_transaction_commit(s->ptimer1); /* defaults */ s->regs[R_ICAP] = ICAP_READY; @@ -292,13 +301,15 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) { MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); - s->bh0 = qemu_bh_new(timer0_hit, s); - s->bh1 = qemu_bh_new(timer1_hit, s); - s->ptimer0 = ptimer_init_with_bh(s->bh0, PTIMER_POLICY_DEFAULT); - s->ptimer1 = ptimer_init_with_bh(s->bh1, PTIMER_POLICY_DEFAULT); + s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT); + s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(s->ptimer0); ptimer_set_freq(s->ptimer0, s->freq_hz); + ptimer_transaction_commit(s->ptimer0); + ptimer_transaction_begin(s->ptimer1); ptimer_set_freq(s->ptimer1, s->freq_hz); + ptimer_transaction_commit(s->ptimer1); } static const VMStateDescription vmstate_milkymist_sysctl = { diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c index 0898da5ce9..697519593b 100644 --- a/hw/timer/puv3_ost.c +++ b/hw/timer/puv3_ost.c @@ -13,7 +13,6 @@ #include "hw/sysbus.h" #include "hw/irq.h" #include "hw/ptimer.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #undef DEBUG_PUV3 @@ -27,7 +26,6 @@ typedef struct PUV3OSTState { SysBusDevice parent_obj; MemoryRegion iomem; - QEMUBH *bh; qemu_irq irq; ptimer_state *ptimer; @@ -68,6 +66,7 @@ static void puv3_ost_write(void *opaque, hwaddr offset, DPRINTF("offset 0x%x, value 0x%x\n", offset, value); switch (offset) { case 0x00: /* Match Register 0 */ + ptimer_transaction_begin(s->ptimer); s->reg_OSMR0 = value; if (s->reg_OSMR0 > s->reg_OSCR) { ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR); @@ -76,6 +75,7 @@ static void puv3_ost_write(void *opaque, hwaddr offset, (0xffffffff - s->reg_OSCR)); } ptimer_run(s->ptimer, 2); + ptimer_transaction_commit(s->ptimer); break; case 0x14: /* Status Register */ assert(value == 0); @@ -128,9 +128,10 @@ 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_with_bh(s->bh, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(puv3_ost_tick, s, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(s->ptimer); ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); + ptimer_transaction_commit(s->ptimer); memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost", PUV3_REGS_OFFSET); diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 48a81b4dc7..13c4051808 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -13,7 +13,6 @@ #include "hw/irq.h" #include "hw/sh4/sh.h" #include "qemu/timer.h" -#include "qemu/main-loop.h" #include "hw/ptimer.h" //#define DEBUG_TIMER @@ -91,13 +90,18 @@ static void sh_timer_write(void *opaque, hwaddr offset, switch (offset >> 2) { case OFFSET_TCOR: s->tcor = value; + ptimer_transaction_begin(s->timer); ptimer_set_limit(s->timer, s->tcor, 0); + ptimer_transaction_commit(s->timer); break; case OFFSET_TCNT: s->tcnt = value; + ptimer_transaction_begin(s->timer); ptimer_set_count(s->timer, s->tcnt); + ptimer_transaction_commit(s->timer); break; case OFFSET_TCR: + ptimer_transaction_begin(s->timer); if (s->enabled) { /* Pause the timer if it is running. This may cause some inaccuracy dure to rounding, but avoids a whole lot of other @@ -148,6 +152,7 @@ static void sh_timer_write(void *opaque, hwaddr offset, /* Restart the timer if still enabled. */ ptimer_run(s->timer, 0); } + ptimer_transaction_commit(s->timer); break; case OFFSET_TCPR: if (s->feat & TIMER_FEAT_CAPT) { @@ -168,12 +173,14 @@ static void sh_timer_start_stop(void *opaque, int enable) printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); #endif + ptimer_transaction_begin(s->timer); if (s->enabled && !enable) { ptimer_stop(s->timer); } if (!s->enabled && enable) { ptimer_run(s->timer, 0); } + ptimer_transaction_commit(s->timer); s->enabled = !!enable; #ifdef DEBUG_TIMER @@ -191,7 +198,6 @@ static void sh_timer_tick(void *opaque) static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) { sh_timer_state *s; - QEMUBH *bh; s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state)); s->freq = freq; @@ -203,8 +209,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) s->enabled = 0; s->irq = irq; - bh = qemu_bh_new(sh_timer_tick, s); - s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(sh_timer_tick, s, 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 692d213897..c55e8d0bf4 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -30,7 +30,6 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "trace.h" -#include "qemu/main-loop.h" #include "qemu/module.h" /* @@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: + ptimer_transaction_begin(t->timer); if (slavio_timer_is_user(tc)) { uint64_t count; @@ -227,15 +227,14 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, // set limit, reset counter qemu_irq_lower(t->irq); t->limit = val & TIMER_MAX_COUNT32; - if (t->timer) { - if (t->limit == 0) { /* free-run */ - ptimer_set_limit(t->timer, - LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); - } else { - ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); - } + if (t->limit == 0) { /* free-run */ + ptimer_set_limit(t->timer, + LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); + } else { + ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); } } + ptimer_transaction_commit(t->timer); break; case TIMER_COUNTER: if (slavio_timer_is_user(tc)) { @@ -247,7 +246,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, t->reached = 0; count = ((uint64_t)t->counthigh) << 32 | t->count; trace_slavio_timer_mem_writel_limit(timer_index, count); + ptimer_transaction_begin(t->timer); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); + ptimer_transaction_commit(t->timer); } else { trace_slavio_timer_mem_writel_counter_invalid(); } @@ -255,13 +256,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, case TIMER_COUNTER_NORST: // set limit without resetting counter t->limit = val & TIMER_MAX_COUNT32; + ptimer_transaction_begin(t->timer); if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); } + ptimer_transaction_commit(t->timer); break; case TIMER_STATUS: + ptimer_transaction_begin(t->timer); if (slavio_timer_is_user(tc)) { // start/stop user counter if (val & 1) { @@ -273,6 +277,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, } } t->run = val & 1; + ptimer_transaction_commit(t->timer); break; case TIMER_MODE: if (timer_index == 0) { @@ -282,6 +287,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, unsigned int processor = 1 << i; CPUTimerState *curr_timer = &s->cputimer[i + 1]; + ptimer_transaction_begin(curr_timer->timer); // check for a change in timer mode for this processor if ((val & processor) != (s->cputimer_mode & processor)) { if (val & processor) { // counter -> user timer @@ -308,6 +314,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr, trace_slavio_timer_mem_writel_mode_counter(timer_index); } } + ptimer_transaction_commit(curr_timer->timer); } } else { trace_slavio_timer_mem_writel_mode_invalid(); @@ -367,10 +374,12 @@ static void slavio_timer_reset(DeviceState *d) curr_timer->count = 0; curr_timer->reached = 0; if (i <= s->num_cpus) { + ptimer_transaction_begin(curr_timer->timer); ptimer_set_limit(curr_timer->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); ptimer_run(curr_timer->timer, 0); curr_timer->run = 1; + ptimer_transaction_commit(curr_timer->timer); } } s->cputimer_mode = 0; @@ -380,7 +389,6 @@ static void slavio_timer_init(Object *obj) { SLAVIO_TIMERState *s = SLAVIO_TIMER(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); - QEMUBH *bh; unsigned int i; TimerContext *tc; @@ -392,9 +400,11 @@ static void slavio_timer_init(Object *obj) tc->s = s; tc->timer_index = i; - bh = qemu_bh_new(slavio_timer_irq, tc); - s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc, + PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(s->cputimer[i].timer); ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); + ptimer_transaction_commit(s->cputimer[i].timer); size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; snprintf(timer_name, sizeof(timer_name), "timer-%i", i); diff --git a/hw/timer/trace-events b/hw/timer/trace-events index db02a9142c..29fda7870e 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -66,24 +66,11 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" -# hw/timer/aspeed-rtc.c -aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 -aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 - -# sun4v-rtc.c -sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64 -sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64 - -# xlnx-zynqmp-rtc.c -xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d" - # nrf51_timer.c nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" -# pl031.c -pl031_irq_state(int level) "irq state %d" -pl031_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -pl031_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -pl031_alarm_raised(void) "alarm raised" -pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks" +# bcm2835_systmr.c +bcm2835_systmr_irq(bool enable) "timer irq state %u" +bcm2835_systmr_read(uint64_t offset, uint64_t data) "timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 +bcm2835_systmr_write(uint64_t offset, uint64_t data) "timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 92dbff304d..7191ea54f5 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -28,7 +28,6 @@ #include "hw/ptimer.h" #include "hw/qdev-properties.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #define D(x) @@ -52,7 +51,6 @@ struct xlx_timer { - QEMUBH *bh; ptimer_state *ptimer; void *parent; int nr; /* for debug. */ @@ -134,6 +132,7 @@ timer_read(void *opaque, hwaddr addr, unsigned int size) return r; } +/* Must be called inside ptimer transaction block */ static void timer_enable(struct xlx_timer *xt) { uint64_t count; @@ -174,8 +173,11 @@ timer_write(void *opaque, hwaddr addr, value &= ~TCSR_TINT; xt->regs[addr] = value & 0x7ff; - if (value & TCSR_ENT) + if (value & TCSR_ENT) { + ptimer_transaction_begin(xt->ptimer); timer_enable(xt); + ptimer_transaction_commit(xt->ptimer); + } break; default: @@ -220,9 +222,10 @@ 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_with_bh(xt->bh, PTIMER_POLICY_DEFAULT); + xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(xt->ptimer); ptimer_set_freq(xt->ptimer, t->freq_hz); + ptimer_transaction_commit(xt->ptimer); } memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer", diff --git a/hw/xtensa/Kconfig b/hw/xtensa/Kconfig index d72817d012..0740657ea5 100644 --- a/hw/xtensa/Kconfig +++ b/hw/xtensa/Kconfig @@ -1,6 +1,12 @@ config XTENSA_SIM bool +config XTENSA_VIRT + bool + select XTENSA_SIM + select PCI_EXPRESS_GENERIC_BRIDGE + select PCI_DEVICES + config XTENSA_XTFPGA bool select OPENCORES_ETH diff --git a/hw/xtensa/Makefile.objs b/hw/xtensa/Makefile.objs index 0bbfccd6de..2b40e1b60a 100644 --- a/hw/xtensa/Makefile.objs +++ b/hw/xtensa/Makefile.objs @@ -2,4 +2,5 @@ obj-y += mx_pic.o obj-y += pic_cpu.o obj-y += xtensa_memory.o obj-$(CONFIG_XTENSA_SIM) += sim.o +obj-$(CONFIG_XTENSA_VIRT) += virt.o obj-$(CONFIG_XTENSA_XTFPGA) += xtfpga.o diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c index 981dbb7bbe..a22743a3d6 100644 --- a/hw/xtensa/sim.c +++ b/hw/xtensa/sim.c @@ -37,6 +37,7 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "xtensa_memory.h" +#include "xtensa_sim.h" static uint64_t translate_phys_addr(void *opaque, uint64_t addr) { @@ -52,12 +53,11 @@ static void sim_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void xtensa_sim_init(MachineState *machine) +XtensaCPU *xtensa_sim_common_init(MachineState *machine) { XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; int n; for (n = 0; n < machine->smp.cpus; n++) { @@ -89,30 +89,41 @@ static void xtensa_sim_init(MachineState *machine) xtensa_create_memory_regions(&sysram, "xtensa.sysram", get_system_memory()); } - if (serial_hd(0)) { xtensa_sim_open_console(serial_hd(0)); } - if (kernel_filename) { - uint64_t elf_entry; - uint64_t elf_lowaddr; + return cpu; +} + +void xtensa_sim_load_kernel(XtensaCPU *cpu, MachineState *machine) +{ + const char *kernel_filename = machine->kernel_filename; #ifdef TARGET_WORDS_BIGENDIAN - int success = load_elf(kernel_filename, NULL, - translate_phys_addr, cpu, - &elf_entry, &elf_lowaddr, - NULL, 1, EM_XTENSA, 0, 0); + int big_endian = true; #else - int success = load_elf(kernel_filename, NULL, - translate_phys_addr, cpu, - &elf_entry, &elf_lowaddr, - NULL, 0, EM_XTENSA, 0, 0); + int big_endian = false; #endif + + if (kernel_filename) { + uint64_t elf_entry; + uint64_t elf_lowaddr; + int success = load_elf(kernel_filename, NULL, translate_phys_addr, cpu, + &elf_entry, &elf_lowaddr, NULL, big_endian, + EM_XTENSA, 0, 0); + if (success > 0) { - env->pc = elf_entry; + cpu->env.pc = elf_entry; } } } +static void xtensa_sim_init(MachineState *machine) +{ + XtensaCPU *cpu = xtensa_sim_common_init(machine); + + xtensa_sim_load_kernel(cpu, machine); +} + static void xtensa_sim_machine_init(MachineClass *mc) { mc->desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")"; diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c new file mode 100644 index 0000000000..b22dcf938a --- /dev/null +++ b/hw/xtensa/virt.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2019, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "sysemu/reset.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/pci-host/gpex.h" +#include "net/net.h" +#include "elf.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "qemu/error-report.h" +#include "xtensa_memory.h" +#include "xtensa_sim.h" + +static void create_pcie(CPUXtensaState *env, int irq_base, hwaddr addr_base) +{ + hwaddr base_ecam = addr_base + 0x00100000; + hwaddr size_ecam = 0x03f00000; + hwaddr base_pio = addr_base + 0x00000000; + hwaddr size_pio = 0x00010000; + hwaddr base_mmio = addr_base + 0x04000000; + hwaddr size_mmio = 0x08000000; + + MemoryRegion *ecam_alias; + MemoryRegion *ecam_reg; + MemoryRegion *pio_alias; + MemoryRegion *pio_reg; + MemoryRegion *mmio_alias; + MemoryRegion *mmio_reg; + + DeviceState *dev; + PCIHostState *pci; + qemu_irq *extints; + int i; + + dev = qdev_create(NULL, TYPE_GPEX_HOST); + qdev_init_nofail(dev); + + /* Map only the first size_ecam bytes of ECAM space. */ + ecam_alias = g_new0(MemoryRegion, 1); + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", + ecam_reg, 0, size_ecam); + memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias); + + /* + * Map the MMIO window into system address space so as to expose + * the section of PCI MMIO space which starts at the same base address + * (ie 1:1 mapping for that part of PCI MMIO space visible through + * the window). + */ + mmio_alias = g_new0(MemoryRegion, 1); + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", + mmio_reg, base_mmio, size_mmio); + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); + + /* Map IO port space. */ + pio_alias = g_new0(MemoryRegion, 1); + pio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 2); + memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio", + pio_reg, 0, size_pio); + memory_region_add_subregion(get_system_memory(), base_pio, pio_alias); + + /* Connect IRQ lines. */ + extints = xtensa_get_extints(env); + + for (i = 0; i < GPEX_NUM_IRQS; i++) { + void *q = extints[irq_base + i]; + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q); + gpex_set_irq_num(GPEX_HOST(dev), i, irq_base + i); + } + + pci = PCI_HOST_BRIDGE(dev); + if (pci->bus) { + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + pci_nic_init_nofail(nd, pci->bus, nd->model, NULL); + } + } +} + +static void xtensa_virt_init(MachineState *machine) +{ + XtensaCPU *cpu = xtensa_sim_common_init(machine); + CPUXtensaState *env = &cpu->env; + + create_pcie(env, 0, 0xf0000000); + xtensa_sim_load_kernel(cpu, machine); +} + +static void xtensa_virt_machine_init(MachineClass *mc) +{ + mc->desc = "virt machine (" XTENSA_DEFAULT_CPU_MODEL ")"; + mc->init = xtensa_virt_init; + mc->max_cpus = 32; + mc->default_cpu_type = XTENSA_DEFAULT_CPU_TYPE; +} + +DEFINE_MACHINE("virt", xtensa_virt_machine_init) diff --git a/hw/xtensa/xtensa_sim.h b/hw/xtensa/xtensa_sim.h new file mode 100644 index 0000000000..bdc92f3d2c --- /dev/null +++ b/hw/xtensa/xtensa_sim.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef XTENSA_SIM_H +#define XTENSA_SIM_H + +XtensaCPU *xtensa_sim_common_init(MachineState *machine); +void xtensa_sim_load_kernel(XtensaCPU *cpu, MachineState *machine); + +#endif |