diff options
Diffstat (limited to 'hw')
177 files changed, 4429 insertions, 9787 deletions
diff --git a/hw/Kconfig b/hw/Kconfig index ff40bd3f7b..805860f564 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -21,6 +21,7 @@ source mem/Kconfig source misc/Kconfig source net/Kconfig source nubus/Kconfig +source nvme/Kconfig source nvram/Kconfig source pci-bridge/Kconfig source pci-host/Kconfig @@ -47,11 +48,9 @@ source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig -source lm32/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig -source moxie/Kconfig source nios2/Kconfig source openrisc/Kconfig source ppc/Kconfig @@ -62,7 +61,6 @@ source sh4/Kconfig source sparc/Kconfig source sparc64/Kconfig source tricore/Kconfig -source unicore32/Kconfig source xtensa/Kconfig # Symbols used by multiple targets diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index d33ce8954a..f0035d2b4a 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1830,6 +1830,7 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, int i; unsigned rsdt_entries_offset; AcpiRsdtDescriptorRev1 *rsdt; + int rsdt_start = table_data->len; const unsigned table_data_len = (sizeof(uint32_t) * table_offsets->len); const unsigned rsdt_entry_size = sizeof(rsdt->table_offset_entry[0]); const size_t rsdt_len = sizeof(*rsdt) + table_data_len; @@ -1846,7 +1847,8 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, ACPI_BUILD_TABLE_FILE, ref_tbl_offset); } build_header(linker, table_data, - (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); + (void *)(table_data->data + rsdt_start), + "RSDT", rsdt_len, 1, oem_id, oem_table_id); } /* Build xsdt table */ @@ -1857,6 +1859,7 @@ build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, int i; unsigned xsdt_entries_offset; AcpiXsdtDescriptorRev2 *xsdt; + int xsdt_start = table_data->len; const unsigned table_data_len = (sizeof(uint64_t) * table_offsets->len); const unsigned xsdt_entry_size = sizeof(xsdt->table_offset_entry[0]); const size_t xsdt_len = sizeof(*xsdt) + table_data_len; @@ -1873,7 +1876,8 @@ build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, ACPI_BUILD_TABLE_FILE, ref_tbl_offset); } build_header(linker, table_data, - (void *)xsdt, "XSDT", xsdt_len, 1, oem_id, oem_table_id); + (void *)(table_data->data + xsdt_start), + "XSDT", xsdt_len, 1, oem_id, oem_table_id); } void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, @@ -2053,10 +2057,9 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog, uint64_t control_area_start_address; TPMIf *tpmif = tpm_find(); uint32_t start_method; - void *tpm2_ptr; tpm2_start = table_data->len; - tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); + acpi_data_push(table_data, sizeof(AcpiTableHeader)); /* Platform Class */ build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); @@ -2095,8 +2098,8 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog, log_addr_offset, 8, ACPI_BUILD_TPMLOG_FILE, 0); build_header(linker, table_data, - tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, oem_id, - oem_table_id); + (void *)(table_data->data + tpm2_start), + "TPM2", table_data->len - tpm2_start, 4, oem_id, oem_table_id); } Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set, uint32_t io_offset, diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index b887f6a5b1..67723d9ea6 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -6,6 +6,7 @@ config ARM_VIRT imply VFIO_PLATFORM imply VFIO_XGMAC imply TPM_TIS_SYSBUS + imply NVDIMM select ARM_GIC select ACPI select ARM_SMMUV3 diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 2e5d0679e7..a1456cb0f4 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -13,6 +13,7 @@ #include "qemu/log.h" #include "qemu/module.h" #include "qemu/bitops.h" +#include "qemu/units.h" #include "qapi/error.h" #include "trace.h" #include "hw/sysbus.h" @@ -59,6 +60,7 @@ struct ARMSSEInfo { const char *cpu_type; uint32_t sse_version; int sram_banks; + uint32_t sram_bank_base; int num_cpus; uint32_t sys_version; uint32_t iidr; @@ -69,6 +71,7 @@ struct ARMSSEInfo { bool has_cpuid; bool has_cpu_pwrctrl; bool has_sse_counter; + bool has_tcms; Property *props; const ARMSSEDeviceInfo *devinfo; const bool *irq_is_common; @@ -102,7 +105,7 @@ static Property sse300_properties[] = { DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64), - DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15), + DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 18), DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true), DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true), @@ -504,6 +507,7 @@ static const ARMSSEInfo armsse_variants[] = { .sse_version = ARMSSE_IOTKIT, .cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"), .sram_banks = 1, + .sram_bank_base = 0x20000000, .num_cpus = 1, .sys_version = 0x41743, .iidr = 0, @@ -514,6 +518,7 @@ static const ARMSSEInfo armsse_variants[] = { .has_cpuid = false, .has_cpu_pwrctrl = false, .has_sse_counter = false, + .has_tcms = false, .props = iotkit_properties, .devinfo = iotkit_devices, .irq_is_common = sse200_irq_is_common, @@ -523,6 +528,7 @@ static const ARMSSEInfo armsse_variants[] = { .sse_version = ARMSSE_SSE200, .cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"), .sram_banks = 4, + .sram_bank_base = 0x20000000, .num_cpus = 2, .sys_version = 0x22041743, .iidr = 0, @@ -533,6 +539,7 @@ static const ARMSSEInfo armsse_variants[] = { .has_cpuid = true, .has_cpu_pwrctrl = false, .has_sse_counter = false, + .has_tcms = false, .props = sse200_properties, .devinfo = sse200_devices, .irq_is_common = sse200_irq_is_common, @@ -542,6 +549,7 @@ static const ARMSSEInfo armsse_variants[] = { .sse_version = ARMSSE_SSE300, .cpu_type = ARM_CPU_TYPE_NAME("cortex-m55"), .sram_banks = 2, + .sram_bank_base = 0x21000000, .num_cpus = 1, .sys_version = 0x7e00043b, .iidr = 0x74a0043b, @@ -552,6 +560,7 @@ static const ARMSSEInfo armsse_variants[] = { .has_cpuid = true, .has_cpu_pwrctrl = true, .has_sse_counter = true, + .has_tcms = true, .props = sse300_properties, .devinfo = sse300_devices, .irq_is_common = sse300_irq_is_common, @@ -909,7 +918,6 @@ static void armsse_realize(DeviceState *dev, Error **errp) const ARMSSEDeviceInfo *devinfo; int i; MemoryRegion *mr; - Error *err = NULL; SysBusDevice *sbd_apb_ppc0; SysBusDevice *sbd_secctl; DeviceState *dev_apb_ppc0; @@ -918,6 +926,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) DeviceState *dev_splitter; uint32_t addr_width_max; + ERRP_GUARD(); + if (!s->board_memory) { error_setg(errp, "memory property was not set"); return; @@ -1147,10 +1157,9 @@ static void armsse_realize(DeviceState *dev, Error **errp) uint32_t sram_bank_size = 1 << s->sram_addr_width; memory_region_init_ram(&s->sram[i], NULL, ramname, - sram_bank_size, &err); + sram_bank_size, errp); g_free(ramname); - if (err) { - error_propagate(errp, err); + if (*errp) { return; } object_property_set_link(OBJECT(&s->mpc[i]), "downstream", @@ -1161,7 +1170,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* Map the upstream end of the MPC into the right place... */ sbd_mpc = SYS_BUS_DEVICE(&s->mpc[i]); memory_region_add_subregion(&s->container, - 0x20000000 + i * sram_bank_size, + info->sram_bank_base + i * sram_bank_size, sysbus_mmio_get_region(sbd_mpc, 1)); /* ...and its register interface */ memory_region_add_subregion(&s->container, 0x50083000 + i * 0x1000, @@ -1210,6 +1219,20 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(sbd, 1)); } + if (info->has_tcms) { + /* The SSE-300 has an ITCM at 0x0000_0000 and a DTCM at 0x2000_0000 */ + memory_region_init_ram(&s->itcm, NULL, "sse300-itcm", 512 * KiB, errp); + if (*errp) { + return; + } + memory_region_init_ram(&s->dtcm, NULL, "sse300-dtcm", 512 * KiB, errp); + if (*errp) { + return; + } + memory_region_add_subregion(&s->container, 0x00000000, &s->itcm); + memory_region_add_subregion(&s->container, 0x20000000, &s->dtcm); + } + /* Devices behind APB PPC0: * 0x40000000: timer0 * 0x40001000: timer1 diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 11426e5ec0..bd16acd4d9 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -65,7 +65,6 @@ static struct arm_boot_info imx25_pdk_binfo; static void imx25_pdk_init(MachineState *machine) { - MachineClass *mc = MACHINE_GET_CLASS(machine); IMX25PDK *s = g_new0(IMX25PDK, 1); unsigned int ram_size; unsigned int alias_offset; @@ -77,8 +76,8 @@ static void imx25_pdk_init(MachineState *machine) /* We need to initialize our memory */ if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); + char *sz = size_to_str(FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE); + error_report("RAM size more than %s is not supported", sz); g_free(sz); exit(EXIT_FAILURE); } diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 25016e464d..e23830f4b7 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -55,6 +55,7 @@ #include "hw/boards.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" +#include "sysemu/reset.h" #include "hw/misc/unimp.h" #include "hw/char/cmsdk-apb-uart.h" #include "hw/timer/cmsdk-apb-timer.h" @@ -72,6 +73,7 @@ #include "hw/core/split-irq.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/irq.h" #define MPS2TZ_NUMIRQ_MAX 96 #define MPS2TZ_RAM_MAX 5 @@ -121,8 +123,10 @@ struct MPS2TZMachineClass { int numirq; /* Number of external interrupts */ int uart_overflow_irq; /* number of the combined UART overflow IRQ */ uint32_t init_svtor; /* init-svtor setting for SSE */ + uint32_t sram_addr_width; /* SRAM_ADDR_WIDTH setting for SSE */ const RAMInfo *raminfo; const char *armsse_type; + uint32_t boot_ram_size; /* size of ram at address 0; 0 == find in raminfo */ }; struct MPS2TZMachineState { @@ -153,6 +157,9 @@ struct MPS2TZMachineState { SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX]; Clock *sysclk; Clock *s32kclk; + + bool remap; + qemu_irq remap_irq; }; #define TYPE_MPS2TZ_MACHINE "mps2tz" @@ -228,6 +235,10 @@ static const RAMInfo an505_raminfo[] = { { }, }; +/* + * Note that the addresses and MPC numbering here should match up + * with those used in remap_memory(), which can swap the BRAM and QSPI. + */ static const RAMInfo an524_raminfo[] = { { .name = "bram", .base = 0x00000000, @@ -235,18 +246,12 @@ static const RAMInfo an524_raminfo[] = { { .mpc = 0, .mrindex = 0, }, { - .name = "sram", - .base = 0x20000000, - .size = 32 * 4 * KiB, - .mpc = -1, - .mrindex = 1, - }, { /* We don't model QSPI flash yet; for now expose it as simple ROM */ .name = "QSPI", .base = 0x28000000, .size = 8 * MiB, .mpc = 1, - .mrindex = 2, + .mrindex = 1, .flags = IS_ROM, }, { .name = "DDR", @@ -260,24 +265,12 @@ static const RAMInfo an524_raminfo[] = { { }; static const RAMInfo an547_raminfo[] = { { - .name = "itcm", - .base = 0x00000000, - .size = 512 * KiB, - .mpc = -1, - .mrindex = 0, - }, { .name = "sram", .base = 0x01000000, .size = 2 * MiB, .mpc = 0, .mrindex = 1, }, { - .name = "dtcm", - .base = 0x20000000, - .size = 4 * 128 * KiB, - .mpc = -1, - .mrindex = 2, - }, { .name = "sram 2", .base = 0x21000000, .size = 4 * MiB, @@ -457,6 +450,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC); sccdev = DEVICE(scc); + qdev_prop_set_uint32(sccdev, "scc-cfg0", mms->remap ? 1 : 0); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); @@ -573,6 +567,52 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0); } +static hwaddr boot_mem_base(MPS2TZMachineState *mms) +{ + /* + * Return the canonical address of the block which will be mapped + * at address 0x0 (i.e. where the vector table is). + * This is usually 0, but if the AN524 alternate memory map is + * enabled it will be the base address of the QSPI block. + */ + return mms->remap ? 0x28000000 : 0; +} + +static void remap_memory(MPS2TZMachineState *mms, int map) +{ + /* + * Remap the memory for the AN524. 'map' is the value of + * SCC CFG_REG0 bit 0, i.e. 0 for the default map and 1 + * for the "option 1" mapping where QSPI is at address 0. + * + * Effectively we need to swap around the "upstream" ends of + * MPC 0 and MPC 1. + */ + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + int i; + + if (mmc->fpga_type != FPGA_AN524) { + return; + } + + memory_region_transaction_begin(); + for (i = 0; i < 2; i++) { + TZMPC *mpc = &mms->mpc[i]; + MemoryRegion *upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); + hwaddr addr = (i ^ map) ? 0x28000000 : 0; + + memory_region_set_address(upstream, addr); + } + memory_region_transaction_commit(); +} + +static void remap_irq_fn(void *opaque, int n, int level) +{ + MPS2TZMachineState *mms = opaque; + + remap_memory(mms, level); +} + static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, const char *name, hwaddr size, const int *irqs) @@ -710,8 +750,16 @@ static uint32_t boot_ram_size(MPS2TZMachineState *mms) const RAMInfo *p; MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + /* + * Use a per-board specification (for when the boot RAM is in + * the SSE and so doesn't have a RAMInfo list entry) + */ + if (mmc->boot_ram_size) { + return mmc->boot_ram_size; + } + for (p = mmc->raminfo; p->name; p++) { - if (p->base == 0) { + if (p->base == boot_mem_base(mms)) { return p->size; } } @@ -756,6 +804,7 @@ static void mps2tz_common_init(MachineState *machine) OBJECT(system_memory), &error_abort); qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", mmc->numirq); qdev_prop_set_uint32(iotkitdev, "init-svtor", mmc->init_svtor); + qdev_prop_set_uint32(iotkitdev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width); qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk); qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk); sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal); @@ -1095,6 +1144,16 @@ static void mps2tz_common_init(MachineState *machine) create_non_mpc_ram(mms); + if (mmc->fpga_type == FPGA_AN524) { + /* + * Connect the line from the SCC so that we can remap when the + * guest updates that register. + */ + mms->remap_irq = qemu_allocate_irq(remap_irq_fn, mms, 0); + qdev_connect_gpio_out_named(DEVICE(&mms->scc), "remap", 0, + mms->remap_irq); + } + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, boot_ram_size(mms)); } @@ -1117,12 +1176,47 @@ static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address, *iregion = region; } +static char *mps2_get_remap(Object *obj, Error **errp) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); + const char *val = mms->remap ? "QSPI" : "BRAM"; + return g_strdup(val); +} + +static void mps2_set_remap(Object *obj, const char *value, Error **errp) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); + + if (!strcmp(value, "BRAM")) { + mms->remap = false; + } else if (!strcmp(value, "QSPI")) { + mms->remap = true; + } else { + error_setg(errp, "Invalid remap value"); + error_append_hint(errp, "Valid values are BRAM and QSPI.\n"); + } +} + +static void mps2_machine_reset(MachineState *machine) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); + + /* + * Set the initial memory mapping before triggering the reset of + * the rest of the system, so that the guest image loader and CPU + * reset see the correct mapping. + */ + remap_memory(mms, mms->remap); + qemu_devices_reset(); +} + static void mps2tz_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); mc->init = mps2tz_common_init; + mc->reset = mps2_machine_reset; iic->check = mps2_tz_idau_check; } @@ -1168,8 +1262,10 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data) mmc->numirq = 92; mmc->uart_overflow_irq = 47; mmc->init_svtor = 0x10000000; + mmc->sram_addr_width = 15; mmc->raminfo = an505_raminfo; mmc->armsse_type = TYPE_IOTKIT; + mmc->boot_ram_size = 0; mps2tz_set_default_ram_info(mmc); } @@ -1195,8 +1291,10 @@ static void mps2tz_an521_class_init(ObjectClass *oc, void *data) mmc->numirq = 92; mmc->uart_overflow_irq = 47; mmc->init_svtor = 0x10000000; + mmc->sram_addr_width = 15; mmc->raminfo = an505_raminfo; /* AN521 is the same as AN505 here */ mmc->armsse_type = TYPE_SSE200; + mmc->boot_ram_size = 0; mps2tz_set_default_ram_info(mmc); } @@ -1222,9 +1320,16 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data) mmc->numirq = 95; mmc->uart_overflow_irq = 47; mmc->init_svtor = 0x10000000; + mmc->sram_addr_width = 15; mmc->raminfo = an524_raminfo; mmc->armsse_type = TYPE_SSE200; + mmc->boot_ram_size = 0; mps2tz_set_default_ram_info(mmc); + + object_class_property_add_str(oc, "remap", mps2_get_remap, mps2_set_remap); + object_class_property_set_description(oc, "remap", + "Set memory mapping. Valid values " + "are BRAM (default) and QSPI."); } static void mps3tz_an547_class_init(ObjectClass *oc, void *data) @@ -1249,8 +1354,10 @@ static void mps3tz_an547_class_init(ObjectClass *oc, void *data) mmc->numirq = 96; mmc->uart_overflow_irq = 48; mmc->init_svtor = 0x00000000; + mmc->sram_addr_width = 21; mmc->raminfo = an547_raminfo; mmc->armsse_type = TYPE_SSE300; + mmc->boot_ram_size = 512 * KiB; mps2tz_set_default_ram_info(mmc); } diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 7bed2ac520..01b60bee49 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -857,43 +857,45 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova, static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) { - uint8_t scale = 0, num = 0, ttl = 0; - dma_addr_t addr = CMD_ADDR(cmd); + dma_addr_t end, addr = CMD_ADDR(cmd); uint8_t type = CMD_TYPE(cmd); uint16_t vmid = CMD_VMID(cmd); + uint8_t scale = CMD_SCALE(cmd); + uint8_t num = CMD_NUM(cmd); + uint8_t ttl = CMD_TTL(cmd); bool leaf = CMD_LEAF(cmd); uint8_t tg = CMD_TG(cmd); - uint64_t first_page = 0, last_page; - uint64_t num_pages = 1; + uint64_t num_pages; + uint8_t granule; int asid = -1; - if (tg) { - scale = CMD_SCALE(cmd); - num = CMD_NUM(cmd); - ttl = CMD_TTL(cmd); - num_pages = (num + 1) * BIT_ULL(scale); - } - if (type == SMMU_CMD_TLBI_NH_VA) { asid = CMD_ASID(cmd); } - /* Split invalidations into ^2 range invalidations */ - last_page = num_pages - 1; - while (num_pages) { - uint8_t granule = tg * 2 + 10; - uint64_t mask, count; + if (!tg) { + trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, 1, ttl, leaf); + smmuv3_inv_notifiers_iova(s, asid, addr, tg, 1); + smmu_iotlb_inv_iova(s, asid, addr, tg, 1, ttl); + return; + } + + /* RIL in use */ - mask = dma_aligned_pow2_mask(first_page, last_page, 64 - granule); - count = mask + 1; + num_pages = (num + 1) * BIT_ULL(scale); + granule = tg * 2 + 10; + + /* Split invalidations into ^2 range invalidations */ + end = addr + (num_pages << granule) - 1; - trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, count, ttl, leaf); - smmuv3_inv_notifiers_iova(s, asid, addr, tg, count); - smmu_iotlb_inv_iova(s, asid, addr, tg, count, ttl); + while (addr != end + 1) { + uint64_t mask = dma_aligned_pow2_mask(addr, end, 64); - num_pages -= count; - first_page += count; - addr += count * BIT_ULL(granule); + num_pages = (mask + 1) >> granule; + trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf); + smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages); + smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl); + addr += mask + 1; } } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0a78532018..840758666d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -50,6 +50,7 @@ #include "sysemu/tpm.h" #include "sysemu/kvm.h" #include "hw/loader.h" +#include "qapi/error.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -1521,8 +1522,10 @@ static void virt_build_smbios(VirtMachineState *vms) vmc->smbios_old_sys_ver ? "1.0" : mc->name, false, true, SMBIOS_ENTRY_POINT_30); - smbios_get_tables(MACHINE(vms), NULL, 0, &smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); + smbios_get_tables(MACHINE(vms), NULL, 0, + &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, + &error_fatal); if (smbios_anchor) { fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-tables", diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 85f25d15db..81af32dc42 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -118,7 +118,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } - object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); + object_property_set_int(OBJECT(dev), "phy-addr", 7, &error_abort); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); diff --git a/hw/audio/meson.build b/hw/audio/meson.build index 32c42bdebe..e48a9fc73d 100644 --- a/hw/audio/meson.build +++ b/hw/audio/meson.build @@ -7,7 +7,6 @@ softmmu_ss.add(when: 'CONFIG_ES1370', if_true: files('es1370.c')) softmmu_ss.add(when: 'CONFIG_GUS', if_true: files('gus.c', 'gusemu_hal.c', 'gusemu_mixer.c')) softmmu_ss.add(when: 'CONFIG_HDA', if_true: files('intel-hda.c', 'hda-codec.c')) softmmu_ss.add(when: 'CONFIG_MARVELL_88W8618', if_true: files('marvell_88w8618.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-ac97.c')) softmmu_ss.add(when: 'CONFIG_PCSPK', if_true: files('pcspk.c')) softmmu_ss.add(when: 'CONFIG_PL041', if_true: files('pl041.c', 'lm4549.c')) softmmu_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c')) diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c deleted file mode 100644 index 7d2e057038..0000000000 --- a/hw/audio/milkymist-ac97.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * QEMU model of the Milkymist System Controller. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/ac97.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "audio/audio.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_AC97_CTRL = 0, - R_AC97_ADDR, - R_AC97_DATAOUT, - R_AC97_DATAIN, - R_D_CTRL, - R_D_ADDR, - R_D_REMAINING, - R_RESERVED, - R_U_CTRL, - R_U_ADDR, - R_U_REMAINING, - R_MAX -}; - -enum { - AC97_CTRL_RQEN = (1<<0), - AC97_CTRL_WRITE = (1<<1), -}; - -enum { - CTRL_EN = (1<<0), -}; - -#define TYPE_MILKYMIST_AC97 "milkymist-ac97" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistAC97State, MILKYMIST_AC97) - -struct MilkymistAC97State { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - QEMUSoundCard card; - SWVoiceIn *voice_in; - SWVoiceOut *voice_out; - - uint32_t regs[R_MAX]; - - qemu_irq crrequest_irq; - qemu_irq crreply_irq; - qemu_irq dmar_irq; - qemu_irq dmaw_irq; -}; - -static void update_voices(MilkymistAC97State *s) -{ - if (s->regs[R_D_CTRL] & CTRL_EN) { - AUD_set_active_out(s->voice_out, 1); - } else { - AUD_set_active_out(s->voice_out, 0); - } - - if (s->regs[R_U_CTRL] & CTRL_EN) { - AUD_set_active_in(s->voice_in, 1); - } else { - AUD_set_active_in(s->voice_in, 0); - } -} - -static uint64_t ac97_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistAC97State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_AC97_CTRL: - case R_AC97_ADDR: - case R_AC97_DATAOUT: - case R_AC97_DATAIN: - case R_D_CTRL: - case R_D_ADDR: - case R_D_REMAINING: - case R_U_CTRL: - case R_U_ADDR: - case R_U_REMAINING: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_ac97: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_ac97_memory_read(addr << 2, r); - - return r; -} - -static void ac97_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistAC97State *s = opaque; - - trace_milkymist_ac97_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_AC97_CTRL: - /* always raise an IRQ according to the direction */ - if (value & AC97_CTRL_RQEN) { - if (value & AC97_CTRL_WRITE) { - trace_milkymist_ac97_pulse_irq_crrequest(); - qemu_irq_pulse(s->crrequest_irq); - } else { - trace_milkymist_ac97_pulse_irq_crreply(); - qemu_irq_pulse(s->crreply_irq); - } - } - - /* RQEN is self clearing */ - s->regs[addr] = value & ~AC97_CTRL_RQEN; - break; - case R_D_CTRL: - case R_U_CTRL: - s->regs[addr] = value; - update_voices(s); - break; - case R_AC97_ADDR: - case R_AC97_DATAOUT: - case R_AC97_DATAIN: - case R_D_ADDR: - case R_D_REMAINING: - case R_U_ADDR: - case R_U_REMAINING: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_ac97: write access to unknown register 0x" - TARGET_FMT_plx, addr); - break; - } - -} - -static const MemoryRegionOps ac97_mmio_ops = { - .read = ac97_read, - .write = ac97_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ac97_in_cb(void *opaque, int avail_b) -{ - MilkymistAC97State *s = opaque; - uint8_t buf[4096]; - uint32_t remaining = s->regs[R_U_REMAINING]; - int temp = MIN(remaining, avail_b); - uint32_t addr = s->regs[R_U_ADDR]; - int transferred = 0; - - trace_milkymist_ac97_in_cb(avail_b, remaining); - - /* prevent from raising an IRQ */ - if (temp == 0) { - return; - } - - while (temp) { - int acquired, to_copy; - - to_copy = MIN(temp, sizeof(buf)); - acquired = AUD_read(s->voice_in, buf, to_copy); - if (!acquired) { - break; - } - - cpu_physical_memory_write(addr, buf, acquired); - - temp -= acquired; - addr += acquired; - transferred += acquired; - } - - trace_milkymist_ac97_in_cb_transferred(transferred); - - s->regs[R_U_ADDR] = addr; - s->regs[R_U_REMAINING] -= transferred; - - if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) { - trace_milkymist_ac97_pulse_irq_dmaw(); - qemu_irq_pulse(s->dmaw_irq); - } -} - -static void ac97_out_cb(void *opaque, int free_b) -{ - MilkymistAC97State *s = opaque; - uint8_t buf[4096]; - uint32_t remaining = s->regs[R_D_REMAINING]; - int temp = MIN(remaining, free_b); - uint32_t addr = s->regs[R_D_ADDR]; - int transferred = 0; - - trace_milkymist_ac97_out_cb(free_b, remaining); - - /* prevent from raising an IRQ */ - if (temp == 0) { - return; - } - - while (temp) { - int copied, to_copy; - - to_copy = MIN(temp, sizeof(buf)); - cpu_physical_memory_read(addr, buf, to_copy); - copied = AUD_write(s->voice_out, buf, to_copy); - if (!copied) { - break; - } - temp -= copied; - addr += copied; - transferred += copied; - } - - trace_milkymist_ac97_out_cb_transferred(transferred); - - s->regs[R_D_ADDR] = addr; - s->regs[R_D_REMAINING] -= transferred; - - if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) { - trace_milkymist_ac97_pulse_irq_dmar(); - qemu_irq_pulse(s->dmar_irq); - } -} - -static void milkymist_ac97_reset(DeviceState *d) -{ - MilkymistAC97State *s = MILKYMIST_AC97(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - AUD_set_active_in(s->voice_in, 0); - AUD_set_active_out(s->voice_out, 0); -} - -static int ac97_post_load(void *opaque, int version_id) -{ - MilkymistAC97State *s = opaque; - - update_voices(s); - - return 0; -} - -static void milkymist_ac97_init(Object *obj) -{ - MilkymistAC97State *s = MILKYMIST_AC97(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->crrequest_irq); - sysbus_init_irq(dev, &s->crreply_irq); - sysbus_init_irq(dev, &s->dmar_irq); - sysbus_init_irq(dev, &s->dmaw_irq); - - memory_region_init_io(&s->regs_region, obj, &ac97_mmio_ops, s, - "milkymist-ac97", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_ac97_realize(DeviceState *dev, Error **errp) -{ - MilkymistAC97State *s = MILKYMIST_AC97(dev); - struct audsettings as; - - AUD_register_card("Milkymist AC'97", &s->card); - - as.freq = 48000; - as.nchannels = 2; - as.fmt = AUDIO_FORMAT_S16; - as.endianness = 1; - - s->voice_in = AUD_open_in(&s->card, s->voice_in, - "mm_ac97.in", s, ac97_in_cb, &as); - s->voice_out = AUD_open_out(&s->card, s->voice_out, - "mm_ac97.out", s, ac97_out_cb, &as); -} - -static const VMStateDescription vmstate_milkymist_ac97 = { - .name = "milkymist-ac97", - .version_id = 1, - .minimum_version_id = 1, - .post_load = ac97_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_ac97_properties[] = { - DEFINE_AUDIO_PROPERTIES(MilkymistAC97State, card), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_ac97_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_ac97_realize; - dc->reset = milkymist_ac97_reset; - dc->vmsd = &vmstate_milkymist_ac97; - device_class_set_props(dc, milkymist_ac97_properties); -} - -static const TypeInfo milkymist_ac97_info = { - .name = TYPE_MILKYMIST_AC97, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistAC97State), - .instance_init = milkymist_ac97_init, - .class_init = milkymist_ac97_class_init, -}; - -static void milkymist_ac97_register_types(void) -{ - type_register_static(&milkymist_ac97_info); -} - -type_init(milkymist_ac97_register_types) diff --git a/hw/audio/trace-events b/hw/audio/trace-events index 60556b4a97..432e10712f 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -6,18 +6,6 @@ cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x" cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x" cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x" -# milkymist-ac97.c -milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request" -milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply" -milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write" -milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read" -milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u" -milkymist_ac97_in_cb_transferred(int transferred) "transferred %d" -milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u" -milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" - # hda-codec.c hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d" hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st %s, %d x %s @ %d Hz" diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index 80b8a41cb5..0608e2d475 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -401,7 +401,7 @@ static void atmega1280_class_init(ObjectClass *oc, void *data) { AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); - amc->cpu_type = AVR_CPU_TYPE_NAME("avr6"); + amc->cpu_type = AVR_CPU_TYPE_NAME("avr51"); amc->flash_size = 128 * KiB; amc->eeprom_size = 4 * KiB; amc->sram_size = 8 * KiB; diff --git a/hw/block/Kconfig b/hw/block/Kconfig index 4fcd152166..295441e64a 100644 --- a/hw/block/Kconfig +++ b/hw/block/Kconfig @@ -25,11 +25,6 @@ config ONENAND config TC58128 bool -config NVME_PCI - bool - default y if PCI_DEVICES - depends on PCI - config VIRTIO_BLK bool default y diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index e9050c8987..cd81893d1d 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -198,19 +198,30 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) goto fail_guest_notifiers; } + memory_region_transaction_begin(); + /* Set up virtqueue notify */ for (i = 0; i < nvqs; i++) { r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true); if (r != 0) { + int j = i; + fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); while (i--) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + while (j--) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } - goto fail_guest_notifiers; + goto fail_host_notifiers; } } + memory_region_transaction_commit(); + s->starting = false; vblk->dataplane_started = true; trace_virtio_blk_data_plane_start(s); @@ -221,7 +232,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) aio_context_release(old_context); if (r < 0) { error_report_err(local_err); - goto fail_guest_notifiers; + goto fail_aio_context; } /* Process queued requests before the ones in vring */ @@ -245,6 +256,20 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) aio_context_release(s->ctx); return 0; + fail_aio_context: + memory_region_transaction_begin(); + + for (i = 0; i < nvqs; i++) { + virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < nvqs; i++) { + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); + } + fail_host_notifiers: + k->set_guest_notifiers(qbus->parent, nvqs, false); fail_guest_notifiers: /* * If we failed to set up the guest notifiers queued requests will be @@ -305,8 +330,15 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) aio_context_release(s->ctx); + memory_region_transaction_begin(); + for (i = 0; i < nvqs; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < nvqs; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } diff --git a/hw/block/meson.build b/hw/block/meson.build index 5b4a7699f9..8b0de54db1 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c')) softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) -softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c', 'nvme-subsys.c', 'nvme-dif.c')) specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c')) diff --git a/hw/block/nvme-dif.h b/hw/block/nvme-dif.h deleted file mode 100644 index 524faffbd7..0000000000 --- a/hw/block/nvme-dif.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * QEMU NVM Express End-to-End Data Protection support - * - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * Authors: - * Klaus Jensen <k.jensen@samsung.com> - * Gollu Appalanaidu <anaidu.gollu@samsung.com> - */ - -#ifndef HW_NVME_DIF_H -#define HW_NVME_DIF_H - -/* from Linux kernel (crypto/crct10dif_common.c) */ -static const uint16_t t10_dif_crc_table[256] = { - 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B, - 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6, - 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6, - 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B, - 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1, - 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C, - 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C, - 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781, - 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8, - 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255, - 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925, - 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698, - 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472, - 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF, - 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF, - 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02, - 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA, - 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067, - 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17, - 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA, - 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640, - 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD, - 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D, - 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30, - 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759, - 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4, - 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394, - 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29, - 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3, - 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E, - 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E, - 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3 -}; - -uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, - uint32_t reftag); -uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, - uint64_t slba); -void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, - uint8_t *mbuf, size_t mlen, uint16_t apptag, - uint32_t reftag); -uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, - uint8_t *mbuf, size_t mlen, uint16_t ctrl, - uint64_t slba, uint16_t apptag, - uint16_t appmask, uint32_t reftag); -uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req); - -#endif /* HW_NVME_DIF_H */ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h deleted file mode 100644 index fb0a41f912..0000000000 --- a/hw/block/nvme-ns.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * QEMU NVM Express Virtual Namespace - * - * Copyright (c) 2019 CNEX Labs - * Copyright (c) 2020 Samsung Electronics - * - * Authors: - * Klaus Jensen <k.jensen@samsung.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See the - * COPYING file in the top-level directory. - * - */ - -#ifndef NVME_NS_H -#define NVME_NS_H - -#include "qemu/uuid.h" - -#define TYPE_NVME_NS "nvme-ns" -#define NVME_NS(obj) \ - OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS) - -typedef struct NvmeZone { - NvmeZoneDescr d; - uint64_t w_ptr; - QTAILQ_ENTRY(NvmeZone) entry; -} NvmeZone; - -typedef struct NvmeNamespaceParams { - bool detached; - bool shared; - uint32_t nsid; - QemuUUID uuid; - - uint16_t ms; - uint8_t mset; - uint8_t pi; - uint8_t pil; - - uint16_t mssrl; - uint32_t mcl; - uint8_t msrc; - - bool zoned; - bool cross_zone_read; - uint64_t zone_size_bs; - uint64_t zone_cap_bs; - uint32_t max_active_zones; - uint32_t max_open_zones; - uint32_t zd_extension_size; -} NvmeNamespaceParams; - -typedef struct NvmeNamespace { - DeviceState parent_obj; - BlockConf blkconf; - int32_t bootindex; - int64_t size; - int64_t mdata_offset; - NvmeIdNs id_ns; - const uint32_t *iocs; - uint8_t csi; - uint16_t status; - int attached; - - QTAILQ_ENTRY(NvmeNamespace) entry; - - NvmeIdNsZoned *id_ns_zoned; - NvmeZone *zone_array; - QTAILQ_HEAD(, NvmeZone) exp_open_zones; - QTAILQ_HEAD(, NvmeZone) imp_open_zones; - QTAILQ_HEAD(, NvmeZone) closed_zones; - QTAILQ_HEAD(, NvmeZone) full_zones; - uint32_t num_zones; - uint64_t zone_size; - uint64_t zone_capacity; - uint32_t zone_size_log2; - uint8_t *zd_extensions; - int32_t nr_open_zones; - int32_t nr_active_zones; - - NvmeNamespaceParams params; - - struct { - uint32_t err_rec; - } features; -} NvmeNamespace; - -static inline uint16_t nvme_ns_status(NvmeNamespace *ns) -{ - return ns->status; -} - -static inline uint32_t nvme_nsid(NvmeNamespace *ns) -{ - if (ns) { - return ns->params.nsid; - } - - return 0; -} - -static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) -{ - NvmeIdNs *id_ns = &ns->id_ns; - return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; -} - -static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) -{ - return nvme_ns_lbaf(ns)->ds; -} - -/* convert an LBA to the equivalent in bytes */ -static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) -{ - return lba << nvme_ns_lbads(ns); -} - -static inline size_t nvme_lsize(NvmeNamespace *ns) -{ - return 1 << nvme_ns_lbads(ns); -} - -static inline uint16_t nvme_msize(NvmeNamespace *ns) -{ - return nvme_ns_lbaf(ns)->ms; -} - -static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) -{ - return nvme_msize(ns) * lba; -} - -static inline bool nvme_ns_ext(NvmeNamespace *ns) -{ - return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); -} - -/* calculate the number of LBAs that the namespace can accomodate */ -static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) -{ - if (nvme_msize(ns)) { - return ns->size / (nvme_lsize(ns) + nvme_msize(ns)); - } - return ns->size >> nvme_ns_lbads(ns); -} - -typedef struct NvmeCtrl NvmeCtrl; - -static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone) -{ - return zone->d.zs >> 4; -} - -static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state) -{ - zone->d.zs = state << 4; -} - -static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone) -{ - return zone->d.zslba + ns->zone_size; -} - -static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone) -{ - return zone->d.zslba + zone->d.zcap; -} - -static inline bool nvme_wp_is_valid(NvmeZone *zone) -{ - uint8_t st = nvme_get_zone_state(zone); - - return st != NVME_ZONE_STATE_FULL && - st != NVME_ZONE_STATE_READ_ONLY && - st != NVME_ZONE_STATE_OFFLINE; -} - -static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns, - uint32_t zone_idx) -{ - return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size]; -} - -static inline void nvme_aor_inc_open(NvmeNamespace *ns) -{ - assert(ns->nr_open_zones >= 0); - if (ns->params.max_open_zones) { - ns->nr_open_zones++; - assert(ns->nr_open_zones <= ns->params.max_open_zones); - } -} - -static inline void nvme_aor_dec_open(NvmeNamespace *ns) -{ - if (ns->params.max_open_zones) { - assert(ns->nr_open_zones > 0); - ns->nr_open_zones--; - } - assert(ns->nr_open_zones >= 0); -} - -static inline void nvme_aor_inc_active(NvmeNamespace *ns) -{ - assert(ns->nr_active_zones >= 0); - if (ns->params.max_active_zones) { - ns->nr_active_zones++; - assert(ns->nr_active_zones <= ns->params.max_active_zones); - } -} - -static inline void nvme_aor_dec_active(NvmeNamespace *ns) -{ - if (ns->params.max_active_zones) { - assert(ns->nr_active_zones > 0); - ns->nr_active_zones--; - assert(ns->nr_active_zones >= ns->nr_open_zones); - } - assert(ns->nr_active_zones >= 0); -} - -void nvme_ns_init_format(NvmeNamespace *ns); -int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); -void nvme_ns_drain(NvmeNamespace *ns); -void nvme_ns_shutdown(NvmeNamespace *ns); -void nvme_ns_cleanup(NvmeNamespace *ns); - -#endif /* NVME_NS_H */ diff --git a/hw/block/nvme-subsys.h b/hw/block/nvme-subsys.h deleted file mode 100644 index 7d7ef5f7f1..0000000000 --- a/hw/block/nvme-subsys.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * QEMU NVM Express Subsystem: nvme-subsys - * - * Copyright (c) 2021 Minwoo Im <minwoo.im.dev@gmail.com> - * - * This code is licensed under the GNU GPL v2. Refer COPYING. - */ - -#ifndef NVME_SUBSYS_H -#define NVME_SUBSYS_H - -#define TYPE_NVME_SUBSYS "nvme-subsys" -#define NVME_SUBSYS(obj) \ - OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS) - -#define NVME_SUBSYS_MAX_CTRLS 32 -#define NVME_MAX_NAMESPACES 256 - -typedef struct NvmeCtrl NvmeCtrl; -typedef struct NvmeNamespace NvmeNamespace; -typedef struct NvmeSubsystem { - DeviceState parent_obj; - uint8_t subnqn[256]; - - NvmeCtrl *ctrls[NVME_SUBSYS_MAX_CTRLS]; - /* Allocated namespaces for this subsystem */ - NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; - - struct { - char *nqn; - } params; -} NvmeSubsystem; - -int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp); - -static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys, - uint32_t cntlid) -{ - if (!subsys || cntlid >= NVME_SUBSYS_MAX_CTRLS) { - return NULL; - } - - return subsys->ctrls[cntlid]; -} - -/* - * Return allocated namespace of the specified nsid in the subsystem. - */ -static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys, - uint32_t nsid) -{ - if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) { - return NULL; - } - - return subsys->namespaces[nsid]; -} - -#endif /* NVME_SUBSYS_H */ diff --git a/hw/block/nvme.h b/hw/block/nvme.h deleted file mode 100644 index 5d05ec368f..0000000000 --- a/hw/block/nvme.h +++ /dev/null @@ -1,266 +0,0 @@ -#ifndef HW_NVME_H -#define HW_NVME_H - -#include "block/nvme.h" -#include "hw/pci/pci.h" -#include "nvme-subsys.h" -#include "nvme-ns.h" - -#define NVME_DEFAULT_ZONE_SIZE (128 * MiB) -#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB) - -typedef struct NvmeParams { - char *serial; - uint32_t num_queues; /* deprecated since 5.1 */ - uint32_t max_ioqpairs; - uint16_t msix_qsize; - uint32_t cmb_size_mb; - uint8_t aerl; - uint32_t aer_max_queued; - uint8_t mdts; - uint8_t vsl; - bool use_intel_id; - uint8_t zasl; - bool legacy_cmb; -} NvmeParams; - -typedef struct NvmeAsyncEvent { - QTAILQ_ENTRY(NvmeAsyncEvent) entry; - NvmeAerResult result; -} NvmeAsyncEvent; - -enum { - NVME_SG_ALLOC = 1 << 0, - NVME_SG_DMA = 1 << 1, -}; - -typedef struct NvmeSg { - int flags; - - union { - QEMUSGList qsg; - QEMUIOVector iov; - }; -} NvmeSg; - -typedef struct NvmeRequest { - struct NvmeSQueue *sq; - struct NvmeNamespace *ns; - BlockAIOCB *aiocb; - uint16_t status; - void *opaque; - NvmeCqe cqe; - NvmeCmd cmd; - BlockAcctCookie acct; - NvmeSg sg; - QTAILQ_ENTRY(NvmeRequest)entry; -} NvmeRequest; - -typedef struct NvmeBounceContext { - NvmeRequest *req; - - struct { - QEMUIOVector iov; - uint8_t *bounce; - } data, mdata; -} NvmeBounceContext; - -static inline const char *nvme_adm_opc_str(uint8_t opc) -{ - switch (opc) { - case NVME_ADM_CMD_DELETE_SQ: return "NVME_ADM_CMD_DELETE_SQ"; - case NVME_ADM_CMD_CREATE_SQ: return "NVME_ADM_CMD_CREATE_SQ"; - case NVME_ADM_CMD_GET_LOG_PAGE: return "NVME_ADM_CMD_GET_LOG_PAGE"; - case NVME_ADM_CMD_DELETE_CQ: return "NVME_ADM_CMD_DELETE_CQ"; - case NVME_ADM_CMD_CREATE_CQ: return "NVME_ADM_CMD_CREATE_CQ"; - case NVME_ADM_CMD_IDENTIFY: return "NVME_ADM_CMD_IDENTIFY"; - case NVME_ADM_CMD_ABORT: return "NVME_ADM_CMD_ABORT"; - case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES"; - case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES"; - case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ"; - case NVME_ADM_CMD_NS_ATTACHMENT: return "NVME_ADM_CMD_NS_ATTACHMENT"; - case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM"; - default: return "NVME_ADM_CMD_UNKNOWN"; - } -} - -static inline const char *nvme_io_opc_str(uint8_t opc) -{ - switch (opc) { - case NVME_CMD_FLUSH: return "NVME_NVM_CMD_FLUSH"; - case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE"; - case NVME_CMD_READ: return "NVME_NVM_CMD_READ"; - case NVME_CMD_COMPARE: return "NVME_NVM_CMD_COMPARE"; - case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES"; - case NVME_CMD_DSM: return "NVME_NVM_CMD_DSM"; - case NVME_CMD_VERIFY: return "NVME_NVM_CMD_VERIFY"; - case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY"; - case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND"; - case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV"; - case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND"; - default: return "NVME_NVM_CMD_UNKNOWN"; - } -} - -typedef struct NvmeSQueue { - struct NvmeCtrl *ctrl; - uint16_t sqid; - uint16_t cqid; - uint32_t head; - uint32_t tail; - uint32_t size; - uint64_t dma_addr; - QEMUTimer *timer; - NvmeRequest *io_req; - QTAILQ_HEAD(, NvmeRequest) req_list; - QTAILQ_HEAD(, NvmeRequest) out_req_list; - QTAILQ_ENTRY(NvmeSQueue) entry; -} NvmeSQueue; - -typedef struct NvmeCQueue { - struct NvmeCtrl *ctrl; - uint8_t phase; - uint16_t cqid; - uint16_t irq_enabled; - uint32_t head; - uint32_t tail; - uint32_t vector; - uint32_t size; - uint64_t dma_addr; - QEMUTimer *timer; - QTAILQ_HEAD(, NvmeSQueue) sq_list; - QTAILQ_HEAD(, NvmeRequest) req_list; -} NvmeCQueue; - -#define TYPE_NVME_BUS "nvme-bus" -#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS) - -typedef struct NvmeBus { - BusState parent_bus; -} NvmeBus; - -#define TYPE_NVME "nvme" -#define NVME(obj) \ - OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME) - -typedef struct NvmeFeatureVal { - struct { - uint16_t temp_thresh_hi; - uint16_t temp_thresh_low; - }; - uint32_t async_config; -} NvmeFeatureVal; - -typedef struct NvmeCtrl { - PCIDevice parent_obj; - MemoryRegion bar0; - MemoryRegion iomem; - NvmeBar bar; - NvmeParams params; - NvmeBus bus; - - uint16_t cntlid; - bool qs_created; - uint32_t page_size; - uint16_t page_bits; - uint16_t max_prp_ents; - uint16_t cqe_size; - uint16_t sqe_size; - uint32_t reg_size; - uint32_t num_namespaces; - uint32_t max_q_ents; - uint8_t outstanding_aers; - uint32_t irq_status; - uint64_t host_timestamp; /* Timestamp sent by the host */ - uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ - uint64_t starttime_ms; - uint16_t temperature; - uint8_t smart_critical_warning; - - struct { - MemoryRegion mem; - uint8_t *buf; - bool cmse; - hwaddr cba; - } cmb; - - struct { - HostMemoryBackend *dev; - bool cmse; - hwaddr cba; - } pmr; - - uint8_t aer_mask; - NvmeRequest **aer_reqs; - QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue; - int aer_queued; - - uint32_t dmrsl; - - /* Namespace ID is started with 1 so bitmap should be 1-based */ -#define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1) - DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE); - - NvmeSubsystem *subsys; - - NvmeNamespace namespace; - /* - * Attached namespaces to this controller. If subsys is not given, all - * namespaces in this list will always be attached. - */ - NvmeNamespace *namespaces[NVME_MAX_NAMESPACES]; - NvmeSQueue **sq; - NvmeCQueue **cq; - NvmeSQueue admin_sq; - NvmeCQueue admin_cq; - NvmeIdCtrl id_ctrl; - NvmeFeatureVal features; -} NvmeCtrl; - -static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid) -{ - if (!nsid || nsid > n->num_namespaces) { - return NULL; - } - - return n->namespaces[nsid - 1]; -} - -static inline NvmeCQueue *nvme_cq(NvmeRequest *req) -{ - NvmeSQueue *sq = req->sq; - NvmeCtrl *n = sq->ctrl; - - return n->cq[sq->cqid]; -} - -static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req) -{ - NvmeSQueue *sq = req->sq; - return sq->ctrl; -} - -static inline uint16_t nvme_cid(NvmeRequest *req) -{ - if (!req) { - return 0xffff; - } - - return le16_to_cpu(req->cqe.cid); -} - -typedef enum NvmeTxDirection { - NVME_TX_DIRECTION_TO_DEVICE = 0, - NVME_TX_DIRECTION_FROM_DEVICE = 1, -} NvmeTxDirection; - -void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns); -uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, - NvmeTxDirection dir, NvmeRequest *req); -uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, - NvmeTxDirection dir, NvmeRequest *req); -void nvme_rw_complete_cb(void *opaque, int ret); -uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, - NvmeCmd *cmd); - -#endif /* HW_NVME_H */ diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 25c053693c..02c514fb6e 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -173,7 +173,6 @@ static void pflash_setup_mappings(PFlashCFI02 *pfl) "pflash-alias", &pfl->orig_mem, 0, size); memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]); } - pfl->rom_mode = true; } static void pflash_reset_state_machine(PFlashCFI02 *pfl) @@ -917,8 +916,13 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) /* Allocate memory for a bitmap for sectors being erased. */ pfl->sector_erase_map = bitmap_new(pfl->total_sectors); - pflash_setup_mappings(pfl); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + pfl->rom_mode = true; + if (pfl->mappings > 1) { + pflash_setup_mappings(pfl); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + } else { + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->orig_mem); + } timer_init_ns(&pfl->timer, QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->status = 0; diff --git a/hw/block/trace-events b/hw/block/trace-events index fa12e3a67a..646917d045 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -49,212 +49,6 @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6 hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" -# nvme.c -# nvme traces for successful events -pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" -pci_nvme_irq_pin(void) "pulsing IRQ pin" -pci_nvme_irq_masked(void) "IRQ is masked" -pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" -pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" -pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" -pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d" -pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64"" -pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" -pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" -pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" -pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" -pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" -pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" -pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" -pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" -pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8"" -pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16"" -pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16"" -pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16"" -pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32"" -pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8"" -pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" -pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d" -pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32"" -pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32"" -pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32"" -pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64"" -pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" -pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" -pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" -pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" -pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid %"PRIu16" cns 0x%"PRIx8" ctrlid %"PRIu16" csi 0x%"PRIx8"" -pci_nvme_identify_ctrl(void) "identify controller" -pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8"" -pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_identify_ns_attached_list(uint16_t cntid) "cntid=%"PRIu16"" -pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8"" -pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8"" -pci_nvme_identify_cmd_set(void) "identify i/o command set" -pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64"" -pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" -pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" -pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" -pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d" -pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" -pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64"" -pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64"" -pci_nvme_process_aers(int queued) "queued %d" -pci_nvme_aer(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aer_aerl_exceeded(void) "aerl exceeded" -pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8"" -pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" -pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8"" -pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32"" -pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" -pci_nvme_enqueue_event_noqueue(int queued) "queued %d" -pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" -pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" -pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16"" -pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d" -pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" -pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" -pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16"" -pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" -pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" -pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" -pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" -pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" -pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" -pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" -pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" -pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" -pci_nvme_mmio_stopped(void) "cleared controller enable bit" -pci_nvme_mmio_shutdown_set(void) "shutdown bit set" -pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" -pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_reset_zone(uint64_t slba, uint32_t zone_idx, int all) "reset zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_offline_zone(uint64_t slba, uint32_t zone_idx, int all) "offline zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone descriptor extension, slba=%"PRIu64", idx=%"PRIu32"" -pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32"" -pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state" -pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state" - -# nvme traces for error conditions -pci_nvme_err_mdts(size_t len) "len %zu" -pci_nvme_err_zasl(size_t len) "len %zu" -pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" -pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" -pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" -pci_nvme_err_cfs(void) "controller fatal status" -pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16"" -pci_nvme_err_copy_invalid_format(uint8_t format) "format 0x%"PRIx8"" -pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" -pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" -pci_nvme_err_invalid_sgl_excess_length(uint32_t residual) "residual %"PRIu32"" -pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" -pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64"" -pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" -pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" -pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" -pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" -pci_nvme_err_invalid_log_page_offset(uint64_t ofs, uint64_t size) "must be <= %"PRIu64", got %"PRIu64"" -pci_nvme_err_cmb_invalid_cba(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" -pci_nvme_err_cmb_not_enabled(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" -pci_nvme_err_unaligned_zone_cmd(uint8_t action, uint64_t slba, uint64_t zslba) "unaligned zone op 0x%"PRIx32", got slba=%"PRIu64", zslba=%"PRIu64"" -pci_nvme_err_invalid_zone_state_transition(uint8_t action, uint64_t slba, uint8_t attrs) "action=0x%"PRIx8", slba=%"PRIu64", attrs=0x%"PRIx32"" -pci_nvme_err_write_not_at_wp(uint64_t slba, uint64_t zone, uint64_t wp) "writing at slba=%"PRIu64", zone=%"PRIu64", but wp=%"PRIu64"" -pci_nvme_err_append_not_at_start(uint64_t slba, uint64_t zone) "appending at slba=%"PRIu64", but zone=%"PRIu64"" -pci_nvme_err_zone_is_full(uint64_t zslba) "zslba 0x%"PRIx64"" -pci_nvme_err_zone_is_read_only(uint64_t zslba) "zslba 0x%"PRIx64"" -pci_nvme_err_zone_is_offline(uint64_t zslba) "zslba 0x%"PRIx64"" -pci_nvme_err_zone_boundary(uint64_t slba, uint32_t nlb, uint64_t zcap) "lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64"" -pci_nvme_err_zone_invalid_write(uint64_t slba, uint64_t wp) "lba 0x%"PRIx64" wp 0x%"PRIx64"" -pci_nvme_err_zone_write_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" -pci_nvme_err_zone_read_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" -pci_nvme_err_insuff_active_res(uint32_t max_active) "max_active=%"PRIu32" zone limit exceeded" -pci_nvme_err_insuff_open_res(uint32_t max_open) "max_open=%"PRIu32" zone limit exceeded" -pci_nvme_err_zd_extension_map_error(uint32_t zone_idx) "can't map descriptor extension for zone_idx=%"PRIu32"" -pci_nvme_err_invalid_iocsci(uint32_t idx) "unsupported command set combination index %"PRIu32"" -pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" -pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" -pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" -pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" -pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" -pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" -pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" -pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" -pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" -pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" -pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" -pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" -pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" -pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" -pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" -pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" -pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16"" -pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" -pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" -pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" -pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" -pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" -pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" -pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" -pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" -pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" -pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" -pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" -pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" -pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u" -pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" -pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" -pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32"" -pci_nvme_err_startfail(void) "setting controller enable bit failed" -pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8"" - -# Traces for undefined behavior -pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" -pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" -pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" -pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" -pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" -pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" -pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" -pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" -pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" -pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" -pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" -pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" -pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" -pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" -pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" -pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" -pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" -pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" -pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" -pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" -pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" -pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field" - # xen-block.c xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index f5e9682703..c6210fad0c 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -47,9 +47,13 @@ static const int user_feature_bits[] = { VIRTIO_RING_F_INDIRECT_DESC, VIRTIO_RING_F_EVENT_IDX, VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_F_RING_PACKED, + VIRTIO_F_IOMMU_PLATFORM, VHOST_INVALID_FEATURE_BIT }; +static void vhost_user_blk_event(void *opaque, QEMUChrEvent event); + static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config) { VHostUserBlk *s = VHOST_USER_BLK(vdev); @@ -309,7 +313,7 @@ static void vhost_user_blk_reset(VirtIODevice *vdev) vhost_dev_free_inflight(s->inflight); } -static int vhost_user_blk_connect(DeviceState *dev) +static int vhost_user_blk_connect(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); @@ -320,6 +324,7 @@ static int vhost_user_blk_connect(DeviceState *dev) } s->connected = true; + s->dev.num_queues = s->num_queues; s->dev.nvqs = s->num_queues; s->dev.vqs = s->vhost_vqs; s->dev.vq_index = 0; @@ -329,8 +334,7 @@ static int vhost_user_blk_connect(DeviceState *dev) ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); if (ret < 0) { - error_report("vhost-user-blk: vhost initialization failed: %s", - strerror(-ret)); + error_setg_errno(errp, -ret, "vhost initialization failed"); return ret; } @@ -338,8 +342,7 @@ static int vhost_user_blk_connect(DeviceState *dev) if (virtio_device_started(vdev, vdev->status)) { ret = vhost_user_blk_start(vdev); if (ret < 0) { - error_report("vhost-user-blk: vhost start failed: %s", - strerror(-ret)); + error_setg_errno(errp, -ret, "vhost start failed"); return ret; } } @@ -362,19 +365,6 @@ static void vhost_user_blk_disconnect(DeviceState *dev) vhost_dev_cleanup(&s->dev); } -static void vhost_user_blk_event(void *opaque, QEMUChrEvent event, - bool realized); - -static void vhost_user_blk_event_realize(void *opaque, QEMUChrEvent event) -{ - vhost_user_blk_event(opaque, event, false); -} - -static void vhost_user_blk_event_oper(void *opaque, QEMUChrEvent event) -{ - vhost_user_blk_event(opaque, event, true); -} - static void vhost_user_blk_chr_closed_bh(void *opaque) { DeviceState *dev = opaque; @@ -382,36 +372,27 @@ static void vhost_user_blk_chr_closed_bh(void *opaque) VHostUserBlk *s = VHOST_USER_BLK(vdev); vhost_user_blk_disconnect(dev); - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, - vhost_user_blk_event_oper, NULL, opaque, NULL, true); + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, + NULL, opaque, NULL, true); } -static void vhost_user_blk_event(void *opaque, QEMUChrEvent event, - bool realized) +static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) { DeviceState *dev = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); + Error *local_err = NULL; switch (event) { case CHR_EVENT_OPENED: - if (vhost_user_blk_connect(dev) < 0) { + if (vhost_user_blk_connect(dev, &local_err) < 0) { + error_report_err(local_err); qemu_chr_fe_disconnect(&s->chardev); return; } break; case CHR_EVENT_CLOSED: - /* - * Closing the connection should happen differently on device - * initialization and operation stages. - * On initalization, we want to re-start vhost_dev initialization - * from the very beginning right away when the connection is closed, - * so we clean up vhost_dev on each connection closing. - * On operation, we want to postpone vhost_dev cleanup to let the - * other code perform its own cleanup sequence using vhost_dev data - * (e.g. vhost_dev_set_log). - */ - if (realized && !runstate_check(RUN_STATE_SHUTDOWN)) { + if (!runstate_check(RUN_STATE_SHUTDOWN)) { /* * A close event may happen during a read/write, but vhost * code assumes the vhost_dev remains setup, so delay the @@ -431,8 +412,6 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event, * knowing its type (in this case vhost-user). */ s->dev.started = false; - } else { - vhost_user_blk_disconnect(dev); } break; case CHR_EVENT_BREAK: @@ -447,11 +426,10 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); - Error *err = NULL; int i, ret; if (!s->chardev.chr) { - error_setg(errp, "vhost-user-blk: chardev is mandatory"); + error_setg(errp, "chardev is mandatory"); return; } @@ -459,16 +437,16 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->num_queues = 1; } if (!s->num_queues || s->num_queues > VIRTIO_QUEUE_MAX) { - error_setg(errp, "vhost-user-blk: invalid number of IO queues"); + error_setg(errp, "invalid number of IO queues"); return; } if (!s->queue_size) { - error_setg(errp, "vhost-user-blk: queue size must be non-zero"); + error_setg(errp, "queue size must be non-zero"); return; } if (s->queue_size > VIRTQUEUE_MAX_SIZE) { - error_setg(errp, "vhost-user-blk: queue size must not exceed %d", + error_setg(errp, "queue size must not exceed %d", VIRTQUEUE_MAX_SIZE); return; } @@ -490,34 +468,31 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); s->connected = false; - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, - vhost_user_blk_event_realize, NULL, (void *)dev, - NULL, true); - -reconnect: - if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) { - error_report_err(err); + if (qemu_chr_fe_wait_connected(&s->chardev, errp) < 0) { goto virtio_err; } - /* check whether vhost_user_blk_connect() failed or not */ - if (!s->connected) { - goto reconnect; + if (vhost_user_blk_connect(dev, errp) < 0) { + qemu_chr_fe_disconnect(&s->chardev); + goto virtio_err; } + assert(s->connected); ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, sizeof(struct virtio_blk_config)); if (ret < 0) { - error_report("vhost-user-blk: get block config failed"); - goto reconnect; + error_setg(errp, "vhost-user-blk: get block config failed"); + goto vhost_err; } - /* we're fully initialized, now we can operate, so change the handler */ + /* we're fully initialized, now we can operate, so add the handler */ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, - vhost_user_blk_event_oper, NULL, (void *)dev, + vhost_user_blk_event, NULL, (void *)dev, NULL, true); return; +vhost_err: + vhost_dev_cleanup(&s->dev); virtio_err: g_free(s->vhost_vqs); s->vhost_vqs = NULL; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index d28979efb8..f139cd7cc9 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -40,7 +40,7 @@ * Starting from the discard feature, we can use this array to properly * set the config size depending on the features enabled. */ -static VirtIOFeature feature_sizes[] = { +static const VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_BLK_F_DISCARD, .end = endof(struct virtio_blk_config, discard_sector_alignment)}, {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 83754a4344..674953f1ad 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -728,6 +728,8 @@ static XenBlockDrive *xen_block_drive_create(const char *id, XenBlockDrive *drive = NULL; QDict *file_layer; QDict *driver_layer; + struct stat st; + int rc; if (params) { char **v = g_strsplit(params, ":", 2); @@ -761,7 +763,17 @@ static XenBlockDrive *xen_block_drive_create(const char *id, file_layer = qdict_new(); driver_layer = qdict_new(); - qdict_put_str(file_layer, "driver", "file"); + rc = stat(filename, &st); + if (rc) { + error_setg_errno(errp, errno, "Could not stat file '%s'", filename); + goto done; + } + if (S_ISBLK(st.st_mode)) { + qdict_put_str(file_layer, "driver", "host_device"); + } else { + qdict_put_str(file_layer, "driver", "file"); + } + qdict_put_str(file_layer, "filename", filename); g_free(filename); diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c deleted file mode 100644 index ce30279650..0000000000 --- a/hw/char/lm32_juart.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * LatticeMico32 JTAG UART model. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "qemu/module.h" -#include "trace.h" -#include "chardev/char-fe.h" - -#include "hw/char/lm32_juart.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "qom/object.h" - -enum { - LM32_JUART_MIN_SAVE_VERSION = 0, - LM32_JUART_CURRENT_SAVE_VERSION = 0, - LM32_JUART_MAX_SAVE_VERSION = 0, -}; - -enum { - JTX_FULL = (1<<8), -}; - -enum { - JRX_FULL = (1<<8), -}; - -OBJECT_DECLARE_SIMPLE_TYPE(LM32JuartState, LM32_JUART) - -struct LM32JuartState { - SysBusDevice parent_obj; - - CharBackend chr; - - uint32_t jtx; - uint32_t jrx; -}; - -uint32_t lm32_juart_get_jtx(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_get_jtx(s->jtx); - return s->jtx; -} - -uint32_t lm32_juart_get_jrx(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_get_jrx(s->jrx); - return s->jrx; -} - -void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) -{ - LM32JuartState *s = LM32_JUART(d); - unsigned char ch = jtx & 0xff; - - trace_lm32_juart_set_jtx(s->jtx); - - s->jtx = jtx; - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ - qemu_chr_fe_write_all(&s->chr, &ch, 1); -} - -void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_set_jrx(s->jrx); - s->jrx &= ~JRX_FULL; -} - -static void juart_rx(void *opaque, const uint8_t *buf, int size) -{ - LM32JuartState *s = opaque; - - s->jrx = *buf | JRX_FULL; -} - -static int juart_can_rx(void *opaque) -{ - LM32JuartState *s = opaque; - - return !(s->jrx & JRX_FULL); -} - -static void juart_event(void *opaque, QEMUChrEvent event) -{ -} - -static void juart_reset(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - s->jtx = 0; - s->jrx = 0; -} - -static void lm32_juart_realize(DeviceState *dev, Error **errp) -{ - LM32JuartState *s = LM32_JUART(dev); - - qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx, - juart_event, NULL, s, NULL, true); -} - -static const VMStateDescription vmstate_lm32_juart = { - .name = "lm32-juart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(jtx, LM32JuartState), - VMSTATE_UINT32(jrx, LM32JuartState), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_juart_properties[] = { - DEFINE_PROP_CHR("chardev", LM32JuartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_juart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = juart_reset; - dc->vmsd = &vmstate_lm32_juart; - device_class_set_props(dc, lm32_juart_properties); - dc->realize = lm32_juart_realize; -} - -static const TypeInfo lm32_juart_info = { - .name = TYPE_LM32_JUART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32JuartState), - .class_init = lm32_juart_class_init, -}; - -static void lm32_juart_register_types(void) -{ - type_register_static(&lm32_juart_info); -} - -type_init(lm32_juart_register_types) diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c deleted file mode 100644 index d8e0331311..0000000000 --- a/hw/char/lm32_uart.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * QEMU model of the LatticeMico32 UART block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://www.latticesemi.com/documents/mico32uart.pdf - */ - - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "chardev/char-fe.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_RXTX = 0, - R_IER, - R_IIR, - R_LCR, - R_MCR, - R_LSR, - R_MSR, - R_DIV, - R_MAX -}; - -enum { - IER_RBRI = (1<<0), - IER_THRI = (1<<1), - IER_RLSI = (1<<2), - IER_MSI = (1<<3), -}; - -enum { - IIR_STAT = (1<<0), - IIR_ID0 = (1<<1), - IIR_ID1 = (1<<2), -}; - -enum { - LCR_WLS0 = (1<<0), - LCR_WLS1 = (1<<1), - LCR_STB = (1<<2), - LCR_PEN = (1<<3), - LCR_EPS = (1<<4), - LCR_SP = (1<<5), - LCR_SB = (1<<6), -}; - -enum { - MCR_DTR = (1<<0), - MCR_RTS = (1<<1), -}; - -enum { - LSR_DR = (1<<0), - LSR_OE = (1<<1), - LSR_PE = (1<<2), - LSR_FE = (1<<3), - LSR_BI = (1<<4), - LSR_THRE = (1<<5), - LSR_TEMT = (1<<6), -}; - -enum { - MSR_DCTS = (1<<0), - MSR_DDSR = (1<<1), - MSR_TERI = (1<<2), - MSR_DDCD = (1<<3), - MSR_CTS = (1<<4), - MSR_DSR = (1<<5), - MSR_RI = (1<<6), - MSR_DCD = (1<<7), -}; - -#define TYPE_LM32_UART "lm32-uart" -OBJECT_DECLARE_SIMPLE_TYPE(LM32UartState, LM32_UART) - -struct LM32UartState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CharBackend chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; -}; - -static void uart_update_irq(LM32UartState *s) -{ - unsigned int irq; - - if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) - && (s->regs[R_IER] & IER_RLSI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID1 | IIR_ID0; - } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID1; - } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID0; - } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) { - irq = 1; - s->regs[R_IIR] = 0; - } else { - irq = 0; - s->regs[R_IIR] = IIR_STAT; - } - - trace_lm32_uart_irq_state(irq); - qemu_set_irq(s->irq, irq); -} - -static uint64_t uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - LM32UartState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_RXTX: - r = s->regs[R_RXTX]; - s->regs[R_LSR] &= ~LSR_DR; - uart_update_irq(s); - qemu_chr_fe_accept_input(&s->chr); - break; - case R_IIR: - case R_LSR: - case R_MSR: - r = s->regs[addr]; - break; - case R_IER: - case R_LCR: - case R_MCR: - case R_DIV: - error_report("lm32_uart: read access to write only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_lm32_uart_memory_read(addr << 2, r); - return r; -} - -static void uart_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32UartState *s = opaque; - unsigned char ch = value; - - trace_lm32_uart_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_RXTX: - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ - qemu_chr_fe_write_all(&s->chr, &ch, 1); - break; - case R_IER: - case R_LCR: - case R_MCR: - case R_DIV: - s->regs[addr] = value; - break; - case R_IIR: - case R_LSR: - case R_MSR: - error_report("lm32_uart: write access to read only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - uart_update_irq(s); -} - -static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - LM32UartState *s = opaque; - - if (s->regs[R_LSR] & LSR_DR) { - s->regs[R_LSR] |= LSR_OE; - } - - s->regs[R_LSR] |= LSR_DR; - s->regs[R_RXTX] = *buf; - - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - LM32UartState *s = opaque; - - return !(s->regs[R_LSR] & LSR_DR); -} - -static void uart_event(void *opaque, QEMUChrEvent event) -{ -} - -static void uart_reset(DeviceState *d) -{ - LM32UartState *s = LM32_UART(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_LSR] = LSR_THRE | LSR_TEMT; -} - -static void lm32_uart_init(Object *obj) -{ - LM32UartState *s = LM32_UART(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, obj, &uart_ops, s, - "uart", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); -} - -static void lm32_uart_realize(DeviceState *dev, Error **errp) -{ - LM32UartState *s = LM32_UART(dev); - - qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, - uart_event, NULL, s, NULL, true); -} - -static const VMStateDescription vmstate_lm32_uart = { - .name = "lm32-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_uart_properties[] = { - DEFINE_PROP_CHR("chardev", LM32UartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = uart_reset; - dc->vmsd = &vmstate_lm32_uart; - device_class_set_props(dc, lm32_uart_properties); - dc->realize = lm32_uart_realize; -} - -static const TypeInfo lm32_uart_info = { - .name = TYPE_LM32_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32UartState), - .instance_init = lm32_uart_init, - .class_init = lm32_uart_class_init, -}; - -static void lm32_uart_register_types(void) -{ - type_register_static(&lm32_uart_info); -} - -type_init(lm32_uart_register_types) diff --git a/hw/char/meson.build b/hw/char/meson.build index da5bb8b762..8361d0ab28 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -8,9 +8,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c')) softmmu_ss.add(when: 'CONFIG_IPACK', if_true: files('ipoctal232.c')) softmmu_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c')) softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_juart.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_uart.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-uart.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c')) softmmu_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c')) softmmu_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c')) @@ -19,6 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c')) +softmmu_ss.add(when: 'CONFIG_SHAKTI', if_true: files('shakti_uart.c')) softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen_console.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c')) diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c deleted file mode 100644 index cb1b3470ad..0000000000 --- a/hw/char/milkymist-uart.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * QEMU model of the Milkymist UART block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/uart.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "chardev/char-fe.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_RXTX = 0, - R_DIV, - R_STAT, - R_CTRL, - R_DBG, - R_MAX -}; - -enum { - STAT_THRE = (1<<0), - STAT_RX_EVT = (1<<1), - STAT_TX_EVT = (1<<2), -}; - -enum { - CTRL_RX_IRQ_EN = (1<<0), - CTRL_TX_IRQ_EN = (1<<1), - CTRL_THRU_EN = (1<<2), -}; - -enum { - DBG_BREAK_EN = (1<<0), -}; - -#define TYPE_MILKYMIST_UART "milkymist-uart" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistUartState, MILKYMIST_UART) - -struct MilkymistUartState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - CharBackend chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; -}; - -static void uart_update_irq(MilkymistUartState *s) -{ - int rx_event = s->regs[R_STAT] & STAT_RX_EVT; - int tx_event = s->regs[R_STAT] & STAT_TX_EVT; - int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN; - int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN; - - if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) { - trace_milkymist_uart_raise_irq(); - qemu_irq_raise(s->irq); - } else { - trace_milkymist_uart_lower_irq(); - qemu_irq_lower(s->irq); - } -} - -static uint64_t uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistUartState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_RXTX: - r = s->regs[addr]; - break; - case R_DIV: - case R_STAT: - case R_CTRL: - case R_DBG: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_uart_memory_read(addr << 2, r); - - return r; -} - -static void uart_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistUartState *s = opaque; - unsigned char ch = value; - - trace_milkymist_uart_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_RXTX: - qemu_chr_fe_write_all(&s->chr, &ch, 1); - s->regs[R_STAT] |= STAT_TX_EVT; - break; - case R_DIV: - case R_CTRL: - case R_DBG: - s->regs[addr] = value; - break; - - case R_STAT: - /* write one to clear bits */ - s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT)); - qemu_chr_fe_accept_input(&s->chr); - break; - - default: - error_report("milkymist_uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - uart_update_irq(s); -} - -static const MemoryRegionOps uart_mmio_ops = { - .read = uart_read, - .write = uart_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - MilkymistUartState *s = opaque; - - assert(!(s->regs[R_STAT] & STAT_RX_EVT)); - - s->regs[R_STAT] |= STAT_RX_EVT; - s->regs[R_RXTX] = *buf; - - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - MilkymistUartState *s = opaque; - - return !(s->regs[R_STAT] & STAT_RX_EVT); -} - -static void uart_event(void *opaque, QEMUChrEvent event) -{ -} - -static void milkymist_uart_reset(DeviceState *d) -{ - MilkymistUartState *s = MILKYMIST_UART(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* THRE is always set */ - s->regs[R_STAT] = STAT_THRE; -} - -static void milkymist_uart_realize(DeviceState *dev, Error **errp) -{ - MilkymistUartState *s = MILKYMIST_UART(dev); - - qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, - uart_event, NULL, s, NULL, true); -} - -static void milkymist_uart_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - MilkymistUartState *s = MILKYMIST_UART(obj); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, - "milkymist-uart", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_uart = { - .name = "milkymist-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_uart_properties[] = { - DEFINE_PROP_CHR("chardev", MilkymistUartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_uart_realize; - dc->reset = milkymist_uart_reset; - dc->vmsd = &vmstate_milkymist_uart; - device_class_set_props(dc, milkymist_uart_properties); -} - -static const TypeInfo milkymist_uart_info = { - .name = TYPE_MILKYMIST_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistUartState), - .instance_init = milkymist_uart_init, - .class_init = milkymist_uart_class_init, -}; - -static void milkymist_uart_register_types(void) -{ - type_register_static(&milkymist_uart_info); -} - -type_init(milkymist_uart_register_types) diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c new file mode 100644 index 0000000000..6870821325 --- /dev/null +++ b/hw/char/shakti_uart.c @@ -0,0 +1,185 @@ +/* + * SHAKTI UART + * + * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/char/shakti_uart.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "qemu/log.h" + +static uint64_t shakti_uart_read(void *opaque, hwaddr addr, unsigned size) +{ + ShaktiUartState *s = opaque; + + switch (addr) { + case SHAKTI_UART_BAUD: + return s->uart_baud; + case SHAKTI_UART_RX: + qemu_chr_fe_accept_input(&s->chr); + s->uart_status &= ~SHAKTI_UART_STATUS_RX_NOT_EMPTY; + return s->uart_rx; + case SHAKTI_UART_STATUS: + return s->uart_status; + case SHAKTI_UART_DELAY: + return s->uart_delay; + case SHAKTI_UART_CONTROL: + return s->uart_control; + case SHAKTI_UART_INT_EN: + return s->uart_interrupt; + case SHAKTI_UART_IQ_CYCLES: + return s->uart_iq_cycles; + case SHAKTI_UART_RX_THRES: + return s->uart_rx_threshold; + default: + /* Also handles TX REG which is write only */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } + + return 0; +} + +static void shakti_uart_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + ShaktiUartState *s = opaque; + uint32_t value = data; + uint8_t ch; + + switch (addr) { + case SHAKTI_UART_BAUD: + s->uart_baud = value; + break; + case SHAKTI_UART_TX: + ch = value; + qemu_chr_fe_write_all(&s->chr, &ch, 1); + s->uart_status &= ~SHAKTI_UART_STATUS_TX_FULL; + break; + case SHAKTI_UART_STATUS: + s->uart_status = value; + break; + case SHAKTI_UART_DELAY: + s->uart_delay = value; + break; + case SHAKTI_UART_CONTROL: + s->uart_control = value; + break; + case SHAKTI_UART_INT_EN: + s->uart_interrupt = value; + break; + case SHAKTI_UART_IQ_CYCLES: + s->uart_iq_cycles = value; + break; + case SHAKTI_UART_RX_THRES: + s->uart_rx_threshold = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static const MemoryRegionOps shakti_uart_ops = { + .read = shakti_uart_read, + .write = shakti_uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.min_access_size = 1, .max_access_size = 4}, + .valid = {.min_access_size = 1, .max_access_size = 4}, +}; + +static void shakti_uart_reset(DeviceState *dev) +{ + ShaktiUartState *s = SHAKTI_UART(dev); + + s->uart_baud = SHAKTI_UART_BAUD_DEFAULT; + s->uart_tx = 0x0; + s->uart_rx = 0x0; + s->uart_status = 0x0000; + s->uart_delay = 0x0000; + s->uart_control = SHAKTI_UART_CONTROL_DEFAULT; + s->uart_interrupt = 0x0000; + s->uart_iq_cycles = 0x00; + s->uart_rx_threshold = 0x00; +} + +static int shakti_uart_can_receive(void *opaque) +{ + ShaktiUartState *s = opaque; + + return !(s->uart_status & SHAKTI_UART_STATUS_RX_NOT_EMPTY); +} + +static void shakti_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + ShaktiUartState *s = opaque; + + s->uart_rx = *buf; + s->uart_status |= SHAKTI_UART_STATUS_RX_NOT_EMPTY; +} + +static void shakti_uart_realize(DeviceState *dev, Error **errp) +{ + ShaktiUartState *sus = SHAKTI_UART(dev); + qemu_chr_fe_set_handlers(&sus->chr, shakti_uart_can_receive, + shakti_uart_receive, NULL, NULL, sus, NULL, true); +} + +static void shakti_uart_instance_init(Object *obj) +{ + ShaktiUartState *sus = SHAKTI_UART(obj); + memory_region_init_io(&sus->mmio, + obj, + &shakti_uart_ops, + sus, + TYPE_SHAKTI_UART, + 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio); +} + +static Property shakti_uart_properties[] = { + DEFINE_PROP_CHR("chardev", ShaktiUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void shakti_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = shakti_uart_reset; + dc->realize = shakti_uart_realize; + device_class_set_props(dc, shakti_uart_properties); +} + +static const TypeInfo shakti_uart_info = { + .name = TYPE_SHAKTI_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ShaktiUartState), + .class_init = shakti_uart_class_init, + .instance_init = shakti_uart_instance_init, +}; + +static void shakti_uart_register_types(void) +{ + type_register_static(&shakti_uart_info); +} +type_init(shakti_uart_register_types) diff --git a/hw/char/trace-events b/hw/char/trace-events index 76d52938ea..2e6e6b119a 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -35,23 +35,6 @@ grlib_apbuart_event(int event) "event:%d" grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 -# lm32_juart.c -lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x" -lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x" -lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x" -lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x" - -# lm32_uart.c -lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_uart_irq_state(int level) "irq state %d" - -# milkymist-uart.c -milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_uart_raise_irq(void) "Raise IRQ" -milkymist_uart_lower_irq(void) "Lower IRQ" - # escc.c escc_put_queue(char channel, int b) "channel %c put: 0x%02x" escc_get_queue(char channel, int val) "channel %c get 0x%02x" @@ -90,6 +73,10 @@ cmsdk_apb_uart_set_params(int speed) "CMSDK APB UART: params set to %d 8N1" nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" +# shakti_uart.c +shakti_uart_read(uint64_t addr, uint16_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx16 " size %u" +shakti_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" + # exynos4210_uart.c exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)" exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready" diff --git a/hw/core/cpu.c b/hw/core/cpu-common.c index 00330ba07d..9530e266ec 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu-common.c @@ -34,7 +34,6 @@ #include "hw/qdev-properties.h" #include "trace/trace-root.h" #include "qemu/plugin.h" -#include "sysemu/hw_accel.h" CPUState *cpu_by_arch_id(int64_t id) { @@ -67,33 +66,6 @@ CPUState *cpu_create(const char *typename) return cpu; } -bool cpu_paging_enabled(const CPUState *cpu) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return cc->get_paging_enabled(cpu); -} - -static bool cpu_common_get_paging_enabled(const CPUState *cpu) -{ - return false; -} - -void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, - Error **errp) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - cc->get_memory_mapping(cpu, list, errp); -} - -static void cpu_common_get_memory_mapping(CPUState *cpu, - MemoryMappingList *list, - Error **errp) -{ - error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); -} - /* Resetting the IRQ comes from across the code base so we take the * BQL here if we need to. cpu_interrupt assumes it is held.*/ void cpu_reset_interrupt(CPUState *cpu, int mask) @@ -117,65 +89,6 @@ void cpu_exit(CPUState *cpu) qatomic_set(&cpu->icount_decr_ptr->u16.high, -1); } -int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf32_qemunote)(f, cpu, opaque); -} - -static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f, - CPUState *cpu, void *opaque) -{ - return 0; -} - -int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf32_note)(f, cpu, cpuid, opaque); -} - -static int cpu_common_write_elf32_note(WriteCoreDumpFunction f, - CPUState *cpu, int cpuid, - void *opaque) -{ - return -1; -} - -int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf64_qemunote)(f, cpu, opaque); -} - -static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f, - CPUState *cpu, void *opaque) -{ - return 0; -} - -int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - return (*cc->write_elf64_note)(f, cpu, cpuid, opaque); -} - -static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, - CPUState *cpu, int cpuid, - void *opaque) -{ - return -1; -} - - static int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) { return 0; @@ -186,28 +99,6 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) return 0; } -static bool cpu_common_virtio_is_big_endian(CPUState *cpu) -{ - return target_words_bigendian(); -} - -/* - * XXX the following #if is always true because this is a common_ss - * module, so target CONFIG_* is never defined. - */ -#if !defined(CONFIG_USER_ONLY) -GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - GuestPanicInformation *res = NULL; - - if (cc->get_crash_info) { - res = cc->get_crash_info(cpu); - } - return res; -} -#endif - void cpu_dump_state(CPUState *cpu, FILE *f, int flags) { CPUClass *cc = CPU_GET_CLASS(cpu); @@ -398,15 +289,8 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->parse_features = cpu_common_parse_features; k->get_arch_id = cpu_common_get_arch_id; k->has_work = cpu_common_has_work; - k->get_paging_enabled = cpu_common_get_paging_enabled; - k->get_memory_mapping = cpu_common_get_memory_mapping; - k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; - k->write_elf32_note = cpu_common_write_elf32_note; - k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; - k->write_elf64_note = cpu_common_write_elf64_note; k->gdb_read_register = cpu_common_gdb_read_register; k->gdb_write_register = cpu_common_gdb_write_register; - k->virtio_is_big_endian = cpu_common_virtio_is_big_endian; set_bit(DEVICE_CATEGORY_CPU, dc->categories); dc->realize = cpu_common_realizefn; dc->unrealize = cpu_common_unrealizefn; diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c new file mode 100644 index 0000000000..00253f8929 --- /dev/null +++ b/hw/core/cpu-sysemu.c @@ -0,0 +1,145 @@ +/* + * QEMU CPU model (system emulation specific) + * + * Copyright (c) 2012-2014 SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * <http://www.gnu.org/licenses/gpl-2.0.html> + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/core/cpu.h" +#include "hw/core/sysemu-cpu-ops.h" + +bool cpu_paging_enabled(const CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->sysemu_ops->get_paging_enabled) { + return cc->sysemu_ops->get_paging_enabled(cpu); + } + + return false; +} + +void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, + Error **errp) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->sysemu_ops->get_memory_mapping) { + cc->sysemu_ops->get_memory_mapping(cpu, list, errp); + return; + } + + error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); +} + +hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, + MemTxAttrs *attrs) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->sysemu_ops->get_phys_page_attrs_debug) { + return cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs); + } + /* Fallback for CPUs which don't implement the _attrs_ hook */ + *attrs = MEMTXATTRS_UNSPECIFIED; + return cc->sysemu_ops->get_phys_page_debug(cpu, addr); +} + +hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr) +{ + MemTxAttrs attrs = {}; + + return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs); +} + +int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + int ret = 0; + + if (cc->sysemu_ops->asidx_from_attrs) { + ret = cc->sysemu_ops->asidx_from_attrs(cpu, attrs); + assert(ret < cpu->num_ases && ret >= 0); + } + return ret; +} + +int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (!cc->sysemu_ops->write_elf32_qemunote) { + return 0; + } + return (*cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque); +} + +int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (!cc->sysemu_ops->write_elf32_note) { + return -1; + } + return (*cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque); +} + +int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (!cc->sysemu_ops->write_elf64_qemunote) { + return 0; + } + return (*cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque); +} + +int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (!cc->sysemu_ops->write_elf64_note) { + return -1; + } + return (*cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque); +} + +bool cpu_virtio_is_big_endian(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->sysemu_ops->virtio_is_big_endian) { + return cc->sysemu_ops->virtio_is_big_endian(cpu); + } + return target_words_bigendian(); +} + +GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + GuestPanicInformation *res = NULL; + + if (cc->sysemu_ops->get_crash_info) { + res = cc->sysemu_ops->get_crash_info(cpu); + } + return res; +} diff --git a/hw/core/machine.c b/hw/core/machine.c index 0f5ce43d0c..55b9bc7817 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -38,6 +38,7 @@ GlobalProperty hw_compat_6_0[] = { { "gpex-pcihost", "allow-unmapped-accesses", "false" }, + { "i8042", "extended-state", "false"}, }; const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0); @@ -1234,6 +1235,7 @@ void machine_run_board_init(MachineState *machine) "on", false); } + accel_init_interfaces(ACCEL_GET_CLASS(machine->accelerator)); machine_class->init(machine); phase_advance(PHASE_MACHINE_INITIALIZED); } diff --git a/hw/core/meson.build b/hw/core/meson.build index 59f1605bb0..18f44fb7c2 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -13,7 +13,7 @@ hwcore_files = files( 'qdev-clock.c', ) -common_ss.add(files('cpu.c')) +common_ss.add(files('cpu-common.c')) common_ss.add(when: 'CONFIG_FITLOADER', if_true: files('loader-fit.c')) common_ss.add(when: 'CONFIG_GENERIC_LOADER', if_true: files('generic-loader.c')) common_ss.add(when: ['CONFIG_GUEST_LOADER', fdt], if_true: files('guest-loader.c')) @@ -25,6 +25,7 @@ common_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) common_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) softmmu_ss.add(files( + 'cpu-sysemu.c', 'fw-path-provider.c', 'loader.c', 'machine-hmp-cmds.c', diff --git a/hw/core/numa.c b/hw/core/numa.c index ac6bed5817..1058d3697b 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -802,9 +802,27 @@ void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms) } } +static int ram_block_notify_add_single(RAMBlock *rb, void *opaque) +{ + const ram_addr_t max_size = qemu_ram_get_max_length(rb); + const ram_addr_t size = qemu_ram_get_used_length(rb); + void *host = qemu_ram_get_host_addr(rb); + RAMBlockNotifier *notifier = opaque; + + if (host) { + notifier->ram_block_added(notifier, host, size, max_size); + } + return 0; +} + void ram_block_notifier_add(RAMBlockNotifier *n) { QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next); + + /* Notify about all existing ram blocks. */ + if (n->ram_block_added) { + qemu_ram_foreach_block(ram_block_notify_add_single, n); + } } void ram_block_notifier_remove(RAMBlockNotifier *n) @@ -812,20 +830,35 @@ void ram_block_notifier_remove(RAMBlockNotifier *n) QLIST_REMOVE(n, next); } -void ram_block_notify_add(void *host, size_t size) +void ram_block_notify_add(void *host, size_t size, size_t max_size) +{ + RAMBlockNotifier *notifier; + + QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { + if (notifier->ram_block_added) { + notifier->ram_block_added(notifier, host, size, max_size); + } + } +} + +void ram_block_notify_remove(void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { - notifier->ram_block_added(notifier, host, size); + if (notifier->ram_block_removed) { + notifier->ram_block_removed(notifier, host, size, max_size); + } } } -void ram_block_notify_remove(void *host, size_t size) +void ram_block_notify_resize(void *host, size_t old_size, size_t new_size) { RAMBlockNotifier *notifier; QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { - notifier->ram_block_removed(notifier, host, size); + if (notifier->ram_block_resized) { + notifier->ram_block_resized(notifier, host, old_size, new_size); + } } } diff --git a/hw/display/Kconfig b/hw/display/Kconfig index ca46b5830e..a2306b67d8 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -72,10 +72,6 @@ config BLIZZARD config FRAMEBUFFER bool -config MILKYMIST_TMU2 - bool - depends on OPENGL && X11 - config SM501 bool select I2C diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index a1bea9a3aa..f2b874d5e3 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -45,6 +45,35 @@ static const struct edid_mode { { .xres = 640, .yres = 480, .byte = 35, .bit = 5 }, }; +typedef struct Timings { + uint32_t xfront; + uint32_t xsync; + uint32_t xblank; + + uint32_t yfront; + uint32_t ysync; + uint32_t yblank; + + uint64_t clock; +} Timings; + +static void generate_timings(Timings *timings, uint32_t refresh_rate, + uint32_t xres, uint32_t yres) +{ + /* pull some realistic looking timings out of thin air */ + timings->xfront = xres * 25 / 100; + timings->xsync = xres * 3 / 100; + timings->xblank = xres * 35 / 100; + + timings->yfront = yres * 5 / 1000; + timings->ysync = yres * 5 / 1000; + timings->yblank = yres * 35 / 1000; + + timings->clock = ((uint64_t)refresh_rate * + (xres + timings->xblank) * + (yres + timings->yblank)) / 10000000; +} + static void edid_ext_dta(uint8_t *dta) { dta[0] = 0x02; @@ -130,20 +159,39 @@ static void edid_fill_modes(uint8_t *edid, uint8_t *xtra3, uint8_t *dta, } } -static void edid_checksum(uint8_t *edid) +static void edid_checksum(uint8_t *edid, size_t len) { uint32_t sum = 0; int i; - for (i = 0; i < 127; i++) { + for (i = 0; i < len; i++) { sum += edid[i]; } sum &= 0xff; if (sum) { - edid[127] = 0x100 - sum; + edid[len] = 0x100 - sum; } } +static uint8_t *edid_desc_next(uint8_t *edid, uint8_t *dta, uint8_t *desc) +{ + if (desc == NULL) { + return NULL; + } + if (desc + 18 + 18 < edid + 127) { + return desc + 18; + } + if (dta) { + if (desc < edid + 127) { + return dta + dta[2]; + } + if (desc + 18 + 18 < dta + 127) { + return desc + 18; + } + } + return NULL; +} + static void edid_desc_type(uint8_t *desc, uint8_t type) { desc[0] = 0; @@ -181,8 +229,8 @@ static void edid_desc_ranges(uint8_t *desc) desc[7] = 30; desc[8] = 160; - /* max dot clock (1200 MHz) */ - desc[9] = 1200 / 10; + /* max dot clock (2550 MHz) */ + desc[9] = 2550 / 10; /* no extended timing information */ desc[10] = 0x01; @@ -204,42 +252,33 @@ static void edid_desc_dummy(uint8_t *desc) edid_desc_type(desc, 0x10); } -static void edid_desc_timing(uint8_t *desc, +static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate, uint32_t xres, uint32_t yres, uint32_t xmm, uint32_t ymm) { - /* pull some realistic looking timings out of thin air */ - uint32_t xfront = xres * 25 / 100; - uint32_t xsync = xres * 3 / 100; - uint32_t xblank = xres * 35 / 100; - - uint32_t yfront = yres * 5 / 1000; - uint32_t ysync = yres * 5 / 1000; - uint32_t yblank = yres * 35 / 1000; - - uint32_t clock = 75 * (xres + xblank) * (yres + yblank); - - stl_le_p(desc, clock / 10000); + Timings timings; + generate_timings(&timings, refresh_rate, xres, yres); + stl_le_p(desc, timings.clock); desc[2] = xres & 0xff; - desc[3] = xblank & 0xff; + desc[3] = timings.xblank & 0xff; desc[4] = (((xres & 0xf00) >> 4) | - ((xblank & 0xf00) >> 8)); + ((timings.xblank & 0xf00) >> 8)); desc[5] = yres & 0xff; - desc[6] = yblank & 0xff; + desc[6] = timings.yblank & 0xff; desc[7] = (((yres & 0xf00) >> 4) | - ((yblank & 0xf00) >> 8)); + ((timings.yblank & 0xf00) >> 8)); - desc[8] = xfront & 0xff; - desc[9] = xsync & 0xff; + desc[8] = timings.xfront & 0xff; + desc[9] = timings.xsync & 0xff; - desc[10] = (((yfront & 0x00f) << 4) | - ((ysync & 0x00f) << 0)); - desc[11] = (((xfront & 0x300) >> 2) | - ((xsync & 0x300) >> 4) | - ((yfront & 0x030) >> 2) | - ((ysync & 0x030) >> 4)); + desc[10] = (((timings.yfront & 0x00f) << 4) | + ((timings.ysync & 0x00f) << 0)); + desc[11] = (((timings.xfront & 0x300) >> 2) | + ((timings.xsync & 0x300) >> 4) | + ((timings.yfront & 0x030) >> 2) | + ((timings.ysync & 0x030) >> 4)); desc[12] = xmm & 0xff; desc[13] = ymm & 0xff; @@ -297,14 +336,61 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res) return res * 254 / 10 / dpi; } +static void init_displayid(uint8_t *did) +{ + did[0] = 0x70; /* display id extension */ + did[1] = 0x13; /* version 1.3 */ + did[2] = 4; /* length */ + did[3] = 0x03; /* product type (0x03 == standalone display device) */ + edid_checksum(did + 1, did[2] + 4); +} + +static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate, + uint32_t xres, uint32_t yres, + uint32_t xmm, uint32_t ymm) +{ + Timings timings; + generate_timings(&timings, refresh_rate, xres, yres); + + did[0] = 0x70; /* display id extension */ + did[1] = 0x13; /* version 1.3 */ + did[2] = 23; /* length */ + did[3] = 0x03; /* product type (0x03 == standalone display device) */ + + did[5] = 0x03; /* Detailed Timings Data Block */ + did[6] = 0x00; /* revision */ + did[7] = 0x14; /* block length */ + + did[8] = timings.clock & 0xff; + did[9] = (timings.clock & 0xff00) >> 8; + did[10] = (timings.clock & 0xff0000) >> 16; + + did[11] = 0x88; /* leave aspect ratio undefined */ + + stw_le_p(did + 12, 0xffff & (xres - 1)); + stw_le_p(did + 14, 0xffff & (timings.xblank - 1)); + stw_le_p(did + 16, 0xffff & (timings.xfront - 1)); + stw_le_p(did + 18, 0xffff & (timings.xsync - 1)); + + stw_le_p(did + 20, 0xffff & (yres - 1)); + stw_le_p(did + 22, 0xffff & (timings.yblank - 1)); + stw_le_p(did + 24, 0xffff & (timings.yfront - 1)); + stw_le_p(did + 26, 0xffff & (timings.ysync - 1)); + + edid_checksum(did + 1, did[2] + 4); +} + void qemu_edid_generate(uint8_t *edid, size_t size, qemu_edid_info *info) { - uint32_t desc = 54; + uint8_t *desc = edid + 54; uint8_t *xtra3 = NULL; uint8_t *dta = NULL; + uint8_t *did = NULL; uint32_t width_mm, height_mm; + uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000; uint32_t dpi = 100; /* if no width_mm/height_mm */ + uint32_t large_screen = 0; /* =============== set defaults =============== */ @@ -320,6 +406,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size, if (!info->prefy) { info->prefy = 768; } + if (info->prefx >= 4096 || info->prefy >= 4096) { + large_screen = 1; + } if (info->width_mm && info->height_mm) { width_mm = info->width_mm; height_mm = info->height_mm; @@ -337,6 +426,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size, edid_ext_dta(dta); } + if (size >= 384 && large_screen) { + did = edid + 256; + edid[126]++; + init_displayid(did); + } + /* =============== header information =============== */ /* fixed */ @@ -401,40 +496,55 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== descriptor blocks =============== */ - edid_desc_timing(edid + desc, info->prefx, info->prefy, - width_mm, height_mm); - desc += 18; + if (!large_screen) { + /* The DTD section has only 12 bits to store the resolution */ + edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy, + width_mm, height_mm); + desc = edid_desc_next(edid, dta, desc); + } - edid_desc_ranges(edid + desc); - desc += 18; + xtra3 = desc; + edid_desc_xtra3_std(xtra3); + desc = edid_desc_next(edid, dta, desc); + edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); + /* + * dta video data block is finished at thus point, + * so dta descriptor offsets don't move any more. + */ + + edid_desc_ranges(desc); + desc = edid_desc_next(edid, dta, desc); - if (info->name) { - edid_desc_text(edid + desc, 0xfc, info->name); - desc += 18; + if (desc && info->name) { + edid_desc_text(desc, 0xfc, info->name); + desc = edid_desc_next(edid, dta, desc); } - if (info->serial) { - edid_desc_text(edid + desc, 0xff, info->serial); - desc += 18; + if (desc && info->serial) { + edid_desc_text(desc, 0xff, info->serial); + desc = edid_desc_next(edid, dta, desc); } - if (desc < 126) { - xtra3 = edid + desc; - edid_desc_xtra3_std(xtra3); - desc += 18; + while (desc) { + edid_desc_dummy(desc); + desc = edid_desc_next(edid, dta, desc); } - while (desc < 126) { - edid_desc_dummy(edid + desc); - desc += 18; + /* =============== display id extensions =============== */ + + if (did && large_screen) { + qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy, + width_mm, height_mm); } /* =============== finish up =============== */ - edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); - edid_checksum(edid); + edid_checksum(edid, 127); if (dta) { - edid_checksum(dta); + edid_checksum(dta, 127); + } + if (did) { + edid_checksum(did, 127); } } diff --git a/hw/display/meson.build b/hw/display/meson.build index 9d79e3951d..aaf797c5e9 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -48,7 +48,6 @@ endif softmmu_ss.add(when: 'CONFIG_DPCD', if_true: files('dpcd.c')) softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dp.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-vgafb.c')) softmmu_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c')) softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d.c', 'ati_dbg.c')) @@ -56,11 +55,14 @@ softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss = ss.source_set() virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU', - if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl]) - virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'], - if_true: [files('virtio-gpu-3d.c'), pixman, virgl]) + if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman]) virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c')) hw_display_modules += {'virtio-gpu': virtio_gpu_ss} + + virtio_gpu_gl_ss = ss.source_set() + virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL', opengl], + if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) + hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss} endif if config_all_devices.has_key('CONFIG_VIRTIO_PCI') @@ -70,6 +72,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI') virtio_gpu_pci_ss.add(when: ['CONFIG_VHOST_USER_GPU', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-gpu-pci.c')) hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss} + + virtio_gpu_pci_gl_ss = ss.source_set() + virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', 'CONFIG_VIRGL', opengl], + if_true: [files('virtio-gpu-pci-gl.c'), pixman]) + hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss} endif if config_all_devices.has_key('CONFIG_VIRTIO_VGA') @@ -79,9 +86,13 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA') virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA', if_true: files('vhost-user-vga.c')) hw_display_modules += {'virtio-vga': virtio_vga_ss} + + virtio_vga_gl_ss = ss.source_set() + virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', 'CONFIG_VIRGL', opengl], + if_true: [files('virtio-vga-gl.c'), pixman]) + hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} endif -specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c')) specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c')) modules += { 'hw-display': hw_display_modules } diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c deleted file mode 100644 index 02a28c807b..0000000000 --- a/hw/display/milkymist-tmu2.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * QEMU model of the Milkymist texture mapping unit. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * Copyright (c) 2010 Sebastien Bourdeauducq - * <sebastien.bourdeauducq@lekernel.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/tmu2.pdf - * - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qapi/error.h" -#include "hw/display/milkymist_tmu2.h" - -#include <X11/Xlib.h> -#include <epoxy/gl.h> -#include <epoxy/glx.h> -#include "qom/object.h" - -enum { - R_CTL = 0, - R_HMESHLAST, - R_VMESHLAST, - R_BRIGHTNESS, - R_CHROMAKEY, - R_VERTICESADDR, - R_TEXFBUF, - R_TEXHRES, - R_TEXVRES, - R_TEXHMASK, - R_TEXVMASK, - R_DSTFBUF, - R_DSTHRES, - R_DSTVRES, - R_DSTHOFFSET, - R_DSTVOFFSET, - R_DSTSQUAREW, - R_DSTSQUAREH, - R_ALPHA, - R_MAX -}; - -enum { - CTL_START_BUSY = (1<<0), - CTL_CHROMAKEY = (1<<1), -}; - -enum { - MAX_BRIGHTNESS = 63, - MAX_ALPHA = 63, -}; - -enum { - MESH_MAXSIZE = 128, -}; - -struct vertex { - int x; - int y; -} QEMU_PACKED; - -#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistTMU2State, MILKYMIST_TMU2) - -struct MilkymistTMU2State { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - Chardev *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; - - Display *dpy; - GLXFBConfig glx_fb_config; - GLXContext glx_context; -}; - -static const int glx_fbconfig_attr[] = { - GLX_GREEN_SIZE, 5, - GLX_GREEN_SIZE, 6, - GLX_BLUE_SIZE, 5, - None -}; - -static int tmu2_glx_init(MilkymistTMU2State *s) -{ - GLXFBConfig *configs; - int nelements; - - s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */ - if (s->dpy == NULL) { - return 1; - } - - configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements); - if (configs == NULL) { - return 1; - } - - s->glx_fb_config = *configs; - XFree(configs); - - /* FIXME: call glXDestroyContext() */ - s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config, - GLX_RGBA_TYPE, NULL, 1); - if (s->glx_context == NULL) { - return 1; - } - - return 0; -} - -static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres, - int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh) -{ - int x, y; - int x0, y0, x1, y1; - int u0, v0, u1, v1, u2, v2, u3, v3; - double xscale = 1.0 / ((double)(64 * texhres)); - double yscale = 1.0 / ((double)(64 * texvres)); - - glLoadIdentity(); - glTranslatef(ho, vo, 0); - glEnable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - - for (y = 0; y < vmeshlast; y++) { - y0 = y * sh; - y1 = y0 + sh; - for (x = 0; x < hmeshlast; x++) { - x0 = x * sw; - x1 = x0 + sw; - - u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x); - v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y); - u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x); - v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y); - u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x); - v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y); - u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x); - v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y); - - glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale); - glVertex3i(x0, y0, 0); - glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale); - glVertex3i(x1, y0, 0); - glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale); - glVertex3i(x1, y1, 0); - glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale); - glVertex3i(x0, y1, 0); - } - } - - glEnd(); -} - -static void tmu2_start(MilkymistTMU2State *s) -{ - int pbuffer_attrib[6] = { - GLX_PBUFFER_WIDTH, - 0, - GLX_PBUFFER_HEIGHT, - 0, - GLX_PRESERVED_CONTENTS, - True - }; - - GLXPbuffer pbuffer; - GLuint texture; - void *fb; - hwaddr fb_len; - void *mesh; - hwaddr mesh_len; - float m; - - trace_milkymist_tmu2_start(); - - /* Create and set up a suitable OpenGL context */ - pbuffer_attrib[1] = s->regs[R_DSTHRES]; - pbuffer_attrib[3] = s->regs[R_DSTVRES]; - pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib); - glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context); - - /* Fixup endianness. TODO: would it work on BE hosts? */ - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - glPixelStorei(GL_PACK_SWAP_BYTES, 1); - - /* Row alignment */ - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); - glPixelStorei(GL_PACK_ALIGNMENT, 2); - - /* Read the QEMU source framebuffer into an OpenGL texture */ - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - fb_len = 2ULL * s->regs[R_TEXHRES] * s->regs[R_TEXVRES]; - fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, false); - if (fb == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES], - 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb); - cpu_physical_memory_unmap(fb, fb_len, 0, fb_len); - - /* Set up texturing options */ - /* WARNING: - * Many cases of TMU2 masking are not supported by OpenGL. - * We only implement the most common ones: - * - full bilinear filtering vs. nearest texel - * - texture clamping vs. texture wrapping - */ - if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - } - if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - /* Translucency and decay */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f; - glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f); - - /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */ - fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; - fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, false); - if (fb == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - - glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB, - GL_UNSIGNED_SHORT_5_6_5, fb); - cpu_physical_memory_unmap(fb, fb_len, 0, fb_len); - glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - - /* Map the texture */ - mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex); - mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, false); - if (mesh == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - - tmu2_gl_map((struct vertex *)mesh, - s->regs[R_TEXHRES], s->regs[R_TEXVRES], - s->regs[R_HMESHLAST], s->regs[R_VMESHLAST], - s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET], - s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]); - cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len); - - /* Write back the OpenGL framebuffer to the QEMU framebuffer */ - fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; - fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, true); - if (fb == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - - glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB, - GL_UNSIGNED_SHORT_5_6_5, fb); - cpu_physical_memory_unmap(fb, fb_len, 1, fb_len); - - /* Free OpenGL allocs */ - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - - s->regs[R_CTL] &= ~CTL_START_BUSY; - - trace_milkymist_tmu2_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static uint64_t tmu2_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistTMU2State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTL: - case R_HMESHLAST: - case R_VMESHLAST: - case R_BRIGHTNESS: - case R_CHROMAKEY: - case R_VERTICESADDR: - case R_TEXFBUF: - case R_TEXHRES: - case R_TEXVRES: - case R_TEXHMASK: - case R_TEXVMASK: - case R_DSTFBUF: - case R_DSTHRES: - case R_DSTVRES: - case R_DSTHOFFSET: - case R_DSTVOFFSET: - case R_DSTSQUAREW: - case R_DSTSQUAREH: - case R_ALPHA: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_tmu2: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_tmu2_memory_read(addr << 2, r); - - return r; -} - -static void tmu2_check_registers(MilkymistTMU2State *s) -{ - if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) { - error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS); - } - - if (s->regs[R_ALPHA] > MAX_ALPHA) { - error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA); - } - - if (s->regs[R_VERTICESADDR] & 0x07) { - error_report("milkymist_tmu2: vertex mesh address has to be 64-bit " - "aligned"); - } - - if (s->regs[R_TEXFBUF] & 0x01) { - error_report("milkymist_tmu2: texture buffer address has to be " - "16-bit aligned"); - } -} - -static void tmu2_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistTMU2State *s = opaque; - - trace_milkymist_tmu2_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTL: - s->regs[addr] = value; - if (value & CTL_START_BUSY) { - tmu2_start(s); - } - break; - case R_BRIGHTNESS: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CHROMAKEY: - case R_VERTICESADDR: - case R_TEXFBUF: - case R_TEXHRES: - case R_TEXVRES: - case R_TEXHMASK: - case R_TEXVMASK: - case R_DSTFBUF: - case R_DSTHRES: - case R_DSTVRES: - case R_DSTHOFFSET: - case R_DSTVOFFSET: - case R_DSTSQUAREW: - case R_DSTSQUAREH: - case R_ALPHA: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_tmu2: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - tmu2_check_registers(s); -} - -static const MemoryRegionOps tmu2_mmio_ops = { - .read = tmu2_read, - .write = tmu2_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_tmu2_reset(DeviceState *d) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } -} - -static void milkymist_tmu2_init(Object *obj) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->regs_region, obj, &tmu2_mmio_ops, s, - "milkymist-tmu2", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_tmu2_realize(DeviceState *dev, Error **errp) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(dev); - - if (tmu2_glx_init(s)) { - error_setg(errp, "tmu2_glx_init failed"); - } -} - -static const VMStateDescription vmstate_milkymist_tmu2 = { - .name = "milkymist-tmu2", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_tmu2_realize; - dc->reset = milkymist_tmu2_reset; - dc->vmsd = &vmstate_milkymist_tmu2; -} - -static const TypeInfo milkymist_tmu2_info = { - .name = TYPE_MILKYMIST_TMU2, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistTMU2State), - .instance_init = milkymist_tmu2_init, - .class_init = milkymist_tmu2_class_init, -}; - -static void milkymist_tmu2_register_types(void) -{ - type_register_static(&milkymist_tmu2_info); -} - -type_init(milkymist_tmu2_register_types) - -DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq) -{ - DeviceState *dev; - Display *d; - GLXFBConfig *configs; - int nelements; - int ver_major, ver_minor; - - /* check that GLX will work */ - d = XOpenDisplay(NULL); - if (d == NULL) { - return NULL; - } - - if (!glXQueryVersion(d, &ver_major, &ver_minor)) { - /* - * Yeah, sometimes getting the GLX version can fail. - * Isn't X beautiful? - */ - XCloseDisplay(d); - return NULL; - } - - if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) { - printf("Your GLX version is %d.%d," - "but TMU emulation needs at least 1.3. TMU disabled.\n", - ver_major, ver_minor); - XCloseDisplay(d); - return NULL; - } - - configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements); - if (configs == NULL) { - XCloseDisplay(d); - return NULL; - } - - XFree(configs); - XCloseDisplay(d); - - dev = qdev_new(TYPE_MILKYMIST_TMU2); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; -} diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c deleted file mode 100644 index e2c587e2df..0000000000 --- a/hw/display/milkymist-vgafb.c +++ /dev/null @@ -1,360 +0,0 @@ - -/* - * QEMU model of the Milkymist VGA framebuffer. - * - * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/vgafb.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/qdev-properties.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "ui/console.h" -#include "framebuffer.h" -#include "ui/pixel_ops.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -#define BITS 8 -#include "migration/vmstate.h" -#include "milkymist-vgafb_template.h" -#define BITS 15 -#include "milkymist-vgafb_template.h" -#define BITS 16 -#include "milkymist-vgafb_template.h" -#define BITS 24 -#include "milkymist-vgafb_template.h" -#define BITS 32 -#include "milkymist-vgafb_template.h" - -enum { - R_CTRL = 0, - R_HRES, - R_HSYNC_START, - R_HSYNC_END, - R_HSCAN, - R_VRES, - R_VSYNC_START, - R_VSYNC_END, - R_VSCAN, - R_BASEADDRESS, - R_BASEADDRESS_ACT, - R_BURST_COUNT, - R_DDC, - R_SOURCE_CLOCK, - R_MAX -}; - -enum { - CTRL_RESET = (1<<0), -}; - -#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistVgafbState, MILKYMIST_VGAFB) - -struct MilkymistVgafbState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - MemoryRegionSection fbsection; - QemuConsole *con; - - int invalidate; - uint32_t fb_offset; - uint32_t fb_mask; - - uint32_t regs[R_MAX]; -}; - -static int vgafb_enabled(MilkymistVgafbState *s) -{ - return !(s->regs[R_CTRL] & CTRL_RESET); -} - -static void vgafb_update_display(void *opaque) -{ - MilkymistVgafbState *s = opaque; - SysBusDevice *sbd; - DisplaySurface *surface = qemu_console_surface(s->con); - int src_width; - int first = 0; - int last = 0; - drawfn fn; - - if (!vgafb_enabled(s)) { - return; - } - - sbd = SYS_BUS_DEVICE(s); - int dest_width = s->regs[R_HRES]; - - switch (surface_bits_per_pixel(surface)) { - case 0: - return; - case 8: - fn = draw_line_8; - break; - case 15: - fn = draw_line_15; - dest_width *= 2; - break; - case 16: - fn = draw_line_16; - dest_width *= 2; - break; - case 24: - fn = draw_line_24; - dest_width *= 3; - break; - case 32: - fn = draw_line_32; - dest_width *= 4; - break; - default: - hw_error("milkymist_vgafb: bad color depth\n"); - break; - } - - src_width = s->regs[R_HRES] * 2; - if (s->invalidate) { - framebuffer_update_memory_section(&s->fbsection, - sysbus_address_space(sbd), - s->regs[R_BASEADDRESS] + s->fb_offset, - s->regs[R_VRES], src_width); - } - - framebuffer_update_display(surface, &s->fbsection, - s->regs[R_HRES], - s->regs[R_VRES], - src_width, - dest_width, - 0, - s->invalidate, - fn, - NULL, - &first, &last); - - if (first >= 0) { - dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1); - } - s->invalidate = 0; -} - -static void vgafb_invalidate_display(void *opaque) -{ - MilkymistVgafbState *s = opaque; - s->invalidate = 1; -} - -static void vgafb_resize(MilkymistVgafbState *s) -{ - if (!vgafb_enabled(s)) { - return; - } - - qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]); - s->invalidate = 1; -} - -static uint64_t vgafb_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistVgafbState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTRL: - case R_HRES: - case R_HSYNC_START: - case R_HSYNC_END: - case R_HSCAN: - case R_VRES: - case R_VSYNC_START: - case R_VSYNC_END: - case R_VSCAN: - case R_BASEADDRESS: - case R_BURST_COUNT: - case R_DDC: - case R_SOURCE_CLOCK: - r = s->regs[addr]; - break; - case R_BASEADDRESS_ACT: - r = s->regs[R_BASEADDRESS]; - break; - - default: - error_report("milkymist_vgafb: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_vgafb_memory_read(addr << 2, r); - - return r; -} - -static void vgafb_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistVgafbState *s = opaque; - - trace_milkymist_vgafb_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - s->regs[addr] = value; - vgafb_resize(s); - break; - case R_HSYNC_START: - case R_HSYNC_END: - case R_HSCAN: - case R_VSYNC_START: - case R_VSYNC_END: - case R_VSCAN: - case R_BURST_COUNT: - case R_DDC: - case R_SOURCE_CLOCK: - s->regs[addr] = value; - break; - case R_BASEADDRESS: - if (value & 0x1f) { - error_report("milkymist_vgafb: framebuffer base address have to " - "be 32 byte aligned"); - break; - } - s->regs[addr] = value & s->fb_mask; - s->invalidate = 1; - break; - case R_HRES: - case R_VRES: - s->regs[addr] = value; - vgafb_resize(s); - break; - case R_BASEADDRESS_ACT: - error_report("milkymist_vgafb: write to read-only register 0x" - TARGET_FMT_plx, addr << 2); - break; - - default: - error_report("milkymist_vgafb: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps vgafb_mmio_ops = { - .read = vgafb_read, - .write = vgafb_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_vgafb_reset(DeviceState *d) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_CTRL] = CTRL_RESET; - s->regs[R_HRES] = 640; - s->regs[R_VRES] = 480; - s->regs[R_BASEADDRESS] = 0; -} - -static const GraphicHwOps vgafb_ops = { - .invalidate = vgafb_invalidate_display, - .gfx_update = vgafb_update_display, -}; - -static void milkymist_vgafb_init(Object *obj) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s, - "milkymist-vgafb", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_vgafb_realize(DeviceState *dev, Error **errp) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(dev); - - s->con = graphic_console_init(dev, 0, &vgafb_ops, s); -} - -static int vgafb_post_load(void *opaque, int version_id) -{ - vgafb_invalidate_display(opaque); - return 0; -} - -static const VMStateDescription vmstate_milkymist_vgafb = { - .name = "milkymist-vgafb", - .version_id = 1, - .minimum_version_id = 1, - .post_load = vgafb_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_vgafb_properties[] = { - DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0), - DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = milkymist_vgafb_reset; - dc->vmsd = &vmstate_milkymist_vgafb; - device_class_set_props(dc, milkymist_vgafb_properties); - dc->realize = milkymist_vgafb_realize; -} - -static const TypeInfo milkymist_vgafb_info = { - .name = TYPE_MILKYMIST_VGAFB, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistVgafbState), - .instance_init = milkymist_vgafb_init, - .class_init = milkymist_vgafb_class_init, -}; - -static void milkymist_vgafb_register_types(void) -{ - type_register_static(&milkymist_vgafb_info); -} - -type_init(milkymist_vgafb_register_types) diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h deleted file mode 100644 index 96137f9709..0000000000 --- a/hw/display/milkymist-vgafb_template.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * QEMU model of the Milkymist VGA framebuffer. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - */ - -#if BITS == 8 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *to = rgb_to_pixel8(r, g, b); \ - to += 1; \ - } while (0) -#elif BITS == 15 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *(uint16_t *)to = rgb_to_pixel15(r, g, b); \ - to += 2; \ - } while (0) -#elif BITS == 16 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *(uint16_t *)to = rgb_to_pixel16(r, g, b); \ - to += 2; \ - } while (0) -#elif BITS == 24 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - uint32_t tmp = rgb_to_pixel24(r, g, b); \ - *(to++) = tmp & 0xff; \ - *(to++) = (tmp >> 8) & 0xff; \ - *(to++) = (tmp >> 16) & 0xff; \ - } while (0) -#elif BITS == 32 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *(uint32_t *)to = rgb_to_pixel32(r, g, b); \ - to += 4; \ - } while (0) -#else -#error unknown bit depth -#endif - -static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s, - int width, int deststep) -{ - uint16_t rgb565; - uint8_t r, g, b; - - while (width--) { - rgb565 = lduw_be_p(s); - r = ((rgb565 >> 11) & 0x1f) << 3; - g = ((rgb565 >> 5) & 0x3f) << 2; - b = ((rgb565 >> 0) & 0x1f) << 3; - COPY_PIXEL(d, r, g, b); - s += 2; - } -} - -#undef BITS -#undef COPY_PIXEL diff --git a/hw/display/trace-events b/hw/display/trace-events index 957b8ba994..9fccca18a1 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -13,16 +13,6 @@ xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d" g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x" g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x" -# milkymist-tmu2.c -milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_tmu2_start(void) "Start TMU" -milkymist_tmu2_pulse_irq(void) "Pulse IRQ" - -# milkymist-vgafb.c -milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" - # vmware_vga.c vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x" vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x" diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 48d29630ab..62fb5c38c1 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -49,7 +49,7 @@ struct PCIVGAState { qemu_edid_info edid_info; MemoryRegion mmio; MemoryRegion mrs[4]; - uint8_t edid[256]; + uint8_t edid[384]; }; #define TYPE_PCI_VGA "pci-vga" diff --git a/hw/display/vga.c b/hw/display/vga.c index 836ad50c7b..28a90e30d0 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -39,6 +39,8 @@ //#define DEBUG_VGA_MEM //#define DEBUG_VGA_REG +bool have_vga = true; + /* 16 state changes per vertical frame @60 Hz */ #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 25f8920fdb..afb3ee7d9a 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -25,7 +25,6 @@ virtio_gpu_base_reset(VirtIOGPUBase *g) int i; g->enable = 0; - g->use_virgl_renderer = false; for (i = 0; i < g->conf.max_outputs; i++) { g->scanout[i].resource_id = 0; @@ -162,7 +161,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev, return false; } - g->use_virgl_renderer = false; if (virtio_gpu_virgl_enabled(g->conf)) { error_setg(&g->migration_blocker, "virgl is not yet migratable"); if (migrate_add_blocker(g->migration_blocker, errp) < 0) { @@ -218,10 +216,8 @@ static void virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) { static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); - VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); - g->use_virgl_renderer = ((features & virgl) == virgl); - trace_virtio_gpu_features(g->use_virgl_renderer); + trace_virtio_gpu_features(((features & virgl) == virgl)); } static void diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c new file mode 100644 index 0000000000..d971b48080 --- /dev/null +++ b/hw/display/virtio-gpu-gl.c @@ -0,0 +1,163 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/iov.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" +#include "hw/qdev-properties.h" + +#include <virglrenderer.h> + +static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id) +{ + uint32_t width, height; + uint32_t pixels, *data; + + data = virgl_renderer_get_cursor_data(resource_id, &width, &height); + if (!data) { + return; + } + + if (width != s->current_cursor->width || + height != s->current_cursor->height) { + free(data); + return; + } + + pixels = s->current_cursor->width * s->current_cursor->height; + memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); + free(data); +} + +static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) +{ + VirtIOGPU *g = VIRTIO_GPU(b); + VirtIOGPUGL *gl = VIRTIO_GPU_GL(b); + + if (gl->renderer_reset) { + gl->renderer_reset = false; + virtio_gpu_virgl_reset(g); + } + virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev); + struct virtio_gpu_ctrl_command *cmd; + + if (!virtio_queue_ready(vq)) { + return; + } + + if (!gl->renderer_inited) { + virtio_gpu_virgl_init(g); + gl->renderer_inited = true; + } + + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + while (cmd) { + cmd->vq = vq; + cmd->error = 0; + cmd->finished = false; + QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + } + + virtio_gpu_process_cmdq(g); + virtio_gpu_virgl_fence_poll(g); +} + +static void virtio_gpu_gl_reset(VirtIODevice *vdev) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev); + + virtio_gpu_reset(vdev); + + if (gl->renderer_inited) { + if (g->parent_obj.renderer_blocked) { + gl->renderer_reset = true; + } else { + virtio_gpu_virgl_reset(g); + } + } +} + +static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) +{ + VirtIOGPU *g = VIRTIO_GPU(qdev); + +#if defined(HOST_WORDS_BIGENDIAN) + error_setg(errp, "virgl is not supported on bigendian platforms"); + return; +#endif + + if (!display_opengl) { + error_setg(errp, "opengl is not available"); + return; + } + + g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); + VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = + virtio_gpu_virgl_get_num_capsets(g); + + virtio_gpu_device_realize(qdev, errp); +} + +static Property virtio_gpu_gl_properties[] = { + DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, + VIRTIO_GPU_FLAG_STATS_ENABLED, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass); + VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + + vbc->gl_flushed = virtio_gpu_gl_flushed; + vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl; + vgc->process_cmd = virtio_gpu_virgl_process_cmd; + vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; + + vdc->realize = virtio_gpu_gl_device_realize; + vdc->reset = virtio_gpu_gl_reset; + device_class_set_props(dc, virtio_gpu_gl_properties); +} + +static const TypeInfo virtio_gpu_gl_info = { + .name = TYPE_VIRTIO_GPU_GL, + .parent = TYPE_VIRTIO_GPU, + .instance_size = sizeof(VirtIOGPUGL), + .class_init = virtio_gpu_gl_class_init, +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_gpu_gl_info); +} + +type_init(virtio_register_types) diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c new file mode 100644 index 0000000000..902dda3452 --- /dev/null +++ b/hw/display/virtio-gpu-pci-gl.c @@ -0,0 +1,55 @@ +/* + * Virtio video device + * + * Copyright Red Hat + * + * Authors: + * Dave Airlie + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-gpu-pci.h" +#include "qom/object.h" + +#define TYPE_VIRTIO_GPU_GL_PCI "virtio-gpu-gl-pci" +typedef struct VirtIOGPUGLPCI VirtIOGPUGLPCI; +DECLARE_INSTANCE_CHECKER(VirtIOGPUGLPCI, VIRTIO_GPU_GL_PCI, + TYPE_VIRTIO_GPU_GL_PCI) + +struct VirtIOGPUGLPCI { + VirtIOGPUPCIBase parent_obj; + VirtIOGPUGL vdev; +}; + +static void virtio_gpu_gl_initfn(Object *obj) +{ + VirtIOGPUGLPCI *dev = VIRTIO_GPU_GL_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU_GL); + VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); +} + +static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = { + .generic_name = TYPE_VIRTIO_GPU_GL_PCI, + .parent = TYPE_VIRTIO_GPU_PCI_BASE, + .instance_size = sizeof(VirtIOGPUGLPCI), + .instance_init = virtio_gpu_gl_initfn, +}; + +static void virtio_gpu_gl_pci_register_types(void) +{ + virtio_pci_types_register(&virtio_gpu_gl_pci_info); +} + +type_init(virtio_gpu_gl_pci_register_types) diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-virgl.c index d98964858e..72c14d9132 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-virgl.c @@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g, { struct virtio_gpu_resource_attach_backing att_rb; struct iovec *res_iovs; + uint32_t res_niov; int ret; VIRTIO_GPU_FILL_CMD(att_rb); trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id); - ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs); + ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, &res_niov); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; } ret = virgl_renderer_resource_attach_iov(att_rb.resource_id, - res_iovs, att_rb.nr_entries); + res_iovs, res_niov); if (ret != 0) - virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries); + virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov); } static void virgl_resource_detach_backing(VirtIOGPU *g, diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index c9f5e36fd0..db56f0454a 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -39,26 +39,9 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); static void virtio_gpu_cleanup_mapping(VirtIOGPU *g, struct virtio_gpu_simple_resource *res); -#ifdef CONFIG_VIRGL -#include <virglrenderer.h> -#define VIRGL(_g, _virgl, _simple, ...) \ - do { \ - if (_g->parent_obj.use_virgl_renderer) { \ - _virgl(__VA_ARGS__); \ - } else { \ - _simple(__VA_ARGS__); \ - } \ - } while (0) -#else -#define VIRGL(_g, _virgl, _simple, ...) \ - do { \ - _simple(__VA_ARGS__); \ - } while (0) -#endif - -static void update_cursor_data_simple(VirtIOGPU *g, - struct virtio_gpu_scanout *s, - uint32_t resource_id) +void virtio_gpu_update_cursor_data(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id) { struct virtio_gpu_simple_resource *res; uint32_t pixels; @@ -79,36 +62,10 @@ static void update_cursor_data_simple(VirtIOGPU *g, pixels * sizeof(uint32_t)); } -#ifdef CONFIG_VIRGL - -static void update_cursor_data_virgl(VirtIOGPU *g, - struct virtio_gpu_scanout *s, - uint32_t resource_id) -{ - uint32_t width, height; - uint32_t pixels, *data; - - data = virgl_renderer_get_cursor_data(resource_id, &width, &height); - if (!data) { - return; - } - - if (width != s->current_cursor->width || - height != s->current_cursor->height) { - free(data); - return; - } - - pixels = s->current_cursor->width * s->current_cursor->height; - memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); - free(data); -} - -#endif - static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) { struct virtio_gpu_scanout *s; + VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR; if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) { @@ -131,8 +88,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) s->current_cursor->hot_y = cursor->hot_y; if (cursor->resource_id > 0) { - VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple, - g, s, cursor->resource_id); + vgc->update_cursor_data(g, s, cursor->resource_id); } dpy_cursor_define(s->con, s->current_cursor); @@ -608,11 +564,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, int virtio_gpu_create_mapping_iov(VirtIOGPU *g, struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_ctrl_command *cmd, - uint64_t **addr, struct iovec **iov) + uint64_t **addr, struct iovec **iov, + uint32_t *niov) { struct virtio_gpu_mem_entry *ents; size_t esize, s; - int i; + int e, v; if (ab->nr_entries > 16384) { qemu_log_mask(LOG_GUEST_ERROR, @@ -633,37 +590,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, return -1; } - *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); + *iov = NULL; if (addr) { - *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); + *addr = NULL; } - for (i = 0; i < ab->nr_entries; i++) { - uint64_t a = le64_to_cpu(ents[i].addr); - uint32_t l = le32_to_cpu(ents[i].length); - hwaddr len = l; - (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, - a, &len, DMA_DIRECTION_TO_DEVICE); - (*iov)[i].iov_len = len; - if (addr) { - (*addr)[i] = a; - } - if (!(*iov)[i].iov_base || len != l) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" - " resource %d element %d\n", - __func__, ab->resource_id, i); - if ((*iov)[i].iov_base) { - i++; /* cleanup the 'i'th map */ + for (e = 0, v = 0; e < ab->nr_entries; e++) { + uint64_t a = le64_to_cpu(ents[e].addr); + uint32_t l = le32_to_cpu(ents[e].length); + hwaddr len; + void *map; + + do { + len = l; + map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, + a, &len, DMA_DIRECTION_TO_DEVICE); + if (!map) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" + " resource %d element %d\n", + __func__, ab->resource_id, e); + virtio_gpu_cleanup_mapping_iov(g, *iov, v); + g_free(ents); + *iov = NULL; + if (addr) { + g_free(*addr); + *addr = NULL; + } + return -1; } - virtio_gpu_cleanup_mapping_iov(g, *iov, i); - g_free(ents); - *iov = NULL; + + if (!(v % 16)) { + *iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16)); + if (addr) { + *addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16)); + } + } + (*iov)[v].iov_base = map; + (*iov)[v].iov_len = len; if (addr) { - g_free(*addr); - *addr = NULL; + (*addr)[v] = a; } - return -1; - } + + a += len; + l -= len; + v += 1; + } while (l > 0); } + *niov = v; + g_free(ents); return 0; } @@ -717,13 +690,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, return; } - ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov); + ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, + &res->iov, &res->iov_cnt); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; } - - res->iov_cnt = ab.nr_entries; } static void @@ -747,8 +719,8 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g, virtio_gpu_cleanup_mapping(g, res); } -static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, - struct virtio_gpu_ctrl_command *cmd) +void virtio_gpu_simple_process_cmd(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) { VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); @@ -806,6 +778,7 @@ static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq) void virtio_gpu_process_cmdq(VirtIOGPU *g) { struct virtio_gpu_ctrl_command *cmd; + VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); if (g->processing_cmdq) { return; @@ -819,8 +792,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) } /* process command */ - VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, - g, cmd); + vgc->process_cmd(g, cmd); QTAILQ_REMOVE(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { @@ -843,19 +815,6 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) g->processing_cmdq = false; } -static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) -{ - VirtIOGPU *g = VIRTIO_GPU(b); - -#ifdef CONFIG_VIRGL - if (g->renderer_reset) { - g->renderer_reset = false; - virtio_gpu_virgl_reset(g); - } -#endif - virtio_gpu_process_cmdq(g); -} - static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -865,13 +824,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } -#ifdef CONFIG_VIRGL - if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_init(g); - g->renderer_inited = true; - } -#endif - cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); while (cmd) { cmd->vq = vq; @@ -882,18 +834,14 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } virtio_gpu_process_cmdq(g); - -#ifdef CONFIG_VIRGL - if (g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_fence_poll(g); - } -#endif } static void virtio_gpu_ctrl_bh(void *opaque) { VirtIOGPU *g = opaque; - virtio_gpu_handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); + VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); + + vgc->handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); } static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) @@ -1105,25 +1053,10 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return 0; } -static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) +void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(qdev); VirtIOGPU *g = VIRTIO_GPU(qdev); - bool have_virgl; - -#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) - have_virgl = false; -#else - have_virgl = display_opengl; -#endif - if (!have_virgl) { - g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); - } else { -#if defined(CONFIG_VIRGL) - VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = - virtio_gpu_virgl_get_num_capsets(g); -#endif - } if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, @@ -1141,18 +1074,12 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) QTAILQ_INIT(&g->fenceq); } -static void virtio_gpu_reset(VirtIODevice *vdev) +void virtio_gpu_reset(VirtIODevice *vdev) { VirtIOGPU *g = VIRTIO_GPU(vdev); struct virtio_gpu_simple_resource *res, *tmp; struct virtio_gpu_ctrl_command *cmd; -#ifdef CONFIG_VIRGL - if (g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_reset(g); - } -#endif - QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { virtio_gpu_resource_destroy(g, res); } @@ -1170,17 +1097,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev) g_free(cmd); } -#ifdef CONFIG_VIRGL - if (g->parent_obj.use_virgl_renderer) { - if (g->parent_obj.renderer_blocked) { - g->renderer_reset = true; - } else { - virtio_gpu_virgl_reset(g); - } - g->parent_obj.use_virgl_renderer = false; - } -#endif - virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev)); } @@ -1235,12 +1151,6 @@ static Property virtio_gpu_properties[] = { VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, 256 * MiB), -#ifdef CONFIG_VIRGL - DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags, - VIRTIO_GPU_FLAG_VIRGL_ENABLED, true), - DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, - VIRTIO_GPU_FLAG_STATS_ENABLED, false), -#endif DEFINE_PROP_END_OF_LIST(), }; @@ -1248,9 +1158,12 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass); + VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + + vgc->handle_ctrl = virtio_gpu_handle_ctrl; + vgc->process_cmd = virtio_gpu_simple_process_cmd; + vgc->update_cursor_data = virtio_gpu_update_cursor_data; - vgc->gl_flushed = virtio_gpu_gl_flushed; vdc->realize = virtio_gpu_device_realize; vdc->reset = virtio_gpu_reset; vdc->get_config = virtio_gpu_get_config; @@ -1264,6 +1177,7 @@ static const TypeInfo virtio_gpu_info = { .name = TYPE_VIRTIO_GPU, .parent = TYPE_VIRTIO_GPU_BASE, .instance_size = sizeof(VirtIOGPU), + .class_size = sizeof(VirtIOGPUClass), .class_init = virtio_gpu_class_init, }; diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c new file mode 100644 index 0000000000..c971340ebb --- /dev/null +++ b/hw/display/virtio-vga-gl.c @@ -0,0 +1,47 @@ +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/display/vga.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "virtio-vga.h" +#include "qom/object.h" + +#define TYPE_VIRTIO_VGA_GL "virtio-vga-gl" + +typedef struct VirtIOVGAGL VirtIOVGAGL; +DECLARE_INSTANCE_CHECKER(VirtIOVGAGL, VIRTIO_VGA_GL, + TYPE_VIRTIO_VGA_GL) + +struct VirtIOVGAGL { + VirtIOVGABase parent_obj; + + VirtIOGPUGL vdev; +}; + +static void virtio_vga_gl_inst_initfn(Object *obj) +{ + VirtIOVGAGL *dev = VIRTIO_VGA_GL(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU_GL); + VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); +} + + +static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = { + .generic_name = TYPE_VIRTIO_VGA_GL, + .parent = TYPE_VIRTIO_VGA_BASE, + .instance_size = sizeof(VirtIOVGAGL), + .instance_init = virtio_vga_gl_inst_initfn, +}; + +static void virtio_vga_register_types(void) +{ + if (have_vga) { + virtio_pci_types_register(&virtio_vga_gl_info); + } +} + +type_init(virtio_vga_register_types) diff --git a/hw/dma/meson.build b/hw/dma/meson.build index 5c78a4e05f..f3f0661bc3 100644 --- a/hw/dma/meson.build +++ b/hw/dma/meson.build @@ -1,4 +1,3 @@ -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_dma.c')) softmmu_ss.add(when: 'CONFIG_RC4030', if_true: files('rc4030.c')) softmmu_ss.add(when: 'CONFIG_PL080', if_true: files('pl080.c')) softmmu_ss.add(when: 'CONFIG_PL330', if_true: files('pl330.c')) diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c deleted file mode 100644 index cca1e9ec21..0000000000 --- a/hw/dma/puv3_dma.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * DMA device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define PUV3_DMA_CH_NR (6) -#define PUV3_DMA_CH_MASK (0xff) -#define PUV3_DMA_CH(offset) ((offset) >> 8) - -#define TYPE_PUV3_DMA "puv3_dma" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3DMAState, PUV3_DMA) - -struct PUV3DMAState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t reg_CFG[PUV3_DMA_CH_NR]; -}; - -static uint64_t puv3_dma_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3DMAState *s = opaque; - uint32_t ret = 0; - - assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR); - - switch (offset & PUV3_DMA_CH_MASK) { - case 0x10: - ret = s->reg_CFG[PUV3_DMA_CH(offset)]; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - - return ret; -} - -static void puv3_dma_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3DMAState *s = opaque; - - assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR); - - switch (offset & PUV3_DMA_CH_MASK) { - case 0x10: - s->reg_CFG[PUV3_DMA_CH(offset)] = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); -} - -static const MemoryRegionOps puv3_dma_ops = { - .read = puv3_dma_read, - .write = puv3_dma_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_dma_realize(DeviceState *dev, Error **errp) -{ - PUV3DMAState *s = PUV3_DMA(dev); - int i; - - for (i = 0; i < PUV3_DMA_CH_NR; i++) { - s->reg_CFG[i] = 0x0; - } - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma", - PUV3_REGS_OFFSET); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); -} - -static void puv3_dma_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_dma_realize; -} - -static const TypeInfo puv3_dma_info = { - .name = TYPE_PUV3_DMA, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3DMAState), - .class_init = puv3_dma_class_init, -}; - -static void puv3_dma_register_type(void) -{ - type_register_static(&puv3_dma_info); -} - -type_init(puv3_dma_register_type) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 985a259e05..34d8acb0e3 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -170,7 +170,7 @@ /* AST2600 only - 1.8V gpios */ /* * The AST2600 has same 3.6V gpios as the AST2400 (memory offsets 0x0-0x198) - * and addtional 1.8V gpios (memory offsets 0x800-0x9D4). + * and additional 1.8V gpios (memory offsets 0x800-0x9D4). */ #define GPIO_1_8V_REG_OFFSET 0x800 #define GPIO_1_8V_ABCD_DATA_VALUE ((0x800 - GPIO_1_8V_REG_OFFSET) >> 2) diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 79568f00ce..7bd6a57264 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -3,7 +3,6 @@ softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c')) softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c')) softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c')) softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c')) diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c deleted file mode 100644 index e003ae505c..0000000000 --- a/hw/gpio/puv3_gpio.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * GPIO device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define TYPE_PUV3_GPIO "puv3_gpio" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3GPIOState, PUV3_GPIO) - -struct PUV3GPIOState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq[9]; - - uint32_t reg_GPLR; - uint32_t reg_GPDR; - uint32_t reg_GPIR; -}; - -static uint64_t puv3_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3GPIOState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x00: - ret = s->reg_GPLR; - break; - case 0x04: - ret = s->reg_GPDR; - break; - case 0x20: - ret = s->reg_GPIR; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - - return ret; -} - -static void puv3_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3GPIOState *s = opaque; - - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); - switch (offset) { - case 0x04: - s->reg_GPDR = value; - break; - case 0x08: - if (s->reg_GPDR & value) { - s->reg_GPLR |= value; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n", - __func__); - } - break; - case 0x0c: - if (s->reg_GPDR & value) { - s->reg_GPLR &= ~value; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n", - __func__); - } - break; - case 0x10: /* GRER */ - case 0x14: /* GFER */ - case 0x18: /* GEDR */ - break; - case 0x20: /* GPIR */ - s->reg_GPIR = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } -} - -static const MemoryRegionOps puv3_gpio_ops = { - .read = puv3_gpio_read, - .write = puv3_gpio_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_gpio_realize(DeviceState *dev, Error **errp) -{ - PUV3GPIOState *s = PUV3_GPIO(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - s->reg_GPLR = 0; - s->reg_GPDR = 0; - - /* FIXME: these irqs not handled yet */ - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW0]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW1]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW2]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW3]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW4]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW5]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW6]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW7]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOHIGH]); - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_gpio_ops, s, "puv3_gpio", - PUV3_REGS_OFFSET); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void puv3_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_gpio_realize; -} - -static const TypeInfo puv3_gpio_info = { - .name = TYPE_PUV3_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3GPIOState), - .class_init = puv3_gpio_class_init, -}; - -static void puv3_gpio_register_type(void) -{ - type_register_static(&puv3_gpio_info); -} - -type_init(puv3_gpio_register_type) diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 09642a6dcb..8d120a25d5 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -28,3 +28,7 @@ config IMX_I2C config MPC_I2C bool select I2C + +config PCA954X + bool + select I2C diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 21ec52ac5a..3a7bae311d 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -77,6 +77,30 @@ int i2c_bus_busy(I2CBus *bus) return !QLIST_EMPTY(&bus->current_devs); } +bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, + I2CNodeList *current_devs) +{ + BusChild *kid; + + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + DeviceState *qdev = kid->child; + I2CSlave *candidate = I2C_SLAVE(qdev); + I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(candidate); + + if (sc->match_and_add(candidate, address, broadcast, current_devs)) { + if (!broadcast) { + return true; + } + } + } + + /* + * If broadcast was true, and the list was full or empty, return true. If + * broadcast was false, return false. + */ + return broadcast; +} + /* TODO: Make this handle multiple masters. */ /* * Start or continue an i2c transaction. When this is called for the @@ -93,7 +117,6 @@ int i2c_bus_busy(I2CBus *bus) */ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) { - BusChild *kid; I2CSlaveClass *sc; I2CNode *node; bool bus_scanned = false; @@ -115,18 +138,8 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) * terminating the previous transaction. */ if (QLIST_EMPTY(&bus->current_devs)) { - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { - DeviceState *qdev = kid->child; - I2CSlave *candidate = I2C_SLAVE(qdev); - if ((candidate->address == address) || (bus->broadcast)) { - node = g_malloc(sizeof(struct I2CNode)); - node->elt = candidate; - QLIST_INSERT_HEAD(&bus->current_devs, node, next); - if (!bus->broadcast) { - break; - } - } - } + /* Disregard whether devices were found. */ + (void)i2c_scan_bus(bus, address, bus->broadcast, &bus->current_devs); bus_scanned = true; } @@ -290,12 +303,28 @@ I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr) return dev; } +static bool i2c_slave_match(I2CSlave *candidate, uint8_t address, + bool broadcast, I2CNodeList *current_devs) +{ + if ((candidate->address == address) || (broadcast)) { + I2CNode *node = g_malloc(sizeof(struct I2CNode)); + node->elt = candidate; + QLIST_INSERT_HEAD(current_devs, node, next); + return true; + } + + /* Not found and not broadcast. */ + return false; +} + static void i2c_slave_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); set_bit(DEVICE_CATEGORY_MISC, k->categories); k->bus_type = TYPE_I2C_BUS; device_class_set_props(k, i2c_props); + sc->match_and_add = i2c_slave_match; } static const TypeInfo i2c_slave_type_info = { diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c new file mode 100644 index 0000000000..847c59921c --- /dev/null +++ b/hw/i2c/i2c_mux_pca954x.c @@ -0,0 +1,290 @@ +/* + * I2C multiplexer for PCA954x series of I2C multiplexer/switch chips. + * + * Copyright 2021 Google LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/i2c_mux_pca954x.h" +#include "hw/i2c/smbus_slave.h" +#include "hw/qdev-core.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/queue.h" +#include "qom/object.h" +#include "trace.h" + +#define PCA9548_CHANNEL_COUNT 8 +#define PCA9546_CHANNEL_COUNT 4 + +/* + * struct Pca954xChannel - The i2c mux device will have N of these states + * that own the i2c channel bus. + * @bus: The owned channel bus. + * @enabled: Is this channel active? + */ +typedef struct Pca954xChannel { + SysBusDevice parent; + + I2CBus *bus; + + bool enabled; +} Pca954xChannel; + +#define TYPE_PCA954X_CHANNEL "pca954x-channel" +#define PCA954X_CHANNEL(obj) \ + OBJECT_CHECK(Pca954xChannel, (obj), TYPE_PCA954X_CHANNEL) + +/* + * struct Pca954xState - The pca954x state object. + * @control: The value written to the mux control. + * @channel: The set of i2c channel buses that act as channels which own the + * i2c children. + */ +typedef struct Pca954xState { + SMBusDevice parent; + + uint8_t control; + + /* The channel i2c buses. */ + Pca954xChannel channel[PCA9548_CHANNEL_COUNT]; +} Pca954xState; + +/* + * struct Pca954xClass - The pca954x class object. + * @nchans: The number of i2c channels this device has. + */ +typedef struct Pca954xClass { + SMBusDeviceClass parent; + + uint8_t nchans; +} Pca954xClass; + +#define TYPE_PCA954X "pca954x" +OBJECT_DECLARE_TYPE(Pca954xState, Pca954xClass, PCA954X) + +/* + * For each channel, if it's enabled, recursively call match on those children. + */ +static bool pca954x_match(I2CSlave *candidate, uint8_t address, + bool broadcast, + I2CNodeList *current_devs) +{ + Pca954xState *mux = PCA954X(candidate); + Pca954xClass *mc = PCA954X_GET_CLASS(mux); + int i; + + /* They are talking to the mux itself (or all devices enabled). */ + if ((candidate->address == address) || broadcast) { + I2CNode *node = g_malloc(sizeof(struct I2CNode)); + node->elt = candidate; + QLIST_INSERT_HEAD(current_devs, node, next); + if (!broadcast) { + return true; + } + } + + for (i = 0; i < mc->nchans; i++) { + if (!mux->channel[i].enabled) { + continue; + } + + if (i2c_scan_bus(mux->channel[i].bus, address, broadcast, + current_devs)) { + if (!broadcast) { + return true; + } + } + } + + /* If we arrived here we didn't find a match, return broadcast. */ + return broadcast; +} + +static void pca954x_enable_channel(Pca954xState *s, uint8_t enable_mask) +{ + Pca954xClass *mc = PCA954X_GET_CLASS(s); + int i; + + /* + * For each channel, check if their bit is set in enable_mask and if yes, + * enable it, otherwise disable, hide it. + */ + for (i = 0; i < mc->nchans; i++) { + if (enable_mask & (1 << i)) { + s->channel[i].enabled = true; + } else { + s->channel[i].enabled = false; + } + } +} + +static void pca954x_write(Pca954xState *s, uint8_t data) +{ + s->control = data; + pca954x_enable_channel(s, data); + + trace_pca954x_write_bytes(data); +} + +static int pca954x_write_data(SMBusDevice *d, uint8_t *buf, uint8_t len) +{ + Pca954xState *s = PCA954X(d); + + if (len == 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); + return -1; + } + + /* + * len should be 1, because they write one byte to enable/disable channels. + */ + if (len > 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: extra data after channel selection mask\n", + __func__); + return -1; + } + + pca954x_write(s, buf[0]); + return 0; +} + +static uint8_t pca954x_read_byte(SMBusDevice *d) +{ + Pca954xState *s = PCA954X(d); + uint8_t data = s->control; + trace_pca954x_read_data(data); + return data; +} + +static void pca954x_enter_reset(Object *obj, ResetType type) +{ + Pca954xState *s = PCA954X(obj); + /* Reset will disable all channels. */ + pca954x_write(s, 0); +} + +I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel) +{ + Pca954xClass *pc = PCA954X_GET_CLASS(mux); + Pca954xState *pca954x = PCA954X(mux); + + g_assert(channel < pc->nchans); + return I2C_BUS(qdev_get_child_bus(DEVICE(&pca954x->channel[channel]), + "i2c-bus")); +} + +static void pca954x_channel_init(Object *obj) +{ + Pca954xChannel *s = PCA954X_CHANNEL(obj); + s->bus = i2c_init_bus(DEVICE(s), "i2c-bus"); + + /* Start all channels as disabled. */ + s->enabled = false; +} + +static void pca954x_channel_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->desc = "Pca954x Channel"; +} + +static void pca9546_class_init(ObjectClass *klass, void *data) +{ + Pca954xClass *s = PCA954X_CLASS(klass); + s->nchans = PCA9546_CHANNEL_COUNT; +} + +static void pca9548_class_init(ObjectClass *klass, void *data) +{ + Pca954xClass *s = PCA954X_CLASS(klass); + s->nchans = PCA9548_CHANNEL_COUNT; +} + +static void pca954x_realize(DeviceState *dev, Error **errp) +{ + Pca954xState *s = PCA954X(dev); + Pca954xClass *c = PCA954X_GET_CLASS(s); + int i; + + /* SMBus modules. Cannot fail. */ + for (i = 0; i < c->nchans; i++) { + sysbus_realize(SYS_BUS_DEVICE(&s->channel[i]), &error_abort); + } +} + +static void pca954x_init(Object *obj) +{ + Pca954xState *s = PCA954X(obj); + Pca954xClass *c = PCA954X_GET_CLASS(obj); + int i; + + /* Only initialize the children we expect. */ + for (i = 0; i < c->nchans; i++) { + object_initialize_child(obj, "channel[*]", &s->channel[i], + TYPE_PCA954X_CHANNEL); + } +} + +static void pca954x_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass); + + sc->match_and_add = pca954x_match; + + rc->phases.enter = pca954x_enter_reset; + + dc->desc = "Pca954x i2c-mux"; + dc->realize = pca954x_realize; + + k->write_data = pca954x_write_data; + k->receive_byte = pca954x_read_byte; +} + +static const TypeInfo pca954x_info[] = { + { + .name = TYPE_PCA954X, + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(Pca954xState), + .instance_init = pca954x_init, + .class_size = sizeof(Pca954xClass), + .class_init = pca954x_class_init, + .abstract = true, + }, + { + .name = TYPE_PCA9546, + .parent = TYPE_PCA954X, + .class_init = pca9546_class_init, + }, + { + .name = TYPE_PCA9548, + .parent = TYPE_PCA954X, + .class_init = pca9548_class_init, + }, + { + .name = TYPE_PCA954X_CHANNEL, + .parent = TYPE_SYS_BUS_DEVICE, + .class_init = pca954x_channel_class_init, + .instance_size = sizeof(Pca954xChannel), + .instance_init = pca954x_channel_init, + } +}; + +DEFINE_TYPES(pca954x_info) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index cdcd694a7f..dd3aef02b2 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -14,4 +14,5 @@ i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c')) i2c_ss.add(when: 'CONFIG_VERSATILE_I2C', if_true: files('versatile_i2c.c')) i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c')) i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c')) +i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) softmmu_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 82fe6f965f..82f19e6a2d 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -26,3 +26,8 @@ npcm7xx_smbus_recv_byte(const char *id, uint8_t value) "%s recv byte: 0x%02x" npcm7xx_smbus_stop(const char *id) "%s stopping" npcm7xx_smbus_nack(const char *id) "%s nacking" npcm7xx_smbus_recv_fifo(const char *id, uint8_t received, uint8_t expected) "%s recv fifo: received %u, expected %u" + +# i2c-mux-pca954x.c + +pca954x_write_bytes(uint8_t value) "PCA954X write data: 0x%02x" +pca954x_read_data(uint8_t value) "PCA954X read data: 0x%02x" diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index 7f91f30877..66838fa397 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -23,6 +23,7 @@ config PC imply TPM_TIS_ISA imply VGA_PCI imply VIRTIO_VGA + imply NVDIMM select FDC select I8259 select I8254 diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index bfecb0038c..80bee00da6 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1815,6 +1815,7 @@ build_hpet(GArray *table_data, BIOSLinker *linker, const char *oem_id, const char *oem_table_id) { Acpi20Hpet *hpet; + int hpet_start = table_data->len; hpet = acpi_data_push(table_data, sizeof(*hpet)); /* Note timer_block_id value must be kept in sync with value advertised by @@ -1823,13 +1824,15 @@ build_hpet(GArray *table_data, BIOSLinker *linker, const char *oem_id, hpet->timer_block_id = cpu_to_le32(0x8086a201); hpet->addr.address = cpu_to_le64(HPET_BASE); build_header(linker, table_data, - (void *)hpet, "HPET", sizeof(*hpet), 1, oem_id, oem_table_id); + (void *)(table_data->data + hpet_start), + "HPET", sizeof(*hpet), 1, oem_id, oem_table_id); } static void build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog, const char *oem_id, const char *oem_table_id) { + int tcpa_start = table_data->len; Acpi20Tcpa *tcpa = acpi_data_push(table_data, sizeof *tcpa); unsigned log_addr_size = sizeof(tcpa->log_area_start_address); unsigned log_addr_offset = @@ -1848,7 +1851,8 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog, ACPI_BUILD_TPMLOG_FILE, 0); build_header(linker, table_data, - (void *)tcpa, "TCPA", sizeof(*tcpa), 2, oem_id, oem_table_id); + (void *)(table_data->data + tcpa_start), + "TCPA", sizeof(*tcpa), 2, oem_id, oem_table_id); } #define HOLE_640K_START (640 * KiB) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 74a93a5d93..2801dff97c 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -99,7 +99,7 @@ static uint64_t amdvi_readq(AMDVIState *s, hwaddr addr) } /* internal write */ -static void amdvi_writeq_raw(AMDVIState *s, uint64_t val, hwaddr addr) +static void amdvi_writeq_raw(AMDVIState *s, hwaddr addr, uint64_t val) { stq_le_p(&s->mmior[addr], val); } @@ -382,7 +382,7 @@ static void amdvi_completion_wait(AMDVIState *s, uint64_t *cmd) } /* set completion interrupt */ if (extract64(cmd[0], 1, 1)) { - amdvi_test_mask(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT); + amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT); /* generate interrupt */ amdvi_generate_msi_interrupt(s); } @@ -553,7 +553,7 @@ static void amdvi_cmdbuf_run(AMDVIState *s) trace_amdvi_command_exec(s->cmdbuf_head, s->cmdbuf_tail, s->cmdbuf); amdvi_cmdbuf_exec(s); s->cmdbuf_head += AMDVI_COMMAND_SIZE; - amdvi_writeq_raw(s, s->cmdbuf_head, AMDVI_MMIO_COMMAND_HEAD); + amdvi_writeq_raw(s, AMDVI_MMIO_COMMAND_HEAD, s->cmdbuf_head); /* wrap head pointer */ if (s->cmdbuf_head >= s->cmdbuf_len * AMDVI_COMMAND_SIZE) { @@ -860,8 +860,8 @@ static inline uint8_t get_pte_translation_mode(uint64_t pte) static inline uint64_t pte_override_page_mask(uint64_t pte) { - uint8_t page_mask = 12; - uint64_t addr = (pte & AMDVI_DEV_PT_ROOT_MASK) ^ AMDVI_DEV_PT_ROOT_MASK; + uint8_t page_mask = 13; + uint64_t addr = (pte & AMDVI_DEV_PT_ROOT_MASK) >> 12; /* find the first zero bit */ while (addr & 1) { page_mask++; diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c index e48a54fa36..4e68d5dea4 100644 --- a/hw/i386/fw_cfg.c +++ b/hw/i386/fw_cfg.c @@ -22,6 +22,7 @@ #include "hw/nvram/fw_cfg.h" #include "e820_memory_layout.h" #include "kvm/kvm_i386.h" +#include "qapi/error.h" #include CONFIG_DEVICES struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; @@ -78,7 +79,8 @@ void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg) } smbios_get_tables(ms, mem_array, array_count, &smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); + &smbios_anchor, &smbios_anchor_len, + &error_fatal); g_free(mem_array); if (smbios_anchor) { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5ac2edbf1f..30b8bd6ea9 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -61,6 +61,7 @@ #include "hw/hyperv/vmbus-bridge.h" #include "hw/mem/nvdimm.h" #include "hw/i386/acpi-build.h" +#include "kvm/kvm-cpu.h" #define MAX_IDE_BUS 2 diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index c53fa17c50..9b432773f0 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -108,6 +108,7 @@ typedef struct XenIOState { shared_iopage_t *shared_page; shared_vmport_iopage_t *shared_vmport_page; buffered_iopage_t *buffered_io_page; + xenforeignmemory_resource_handle *fres; QEMUTimer *buffered_io_timer; CPUState **cpu_by_vcpu_id; /* the evtchn port for polling the notification, */ @@ -1253,6 +1254,9 @@ static void xen_exit_notifier(Notifier *n, void *data) XenIOState *state = container_of(n, XenIOState, exit); xen_destroy_ioreq_server(xen_domid, state->ioservid); + if (state->fres != NULL) { + xenforeignmemory_unmap_resource(xen_fmem, state->fres); + } xenevtchn_close(state->xce_handle); xs_daemon_close(state->xenstore); @@ -1320,7 +1324,6 @@ static void xen_wakeup_notifier(Notifier *notifier, void *data) static int xen_map_ioreq_server(XenIOState *state) { void *addr = NULL; - xenforeignmemory_resource_handle *fres; xen_pfn_t ioreq_pfn; xen_pfn_t bufioreq_pfn; evtchn_port_t bufioreq_evtchn; @@ -1332,12 +1335,12 @@ static int xen_map_ioreq_server(XenIOState *state) */ QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_bufioreq != 0); QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_ioreq(0) != 1); - fres = xenforeignmemory_map_resource(xen_fmem, xen_domid, + state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid, XENMEM_resource_ioreq_server, state->ioservid, 0, 2, &addr, PROT_READ | PROT_WRITE, 0); - if (fres != NULL) { + if (state->fres != NULL) { trace_xen_map_resource_ioreq(state->ioservid, addr); state->buffered_io_page = addr; state->shared_page = addr + TARGET_PAGE_SIZE; diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index 5b120ed44b..bd47c3d672 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -169,9 +169,23 @@ static void xen_remap_bucket(MapCacheEntry *entry, if (entry->vaddr_base != NULL) { if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { - ram_block_notify_remove(entry->vaddr_base, entry->size); + ram_block_notify_remove(entry->vaddr_base, entry->size, + entry->size); } - if (munmap(entry->vaddr_base, entry->size) != 0) { + + /* + * If an entry is being replaced by another mapping and we're using + * MAP_FIXED flag for it - there is possibility of a race for vaddr + * address with another thread doing an mmap call itself + * (see man 2 mmap). To avoid that we skip explicit unmapping here + * and allow the kernel to destroy the previous mappings by replacing + * them in mmap call later. + * + * Non-identical replacements are not allowed therefore. + */ + assert(!vaddr || (entry->vaddr_base == vaddr && entry->size == size)); + + if (!vaddr && munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } @@ -211,7 +225,7 @@ static void xen_remap_bucket(MapCacheEntry *entry, } if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { - ram_block_notify_add(vaddr_base, size); + ram_block_notify_add(vaddr_base, size, size); } entry->vaddr_base = vaddr_base; @@ -452,7 +466,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer) } pentry->next = entry->next; - ram_block_notify_remove(entry->vaddr_base, entry->size); + ram_block_notify_remove(entry->vaddr_base, entry->size, entry->size); if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); diff --git a/hw/input/meson.build b/hw/input/meson.build index 0042c3f0dc..8deb011d4a 100644 --- a/hw/input/meson.build +++ b/hw/input/meson.build @@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c') softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c')) softmmu_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-softusb.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c')) softmmu_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c')) softmmu_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c')) diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c deleted file mode 100644 index d885c708d7..0000000000 --- a/hw/input/milkymist-softusb.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * QEMU model of the Milkymist SoftUSB block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * not available yet - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "ui/console.h" -#include "hw/input/hid.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_CTRL = 0, - R_MAX -}; - -enum { - CTRL_RESET = (1<<0), -}; - -#define COMLOC_DEBUG_PRODUCE 0x1000 -#define COMLOC_DEBUG_BASE 0x1001 -#define COMLOC_MEVT_PRODUCE 0x1101 -#define COMLOC_MEVT_BASE 0x1102 -#define COMLOC_KEVT_PRODUCE 0x1142 -#define COMLOC_KEVT_BASE 0x1143 - -#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSoftUsbState, MILKYMIST_SOFTUSB) - -struct MilkymistSoftUsbState { - SysBusDevice parent_obj; - - HIDState hid_kbd; - HIDState hid_mouse; - - MemoryRegion regs_region; - MemoryRegion pmem; - MemoryRegion dmem; - qemu_irq irq; - - void *pmem_ptr; - void *dmem_ptr; - - /* device properties */ - uint32_t pmem_size; - uint32_t dmem_size; - - /* device registers */ - uint32_t regs[R_MAX]; - - /* mouse state */ - uint8_t mouse_hid_buffer[4]; - - /* keyboard state */ - uint8_t kbd_hid_buffer[8]; -}; - -static uint64_t softusb_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistSoftUsbState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTRL: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_softusb: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_softusb_memory_read(addr << 2, r); - - return r; -} - -static void -softusb_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistSoftUsbState *s = opaque; - - trace_milkymist_softusb_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_softusb: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps softusb_mmio_ops = { - .read = softusb_read, - .write = softusb_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static inline void softusb_read_dmem(MilkymistSoftUsbState *s, - uint32_t offset, uint8_t *buf, uint32_t len) -{ - if (offset + len >= s->dmem_size) { - error_report("milkymist_softusb: read dmem out of bounds " - "at offset 0x%x, len %d", offset, len); - memset(buf, 0, len); - return; - } - - memcpy(buf, s->dmem_ptr + offset, len); -} - -static inline void softusb_write_dmem(MilkymistSoftUsbState *s, - uint32_t offset, uint8_t *buf, uint32_t len) -{ - if (offset + len >= s->dmem_size) { - error_report("milkymist_softusb: write dmem out of bounds " - "at offset 0x%x, len %d", offset, len); - return; - } - - memcpy(s->dmem_ptr + offset, buf, len); -} - -static void softusb_mouse_changed(MilkymistSoftUsbState *s) -{ - uint8_t m; - - softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); - trace_milkymist_softusb_mevt(m); - softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4); - m = (m + 1) & 0xf; - softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); - - trace_milkymist_softusb_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static void softusb_kbd_changed(MilkymistSoftUsbState *s) -{ - uint8_t m; - - softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); - trace_milkymist_softusb_kevt(m); - softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8); - m = (m + 1) & 0x7; - softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); - - trace_milkymist_softusb_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static void softusb_kbd_hid_datain(HIDState *hs) -{ - MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd); - int len; - - /* if device is in reset, do nothing */ - if (s->regs[R_CTRL] & CTRL_RESET) { - return; - } - - while (hid_has_events(hs)) { - len = hid_keyboard_poll(hs, s->kbd_hid_buffer, - sizeof(s->kbd_hid_buffer)); - - if (len == 8) { - softusb_kbd_changed(s); - } - } -} - -static void softusb_mouse_hid_datain(HIDState *hs) -{ - MilkymistSoftUsbState *s = - container_of(hs, MilkymistSoftUsbState, hid_mouse); - int len; - - /* if device is in reset, do nothing */ - if (s->regs[R_CTRL] & CTRL_RESET) { - return; - } - - while (hid_has_events(hs)) { - len = hid_pointer_poll(hs, s->mouse_hid_buffer, - sizeof(s->mouse_hid_buffer)); - - if (len == 4) { - softusb_mouse_changed(s); - } - } -} - -static void milkymist_softusb_reset(DeviceState *d) -{ - MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer)); - memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer)); - - hid_reset(&s->hid_kbd); - hid_reset(&s->hid_mouse); - - /* defaults */ - s->regs[R_CTRL] = CTRL_RESET; -} - -static void milkymist_softusb_realize(DeviceState *dev, Error **errp) -{ - MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(s), &softusb_mmio_ops, s, - "milkymist-softusb", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); - - /* register pmem and dmem */ - memory_region_init_ram_nomigrate(&s->pmem, OBJECT(s), "milkymist-softusb.pmem", - s->pmem_size, &error_fatal); - vmstate_register_ram_global(&s->pmem); - s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem); - sysbus_init_mmio(sbd, &s->pmem); - memory_region_init_ram_nomigrate(&s->dmem, OBJECT(s), "milkymist-softusb.dmem", - s->dmem_size, &error_fatal); - vmstate_register_ram_global(&s->dmem); - s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem); - sysbus_init_mmio(sbd, &s->dmem); - - hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain); - hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain); -} - -static const VMStateDescription vmstate_milkymist_softusb = { - .name = "milkymist-softusb", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX), - VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState), - VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState), - VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState), - VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_softusb_properties[] = { - DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000), - DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_softusb_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_softusb_realize; - dc->reset = milkymist_softusb_reset; - dc->vmsd = &vmstate_milkymist_softusb; - device_class_set_props(dc, milkymist_softusb_properties); -} - -static const TypeInfo milkymist_softusb_info = { - .name = TYPE_MILKYMIST_SOFTUSB, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistSoftUsbState), - .class_init = milkymist_softusb_class_init, -}; - -static void milkymist_softusb_register_types(void) -{ - type_register_static(&milkymist_softusb_info); -} - -type_init(milkymist_softusb_register_types) diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index dde85ba6c6..baba62f357 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -23,13 +23,16 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "hw/isa/isa.h" #include "migration/vmstate.h" #include "hw/acpi/aml-build.h" #include "hw/input/ps2.h" #include "hw/irq.h" #include "hw/input/i8042.h" +#include "hw/qdev-properties.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" @@ -59,21 +62,6 @@ #define KBD_CCMD_RESET 0xFE /* Pulse bit 0 of the output port P2 = CPU reset. */ #define KBD_CCMD_NO_OP 0xFF /* Pulse no bits of the output port P2. */ -/* Keyboard Commands */ -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_ECHO 0xEE -#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ -#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* Keyboard Replies */ -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - /* Status Register Bits */ #define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ #define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ @@ -106,41 +94,37 @@ */ #define KBD_OUT_ONES 0xcc -/* Mouse Commands */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_POLL 0xEB /* Poll */ -#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ -#define AUX_SET_WRAP 0xEE /* Set wrap mode */ -#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ -#define AUX_GET_TYPE 0xF2 /* Get type */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_SET_DEFAULT 0xF6 -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define MOUSE_STATUS_REMOTE 0x40 -#define MOUSE_STATUS_ENABLED 0x20 -#define MOUSE_STATUS_SCALE21 0x10 - -#define KBD_PENDING_KBD 1 -#define KBD_PENDING_AUX 2 +#define KBD_PENDING_KBD_COMPAT 0x01 +#define KBD_PENDING_AUX_COMPAT 0x02 +#define KBD_PENDING_CTRL_KBD 0x04 +#define KBD_PENDING_CTRL_AUX 0x08 +#define KBD_PENDING_KBD KBD_MODE_DISABLE_KBD /* 0x10 */ +#define KBD_PENDING_AUX KBD_MODE_DISABLE_MOUSE /* 0x20 */ + +#define KBD_MIGR_TIMER_PENDING 0x1 + +#define KBD_OBSRC_KBD 0x01 +#define KBD_OBSRC_MOUSE 0x02 +#define KBD_OBSRC_CTRL 0x04 typedef struct KBDState { uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; uint8_t outport; + uint32_t migration_flags; + uint32_t obsrc; bool outport_present; + bool extended_state; + bool extended_state_loaded; /* Bitmask of devices with data available. */ uint8_t pending; + uint8_t obdata; + uint8_t cbdata; + uint8_t pending_tmp; void *kbd; void *mouse; + QEMUTimer *throttle_timer; qemu_irq irq_kbd; qemu_irq irq_mouse; @@ -148,56 +132,123 @@ typedef struct KBDState { hwaddr mask; } KBDState; -/* update irq and KBD_STAT_[MOUSE_]OBF */ /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be incorrect, but it avoids having to simulate exact delays */ -static void kbd_update_irq(KBDState *s) +static void kbd_update_irq_lines(KBDState *s) { int irq_kbd_level, irq_mouse_level; irq_kbd_level = 0; irq_mouse_level = 0; + + if (s->status & KBD_STAT_OBF) { + if (s->status & KBD_STAT_MOUSE_OBF) { + if (s->mode & KBD_MODE_MOUSE_INT) { + irq_mouse_level = 1; + } + } else { + if ((s->mode & KBD_MODE_KBD_INT) && + !(s->mode & KBD_MODE_DISABLE_KBD)) { + irq_kbd_level = 1; + } + } + } + qemu_set_irq(s->irq_kbd, irq_kbd_level); + qemu_set_irq(s->irq_mouse, irq_mouse_level); +} + +static void kbd_deassert_irq(KBDState *s) +{ + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); + s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF); + kbd_update_irq_lines(s); +} + +static uint8_t kbd_pending(KBDState *s) +{ + if (s->extended_state) { + return s->pending & (~s->mode | ~(KBD_PENDING_KBD | KBD_PENDING_AUX)); + } else { + return s->pending; + } +} + +/* update irq and KBD_STAT_[MOUSE_]OBF */ +static void kbd_update_irq(KBDState *s) +{ + uint8_t pending = kbd_pending(s); + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF); - if (s->pending) { + if (pending) { s->status |= KBD_STAT_OBF; s->outport |= KBD_OUT_OBF; - /* kbd data takes priority over aux data. */ - if (s->pending == KBD_PENDING_AUX) { + if (pending & KBD_PENDING_CTRL_KBD) { + s->obsrc = KBD_OBSRC_CTRL; + } else if (pending & KBD_PENDING_CTRL_AUX) { s->status |= KBD_STAT_MOUSE_OBF; s->outport |= KBD_OUT_MOUSE_OBF; - if (s->mode & KBD_MODE_MOUSE_INT) - irq_mouse_level = 1; + s->obsrc = KBD_OBSRC_CTRL; + } else if (pending & KBD_PENDING_KBD) { + s->obsrc = KBD_OBSRC_KBD; } else { - if ((s->mode & KBD_MODE_KBD_INT) && - !(s->mode & KBD_MODE_DISABLE_KBD)) - irq_kbd_level = 1; + s->status |= KBD_STAT_MOUSE_OBF; + s->outport |= KBD_OUT_MOUSE_OBF; + s->obsrc = KBD_OBSRC_MOUSE; } } - qemu_set_irq(s->irq_kbd, irq_kbd_level); - qemu_set_irq(s->irq_mouse, irq_mouse_level); + kbd_update_irq_lines(s); +} + +static void kbd_safe_update_irq(KBDState *s) +{ + /* + * with KBD_STAT_OBF set, a call to kbd_read_data() will eventually call + * kbd_update_irq() + */ + if (s->status & KBD_STAT_OBF) { + return; + } + /* the throttle timer is pending and will call kbd_update_irq() */ + if (s->throttle_timer && timer_pending(s->throttle_timer)) { + return; + } + if (kbd_pending(s)) { + kbd_update_irq(s); + } } static void kbd_update_kbd_irq(void *opaque, int level) { - KBDState *s = (KBDState *)opaque; + KBDState *s = opaque; - if (level) + if (level) { s->pending |= KBD_PENDING_KBD; - else + } else { s->pending &= ~KBD_PENDING_KBD; - kbd_update_irq(s); + } + kbd_safe_update_irq(s); } static void kbd_update_aux_irq(void *opaque, int level) { - KBDState *s = (KBDState *)opaque; + KBDState *s = opaque; - if (level) + if (level) { s->pending |= KBD_PENDING_AUX; - else + } else { s->pending &= ~KBD_PENDING_AUX; - kbd_update_irq(s); + } + kbd_safe_update_irq(s); +} + +static void kbd_throttle_timeout(void *opaque) +{ + KBDState *s = opaque; + + if (kbd_pending(s)) { + kbd_update_irq(s); + } } static uint64_t kbd_read_status(void *opaque, hwaddr addr, @@ -212,10 +263,25 @@ static uint64_t kbd_read_status(void *opaque, hwaddr addr, static void kbd_queue(KBDState *s, int b, int aux) { - if (aux) - ps2_queue(s->mouse, b); - else - ps2_queue(s->kbd, b); + if (s->extended_state) { + s->cbdata = b; + s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX; + s->pending |= aux ? KBD_PENDING_CTRL_AUX : KBD_PENDING_CTRL_KBD; + kbd_safe_update_irq(s); + } else { + ps2_queue(aux ? s->mouse : s->kbd, b); + } +} + +static uint8_t kbd_dequeue(KBDState *s) +{ + uint8_t b = s->cbdata; + + s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX; + if (kbd_pending(s)) { + kbd_update_irq(s); + } + return b; } static void outport_write(KBDState *s, uint32_t val) @@ -265,6 +331,7 @@ static void kbd_write_command(void *opaque, hwaddr addr, break; case KBD_CCMD_MOUSE_ENABLE: s->mode &= ~KBD_MODE_DISABLE_MOUSE; + kbd_safe_update_irq(s); break; case KBD_CCMD_TEST_MOUSE: kbd_queue(s, 0x00, 0); @@ -278,11 +345,10 @@ static void kbd_write_command(void *opaque, hwaddr addr, break; case KBD_CCMD_KBD_DISABLE: s->mode |= KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); break; case KBD_CCMD_KBD_ENABLE: s->mode &= ~KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); + kbd_safe_update_irq(s); break; case KBD_CCMD_READ_INPORT: kbd_queue(s, 0x80, 0); @@ -315,15 +381,24 @@ static uint64_t kbd_read_data(void *opaque, hwaddr addr, unsigned size) { KBDState *s = opaque; - uint32_t val; - if (s->pending == KBD_PENDING_AUX) - val = ps2_read_data(s->mouse); - else - val = ps2_read_data(s->kbd); + if (s->status & KBD_STAT_OBF) { + kbd_deassert_irq(s); + if (s->obsrc & KBD_OBSRC_KBD) { + if (s->throttle_timer) { + timer_mod(s->throttle_timer, + qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000); + } + s->obdata = ps2_read_data(s->kbd); + } else if (s->obsrc & KBD_OBSRC_MOUSE) { + s->obdata = ps2_read_data(s->mouse); + } else if (s->obsrc & KBD_OBSRC_CTRL) { + s->obdata = kbd_dequeue(s); + } + } - trace_pckbd_kbd_read_data(val); - return val; + trace_pckbd_kbd_read_data(s->obdata); + return s->obdata; } static void kbd_write_data(void *opaque, hwaddr addr, @@ -336,12 +411,23 @@ static void kbd_write_data(void *opaque, hwaddr addr, switch(s->write_cmd) { case 0: ps2_write_keyboard(s->kbd, val); + /* sending data to the keyboard reenables PS/2 communication */ + s->mode &= ~KBD_MODE_DISABLE_KBD; + kbd_safe_update_irq(s); break; case KBD_CCMD_WRITE_MODE: s->mode = val; ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0); - /* ??? */ - kbd_update_irq(s); + /* + * a write to the mode byte interrupt enable flags directly updates + * the irq lines + */ + kbd_update_irq_lines(s); + /* + * a write to the mode byte disable interface flags may raise + * an irq if there is pending data in the PS/2 queues. + */ + kbd_safe_update_irq(s); break; case KBD_CCMD_WRITE_OBUF: kbd_queue(s, val, 0); @@ -354,6 +440,9 @@ static void kbd_write_data(void *opaque, hwaddr addr, break; case KBD_CCMD_WRITE_MOUSE: ps2_write_mouse(s->mouse, val); + /* sending data to the mouse reenables PS/2 communication */ + s->mode &= ~KBD_MODE_DISABLE_MOUSE; + kbd_safe_update_irq(s); break; default: break; @@ -368,7 +457,11 @@ static void kbd_reset(void *opaque) s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES; - s->outport_present = false; + s->pending = 0; + kbd_deassert_irq(s); + if (s->throttle_timer) { + timer_del(s->throttle_timer); + } } static uint8_t kbd_outport_default(KBDState *s) @@ -403,13 +496,99 @@ static const VMStateDescription vmstate_kbd_outport = { } }; +static int kbd_extended_state_pre_save(void *opaque) +{ + KBDState *s = opaque; + + s->migration_flags = 0; + if (s->throttle_timer && timer_pending(s->throttle_timer)) { + s->migration_flags |= KBD_MIGR_TIMER_PENDING; + } + + return 0; +} + +static int kbd_extended_state_post_load(void *opaque, int version_id) +{ + KBDState *s = opaque; + + if (s->migration_flags & KBD_MIGR_TIMER_PENDING) { + kbd_throttle_timeout(s); + } + s->extended_state_loaded = true; + + return 0; +} + +static bool kbd_extended_state_needed(void *opaque) +{ + KBDState *s = opaque; + + return s->extended_state; +} + +static const VMStateDescription vmstate_kbd_extended_state = { + .name = "pckbd/extended_state", + .post_load = kbd_extended_state_post_load, + .pre_save = kbd_extended_state_pre_save, + .needed = kbd_extended_state_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(migration_flags, KBDState), + VMSTATE_UINT32(obsrc, KBDState), + VMSTATE_UINT8(obdata, KBDState), + VMSTATE_UINT8(cbdata, KBDState), + VMSTATE_END_OF_LIST() + } +}; + +static int kbd_pre_save(void *opaque) +{ + KBDState *s = opaque; + + if (s->extended_state) { + s->pending_tmp = s->pending; + } else { + s->pending_tmp = 0; + if (s->pending & KBD_PENDING_KBD) { + s->pending_tmp |= KBD_PENDING_KBD_COMPAT; + } + if (s->pending & KBD_PENDING_AUX) { + s->pending_tmp |= KBD_PENDING_AUX_COMPAT; + } + } + return 0; +} + +static int kbd_pre_load(void *opaque) +{ + KBDState *s = opaque; + + s->outport_present = false; + s->extended_state_loaded = false; + return 0; +} + static int kbd_post_load(void *opaque, int version_id) { KBDState *s = opaque; if (!s->outport_present) { s->outport = kbd_outport_default(s); } - s->outport_present = false; + s->pending = s->pending_tmp; + if (!s->extended_state_loaded) { + s->obsrc = s->status & KBD_STAT_OBF ? + (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) : + 0; + if (s->pending & KBD_PENDING_KBD_COMPAT) { + s->pending |= KBD_PENDING_KBD; + } + if (s->pending & KBD_PENDING_AUX_COMPAT) { + s->pending |= KBD_PENDING_AUX; + } + } + /* clear all unused flags */ + s->pending &= KBD_PENDING_CTRL_KBD | KBD_PENDING_CTRL_AUX | + KBD_PENDING_KBD | KBD_PENDING_AUX; return 0; } @@ -417,16 +596,19 @@ static const VMStateDescription vmstate_kbd = { .name = "pckbd", .version_id = 3, .minimum_version_id = 3, + .pre_load = kbd_pre_load, .post_load = kbd_post_load, + .pre_save = kbd_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT8(write_cmd, KBDState), VMSTATE_UINT8(status, KBDState), VMSTATE_UINT8(mode, KBDState), - VMSTATE_UINT8(pending, KBDState), + VMSTATE_UINT8(pending_tmp, KBDState), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription*[]) { &vmstate_kbd_outport, + &vmstate_kbd_extended_state, NULL } }; @@ -472,6 +654,8 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, s->irq_mouse = mouse_irq; s->mask = mask; + s->extended_state = true; + vmstate_register(NULL, 0, &vmstate_kbd, s); memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size); @@ -485,6 +669,7 @@ struct ISAKBDState { ISADevice parent_obj; KBDState kbd; + bool kbd_throttle; MemoryRegion io[2]; }; @@ -557,6 +742,13 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); + if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) { + warn_report(TYPE_I8042 ": can't enable kbd-throttle without" + " extended-state, disabling kbd-throttle"); + } else if (isa_s->kbd_throttle) { + s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, + kbd_throttle_timeout, s); + } qemu_register_reset(kbd_reset, s); } @@ -588,11 +780,18 @@ static void i8042_build_aml(ISADevice *isadev, Aml *scope) aml_append(scope, mou); } +static Property i8042_properties[] = { + DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true), + DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false), + DEFINE_PROP_END_OF_LIST(), +}; + static void i8042_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + device_class_set_props(dc, i8042_properties); dc->realize = i8042_realizefn; dc->vmsd = &vmstate_kbd_isa; isa->build_aml = i8042_build_aml; diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 72cdb80ae1..8dd482c1f6 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -212,8 +212,12 @@ void ps2_raise_irq(PS2State *s) void ps2_queue(PS2State *s, int b) { + if (PS2_QUEUE_SIZE - s->queue.count < 1) { + return; + } + ps2_queue_noirq(s, b); - s->update_irq(s->update_arg, 1); + ps2_raise_irq(s); } void ps2_queue_2(PS2State *s, int b1, int b2) @@ -224,7 +228,7 @@ void ps2_queue_2(PS2State *s, int b1, int b2) ps2_queue_noirq(s, b1); ps2_queue_noirq(s, b2); - s->update_irq(s->update_arg, 1); + ps2_raise_irq(s); } void ps2_queue_3(PS2State *s, int b1, int b2, int b3) @@ -236,7 +240,7 @@ void ps2_queue_3(PS2State *s, int b1, int b2, int b3) ps2_queue_noirq(s, b1); ps2_queue_noirq(s, b2); ps2_queue_noirq(s, b3); - s->update_irq(s->update_arg, 1); + ps2_raise_irq(s); } void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) @@ -249,7 +253,7 @@ void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) ps2_queue_noirq(s, b2); ps2_queue_noirq(s, b3); ps2_queue_noirq(s, b4); - s->update_irq(s->update_arg, 1); + ps2_raise_irq(s); } /* keycode is the untranslated scancode in the current scancode set. */ @@ -293,7 +297,8 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, qcode = qemu_input_key_value_to_qcode(key->key); mod = ps2_modifier_bit(qcode); - trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers); + trace_ps2_keyboard_event(s, qcode, key->down, mod, + s->modifiers, s->scancode_set, s->translate); if (key->down) { s->modifiers |= mod; } else { @@ -515,7 +520,9 @@ uint32_t ps2_read_data(PS2State *s) /* reading deasserts IRQ */ s->update_irq(s->update_arg, 0); /* reassert IRQs if data left */ - s->update_irq(s->update_arg, q->count != 0); + if (q->count) { + s->update_irq(s->update_arg, 1); + } } return val; } @@ -645,7 +652,8 @@ void ps2_keyboard_set_translation(void *opaque, int mode) static int ps2_mouse_send_packet(PS2MouseState *s) { - const int needed = 3 + (s->mouse_type - 2); + /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ + const int needed = s->mouse_type ? 4 : 3; unsigned int b; int dx1, dy1, dz1; diff --git a/hw/input/trace-events b/hw/input/trace-events index 1dd8ad6018..109bdf7a18 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -30,7 +30,7 @@ pckbd_kbd_write_data(uint64_t val) "0x%02"PRIx64 # ps2.c ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x" -ps2_keyboard_event(void *opaque, int qcode, int down, unsigned int modifier, unsigned int modifiers) "%p qcode %d down %d modifier 0x%x modifiers 0x%x" +ps2_keyboard_event(void *opaque, int qcode, int down, unsigned int modifier, unsigned int modifiers, int set, int xlate) "%p qcode %d down %d modifier 0x%x modifiers 0x%x set %d xlate %d" ps2_read_data(void *opaque) "%p" ps2_set_ledstate(void *s, int ledstate) "%p ledstate %d" ps2_reset_keyboard(void *s) "%p" @@ -44,13 +44,6 @@ ps2_mouse_reset(void *opaque) "%p" ps2_kbd_init(void *s) "%p" ps2_mouse_init(void *s) "%p" -# milkymist-softusb.c -milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_softusb_mevt(uint8_t m) "m %d" -milkymist_softusb_kevt(uint8_t m) "m %d" -milkymist_softusb_pulse_irq(void) "Pulse IRQ" - # hid.c hid_kbd_queue_full(void) "queue full" hid_kbd_queue_empty(void) "queue empty" diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 85daf73f1a..137efba57b 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -193,13 +193,16 @@ static void virtio_input_host_handle_status(VirtIOInput *vinput, { VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput); struct input_event evdev; + struct timeval tval; int rc; - if (gettimeofday(&evdev.time, NULL)) { + if (gettimeofday(&tval, NULL)) { perror("virtio_input_host_handle_status: gettimeofday"); return; } + evdev.input_event_sec = tval.tv_sec; + evdev.input_event_usec = tval.tv_usec; evdev.type = le16_to_cpu(event->type); evdev.code = le16_to_cpu(event->code); evdev.value = le32_to_cpu(event->value); diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 43ef1d7a84..81f94c7f4a 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -1307,27 +1307,16 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, GICv3CPUState *cs = icc_cs_from_env(env); int irq = value & 0xffffff; int grp; + bool is_eoir0 = ri->crm == 8; - if (icv_access(env, ri->crm == 8 ? HCR_FMO : HCR_IMO)) { + if (icv_access(env, is_eoir0 ? HCR_FMO : HCR_IMO)) { icv_eoir_write(env, ri, value); return; } - trace_gicv3_icc_eoir_write(ri->crm == 8 ? 0 : 1, + trace_gicv3_icc_eoir_write(is_eoir0 ? 0 : 1, gicv3_redist_affid(cs), value); - if (ri->crm == 8) { - /* EOIR0 */ - grp = GICV3_G0; - } else { - /* EOIR1 */ - if (arm_is_secure(env)) { - grp = GICV3_G1; - } else { - grp = GICV3_G1NS; - } - } - if (irq >= cs->gic->num_irq) { /* This handles two cases: * 1. If software writes the ID of a spurious interrupt [ie 1020-1023] @@ -1340,8 +1329,35 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, return; } - if (icc_highest_active_group(cs) != grp) { - return; + grp = icc_highest_active_group(cs); + switch (grp) { + case GICV3_G0: + if (!is_eoir0) { + return; + } + if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) + && arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env)) { + return; + } + break; + case GICV3_G1: + if (is_eoir0) { + return; + } + if (!arm_is_secure(env)) { + return; + } + break; + case GICV3_G1NS: + if (is_eoir0) { + return; + } + if (!arm_is_el3_or_mon(env) && arm_is_secure(env)) { + return; + } + break; + default: + g_assert_not_reached(); } icc_drop_prio(cs, grp); diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c index c1b72fcab0..edf76e4f61 100644 --- a/hw/intc/ibex_plic.c +++ b/hw/intc/ibex_plic.c @@ -225,23 +225,23 @@ static void ibex_plic_irq_request(void *opaque, int irq, int level) static Property ibex_plic_properties[] = { DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1), - DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80), + DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 176), DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0), - DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3), + DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 6), - DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c), - DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3), + DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x18), + DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 6), - DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18), - DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80), + DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x30), + DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 177), - DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200), - DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3), + DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x300), + DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 6), - DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c), + DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x318), - DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210), + DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x31c), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c deleted file mode 100644 index 991a90bc99..0000000000 --- a/hw/intc/lm32_pic.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * LatticeMico32 CPU interrupt controller logic. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" - -#include "migration/vmstate.h" -#include "monitor/monitor.h" -#include "qemu/module.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "hw/lm32/lm32_pic.h" -#include "hw/intc/intc.h" -#include "hw/irq.h" -#include "qom/object.h" - -#define TYPE_LM32_PIC "lm32-pic" -OBJECT_DECLARE_SIMPLE_TYPE(LM32PicState, LM32_PIC) - -struct LM32PicState { - SysBusDevice parent_obj; - - qemu_irq parent_irq; - uint32_t im; /* interrupt mask */ - uint32_t ip; /* interrupt pending */ - uint32_t irq_state; - - /* statistics */ - uint64_t stats_irq_count[32]; -}; - -static void update_irq(LM32PicState *s) -{ - s->ip |= s->irq_state; - - if (s->ip & s->im) { - trace_lm32_pic_raise_irq(); - qemu_irq_raise(s->parent_irq); - } else { - trace_lm32_pic_lower_irq(); - qemu_irq_lower(s->parent_irq); - } -} - -static void irq_handler(void *opaque, int irq, int level) -{ - LM32PicState *s = opaque; - - assert(irq < 32); - trace_lm32_pic_interrupt(irq, level); - - if (level) { - s->irq_state |= (1 << irq); - s->stats_irq_count[irq]++; - } else { - s->irq_state &= ~(1 << irq); - } - - update_irq(s); -} - -void lm32_pic_set_im(DeviceState *d, uint32_t im) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_set_im(im); - s->im = im; - - update_irq(s); -} - -void lm32_pic_set_ip(DeviceState *d, uint32_t ip) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_set_ip(ip); - - /* ack interrupt */ - s->ip &= ~ip; - - update_irq(s); -} - -uint32_t lm32_pic_get_im(DeviceState *d) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_get_im(s->im); - return s->im; -} - -uint32_t lm32_pic_get_ip(DeviceState *d) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_get_ip(s->ip); - return s->ip; -} - -static void pic_reset(DeviceState *d) -{ - LM32PicState *s = LM32_PIC(d); - int i; - - s->im = 0; - s->ip = 0; - s->irq_state = 0; - for (i = 0; i < 32; i++) { - s->stats_irq_count[i] = 0; - } -} - -static bool lm32_get_statistics(InterruptStatsProvider *obj, - uint64_t **irq_counts, unsigned int *nb_irqs) -{ - LM32PicState *s = LM32_PIC(obj); - *irq_counts = s->stats_irq_count; - *nb_irqs = ARRAY_SIZE(s->stats_irq_count); - return true; -} - -static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon) -{ - LM32PicState *s = LM32_PIC(obj); - monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", - s->im, s->ip, s->irq_state); -} - -static void lm32_pic_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - LM32PicState *s = LM32_PIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - qdev_init_gpio_in(dev, irq_handler, 32); - sysbus_init_irq(sbd, &s->parent_irq); -} - -static const VMStateDescription vmstate_lm32_pic = { - .name = "lm32-pic", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(im, LM32PicState), - VMSTATE_UINT32(ip, LM32PicState), - VMSTATE_UINT32(irq_state, LM32PicState), - VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32), - VMSTATE_END_OF_LIST() - } -}; - -static void lm32_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); - - dc->reset = pic_reset; - dc->vmsd = &vmstate_lm32_pic; - ic->get_statistics = lm32_get_statistics; - ic->print_info = lm32_print_info; -} - -static const TypeInfo lm32_pic_info = { - .name = TYPE_LM32_PIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32PicState), - .instance_init = lm32_pic_init, - .class_init = lm32_pic_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_INTERRUPT_STATS_PROVIDER }, - { } - }, -}; - -static void lm32_pic_register_types(void) -{ - type_register_static(&lm32_pic_info); -} - -type_init(lm32_pic_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 1c299039f6..6e52a166e3 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -14,10 +14,8 @@ softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c')) softmmu_ss.add(when: 'CONFIG_I8259', if_true: files('i8259_common.c', 'i8259.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c')) softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_pic.c')) softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c')) softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c')) -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_intc.c')) softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_gic.c')) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_intctl.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c')) diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c deleted file mode 100644 index 65226f5e7c..0000000000 --- a/hw/intc/puv3_intc.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * INTC device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define TYPE_PUV3_INTC "puv3_intc" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3INTCState, PUV3_INTC) - -struct PUV3INTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq parent_irq; - - uint32_t reg_ICMR; - uint32_t reg_ICPR; -}; - -/* Update interrupt status after enabled or pending bits have been changed. */ -static void puv3_intc_update(PUV3INTCState *s) -{ - if (s->reg_ICMR & s->reg_ICPR) { - qemu_irq_raise(s->parent_irq); - } else { - qemu_irq_lower(s->parent_irq); - } -} - -/* Process a change in an external INTC input. */ -static void puv3_intc_handler(void *opaque, int irq, int level) -{ - PUV3INTCState *s = opaque; - - DPRINTF("irq 0x%x, level 0x%x\n", irq, level); - if (level) { - s->reg_ICPR |= (1 << irq); - } else { - s->reg_ICPR &= ~(1 << irq); - } - puv3_intc_update(s); -} - -static uint64_t puv3_intc_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3INTCState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x04: /* INTC_ICMR */ - ret = s->reg_ICMR; - break; - case 0x0c: /* INTC_ICIP */ - ret = s->reg_ICPR; /* the same value with ICPR */ - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - return ret; -} - -static void puv3_intc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3INTCState *s = opaque; - - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); - switch (offset) { - case 0x00: /* INTC_ICLR */ - case 0x14: /* INTC_ICCR */ - break; - case 0x04: /* INTC_ICMR */ - s->reg_ICMR = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - return; - } - puv3_intc_update(s); -} - -static const MemoryRegionOps puv3_intc_ops = { - .read = puv3_intc_read, - .write = puv3_intc_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_intc_realize(DeviceState *dev, Error **errp) -{ - PUV3INTCState *s = PUV3_INTC(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR); - sysbus_init_irq(sbd, &s->parent_irq); - - s->reg_ICMR = 0; - s->reg_ICPR = 0; - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc", - PUV3_REGS_OFFSET); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void puv3_intc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = puv3_intc_realize; -} - -static const TypeInfo puv3_intc_info = { - .name = TYPE_PUV3_INTC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3INTCState), - .class_init = puv3_intc_class_init, -}; - -static void puv3_intc_register_type(void) -{ - type_register_static(&puv3_intc_info); -} - -type_init(puv3_intc_register_type) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index c9ab17234b..626bb554b2 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -51,15 +51,6 @@ grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d" grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" -# lm32_pic.c -lm32_pic_raise_irq(void) "Raise CPU interrupt" -lm32_pic_lower_irq(void) "Lower CPU interrupt" -lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d" -lm32_pic_set_im(uint32_t im) "im 0x%08x" -lm32_pic_set_ip(uint32_t ip) "ip 0x%08x" -lm32_pic_get_im(uint32_t im) "im 0x%08x" -lm32_pic_get_ip(uint32_t ip) "ip 0x%08x" - # xics.c xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=0x%x" xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx32"->0x%"PRIx32 diff --git a/hw/lm32/Kconfig b/hw/lm32/Kconfig deleted file mode 100644 index 8ac94205d7..0000000000 --- a/hw/lm32/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config LM32_DEVICES - bool - select PTIMER - -config MILKYMIST - bool - # FIXME: disabling it results in compile-time errors - select MILKYMIST_TMU2 if OPENGL && X11 - select PFLASH_CFI01 - select FRAMEBUFFER - select SD - select USB_OHCI - select LM32_DEVICES - -config LM32_EVR - bool - select LM32_DEVICES - select PFLASH_CFI02 diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h deleted file mode 100644 index 7b4f6255b9..0000000000 --- a/hw/lm32/lm32.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef HW_LM32_H -#define HW_LM32_H - -#include "hw/char/lm32_juart.h" -#include "hw/qdev-properties.h" -#include "qapi/error.h" - -static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) -{ - DeviceState *dev; - SysBusDevice *d; - - dev = qdev_new("lm32-pic"); - d = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(d, &error_fatal); - sysbus_connect_irq(d, 0, cpu_irq); - - return dev; -} - -static inline DeviceState *lm32_juart_init(Chardev *chr) -{ - DeviceState *dev; - - dev = qdev_new(TYPE_LM32_JUART); - qdev_prop_set_chr(dev, "chardev", chr); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - return dev; -} - -static inline DeviceState *lm32_uart_create(hwaddr addr, - qemu_irq irq, - Chardev *chr) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_new("lm32-uart"); - s = SYS_BUS_DEVICE(dev); - qdev_prop_set_chr(dev, "chardev", chr); - sysbus_realize_and_unref(s, &error_fatal); - sysbus_mmio_map(s, 0, addr); - sysbus_connect_irq(s, 0, irq); - return dev; -} - -#endif diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c deleted file mode 100644 index 2961e4c2b4..0000000000 --- a/hw/lm32/lm32_boards.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * QEMU models for LatticeMico32 uclinux and evr32 boards. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/units.h" -#include "qemu/cutils.h" -#include "qemu/error-report.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/irq.h" -#include "hw/block/flash.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "lm32_hwsetup.h" -#include "lm32.h" -#include "sysemu/reset.h" -#include "sysemu/sysemu.h" - -typedef struct { - LM32CPU *cpu; - hwaddr bootstrap_pc; - hwaddr flash_base; - hwaddr hwsetup_base; - hwaddr initrd_base; - size_t initrd_size; - hwaddr cmdline_base; -} ResetInfo; - -static void cpu_irq_handler(void *opaque, int irq, int level) -{ - LM32CPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - -static void main_cpu_reset(void *opaque) -{ - ResetInfo *reset_info = opaque; - CPULM32State *env = &reset_info->cpu->env; - - cpu_reset(CPU(reset_info->cpu)); - - /* init defaults */ - env->pc = (uint32_t)reset_info->bootstrap_pc; - env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base; - env->regs[R_R2] = (uint32_t)reset_info->cmdline_base; - env->regs[R_R3] = (uint32_t)reset_info->initrd_base; - env->regs[R_R4] = (uint32_t)(reset_info->initrd_base + - reset_info->initrd_size); - env->eba = reset_info->flash_base; - env->deba = reset_info->flash_base; -} - -static void lm32_evr_init(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *kernel_filename = machine->kernel_filename; - LM32CPU *cpu; - CPULM32State *env; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq irq[32]; - ResetInfo *reset_info; - int i; - - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - /* memory map */ - hwaddr flash_base = 0x04000000; - size_t flash_sector_size = 256 * KiB; - size_t flash_size = 32 * MiB; - hwaddr ram_base = 0x08000000; - hwaddr timer0_base = 0x80002000; - hwaddr uart0_base = 0x80006000; - hwaddr timer1_base = 0x8000a000; - int uart0_irq = 0; - int timer0_irq = 1; - int timer1_irq = 3; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - cpu = LM32_CPU(cpu_create(machine->cpu_type)); - - env = &cpu->env; - reset_info->cpu = cpu; - - reset_info->flash_base = flash_base; - - memory_region_add_subregion(address_space_mem, ram_base, machine->ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Spansion S29NS128P */ - pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - flash_sector_size, - 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); - - /* create irq lines */ - env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0)); - sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); - sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hd(1)); - - reset_info->bootstrap_pc = flash_base; - - if (kernel_filename) { - uint64_t entry; - int kernel_size; - - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &entry, NULL, NULL, NULL, - 1, EM_LATTICEMICO32, 0, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ram_base, - machine->ram_size); - reset_info->bootstrap_pc = ram_base; - } - - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void lm32_uclinux_init(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - LM32CPU *cpu; - CPULM32State *env; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq irq[32]; - HWSetup *hw; - ResetInfo *reset_info; - int i; - - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - /* memory map */ - hwaddr flash_base = 0x04000000; - size_t flash_sector_size = 256 * KiB; - size_t flash_size = 32 * MiB; - hwaddr ram_base = 0x08000000; - hwaddr uart0_base = 0x80000000; - hwaddr timer0_base = 0x80002000; - hwaddr timer1_base = 0x80010000; - hwaddr timer2_base = 0x80012000; - int uart0_irq = 0; - int timer0_irq = 1; - int timer1_irq = 20; - int timer2_irq = 21; - hwaddr hwsetup_base = 0x0bffe000; - hwaddr cmdline_base = 0x0bfff000; - hwaddr initrd_base = 0x08400000; - size_t initrd_max = 0x01000000; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - cpu = LM32_CPU(cpu_create(machine->cpu_type)); - - env = &cpu->env; - reset_info->cpu = cpu; - - reset_info->flash_base = flash_base; - - memory_region_add_subregion(address_space_mem, ram_base, machine->ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Spansion S29NS128P */ - pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - flash_sector_size, - 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); - - /* create irq lines */ - env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0)); - sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); - sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); - sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hd(1)); - - reset_info->bootstrap_pc = flash_base; - - if (kernel_filename) { - uint64_t entry; - int kernel_size; - - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &entry, NULL, NULL, NULL, - 1, EM_LATTICEMICO32, 0, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ram_base, - machine->ram_size); - reset_info->bootstrap_pc = ram_base; - } - - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - /* generate a rom with the hardware description */ - hw = hwsetup_init(); - hwsetup_add_cpu(hw, "LM32", 75000000); - hwsetup_add_flash(hw, "flash", flash_base, flash_size); - hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, machine->ram_size); - hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq); - hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq); - hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq); - hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq); - hwsetup_add_trailer(hw); - hwsetup_create_rom(hw, hwsetup_base); - hwsetup_free(hw); - - reset_info->hwsetup_base = hwsetup_base; - - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, - kernel_cmdline); - reset_info->cmdline_base = cmdline_base; - } - - if (initrd_filename) { - size_t initrd_size; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - initrd_max); - reset_info->initrd_base = initrd_base; - reset_info->initrd_size = initrd_size; - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void lm32_evr_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "LatticeMico32 EVR32 eval system"; - mc->init = lm32_evr_init; - mc->is_default = true; - mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); - mc->default_ram_size = 64 * MiB; - mc->default_ram_id = "lm32_evr.sdram"; -} - -static const TypeInfo lm32_evr_type = { - .name = MACHINE_TYPE_NAME("lm32-evr"), - .parent = TYPE_MACHINE, - .class_init = lm32_evr_class_init, -}; - -static void lm32_uclinux_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "lm32 platform for uClinux and u-boot by Theobroma Systems"; - mc->init = lm32_uclinux_init; - mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); - mc->default_ram_size = 64 * MiB; - mc->default_ram_id = "lm32_uclinux.sdram"; -} - -static const TypeInfo lm32_uclinux_type = { - .name = MACHINE_TYPE_NAME("lm32-uclinux"), - .parent = TYPE_MACHINE, - .class_init = lm32_uclinux_class_init, -}; - -static void lm32_machine_init(void) -{ - type_register_static(&lm32_evr_type); - type_register_static(&lm32_uclinux_type); -} - -type_init(lm32_machine_init) diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h deleted file mode 100644 index e6cd30ad68..0000000000 --- a/hw/lm32/lm32_hwsetup.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * LatticeMico32 hwsetup helper functions. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -/* - * These are helper functions for creating the hardware description blob used - * in the Theobroma's uClinux port. - */ - -#ifndef QEMU_HW_LM32_HWSETUP_H -#define QEMU_HW_LM32_HWSETUP_H - -#include "qemu/cutils.h" -#include "hw/loader.h" - -typedef struct { - void *data; - void *ptr; -} HWSetup; - -enum hwsetup_tag { - HWSETUP_TAG_EOL = 0, - HWSETUP_TAG_CPU = 1, - HWSETUP_TAG_ASRAM = 2, - HWSETUP_TAG_FLASH = 3, - HWSETUP_TAG_SDRAM = 4, - HWSETUP_TAG_OCM = 5, - HWSETUP_TAG_DDR_SDRAM = 6, - HWSETUP_TAG_DDR2_SDRAM = 7, - HWSETUP_TAG_TIMER = 8, - HWSETUP_TAG_UART = 9, - HWSETUP_TAG_GPIO = 10, - HWSETUP_TAG_TRISPEEDMAC = 11, - HWSETUP_TAG_I2CM = 12, - HWSETUP_TAG_LEDS = 13, - HWSETUP_TAG_7SEG = 14, - HWSETUP_TAG_SPI_S = 15, - HWSETUP_TAG_SPI_M = 16, -}; - -static inline HWSetup *hwsetup_init(void) -{ - HWSetup *hw; - - hw = g_malloc(sizeof(HWSetup)); - hw->data = g_malloc0(TARGET_PAGE_SIZE); - hw->ptr = hw->data; - - return hw; -} - -static inline void hwsetup_free(HWSetup *hw) -{ - g_free(hw->data); - g_free(hw); -} - -static inline void hwsetup_create_rom(HWSetup *hw, - hwaddr base) -{ - rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, - TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true); -} - -static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u) -{ - stb_p(hw->ptr, u); - hw->ptr += 1; -} - -static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u) -{ - stl_p(hw->ptr, u); - hw->ptr += 4; -} - -static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t) -{ - stl_p(hw->ptr, t); - hw->ptr += 4; -} - -static inline void hwsetup_add_str(HWSetup *hw, const char *str) -{ - pstrcpy(hw->ptr, 32, str); - hw->ptr += 32; -} - -static inline void hwsetup_add_trailer(HWSetup *hw) -{ - hwsetup_add_u32(hw, 8); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_EOL); -} - -static inline void hwsetup_add_cpu(HWSetup *hw, - const char *name, uint32_t frequency) -{ - hwsetup_add_u32(hw, 44); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_CPU); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, frequency); -} - -static inline void hwsetup_add_flash(HWSetup *hw, - const char *name, uint32_t base, uint32_t size) -{ - hwsetup_add_u32(hw, 52); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_FLASH); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u32(hw, size); - hwsetup_add_u8(hw, 8); /* read latency */ - hwsetup_add_u8(hw, 8); /* write latency */ - hwsetup_add_u8(hw, 25); /* address width */ - hwsetup_add_u8(hw, 32); /* data width */ -} - -static inline void hwsetup_add_ddr_sdram(HWSetup *hw, - const char *name, uint32_t base, uint32_t size) -{ - hwsetup_add_u32(hw, 48); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u32(hw, size); -} - -static inline void hwsetup_add_timer(HWSetup *hw, - const char *name, uint32_t base, uint32_t irq) -{ - hwsetup_add_u32(hw, 56); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_TIMER); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u8(hw, 1); /* wr_tickcount */ - hwsetup_add_u8(hw, 1); /* rd_tickcount */ - hwsetup_add_u8(hw, 1); /* start_stop_control */ - hwsetup_add_u8(hw, 32); /* counter_width */ - hwsetup_add_u32(hw, 20); /* reload_ticks */ - hwsetup_add_u8(hw, irq); - hwsetup_add_u8(hw, 0); /* padding */ - hwsetup_add_u8(hw, 0); /* padding */ - hwsetup_add_u8(hw, 0); /* padding */ -} - -static inline void hwsetup_add_uart(HWSetup *hw, - const char *name, uint32_t base, uint32_t irq) -{ - hwsetup_add_u32(hw, 56); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_UART); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u32(hw, 115200); /* baudrate */ - hwsetup_add_u8(hw, 8); /* databits */ - hwsetup_add_u8(hw, 1); /* stopbits */ - hwsetup_add_u8(hw, 1); /* use_interrupt */ - hwsetup_add_u8(hw, 1); /* block_on_transmit */ - hwsetup_add_u8(hw, 1); /* block_on_receive */ - hwsetup_add_u8(hw, 4); /* rx_buffer_size */ - hwsetup_add_u8(hw, 4); /* tx_buffer_size */ - hwsetup_add_u8(hw, irq); -} - -#endif /* QEMU_HW_LM32_HWSETUP_H */ diff --git a/hw/lm32/meson.build b/hw/lm32/meson.build deleted file mode 100644 index 42d6f8db3d..0000000000 --- a/hw/lm32/meson.build +++ /dev/null @@ -1,6 +0,0 @@ -lm32_ss = ss.source_set() -# LM32 boards -lm32_ss.add(when: 'CONFIG_LM32_EVR', if_true: files('lm32_boards.c')) -lm32_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist.c')) - -hw_arch += {'lm32': lm32_ss} diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h deleted file mode 100644 index 5dca5d52f5..0000000000 --- a/hw/lm32/milkymist-hw.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef QEMU_HW_MILKYMIST_HW_H -#define QEMU_HW_MILKYMIST_HW_H - -#include "hw/qdev-core.h" -#include "net/net.h" -#include "qapi/error.h" - -static inline DeviceState *milkymist_uart_create(hwaddr base, - qemu_irq irq, - Chardev *chr) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-uart"); - qdev_prop_set_chr(dev, "chardev", chr); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; -} - -static inline DeviceState *milkymist_hpdmc_create(hwaddr base) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-hpdmc"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - return dev; -} - -static inline DeviceState *milkymist_vgafb_create(hwaddr base, - uint32_t fb_offset, uint32_t fb_mask) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-vgafb"); - qdev_prop_set_uint32(dev, "fb_offset", fb_offset); - qdev_prop_set_uint32(dev, "fb_mask", fb_mask); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - return dev; -} - -static inline DeviceState *milkymist_sysctl_create(hwaddr base, - qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq, - uint32_t freq_hz, uint32_t system_id, uint32_t capabilities, - uint32_t gpio_strappings) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-sysctl"); - qdev_prop_set_uint32(dev, "frequency", freq_hz); - qdev_prop_set_uint32(dev, "systemid", system_id); - qdev_prop_set_uint32(dev, "capabilities", capabilities); - qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq); - - return dev; -} - -static inline DeviceState *milkymist_pfpu_create(hwaddr base, - qemu_irq irq) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-pfpu"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - return dev; -} - -static inline DeviceState *milkymist_ac97_create(hwaddr base, - qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq, - qemu_irq dmaw_irq) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-ac97"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq); - - return dev; -} - -static inline DeviceState *milkymist_minimac2_create(hwaddr base, - hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq) -{ - DeviceState *dev; - - qemu_check_nic_model(&nd_table[0], "minimac2"); - dev = qdev_new("milkymist-minimac2"); - qdev_set_nic_properties(dev, &nd_table[0]); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq); - - return dev; -} - -static inline DeviceState *milkymist_softusb_create(hwaddr base, - qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size, - uint32_t dmem_base, uint32_t dmem_size) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-softusb"); - qdev_prop_set_uint32(dev, "pmem_size", pmem_size); - qdev_prop_set_uint32(dev, "dmem_size", dmem_size); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; -} - -#endif /* QEMU_HW_MILKYMIST_HW_H */ diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c deleted file mode 100644 index bef7855328..0000000000 --- a/hw/lm32/milkymist.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * QEMU model for the Milkymist board. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/units.h" -#include "qemu/error-report.h" -#include "qemu-common.h" -#include "qemu/datadir.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/irq.h" -#include "hw/block/flash.h" -#include "sysemu/sysemu.h" -#include "sysemu/qtest.h" -#include "sysemu/reset.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/qdev-properties.h" -#include "elf.h" -#include "milkymist-hw.h" -#include "hw/display/milkymist_tmu2.h" -#include "hw/sd/sd.h" -#include "lm32.h" -#include "qemu/cutils.h" - -#define BIOS_FILENAME "mmone-bios.bin" -#define BIOS_OFFSET 0x00860000 -#define BIOS_SIZE (512 * KiB) -#define KERNEL_LOAD_ADDR 0x40000000 - -typedef struct { - LM32CPU *cpu; - hwaddr bootstrap_pc; - hwaddr flash_base; - hwaddr initrd_base; - size_t initrd_size; - hwaddr cmdline_base; -} ResetInfo; - -static void cpu_irq_handler(void *opaque, int irq, int level) -{ - LM32CPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - -static void main_cpu_reset(void *opaque) -{ - ResetInfo *reset_info = opaque; - CPULM32State *env = &reset_info->cpu->env; - - cpu_reset(CPU(reset_info->cpu)); - - /* init defaults */ - env->pc = reset_info->bootstrap_pc; - env->regs[R_R1] = reset_info->cmdline_base; - env->regs[R_R2] = reset_info->initrd_base; - env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size; - env->eba = reset_info->flash_base; - env->deba = reset_info->flash_base; -} - -static DeviceState *milkymist_memcard_create(hwaddr base) -{ - DeviceState *dev; - DriveInfo *dinfo; - - dev = qdev_new("milkymist-memcard"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - dinfo = drive_get_next(IF_SD); - if (dinfo) { - DeviceState *card; - - card = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); - qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"), - &error_fatal); - } - - return dev; -} - -static void -milkymist_init(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *bios_name = machine->firmware ?: BIOS_FILENAME; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - LM32CPU *cpu; - CPULM32State *env; - int kernel_size; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq irq[32]; - int i; - char *bios_filename; - ResetInfo *reset_info; - - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - /* memory map */ - hwaddr flash_base = 0x00000000; - size_t flash_sector_size = 128 * KiB; - size_t flash_size = 32 * MiB; - hwaddr sdram_base = 0x40000000; - - hwaddr initrd_base = sdram_base + 0x1002000; - hwaddr cmdline_base = sdram_base + 0x1000000; - size_t initrd_max = machine->ram_size - 0x1002000; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - cpu = LM32_CPU(cpu_create(machine->cpu_type)); - - env = &cpu->env; - reset_info->cpu = cpu; - - cpu_lm32_set_phys_msb_ignore(env, 1); - - memory_region_add_subregion(address_space_mem, sdram_base, machine->ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Numonyx JS28F256J3F105 */ - pflash_cfi01_register(flash_base, "milkymist.flash", flash_size, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - flash_sector_size, 2, 0x00, 0x89, 0x00, 0x1d, 1); - - /* create irq lines */ - env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - /* load bios rom */ - bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - - if (bios_filename) { - if (load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE) < 0) { - error_report("could not load bios '%s'", bios_filename); - exit(1); - } - } - - reset_info->bootstrap_pc = BIOS_OFFSET; - - /* if no kernel is given no valid bios rom is a fatal error */ - if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) { - error_report("could not load Milkymist One bios '%s'", bios_name); - exit(1); - } - g_free(bios_filename); - - milkymist_uart_create(0x60000000, irq[0], serial_hd(0)); - milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3], - 80000000, 0x10014d31, 0x0000041f, 0x00000001); - milkymist_hpdmc_create(0x60002000); - milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff); - milkymist_memcard_create(0x60004000); - milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]); - milkymist_pfpu_create(0x60006000, irq[8]); - if (machine->enable_graphics) { - milkymist_tmu2_create(0x60007000, irq[9]); - } - milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]); - milkymist_softusb_create(0x6000f000, irq[15], - 0x20000000, 0x1000, 0x20020000, 0x2000); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hd(1)); - - if (kernel_filename) { - uint64_t entry; - - /* Boots a kernel elf binary. */ - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &entry, NULL, NULL, NULL, - 1, EM_LATTICEMICO32, 0, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, sdram_base, - machine->ram_size); - reset_info->bootstrap_pc = sdram_base; - } - - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, - kernel_cmdline); - reset_info->cmdline_base = (uint32_t)cmdline_base; - } - - if (initrd_filename) { - size_t initrd_size; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - initrd_max); - reset_info->initrd_base = (uint32_t)initrd_base; - reset_info->initrd_size = (uint32_t)initrd_size; - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void milkymist_machine_init(MachineClass *mc) -{ - mc->desc = "Milkymist One"; - mc->init = milkymist_init; - mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); - mc->default_ram_size = 128 * MiB; - mc->default_ram_id = "milkymist.sdram"; -} - -DEFINE_MACHINE("milkymist", milkymist_machine_init) diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig index a0ef2cf648..8b19fdc49f 100644 --- a/hw/mem/Kconfig +++ b/hw/mem/Kconfig @@ -7,6 +7,4 @@ config MEM_DEVICE config NVDIMM bool - default y - depends on (PC || PSERIES || ARM_VIRT) select MEM_DEVICE diff --git a/hw/mem/meson.build b/hw/mem/meson.build index ef79e04678..3c8fdef9f9 100644 --- a/hw/mem/meson.build +++ b/hw/mem/meson.build @@ -1,8 +1,9 @@ mem_ss = ss.source_set() mem_ss.add(files('memory-device.c')) -mem_ss.add(when: 'CONFIG_FUZZ', if_true: files('sparse-mem.c')) mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c')) mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c')) mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c')) softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss) + +softmmu_ss.add(when: 'CONFIG_FUZZ', if_true: files('sparse-mem.c')) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 12b655eda8..a3a2560301 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -34,6 +34,16 @@ static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp); +static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) +{ + if (!dimm->hostmem) { + error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set"); + return NULL; + } + + return host_memory_backend_get_memory(dimm->hostmem); +} + void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, const uint64_t *legacy_align, Error **errp) { @@ -66,9 +76,8 @@ void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine) { - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm, - &error_abort); + MemoryRegion *vmstate_mr = pc_dimm_get_memory_region(dimm, + &error_abort); memory_device_plug(MEMORY_DEVICE(dimm), machine); vmstate_register_ram(vmstate_mr, DEVICE(dimm)); @@ -76,9 +85,8 @@ void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine) void pc_dimm_unplug(PCDIMMDevice *dimm, MachineState *machine) { - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm, - &error_abort); + MemoryRegion *vmstate_mr = pc_dimm_get_memory_region(dimm, + &error_abort); memory_device_unplug(MEMORY_DEVICE(dimm), machine); vmstate_unregister_ram(vmstate_mr, DEVICE(dimm)); @@ -205,16 +213,6 @@ static void pc_dimm_unrealize(DeviceState *dev) host_memory_backend_set_mapped(dimm->hostmem, false); } -static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) -{ - if (!dimm->hostmem) { - error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set"); - return NULL; - } - - return host_memory_backend_get_memory(dimm->hostmem); -} - static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md) { return object_property_get_uint(OBJECT(md), PC_DIMM_ADDR_PROP, @@ -266,7 +264,6 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md, static void pc_dimm_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); dc->realize = pc_dimm_realize; @@ -274,8 +271,6 @@ static void pc_dimm_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, pc_dimm_properties); dc->desc = "DIMM memory module"; - ddc->get_vmstate_memory_region = pc_dimm_get_memory_region; - mdc->get_addr = pc_dimm_md_get_addr; mdc->set_addr = pc_dimm_md_set_addr; /* for a dimm plugged_size == region_size */ diff --git a/hw/meson.build b/hw/meson.build index 8ba79b1a52..ba0601e36e 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -21,6 +21,7 @@ subdir('mem') subdir('misc') subdir('net') subdir('nubus') +subdir('nvme') subdir('nvram') subdir('pci') subdir('pci-bridge') @@ -47,11 +48,9 @@ subdir('avr') subdir('cris') subdir('hppa') subdir('i386') -subdir('lm32') subdir('m68k') subdir('microblaze') subdir('mips') -subdir('moxie') subdir('nios2') subdir('openrisc') subdir('ppc') @@ -63,5 +62,4 @@ subdir('sh4') subdir('sparc') subdir('sparc64') subdir('tricore') -subdir('unicore32') subdir('xtensa') diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index dba2088ed1..1e1cf8154e 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -119,30 +119,6 @@ static const MemoryRegionOps dma_dummy_ops = { #define MAGNUM_BIOS_SIZE \ (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX) -#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) -static void (*real_do_transaction_failed)(CPUState *cpu, hwaddr physaddr, - vaddr addr, unsigned size, - MMUAccessType access_type, - int mmu_idx, MemTxAttrs attrs, - MemTxResult response, - uintptr_t retaddr); - -static void mips_jazz_do_transaction_failed(CPUState *cs, hwaddr physaddr, - vaddr addr, unsigned size, - MMUAccessType access_type, - int mmu_idx, MemTxAttrs attrs, - MemTxResult response, - uintptr_t retaddr) -{ - if (access_type != MMU_INST_FETCH) { - /* ignore invalid access (ie do not raise exception) */ - return; - } - (*real_do_transaction_failed)(cs, physaddr, addr, size, access_type, - mmu_idx, attrs, response, retaddr); -} -#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ - static void mips_jazz_init(MachineState *machine, enum jazz_model_e jazz_model) { @@ -151,7 +127,7 @@ static void mips_jazz_init(MachineState *machine, int bios_size, n; Clock *cpuclk; MIPSCPU *cpu; - CPUClass *cc; + MIPSCPUClass *mcc; CPUMIPSState *env; qemu_irq *i8259; rc4030_dma *dmas; @@ -198,8 +174,6 @@ static void mips_jazz_init(MachineState *machine, * However, we can't simply add a global memory region to catch * everything, as this would make all accesses including instruction * accesses be ignored and not raise exceptions. - * So instead we hijack the do_transaction_failed method on the CPU, and - * do not raise exceptions for data access. * * NOTE: this behaviour of raising exceptions for bad instruction * fetches but not bad data accesses was added in commit 54e755588cf1e9 @@ -209,11 +183,8 @@ static void mips_jazz_init(MachineState *machine, * we could replace this hijacking of CPU methods with a simple global * memory region that catches all memory accesses, as we do on Malta. */ - cc = CPU_GET_CLASS(cpu); -#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) - real_do_transaction_failed = cc->tcg_ops->do_transaction_failed; - cc->tcg_ops->do_transaction_failed = mips_jazz_do_transaction_failed; -#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ + mcc = MIPS_CPU_GET_CLASS(cpu); + mcc->no_data_aborts = true; /* allocate RAM */ memory_region_add_subregion(address_space, 0, machine->ram); diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 1e7b8b064b..66e1648533 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -36,9 +36,6 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) -# PKUnity SoC devices -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c')) - subdir('macio') softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) @@ -63,7 +60,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx_ccm.c', 'imx_rngc.c', )) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-hpdmc.c', 'milkymist-pfpu.c')) softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files( 'npcm7xx_clk.c', diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c deleted file mode 100644 index 09a3875f02..0000000000 --- a/hw/misc/milkymist-hpdmc.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * QEMU model of the Milkymist High Performance Dynamic Memory Controller. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/hpdmc.pdf - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_SYSTEM = 0, - R_BYPASS, - R_TIMING, - R_IODELAY, - R_MAX -}; - -enum { - IODELAY_DQSDELAY_RDY = (1<<5), - IODELAY_PLL1_LOCKED = (1<<6), - IODELAY_PLL2_LOCKED = (1<<7), -}; - -#define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistHpdmcState, MILKYMIST_HPDMC) - -struct MilkymistHpdmcState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - uint32_t regs[R_MAX]; -}; - -static uint64_t hpdmc_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistHpdmcState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SYSTEM: - case R_BYPASS: - case R_TIMING: - case R_IODELAY: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_hpdmc: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_hpdmc_memory_read(addr << 2, r); - - return r; -} - -static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistHpdmcState *s = opaque; - - trace_milkymist_hpdmc_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_SYSTEM: - case R_BYPASS: - case R_TIMING: - s->regs[addr] = value; - break; - case R_IODELAY: - /* ignore writes */ - break; - - default: - error_report("milkymist_hpdmc: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps hpdmc_mmio_ops = { - .read = hpdmc_read, - .write = hpdmc_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_hpdmc_reset(DeviceState *d) -{ - MilkymistHpdmcState *s = MILKYMIST_HPDMC(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED - | IODELAY_PLL2_LOCKED; -} - -static void milkymist_hpdmc_realize(DeviceState *dev, Error **errp) -{ - MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev); - - memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s, - "milkymist-hpdmc", R_MAX * 4); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_hpdmc = { - .name = "milkymist-hpdmc", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_hpdmc_realize; - dc->reset = milkymist_hpdmc_reset; - dc->vmsd = &vmstate_milkymist_hpdmc; -} - -static const TypeInfo milkymist_hpdmc_info = { - .name = TYPE_MILKYMIST_HPDMC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistHpdmcState), - .class_init = milkymist_hpdmc_class_init, -}; - -static void milkymist_hpdmc_register_types(void) -{ - type_register_static(&milkymist_hpdmc_info); -} - -type_init(milkymist_hpdmc_register_types) diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c deleted file mode 100644 index e4ee209c10..0000000000 --- a/hw/misc/milkymist-pfpu.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * QEMU model of the Milkymist programmable FPU. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/pfpu.pdf - * - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/error-report.h" -#include <math.h> -#include "qom/object.h" - -/* #define TRACE_EXEC */ - -#ifdef TRACE_EXEC -# define D_EXEC(x) x -#else -# define D_EXEC(x) -#endif - -enum { - R_CTL = 0, - R_MESHBASE, - R_HMESHLAST, - R_VMESHLAST, - R_CODEPAGE, - R_VERTICES, - R_COLLISIONS, - R_STRAYWRITES, - R_LASTDMA, - R_PC, - R_DREGBASE, - R_CODEBASE, - R_MAX -}; - -enum { - CTL_START_BUSY = (1<<0), -}; - -enum { - OP_NOP = 0, - OP_FADD, - OP_FSUB, - OP_FMUL, - OP_FABS, - OP_F2I, - OP_I2F, - OP_VECTOUT, - OP_SIN, - OP_COS, - OP_ABOVE, - OP_EQUAL, - OP_COPY, - OP_IF, - OP_TSIGN, - OP_QUAKE, -}; - -enum { - GPR_X = 0, - GPR_Y = 1, - GPR_FLAGS = 2, -}; - -enum { - LATENCY_FADD = 5, - LATENCY_FSUB = 5, - LATENCY_FMUL = 7, - LATENCY_FABS = 2, - LATENCY_F2I = 2, - LATENCY_I2F = 3, - LATENCY_VECTOUT = 0, - LATENCY_SIN = 4, - LATENCY_COS = 4, - LATENCY_ABOVE = 2, - LATENCY_EQUAL = 2, - LATENCY_COPY = 2, - LATENCY_IF = 2, - LATENCY_TSIGN = 2, - LATENCY_QUAKE = 2, - MAX_LATENCY = 7 -}; - -#define GPR_BEGIN 0x100 -#define GPR_END 0x17f -#define MICROCODE_BEGIN 0x200 -#define MICROCODE_END 0x3ff -#define MICROCODE_WORDS 2048 - -#define REINTERPRET_CAST(type, val) (*((type *)&(val))) - -#ifdef TRACE_EXEC -static const char *opcode_to_str[] = { - "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT", - "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE", -}; -#endif - -#define TYPE_MILKYMIST_PFPU "milkymist-pfpu" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistPFPUState, MILKYMIST_PFPU) - -struct MilkymistPFPUState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - Chardev *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; - uint32_t gp_regs[128]; - uint32_t microcode[MICROCODE_WORDS]; - - int output_queue_pos; - uint32_t output_queue[MAX_LATENCY]; -}; - -static inline uint32_t -get_dma_address(uint32_t base, uint32_t x, uint32_t y) -{ - return base + 8 * (128 * y + x); -} - -static inline void -output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos) -{ - s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val; -} - -static inline uint32_t -output_queue_remove(MilkymistPFPUState *s) -{ - return s->output_queue[s->output_queue_pos]; -} - -static inline void -output_queue_advance(MilkymistPFPUState *s) -{ - s->output_queue[s->output_queue_pos] = 0; - s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY; -} - -static int pfpu_decode_insn(MilkymistPFPUState *s) -{ - uint32_t pc = s->regs[R_PC]; - uint32_t insn = s->microcode[pc]; - uint32_t reg_a = (insn >> 18) & 0x7f; - uint32_t reg_b = (insn >> 11) & 0x7f; - uint32_t op = (insn >> 7) & 0xf; - uint32_t reg_d = insn & 0x7f; - uint32_t r = 0; - int latency = 0; - - switch (op) { - case OP_NOP: - break; - case OP_FADD: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a + b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FADD; - D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FSUB: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a - b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FSUB; - D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FMUL: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a * b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FMUL; - D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FABS: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float t = fabsf(a); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FABS; - D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r)); - } break; - case OP_F2I: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - int32_t t = a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_F2I; - D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r)); - } break; - case OP_I2F: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_I2F; - D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r)); - } break; - case OP_VECTOUT: - { - uint32_t a = cpu_to_be32(s->gp_regs[reg_a]); - uint32_t b = cpu_to_be32(s->gp_regs[reg_b]); - hwaddr dma_ptr = - get_dma_address(s->regs[R_MESHBASE], - s->gp_regs[GPR_X], s->gp_regs[GPR_Y]); - cpu_physical_memory_write(dma_ptr, &a, 4); - cpu_physical_memory_write(dma_ptr + 4, &b, 4); - s->regs[R_LASTDMA] = dma_ptr + 4; - D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr)); - trace_milkymist_pfpu_vectout(a, b, dma_ptr); - } break; - case OP_SIN: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = sinf(a * (1.0f / (M_PI * 4096.0f))); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_SIN; - D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r)); - } break; - case OP_COS: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = cosf(a * (1.0f / (M_PI * 4096.0f))); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_COS; - D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r)); - } break; - case OP_ABOVE: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (a > b) ? 1.0f : 0.0f; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_ABOVE; - D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_EQUAL: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (a == b) ? 1.0f : 0.0f; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_EQUAL; - D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_COPY: - { - r = s->gp_regs[reg_a]; - latency = LATENCY_COPY; - D_EXEC(qemu_log("COPY")); - } break; - case OP_IF: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - uint32_t f = s->gp_regs[GPR_FLAGS]; - float t = (f != 0) ? a : b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_IF; - D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r)); - } break; - case OP_TSIGN: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (b < 0) ? -a : a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_TSIGN; - D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_QUAKE: - { - uint32_t a = s->gp_regs[reg_a]; - r = 0x5f3759df - (a >> 1); - latency = LATENCY_QUAKE; - D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r)); - } break; - - default: - error_report("milkymist_pfpu: unknown opcode %d", op); - break; - } - - if (!reg_d) { - D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n", - s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, - s->regs[R_PC] + latency)); - } else { - D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n", - s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, - s->regs[R_PC] + latency, reg_d)); - } - - if (op == OP_VECTOUT) { - return 0; - } - - /* store output for this cycle */ - if (reg_d) { - uint32_t val = output_queue_remove(s); - D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val)); - s->gp_regs[reg_d] = val; - } - - output_queue_advance(s); - - /* store op output */ - if (op != OP_NOP) { - output_queue_insert(s, r, latency-1); - } - - /* advance PC */ - s->regs[R_PC]++; - - return 1; -}; - -static void pfpu_start(MilkymistPFPUState *s) -{ - int x, y; - int i; - - for (y = 0; y <= s->regs[R_VMESHLAST]; y++) { - for (x = 0; x <= s->regs[R_HMESHLAST]; x++) { - D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y)); - - /* set current position */ - s->gp_regs[GPR_X] = x; - s->gp_regs[GPR_Y] = y; - - /* run microcode on this position */ - i = 0; - while (pfpu_decode_insn(s)) { - /* decode at most MICROCODE_WORDS instructions */ - if (++i >= MICROCODE_WORDS) { - error_report("milkymist_pfpu: too many instructions " - "executed in microcode. No VECTOUT?"); - break; - } - } - - /* reset pc for next run */ - s->regs[R_PC] = 0; - } - } - - s->regs[R_VERTICES] = x * y; - - trace_milkymist_pfpu_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr) -{ - return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN; -} - -static uint64_t pfpu_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistPFPUState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTL: - case R_MESHBASE: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CODEPAGE: - case R_VERTICES: - case R_COLLISIONS: - case R_STRAYWRITES: - case R_LASTDMA: - case R_PC: - case R_DREGBASE: - case R_CODEBASE: - r = s->regs[addr]; - break; - case GPR_BEGIN ... GPR_END: - r = s->gp_regs[addr - GPR_BEGIN]; - break; - case MICROCODE_BEGIN ... MICROCODE_END: - r = s->microcode[get_microcode_address(s, addr)]; - break; - - default: - error_report("milkymist_pfpu: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_pfpu_memory_read(addr << 2, r); - - return r; -} - -static void pfpu_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistPFPUState *s = opaque; - - trace_milkymist_pfpu_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTL: - if (value & CTL_START_BUSY) { - pfpu_start(s); - } - break; - case R_MESHBASE: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CODEPAGE: - case R_VERTICES: - case R_COLLISIONS: - case R_STRAYWRITES: - case R_LASTDMA: - case R_PC: - case R_DREGBASE: - case R_CODEBASE: - s->regs[addr] = value; - break; - case GPR_BEGIN ... GPR_END: - s->gp_regs[addr - GPR_BEGIN] = value; - break; - case MICROCODE_BEGIN ... MICROCODE_END: - s->microcode[get_microcode_address(s, addr)] = value; - break; - - default: - error_report("milkymist_pfpu: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps pfpu_mmio_ops = { - .read = pfpu_read, - .write = pfpu_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_pfpu_reset(DeviceState *d) -{ - MilkymistPFPUState *s = MILKYMIST_PFPU(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - for (i = 0; i < 128; i++) { - s->gp_regs[i] = 0; - } - for (i = 0; i < MICROCODE_WORDS; i++) { - s->microcode[i] = 0; - } - s->output_queue_pos = 0; - for (i = 0; i < MAX_LATENCY; i++) { - s->output_queue[i] = 0; - } -} - -static void milkymist_pfpu_realize(DeviceState *dev, Error **errp) -{ - MilkymistPFPUState *s = MILKYMIST_PFPU(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(dev), &pfpu_mmio_ops, s, - "milkymist-pfpu", MICROCODE_END * 4); - sysbus_init_mmio(sbd, &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_pfpu = { - .name = "milkymist-pfpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), - VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), - VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), - VMSTATE_INT32(output_queue_pos, MilkymistPFPUState), - VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_pfpu_realize; - dc->reset = milkymist_pfpu_reset; - dc->vmsd = &vmstate_milkymist_pfpu; -} - -static const TypeInfo milkymist_pfpu_info = { - .name = TYPE_MILKYMIST_PFPU, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistPFPUState), - .class_init = milkymist_pfpu_class_init, -}; - -static void milkymist_pfpu_register_types(void) -{ - type_register_static(&milkymist_pfpu_info); -} - -type_init(milkymist_pfpu_register_types) diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c index c56aca86ad..b3b42a792c 100644 --- a/hw/misc/mps2-scc.c +++ b/hw/misc/mps2-scc.c @@ -23,6 +23,7 @@ #include "qemu/bitops.h" #include "trace.h" #include "hw/sysbus.h" +#include "hw/irq.h" #include "migration/vmstate.h" #include "hw/registerfields.h" #include "hw/misc/mps2-scc.h" @@ -186,10 +187,13 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case A_CFG0: /* - * TODO on some boards bit 0 controls RAM remapping; - * on others bit 1 is CPU_WAIT. + * On some boards bit 0 controls board-specific remapping; + * we always reflect bit 0 in the 'remap' GPIO output line, + * and let the board wire it up or not as it chooses. + * TODO on some boards bit 1 is CPU_WAIT. */ s->cfg0 = value; + qemu_set_irq(s->remap, s->cfg0 & 1); break; case A_CFG1: s->cfg1 = value; @@ -283,7 +287,7 @@ static void mps2_scc_reset(DeviceState *dev) int i; trace_mps2_scc_reset(); - s->cfg0 = 0; + s->cfg0 = s->cfg0_reset; s->cfg1 = 0; s->cfg2 = 0; s->cfg5 = 0; @@ -308,6 +312,7 @@ static void mps2_scc_init(Object *obj) memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_out_named(DEVICE(obj), &s->remap, "remap", 1); } static void mps2_scc_realize(DeviceState *dev, Error **errp) @@ -353,6 +358,8 @@ static Property mps2_scc_properties[] = { DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0), DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0), DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0), + /* Reset value for CFG0 register */ + DEFINE_PROP_UINT32("scc-cfg0", MPS2SCC, cfg0_reset, 0), /* * These are the initial settings for the source clocks on the board. * In hardware they can be configured via a config file read by the diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c deleted file mode 100644 index 676c23f7db..0000000000 --- a/hw/misc/puv3_pm.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Power Management device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define TYPE_PUV3_PM "puv3_pm" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3PMState, PUV3_PM) - -struct PUV3PMState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - uint32_t reg_PMCR; - uint32_t reg_PCGR; - uint32_t reg_PLL_SYS_CFG; - uint32_t reg_PLL_DDR_CFG; - uint32_t reg_PLL_VGA_CFG; - uint32_t reg_DIVCFG; -}; - -static uint64_t puv3_pm_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3PMState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x14: - ret = s->reg_PCGR; - break; - case 0x18: - ret = s->reg_PLL_SYS_CFG; - break; - case 0x1c: - ret = s->reg_PLL_DDR_CFG; - break; - case 0x20: - ret = s->reg_PLL_VGA_CFG; - break; - case 0x24: - ret = s->reg_DIVCFG; - break; - case 0x28: /* PLL SYS STATUS */ - ret = 0x00002401; - break; - case 0x2c: /* PLL DDR STATUS */ - ret = 0x00100c00; - break; - case 0x30: /* PLL VGA STATUS */ - ret = 0x00003801; - break; - case 0x34: /* DIV STATUS */ - ret = 0x22f52015; - break; - case 0x38: /* SW RESET */ - ret = 0x0; - break; - case 0x44: /* PLL DFC DONE */ - ret = 0x7; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - - return ret; -} - -static void puv3_pm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3PMState *s = opaque; - - switch (offset) { - case 0x0: - s->reg_PMCR = value; - break; - case 0x14: - s->reg_PCGR = value; - break; - case 0x18: - s->reg_PLL_SYS_CFG = value; - break; - case 0x1c: - s->reg_PLL_DDR_CFG = value; - break; - case 0x20: - s->reg_PLL_VGA_CFG = value; - break; - case 0x24: - case 0x38: - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); -} - -static const MemoryRegionOps puv3_pm_ops = { - .read = puv3_pm_read, - .write = puv3_pm_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_pm_realize(DeviceState *dev, Error **errp) -{ - PUV3PMState *s = PUV3_PM(dev); - - s->reg_PCGR = 0x0; - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm", - PUV3_REGS_OFFSET); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); -} - -static void puv3_pm_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_pm_realize; -} - -static const TypeInfo puv3_pm_info = { - .name = TYPE_PUV3_PM, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3PMState), - .class_init = puv3_pm_class_init, -}; - -static void puv3_pm_register_type(void) -{ - type_register_static(&puv3_pm_info); -} - -type_init(puv3_pm_register_type) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index d0a89eb059..0752217636 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -67,16 +67,6 @@ slavio_sysctrl_mem_readl(uint32_t ret) "Read system control 0x%08x" slavio_led_mem_writew(uint32_t val) "Write diagnostic LED 0x%04x" slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x" -# milkymist-hpdmc.c -milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x" -milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x" - -# milkymist-pfpu.c -milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a 0x%08x b 0x%08x dma_ptr 0x%08x" -milkymist_pfpu_pulse_irq(void) "Pulse IRQ" - # aspeed_scu.c aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 diff --git a/hw/moxie/Kconfig b/hw/moxie/Kconfig deleted file mode 100644 index 3793ef0372..0000000000 --- a/hw/moxie/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -config MOXIESIM - bool - select SERIAL diff --git a/hw/moxie/meson.build b/hw/moxie/meson.build deleted file mode 100644 index 05a7c2e00f..0000000000 --- a/hw/moxie/meson.build +++ /dev/null @@ -1,4 +0,0 @@ -moxie_ss = ss.source_set() -moxie_ss.add(when: 'CONFIG_MOXIESIM', if_true: files('moxiesim.c')) - -hw_arch += {'moxie': moxie_ss} diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c deleted file mode 100644 index 3d255d4879..0000000000 --- a/hw/moxie/moxiesim.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * QEMU/moxiesim emulation - * - * Emulates a very simple machine model similar to the one used by the - * GDB moxie simulator. - * - * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qapi/error.h" -#include "cpu.h" -#include "net/net.h" -#include "sysemu/reset.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/char/serial.h" -#include "elf.h" - -#define PHYS_MEM_BASE 0x80000000 -#define FIRMWARE_BASE 0x1000 -#define FIRMWARE_SIZE (128 * 0x1000) - -typedef struct { - uint64_t ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} LoaderParams; - -static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) -{ - uint64_t entry, kernel_high; - int64_t initrd_size; - long kernel_size; - ram_addr_t initrd_offset; - - kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL, NULL, - &entry, NULL, &kernel_high, NULL, 1, EM_MOXIE, - 0, 0); - - if (kernel_size <= 0) { - error_report("could not load kernel '%s'", - loader_params->kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (loader_params->initrd_filename) { - initrd_size = get_image_size(loader_params->initrd_filename); - if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) - & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > loader_params->ram_size) { - error_report("memory too small for initial ram disk '%s'", - loader_params->initrd_filename); - exit(1); - } - initrd_size = load_image_targphys(loader_params->initrd_filename, - initrd_offset, - loader_params->ram_size); - } - if (initrd_size == (target_ulong)-1) { - error_report("could not load initial ram disk '%s'", - loader_params->initrd_filename); - exit(1); - } - } -} - -static void main_cpu_reset(void *opaque) -{ - MoxieCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -static void moxiesim_init(MachineState *machine) -{ - MoxieCPU *cpu = NULL; - ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - CPUMoxieState *env; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *rom = g_new(MemoryRegion, 1); - hwaddr ram_base = 0x200000; - LoaderParams loader_params; - - /* Init CPUs. */ - cpu = MOXIE_CPU(cpu_create(machine->cpu_type)); - env = &cpu->env; - - qemu_register_reset(main_cpu_reset, cpu); - - /* Allocate RAM. */ - memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal); - memory_region_add_subregion(address_space_mem, ram_base, ram); - - memory_region_init_ram(rom, NULL, "moxie.rom", FIRMWARE_SIZE, &error_fatal); - memory_region_add_subregion(get_system_memory(), FIRMWARE_BASE, rom); - - if (kernel_filename) { - loader_params.ram_size = ram_size; - loader_params.kernel_filename = kernel_filename; - loader_params.kernel_cmdline = kernel_cmdline; - loader_params.initrd_filename = initrd_filename; - load_kernel(cpu, &loader_params); - } - if (machine->firmware) { - if (load_image_targphys(machine->firmware, FIRMWARE_BASE, FIRMWARE_SIZE) < 0) { - error_report("Failed to load firmware '%s'", machine->firmware); - } - } - - /* A single 16450 sits at offset 0x3f8. */ - if (serial_hd(0)) { - serial_mm_init(address_space_mem, 0x3f8, 0, env->irq[4], - 8000000/16, serial_hd(0), DEVICE_LITTLE_ENDIAN); - } -} - -static void moxiesim_machine_init(MachineClass *mc) -{ - mc->desc = "Moxie simulator platform"; - mc->init = moxiesim_init; - mc->is_default = true; - mc->default_cpu_type = MOXIE_CPU_TYPE_NAME("MoxieLite"); -} - -DEFINE_MACHINE("moxiesim", moxiesim_machine_init) diff --git a/hw/net/meson.build b/hw/net/meson.build index af0749c42b..bdf71f1f40 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -39,7 +39,6 @@ softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c')) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c')) softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c')) -specific_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-minimac2.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c')) specific_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c')) diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c deleted file mode 100644 index 5826944fd5..0000000000 --- a/hw/net/milkymist-minimac2.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * QEMU model of the Milkymist minimac2 block. - * - * Copyright (c) 2011 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * not available yet - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qom/object.h" -#include "cpu.h" /* FIXME: why does this use TARGET_PAGE_ALIGN? */ -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "net/net.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/error-report.h" - -#include <zlib.h> - -enum { - R_SETUP = 0, - R_MDIO, - R_STATE0, - R_COUNT0, - R_STATE1, - R_COUNT1, - R_TXCOUNT, - R_MAX -}; - -enum { - SETUP_PHY_RST = (1<<0), -}; - -enum { - MDIO_DO = (1<<0), - MDIO_DI = (1<<1), - MDIO_OE = (1<<2), - MDIO_CLK = (1<<3), -}; - -enum { - STATE_EMPTY = 0, - STATE_LOADED = 1, - STATE_PENDING = 2, -}; - -enum { - MDIO_OP_WRITE = 1, - MDIO_OP_READ = 2, -}; - -enum mdio_state { - MDIO_STATE_IDLE, - MDIO_STATE_READING, - MDIO_STATE_WRITING, -}; - -enum { - R_PHY_ID1 = 2, - R_PHY_ID2 = 3, - R_PHY_MAX = 32 -}; - -#define MINIMAC2_MTU 1530 -#define MINIMAC2_BUFFER_SIZE 2048 - -struct MilkymistMinimac2MdioState { - int last_clk; - int count; - uint32_t data; - uint16_t data_out; - int state; - - uint8_t phy_addr; - uint8_t reg_addr; -}; -typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState; - -#define TYPE_MILKYMIST_MINIMAC2 "milkymist-minimac2" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMinimac2State, MILKYMIST_MINIMAC2) - -struct MilkymistMinimac2State { - SysBusDevice parent_obj; - - NICState *nic; - NICConf conf; - char *phy_model; - MemoryRegion buffers; - MemoryRegion regs_region; - - qemu_irq rx_irq; - qemu_irq tx_irq; - - uint32_t regs[R_MAX]; - - MilkymistMinimac2MdioState mdio; - - uint16_t phy_regs[R_PHY_MAX]; - - uint8_t *rx0_buf; - uint8_t *rx1_buf; - uint8_t *tx_buf; -}; - -static const uint8_t preamble_sfd[] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5 -}; - -static void minimac2_mdio_write_reg(MilkymistMinimac2State *s, - uint8_t phy_addr, uint8_t reg_addr, uint16_t value) -{ - trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value); - - /* nop */ -} - -static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s, - uint8_t phy_addr, uint8_t reg_addr) -{ - uint16_t r = s->phy_regs[reg_addr]; - - trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r); - - return r; -} - -static void minimac2_update_mdio(MilkymistMinimac2State *s) -{ - MilkymistMinimac2MdioState *m = &s->mdio; - - /* detect rising clk edge */ - if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) { - /* shift data in */ - int bit = ((s->regs[R_MDIO] & MDIO_DO) - && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0; - m->data = (m->data << 1) | bit; - - /* check for sync */ - if (m->data == 0xffffffff) { - m->count = 32; - } - - if (m->count == 16) { - uint8_t start = (m->data >> 14) & 0x3; - uint8_t op = (m->data >> 12) & 0x3; - uint8_t ta = (m->data) & 0x3; - - if (start == 1 && op == MDIO_OP_WRITE && ta == 2) { - m->state = MDIO_STATE_WRITING; - } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) { - m->state = MDIO_STATE_READING; - } else { - m->state = MDIO_STATE_IDLE; - } - - if (m->state != MDIO_STATE_IDLE) { - m->phy_addr = (m->data >> 7) & 0x1f; - m->reg_addr = (m->data >> 2) & 0x1f; - } - - if (m->state == MDIO_STATE_READING) { - m->data_out = minimac2_mdio_read_reg(s, m->phy_addr, - m->reg_addr); - } - } - - if (m->count < 16 && m->state == MDIO_STATE_READING) { - int bit = (m->data_out & 0x8000) ? 1 : 0; - m->data_out <<= 1; - - if (bit) { - s->regs[R_MDIO] |= MDIO_DI; - } else { - s->regs[R_MDIO] &= ~MDIO_DI; - } - } - - if (m->count == 0 && m->state) { - if (m->state == MDIO_STATE_WRITING) { - uint16_t data = m->data & 0xffff; - minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data); - } - m->state = MDIO_STATE_IDLE; - } - m->count--; - } - - m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0; -} - -static size_t assemble_frame(uint8_t *buf, size_t size, - const uint8_t *payload, size_t payload_size) -{ - uint32_t crc; - - if (size < payload_size + 12) { - qemu_log_mask(LOG_GUEST_ERROR, "milkymist_minimac2: frame too big " - "(%zd bytes)\n", payload_size); - return 0; - } - - /* prepend preamble and sfd */ - memcpy(buf, preamble_sfd, 8); - - /* now copy the payload */ - memcpy(buf + 8, payload, payload_size); - - /* pad frame if needed */ - if (payload_size < 60) { - memset(buf + payload_size + 8, 0, 60 - payload_size); - payload_size = 60; - } - - /* append fcs */ - crc = cpu_to_le32(crc32(0, buf + 8, payload_size)); - memcpy(buf + payload_size + 8, &crc, 4); - - return payload_size + 12; -} - -static void minimac2_tx(MilkymistMinimac2State *s) -{ - uint32_t txcount = s->regs[R_TXCOUNT]; - uint8_t *buf = s->tx_buf; - - if (txcount < 64) { - error_report("milkymist_minimac2: ethernet frame too small (%u < %u)", - txcount, 64); - goto err; - } - - if (txcount > MINIMAC2_MTU) { - error_report("milkymist_minimac2: MTU exceeded (%u > %u)", - txcount, MINIMAC2_MTU); - goto err; - } - - if (memcmp(buf, preamble_sfd, 8) != 0) { - error_report("milkymist_minimac2: frame doesn't contain the preamble " - "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - goto err; - } - - trace_milkymist_minimac2_tx_frame(txcount - 12); - - /* send packet, skipping preamble and sfd */ - qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12); - - s->regs[R_TXCOUNT] = 0; - -err: - trace_milkymist_minimac2_pulse_irq_tx(); - qemu_irq_pulse(s->tx_irq); -} - -static void update_rx_interrupt(MilkymistMinimac2State *s) -{ - if (s->regs[R_STATE0] == STATE_PENDING - || s->regs[R_STATE1] == STATE_PENDING) { - trace_milkymist_minimac2_raise_irq_rx(); - qemu_irq_raise(s->rx_irq); - } else { - trace_milkymist_minimac2_lower_irq_rx(); - qemu_irq_lower(s->rx_irq); - } -} - -static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size) -{ - MilkymistMinimac2State *s = qemu_get_nic_opaque(nc); - - uint32_t r_count; - uint32_t r_state; - uint8_t *rx_buf; - - size_t frame_size; - - trace_milkymist_minimac2_rx_frame(buf, size); - - /* choose appropriate slot */ - if (s->regs[R_STATE0] == STATE_LOADED) { - r_count = R_COUNT0; - r_state = R_STATE0; - rx_buf = s->rx0_buf; - } else if (s->regs[R_STATE1] == STATE_LOADED) { - r_count = R_COUNT1; - r_state = R_STATE1; - rx_buf = s->rx1_buf; - } else { - return 0; - } - - /* assemble frame */ - frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size); - - if (frame_size == 0) { - return size; - } - - trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size); - - /* update slot */ - s->regs[r_count] = frame_size; - s->regs[r_state] = STATE_PENDING; - - update_rx_interrupt(s); - - return size; -} - -static uint64_t -minimac2_read(void *opaque, hwaddr addr, unsigned size) -{ - MilkymistMinimac2State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SETUP: - case R_MDIO: - case R_STATE0: - case R_COUNT0: - case R_STATE1: - case R_COUNT1: - case R_TXCOUNT: - r = s->regs[addr]; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "milkymist_minimac2_rd%d: 0x%" HWADDR_PRIx "\n", - size, addr << 2); - break; - } - - trace_milkymist_minimac2_memory_read(addr << 2, r); - - return r; -} - -static int minimac2_can_rx(MilkymistMinimac2State *s) -{ - if (s->regs[R_STATE0] == STATE_LOADED) { - return 1; - } - if (s->regs[R_STATE1] == STATE_LOADED) { - return 1; - } - - return 0; -} - -static void -minimac2_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistMinimac2State *s = opaque; - - trace_milkymist_minimac2_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_MDIO: - { - /* MDIO_DI is read only */ - int mdio_di = (s->regs[R_MDIO] & MDIO_DI); - s->regs[R_MDIO] = value; - if (mdio_di) { - s->regs[R_MDIO] |= mdio_di; - } else { - s->regs[R_MDIO] &= ~mdio_di; - } - - minimac2_update_mdio(s); - } break; - case R_TXCOUNT: - s->regs[addr] = value; - if (value > 0) { - minimac2_tx(s); - } - break; - case R_STATE0: - case R_STATE1: - s->regs[addr] = value; - update_rx_interrupt(s); - if (minimac2_can_rx(s)) { - qemu_flush_queued_packets(qemu_get_queue(s->nic)); - } - break; - case R_SETUP: - case R_COUNT0: - case R_COUNT1: - s->regs[addr] = value; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "milkymist_minimac2_wr%d: 0x%" HWADDR_PRIx - " = 0x%" PRIx64 "\n", - size, addr << 2, value); - break; - } -} - -static const MemoryRegionOps minimac2_ops = { - .read = minimac2_read, - .write = minimac2_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_minimac2_reset(DeviceState *d) -{ - MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - for (i = 0; i < R_PHY_MAX; i++) { - s->phy_regs[i] = 0; - } - - /* defaults */ - s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */ - s->phy_regs[R_PHY_ID2] = 0x161a; -} - -static NetClientInfo net_milkymist_minimac2_info = { - .type = NET_CLIENT_DRIVER_NIC, - .size = sizeof(NICState), - .receive = minimac2_rx, -}; - -static void milkymist_minimac2_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev); - size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE); - - sysbus_init_irq(sbd, &s->rx_irq); - sysbus_init_irq(sbd, &s->tx_irq); - - memory_region_init_io(&s->regs_region, OBJECT(dev), &minimac2_ops, s, - "milkymist-minimac2", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); - - /* register buffers memory */ - memory_region_init_ram_nomigrate(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers", - buffers_size, &error_fatal); - vmstate_register_ram_global(&s->buffers); - s->rx0_buf = memory_region_get_ram_ptr(&s->buffers); - s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE; - s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE; - - sysbus_init_mmio(sbd, &s->buffers); - - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->id, s); - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); -} - -static const VMStateDescription vmstate_milkymist_minimac2_mdio = { - .name = "milkymist-minimac2-mdio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState), - VMSTATE_INT32(count, MilkymistMinimac2MdioState), - VMSTATE_UINT32(data, MilkymistMinimac2MdioState), - VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState), - VMSTATE_INT32(state, MilkymistMinimac2MdioState), - VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState), - VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_milkymist_minimac2 = { - .name = "milkymist-minimac2", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX), - VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX), - VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0, - vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_minimac2_properties[] = { - DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf), - DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_minimac2_realize; - dc->reset = milkymist_minimac2_reset; - dc->vmsd = &vmstate_milkymist_minimac2; - device_class_set_props(dc, milkymist_minimac2_properties); -} - -static const TypeInfo milkymist_minimac2_info = { - .name = TYPE_MILKYMIST_MINIMAC2, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistMinimac2State), - .class_init = milkymist_minimac2_class_init, -}; - -static void milkymist_minimac2_register_types(void) -{ - type_register_static(&milkymist_minimac2_info); -} - -type_init(milkymist_minimac2_register_types) diff --git a/hw/net/trace-events b/hw/net/trace-events index 78e85660bf..1704bb0664 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -19,18 +19,6 @@ mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) " lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x" lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x" -# milkymist-minimac2.c -milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x" -milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x" -milkymist_minimac2_tx_frame(uint32_t length) "length %u" -milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u" -milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" -milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX" -milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX" -milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX" - # mipsnet.c mipsnet_send(uint32_t size) "sending len=%u" mipsnet_receive(uint32_t size) "receiving len=%u" diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 914051feb7..05bd50d3f6 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -89,7 +89,7 @@ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) -static VirtIOFeature feature_sizes[] = { +static const VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_NET_F_MAC, .end = endof(struct virtio_net_config, mac)}, {.flags = 1ULL << VIRTIO_NET_F_STATUS, diff --git a/hw/nvme/Kconfig b/hw/nvme/Kconfig new file mode 100644 index 0000000000..8ac90942e5 --- /dev/null +++ b/hw/nvme/Kconfig @@ -0,0 +1,4 @@ +config NVME_PCI + bool + default y if PCI_DEVICES + depends on PCI diff --git a/hw/block/nvme.c b/hw/nvme/ctrl.c index 5fe082ec34..0bcaf7192f 100644 --- a/hw/block/nvme.c +++ b/hw/nvme/ctrl.c @@ -12,10 +12,19 @@ * Reference Specs: http://www.nvmexpress.org, 1.4, 1.3, 1.2, 1.1, 1.0e * * https://nvmexpress.org/developers/nvme-specification/ - */ - -/** - * Usage: add options: + * + * + * Notes on coding style + * --------------------- + * While QEMU coding style prefers lowercase hexadecimals in constants, the + * NVMe subsystem use thes format from the NVMe specifications in the comments + * (i.e. 'h' suffix instead of '0x' prefix). + * + * Usage + * ----- + * See docs/system/nvme.rst for extensive documentation. + * + * Add options: * -drive file=<file>,if=none,id=<drive_id> * -device nvme-subsys,id=<subsys_id>,nqn=<nqn_id> * -device nvme,serial=<serial>,id=<bus_name>, \ @@ -135,26 +144,20 @@ */ #include "qemu/osdep.h" -#include "qemu/units.h" +#include "qemu/cutils.h" #include "qemu/error-report.h" -#include "hw/block/block.h" -#include "hw/pci/msix.h" -#include "hw/pci/pci.h" -#include "hw/qdev-properties.h" -#include "migration/vmstate.h" -#include "sysemu/sysemu.h" +#include "qemu/log.h" +#include "qemu/units.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "sysemu/hostmem.h" +#include "sysemu/sysemu.h" #include "sysemu/block-backend.h" -#include "exec/memory.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/cutils.h" -#include "trace.h" +#include "sysemu/hostmem.h" +#include "hw/pci/msix.h" +#include "migration/vmstate.h" + #include "nvme.h" -#include "nvme-ns.h" -#include "nvme-dif.h" +#include "trace.h" #define NVME_MAX_IOQPAIRS 0xffff #define NVME_DB_SIZE 4 @@ -165,6 +168,7 @@ #define NVME_TEMPERATURE_WARNING 0x157 #define NVME_TEMPERATURE_CRITICAL 0x175 #define NVME_NUM_FW_SLOTS 1 +#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB) #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ @@ -185,6 +189,7 @@ static const bool nvme_feature_support[NVME_FID_MAX] = { [NVME_WRITE_ATOMICITY] = true, [NVME_ASYNCHRONOUS_EVENT_CONF] = true, [NVME_TIMESTAMP] = true, + [NVME_COMMAND_SET_PROFILE] = true, }; static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { @@ -194,6 +199,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { [NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE, [NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE, [NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE, + [NVME_COMMAND_SET_PROFILE] = NVME_FEAT_CAP_CHANGE, }; static const uint32_t nvme_cse_acs[256] = { @@ -387,7 +393,8 @@ static int nvme_addr_write(NvmeCtrl *n, hwaddr addr, void *buf, int size) static bool nvme_nsid_valid(NvmeCtrl *n, uint32_t nsid) { - return nsid && (nsid == NVME_NSID_BROADCAST || nsid <= n->num_namespaces); + return nsid && + (nsid == NVME_NSID_BROADCAST || nsid <= NVME_MAX_NAMESPACES); } static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) @@ -511,9 +518,7 @@ static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data, NvmeSg *mdata) { NvmeSg *dst = data; - size_t size = nvme_lsize(ns); - size_t msize = nvme_msize(ns); - uint32_t trans_len, count = size; + uint32_t trans_len, count = ns->lbasz; uint64_t offset = 0; bool dma = sg->flags & NVME_SG_DMA; size_t sge_len; @@ -545,7 +550,7 @@ static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data, if (count == 0) { dst = (dst == data) ? mdata : data; - count = (dst == data) ? size : msize; + count = (dst == data) ? ns->lbasz : ns->lbaf.ms; } if (sge_len == offset) { @@ -574,7 +579,7 @@ static uint16_t nvme_map_addr_cmb(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr, } static uint16_t nvme_map_addr_pmr(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr, - size_t len) + size_t len) { if (!len) { return NVME_SUCCESS; @@ -1004,7 +1009,7 @@ static uint16_t nvme_map_data(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) uint16_t status; if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) && - (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) { + (ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8)) { goto out; } @@ -1187,12 +1192,9 @@ uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, uint16_t ctrl = le16_to_cpu(rw->control); if (nvme_ns_ext(ns) && - !(ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) { - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); - - return nvme_tx_interleaved(n, &req->sg, ptr, len, lsize, msize, 0, - dir); + !(ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8)) { + return nvme_tx_interleaved(n, &req->sg, ptr, len, ns->lbasz, + ns->lbaf.ms, 0, dir); } return nvme_tx(n, &req->sg, ptr, len, dir); @@ -1205,11 +1207,8 @@ uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, uint16_t status; if (nvme_ns_ext(ns)) { - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); - - return nvme_tx_interleaved(n, &req->sg, ptr, len, msize, lsize, lsize, - dir); + return nvme_tx_interleaved(n, &req->sg, ptr, len, ns->lbaf.ms, + ns->lbasz, ns->lbasz, dir); } nvme_sg_unmap(&req->sg); @@ -1426,6 +1425,7 @@ static inline uint16_t nvme_check_bounds(NvmeNamespace *ns, uint64_t slba, uint64_t nsze = le64_to_cpu(ns->id_ns.nsze); if (unlikely(UINT64_MAX - slba < nlb || slba + nlb > nsze)) { + trace_pci_nvme_err_invalid_lba_range(slba, nlb, nsze); return NVME_LBA_RANGE | NVME_DNR; } @@ -1682,8 +1682,12 @@ static void nvme_zrm_auto_transition_zone(NvmeNamespace *ns) } } -static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, - bool implicit) +enum { + NVME_ZRM_AUTO = 1 << 0, +}; + +static uint16_t nvme_zrm_open_flags(NvmeNamespace *ns, NvmeZone *zone, + int flags) { int act = 0; uint16_t status; @@ -1707,7 +1711,7 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, nvme_aor_inc_open(ns); - if (implicit) { + if (flags & NVME_ZRM_AUTO) { nvme_assign_zone_state(ns, zone, NVME_ZONE_STATE_IMPLICITLY_OPEN); return NVME_SUCCESS; } @@ -1715,7 +1719,7 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, /* fallthrough */ case NVME_ZONE_STATE_IMPLICITLY_OPEN: - if (implicit) { + if (flags & NVME_ZRM_AUTO) { return NVME_SUCCESS; } @@ -1733,16 +1737,16 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, static inline uint16_t nvme_zrm_auto(NvmeNamespace *ns, NvmeZone *zone) { - return __nvme_zrm_open(ns, zone, true); + return nvme_zrm_open_flags(ns, zone, NVME_ZRM_AUTO); } static inline uint16_t nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone) { - return __nvme_zrm_open(ns, zone, false); + return nvme_zrm_open_flags(ns, zone, 0); } -static void __nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone, - uint32_t nlb) +static void nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone, + uint32_t nlb) { zone->d.wp += nlb; @@ -1762,7 +1766,7 @@ static void nvme_finalize_zoned_write(NvmeNamespace *ns, NvmeRequest *req) nlb = le16_to_cpu(rw->nlb) + 1; zone = nvme_get_zone_by_slba(ns, slba); - __nvme_advance_zone_wp(ns, zone, nlb); + nvme_advance_zone_wp(ns, zone, nlb); } static inline bool nvme_is_write(NvmeRequest *req) @@ -1832,11 +1836,11 @@ static void nvme_rw_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); if (req->cmd.opcode == NVME_CMD_WRITE_ZEROES) { size_t mlen = nvme_m2b(ns, nlb); @@ -2002,7 +2006,7 @@ static void nvme_verify_mdata_in_cb(void *opaque, int ret) uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; size_t mlen = nvme_m2b(ns, nlb); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); BlockBackend *blk = ns->blkconf.blk; trace_pci_nvme_verify_mdata_in_cb(nvme_cid(req), blk_name(blk)); @@ -2104,8 +2108,8 @@ static void nvme_aio_zone_reset_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { - int64_t offset = ns->mdata_offset + nvme_m2b(ns, zone->d.zslba); + if (ns->lbaf.ms) { + int64_t offset = nvme_moff(ns, zone->d.zslba); blk_aio_pwrite_zeroes(ns->blkconf.blk, offset, nvme_m2b(ns, ns->zone_size), BDRV_REQ_MAY_UNMAP, @@ -2151,7 +2155,7 @@ out: uint64_t sdlba = le64_to_cpu(copy->sdlba); NvmeZone *zone = nvme_get_zone_by_slba(ns, sdlba); - __nvme_advance_zone_wp(ns, zone, ctx->nlb); + nvme_advance_zone_wp(ns, zone, ctx->nlb); } g_free(ctx->bounce); @@ -2173,10 +2177,10 @@ static void nvme_copy_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd; uint64_t sdlba = le64_to_cpu(copy->sdlba); - int64_t offset = ns->mdata_offset + nvme_m2b(ns, sdlba); + int64_t offset = nvme_moff(ns, sdlba); qemu_iovec_reset(&req->sg.iov); qemu_iovec_add(&req->sg.iov, ctx->mbounce, nvme_m2b(ns, ctx->nlb)); @@ -2268,7 +2272,6 @@ static void nvme_copy_in_complete(NvmeRequest *req) status = nvme_check_bounds(ns, sdlba, ctx->nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(sdlba, ctx->nlb, ns->id_ns.nsze); goto invalid; } @@ -2369,10 +2372,19 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) uint32_t reftag = le32_to_cpu(rw->reftag); struct nvme_compare_ctx *ctx = req->opaque; g_autofree uint8_t *buf = NULL; + BlockBackend *blk = ns->blkconf.blk; + BlockAcctCookie *acct = &req->acct; + BlockAcctStats *stats = blk_get_stats(blk); uint16_t status = NVME_SUCCESS; trace_pci_nvme_compare_mdata_cb(nvme_cid(req)); + if (ret) { + block_acct_failed(stats, acct); + nvme_aio_err(req, ret); + goto out; + } + buf = g_malloc(ctx->mdata.iov.size); status = nvme_bounce_mdata(n, buf, ctx->mdata.iov.size, @@ -2387,7 +2399,6 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) uint8_t *bufp; uint8_t *mbufp = ctx->mdata.bounce; uint8_t *end = mbufp + ctx->mdata.iov.size; - size_t msize = nvme_msize(ns); int16_t pil = 0; status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size, @@ -2403,11 +2414,11 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) * tuple. */ if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } - for (bufp = buf; mbufp < end; bufp += msize, mbufp += msize) { - if (memcmp(bufp + pil, mbufp + pil, msize - pil)) { + for (bufp = buf; mbufp < end; bufp += ns->lbaf.ms, mbufp += ns->lbaf.ms) { + if (memcmp(bufp + pil, mbufp + pil, ns->lbaf.ms - pil)) { req->status = NVME_CMP_FAILURE; goto out; } @@ -2421,6 +2432,8 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) goto out; } + block_acct_done(stats, acct); + out: qemu_iovec_destroy(&ctx->data.iov); g_free(ctx->data.bounce); @@ -2468,12 +2481,12 @@ static void nvme_compare_data_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; size_t mlen = nvme_m2b(ns, nlb); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); ctx->mdata.bounce = g_malloc(mlen); @@ -2530,8 +2543,6 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req) uint32_t nlb = le32_to_cpu(range[i].nlb); if (nvme_check_bounds(ns, slba, nlb)) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, - ns->id_ns.nsze); continue; } @@ -2604,7 +2615,6 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return status; } @@ -2689,7 +2699,6 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, _nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, _nlb, ns->id_ns.nsze); goto out; } @@ -2716,7 +2725,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) } bounce = bouncep = g_malloc(nvme_l2b(ns, nlb)); - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { mbounce = mbouncep = g_malloc(nvme_m2b(ns, nlb)); } @@ -2752,9 +2761,9 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) bouncep += len; - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { len = nvme_m2b(ns, nlb); - offset = ns->mdata_offset + nvme_m2b(ns, slba); + offset = nvme_moff(ns, slba); in_ctx = g_new(struct nvme_copy_in_ctx, 1); in_ctx->req = req; @@ -2818,7 +2827,6 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return status; } @@ -2875,7 +2883,7 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) /* 1-initialize; see comment in nvme_dsm */ *num_flushes = 1; - for (int i = 1; i <= n->num_namespaces; i++) { + for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -2923,7 +2931,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { bool pract = ctrl & NVME_RW_PRINFO_PRACT; - if (pract && nvme_msize(ns) == 8) { + if (pract && ns->lbaf.ms == 8) { mapped_size = data_size; } } @@ -2938,7 +2946,6 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); goto invalid; } @@ -3000,7 +3007,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { bool pract = ctrl & NVME_RW_PRINFO_PRACT; - if (pract && nvme_msize(ns) == 8) { + if (pract && ns->lbaf.ms == 8) { mapped_size -= nvme_m2b(ns, nlb); } } @@ -3018,7 +3025,6 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); goto invalid; } @@ -3595,8 +3601,8 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) { + NvmeNamespace *ns; uint32_t nsid = le32_to_cpu(req->cmd.nsid); - uint16_t status; trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode)); @@ -3607,18 +3613,18 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) /* * In the base NVM command set, Flush may apply to all namespaces - * (indicated by NSID being set to 0xFFFFFFFF). But if that feature is used + * (indicated by NSID being set to FFFFFFFFh). But if that feature is used * along with TP 4056 (Namespace Types), it may be pretty screwed up. * - * If NSID is indeed set to 0xFFFFFFFF, we simply cannot associate the + * If NSID is indeed set to FFFFFFFFh, we simply cannot associate the * opcode with a specific command since we cannot determine a unique I/O - * command set. Opcode 0x0 could have any other meaning than something + * command set. Opcode 0h could have any other meaning than something * equivalent to flushing and say it DOES have completely different - * semantics in some other command set - does an NSID of 0xFFFFFFFF then + * semantics in some other command set - does an NSID of FFFFFFFFh then * mean "for all namespaces, apply whatever command set specific command - * that uses the 0x0 opcode?" Or does it mean "for all namespaces, apply - * whatever command that uses the 0x0 opcode if, and only if, it allows - * NSID to be 0xFFFFFFFF"? + * that uses the 0h opcode?" Or does it mean "for all namespaces, apply + * whatever command that uses the 0h opcode if, and only if, it allows NSID + * to be FFFFFFFFh"? * * Anyway (and luckily), for now, we do not care about this since the * device only supports namespace types that includes the NVM Flush command @@ -3628,21 +3634,22 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return nvme_flush(n, req); } - req->ns = nvme_ns(n, nsid); - if (unlikely(!req->ns)) { + ns = nvme_ns(n, nsid); + if (unlikely(!ns)) { return NVME_INVALID_FIELD | NVME_DNR; } - if (!(req->ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) { + if (!(ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) { trace_pci_nvme_err_invalid_opc(req->cmd.opcode); return NVME_INVALID_OPCODE | NVME_DNR; } - status = nvme_ns_status(req->ns); - if (unlikely(status)) { - return status; + if (ns->status) { + return ns->status; } + req->ns = ns; + switch (req->cmd.opcode) { case NVME_CMD_WRITE_ZEROES: return nvme_write_zeroes(n, req); @@ -3844,7 +3851,7 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len, } else { int i; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -3934,7 +3941,7 @@ static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len, NVME_CHANGED_NSID_SIZE) { /* * If more than 1024 namespaces, the first entry in the log page should - * be set to 0xffffffff and the others to 0 as spec. + * be set to FFFFFFFFh and the others to 0 as spec. */ if (i == ARRAY_SIZE(nslist)) { memset(nslist, 0x0, sizeof(nslist)); @@ -4332,7 +4339,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req, trace_pci_nvme_identify_nslist(min_nsid); /* - * Both 0xffffffff (NVME_NSID_BROADCAST) and 0xfffffffe are invalid values + * Both FFFFFFFFh (NVME_NSID_BROADCAST) and FFFFFFFFEh are invalid values * since the Active Namespace ID List should return namespaces with ids * *higher* than the NSID specified in the command. This is also specified * in the spec (NVM Express v1.3d, Section 5.15.4). @@ -4341,7 +4348,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req, return NVME_INVALID_NSID | NVME_DNR; } - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { if (!active) { @@ -4379,7 +4386,7 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req, trace_pci_nvme_identify_nslist_csi(min_nsid, c->csi); /* - * Same as in nvme_identify_nslist(), 0xffffffff/0xfffffffe are invalid. + * Same as in nvme_identify_nslist(), FFFFFFFFh/FFFFFFFFEh are invalid. */ if (min_nsid >= NVME_NSID_BROADCAST - 1) { return NVME_INVALID_NSID | NVME_DNR; @@ -4389,7 +4396,7 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req, return NVME_INVALID_FIELD | NVME_DNR; } - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { if (!active) { @@ -4446,7 +4453,7 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) /* * Because the NGUID and EUI64 fields are 0 in the Identify Namespace data - * structure, a Namespace UUID (nidt = 0x3) must be reported in the + * structure, a Namespace UUID (nidt = 3h) must be reported in the * Namespace Identification Descriptor. Add the namespace UUID here. */ ns_descrs->uuid.hdr.nidt = NVME_NIDT_UUID; @@ -4595,7 +4602,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) /* * The Reservation Notification Mask and Reservation Persistence * features require a status code of Invalid Field in Command when - * NSID is 0xFFFFFFFF. Since the device does not support those + * NSID is FFFFFFFFh. Since the device does not support those * features we can always return Invalid Namespace or Format as we * should do for all other features. */ @@ -4655,7 +4662,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) goto out; case NVME_VOLATILE_WRITE_CACHE: result = 0; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -4707,9 +4714,6 @@ defaults: result |= NVME_INTVC_NOCOALESCING; } break; - case NVME_COMMAND_SET_PROFILE: - result = 0; - break; default: result = nvme_feature_default[fid]; break; @@ -4805,7 +4809,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) break; case NVME_ERROR_RECOVERY: if (nsid == NVME_NSID_BROADCAST) { - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { @@ -4826,7 +4830,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) } break; case NVME_VOLATILE_WRITE_CACHE: - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -4847,15 +4851,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) } /* - * NVMe v1.3, Section 5.21.1.7: 0xffff is not an allowed value for NCQR + * NVMe v1.3, Section 5.21.1.7: FFFFh is not an allowed value for NCQR * and NSQR. */ if ((dw11 & 0xffff) == 0xffff || ((dw11 >> 16) & 0xffff) == 0xffff) { return NVME_INVALID_FIELD | NVME_DNR; } - trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, - ((dw11 >> 16) & 0xFFFF) + 1, + trace_pci_nvme_setfeat_numq((dw11 & 0xffff) + 1, + ((dw11 >> 16) & 0xffff) + 1, n->params.max_ioqpairs, n->params.max_ioqpairs); req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) | @@ -4912,7 +4916,25 @@ static void nvme_update_dmrsl(NvmeCtrl *n) } } -static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns); +static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns) +{ + ns->iocs = nvme_cse_iocs_none; + switch (ns->csi) { + case NVME_CSI_NVM: + if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) { + ns->iocs = nvme_cse_iocs_nvm; + } + break; + case NVME_CSI_ZONED: + if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) { + ns->iocs = nvme_cse_iocs_zoned; + } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) { + ns->iocs = nvme_cse_iocs_nvm; + } + break; + } +} + static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns; @@ -4963,13 +4985,13 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) } nvme_attach_ns(ctrl, ns); - __nvme_select_ns_iocs(ctrl, ns); + nvme_select_iocs_ns(ctrl, ns); } else { if (!nvme_ns(ctrl, nsid)) { return NVME_NS_NOT_ATTACHED | NVME_DNR; } - ctrl->namespaces[nsid - 1] = NULL; + ctrl->namespaces[nsid] = NULL; ns->attached--; nvme_update_dmrsl(ctrl); @@ -5101,7 +5123,7 @@ static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest *req) req->status = status; } } else { - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5212,7 +5234,7 @@ static void nvme_ctrl_reset(NvmeCtrl *n) NvmeNamespace *ns; int i; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5254,7 +5276,7 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n) memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); } - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5264,37 +5286,18 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n) } } -static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns) -{ - ns->iocs = nvme_cse_iocs_none; - switch (ns->csi) { - case NVME_CSI_NVM: - if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) { - ns->iocs = nvme_cse_iocs_nvm; - } - break; - case NVME_CSI_ZONED: - if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) { - ns->iocs = nvme_cse_iocs_zoned; - } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) { - ns->iocs = nvme_cse_iocs_nvm; - } - break; - } -} - -static void nvme_select_ns_iocs(NvmeCtrl *n) +static void nvme_select_iocs(NvmeCtrl *n) { NvmeNamespace *ns; int i; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; } - __nvme_select_ns_iocs(n, ns); + nvme_select_iocs_ns(n, ns); } } @@ -5396,7 +5399,7 @@ static int nvme_start_ctrl(NvmeCtrl *n) QTAILQ_INIT(&n->aer_queue); - nvme_select_ns_iocs(n); + nvme_select_iocs(n); return 0; } @@ -5493,7 +5496,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.cc = data; } break; - case 0x1C: /* CSTS */ + case 0x1c: /* CSTS */ if (data & (1 << 4)) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_ssreset_w1c_unsupported, "attempted to W1C CSTS.NSSRO" @@ -5505,7 +5508,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } break; case 0x20: /* NSSR */ - if (data == 0x4E564D65) { + if (data == 0x4e564d65) { trace_pci_nvme_ub_mmiowr_ssreset_unsupported(); } else { /* The spec says that writes of other values have no effect */ @@ -5575,11 +5578,11 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.cmbmsc = (n->bar.cmbmsc & 0xffffffff) | (data << 32); return; - case 0xE00: /* PMRCAP */ + case 0xe00: /* PMRCAP */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrcap_readonly, "invalid write to PMRCAP register, ignored"); return; - case 0xE04: /* PMRCTL */ + case 0xe04: /* PMRCTL */ n->bar.pmrctl = data; if (NVME_PMRCTL_EN(data)) { memory_region_set_enabled(&n->pmr.dev->mr, true); @@ -5590,19 +5593,19 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->pmr.cmse = false; } return; - case 0xE08: /* PMRSTS */ + case 0xe08: /* PMRSTS */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrsts_readonly, "invalid write to PMRSTS register, ignored"); return; - case 0xE0C: /* PMREBS */ + case 0xe0C: /* PMREBS */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrebs_readonly, "invalid write to PMREBS register, ignored"); return; - case 0xE10: /* PMRSWTP */ + case 0xe10: /* PMRSWTP */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrswtp_readonly, "invalid write to PMRSWTP register, ignored"); return; - case 0xE14: /* PMRMSCL */ + case 0xe14: /* PMRMSCL */ if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5622,7 +5625,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } return; - case 0xE18: /* PMRMSCU */ + case 0xe18: /* PMRMSCU */ if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5664,7 +5667,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) * from PMRSTS should ensure prior writes * made it to persistent media */ - if (addr == 0xE08 && + if (addr == 0xe08 && (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); } @@ -5915,7 +5918,6 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) static void nvme_init_state(NvmeCtrl *n) { - n->num_namespaces = NVME_MAX_NAMESPACES; /* add one to max_ioqpairs to account for the admin queue pair */ n->reg_size = pow2ceil(sizeof(NvmeBar) + 2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE); @@ -6096,7 +6098,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->sqes = (0x6 << 4) | 0x6; id->cqes = (0x4 << 4) | 0x4; - id->nn = cpu_to_le32(n->num_namespaces); + id->nn = cpu_to_le32(NVME_MAX_NAMESPACES); id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP | NVME_ONCS_FEATURES | NVME_ONCS_DSM | NVME_ONCS_COMPARE | NVME_ONCS_COPY); @@ -6161,7 +6163,7 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns) uint32_t nsid = ns->params.nsid; assert(nsid && nsid <= NVME_MAX_NAMESPACES); - n->namespaces[nsid - 1] = ns; + n->namespaces[nsid] = ns; ns->attached++; n->dmrsl = MIN_NON_ZERO(n->dmrsl, @@ -6215,7 +6217,7 @@ static void nvme_exit(PCIDevice *pci_dev) nvme_ctrl_reset(n); - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; diff --git a/hw/block/nvme-dif.c b/hw/nvme/dif.c index 81b0a4cb13..88efcbe9bd 100644 --- a/hw/block/nvme-dif.c +++ b/hw/nvme/dif.c @@ -9,13 +9,11 @@ */ #include "qemu/osdep.h" -#include "hw/block/block.h" -#include "sysemu/dma.h" -#include "sysemu/block-backend.h" #include "qapi/error.h" -#include "trace.h" +#include "sysemu/block-backend.h" + #include "nvme.h" -#include "nvme-dif.h" +#include "trace.h" uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, uint32_t reftag) @@ -46,20 +44,18 @@ void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, uint32_t reftag) { uint8_t *end = buf + len; - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); int16_t pil = 0; if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } - trace_pci_nvme_dif_pract_generate_dif(len, lsize, lsize + pil, apptag, - reftag); + trace_pci_nvme_dif_pract_generate_dif(len, ns->lbasz, ns->lbasz + pil, + apptag, reftag); - for (; buf < end; buf += lsize, mbuf += msize) { + for (; buf < end; buf += ns->lbasz, mbuf += ns->lbaf.ms) { NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); - uint16_t crc = crc_t10dif(0x0, buf, lsize); + uint16_t crc = crc_t10dif(0x0, buf, ns->lbasz); if (pil) { crc = crc_t10dif(crc, mbuf, pil); @@ -100,7 +96,7 @@ static uint16_t nvme_dif_prchk(NvmeNamespace *ns, NvmeDifTuple *dif, } if (ctrl & NVME_RW_PRINFO_PRCHK_GUARD) { - uint16_t crc = crc_t10dif(0x0, buf, nvme_lsize(ns)); + uint16_t crc = crc_t10dif(0x0, buf, ns->lbasz); if (pil) { crc = crc_t10dif(crc, mbuf, pil); @@ -139,8 +135,6 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, uint16_t appmask, uint32_t reftag) { uint8_t *end = buf + len; - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); int16_t pil = 0; uint16_t status; @@ -150,12 +144,12 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, } if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } - trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), lsize + pil); + trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), ns->lbasz + pil); - for (; buf < end; buf += lsize, mbuf += msize) { + for (; buf < end; buf += ns->lbasz, mbuf += ns->lbaf.ms) { NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); status = nvme_dif_prchk(ns, dif, buf, mbuf, pil, ctrl, apptag, @@ -178,20 +172,18 @@ uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, BlockBackend *blk = ns->blkconf.blk; BlockDriverState *bs = blk_bs(blk); - size_t msize = nvme_msize(ns); - size_t lsize = nvme_lsize(ns); int64_t moffset = 0, offset = nvme_l2b(ns, slba); uint8_t *mbufp, *end; bool zeroed; int16_t pil = 0; - int64_t bytes = (mlen / msize) * lsize; + int64_t bytes = (mlen / ns->lbaf.ms) << ns->lbaf.ds; int64_t pnum = 0; Error *err = NULL; if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } do { @@ -213,15 +205,15 @@ uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, if (zeroed) { mbufp = mbuf + moffset; - mlen = (pnum / lsize) * msize; + mlen = (pnum >> ns->lbaf.ds) * ns->lbaf.ms; end = mbufp + mlen; - for (; mbufp < end; mbufp += msize) { + for (; mbufp < end; mbufp += ns->lbaf.ms) { memset(mbufp + pil, 0xff, sizeof(NvmeDifTuple)); } } - moffset += (pnum / lsize) * msize; + moffset += (pnum >> ns->lbaf.ds) * ns->lbaf.ms; offset += pnum; } while (pnum != bytes); @@ -291,7 +283,7 @@ static void nvme_dif_rw_check_cb(void *opaque, int ret) goto out; } - if (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8) { + if (ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8) { goto out; } @@ -314,7 +306,7 @@ static void nvme_dif_rw_mdata_in_cb(void *opaque, int ret) uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; size_t mlen = nvme_m2b(ns, nlb); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); BlockBackend *blk = ns->blkconf.blk; trace_pci_nvme_dif_rw_mdata_in_cb(nvme_cid(req), blk_name(blk)); @@ -343,7 +335,7 @@ static void nvme_dif_rw_mdata_out_cb(void *opaque, int ret) NvmeNamespace *ns = req->ns; NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); BlockBackend *blk = ns->blkconf.blk; trace_pci_nvme_dif_rw_mdata_out_cb(nvme_cid(req), blk_name(blk)); @@ -395,8 +387,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) if (pract) { uint8_t *mbuf, *end; - size_t msize = nvme_msize(ns); - int16_t pil = msize - sizeof(NvmeDifTuple); + int16_t pil = ns->lbaf.ms - sizeof(NvmeDifTuple); status = nvme_check_prinfo(ns, ctrl, slba, reftag); if (status) { @@ -417,7 +408,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) pil = 0; } - for (; mbuf < end; mbuf += msize) { + for (; mbuf < end; mbuf += ns->lbaf.ms) { NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); dif->apptag = cpu_to_be16(apptag); @@ -436,7 +427,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) return NVME_NO_COMPLETE; } - if (nvme_ns_ext(ns) && !(pract && nvme_msize(ns) == 8)) { + if (nvme_ns_ext(ns) && !(pract && ns->lbaf.ms == 8)) { mapped_len += mlen; } @@ -470,7 +461,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) qemu_iovec_init(&ctx->mdata.iov, 1); qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); - if (!(pract && nvme_msize(ns) == 8)) { + if (!(pract && ns->lbaf.ms == 8)) { status = nvme_bounce_mdata(n, ctx->mdata.bounce, ctx->mdata.iov.size, NVME_TX_DIRECTION_TO_DEVICE, req); if (status) { diff --git a/hw/nvme/meson.build b/hw/nvme/meson.build new file mode 100644 index 0000000000..3cf40046ee --- /dev/null +++ b/hw/nvme/meson.build @@ -0,0 +1 @@ +softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c', 'dif.c', 'ns.c', 'subsys.c')) diff --git a/hw/block/nvme-ns.c b/hw/nvme/ns.c index 7bb618f182..992e5a13f5 100644 --- a/hw/block/nvme-ns.c +++ b/hw/nvme/ns.c @@ -14,23 +14,16 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu/cutils.h" -#include "qemu/log.h" #include "qemu/error-report.h" -#include "hw/block/block.h" -#include "hw/pci/pci.h" +#include "qapi/error.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" -#include "qapi/error.h" - -#include "hw/qdev-properties.h" -#include "hw/qdev-core.h" -#include "trace.h" #include "nvme.h" -#include "nvme-ns.h" +#include "trace.h" #define MIN_DISCARD_GRANULARITY (4 * KiB) +#define NVME_DEFAULT_ZONE_SIZE (128 * MiB) void nvme_ns_init_format(NvmeNamespace *ns) { @@ -38,7 +31,10 @@ void nvme_ns_init_format(NvmeNamespace *ns) BlockDriverInfo bdi; int npdg, nlbas, ret; - nlbas = nvme_ns_nlbas(ns); + ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; + ns->lbasz = 1 << ns->lbaf.ds; + + nlbas = ns->size / (ns->lbasz + ns->lbaf.ms); id_ns->nsze = cpu_to_le64(nlbas); @@ -46,13 +42,13 @@ void nvme_ns_init_format(NvmeNamespace *ns) id_ns->ncap = id_ns->nsze; id_ns->nuse = id_ns->ncap; - ns->mdata_offset = nvme_l2b(ns, nlbas); + ns->moff = (int64_t)nlbas << ns->lbaf.ds; - npdg = ns->blkconf.discard_granularity / nvme_lsize(ns); + npdg = ns->blkconf.discard_granularity / ns->lbasz; ret = bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi); if (ret >= 0 && bdi.cluster_size > ns->blkconf.discard_granularity) { - npdg = bdi.cluster_size / nvme_lsize(ns); + npdg = bdi.cluster_size / ns->lbasz; } id_ns->npda = id_ns->npdg = npdg - 1; @@ -170,7 +166,6 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp) static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) { uint64_t zone_size, zone_cap; - uint32_t lbasz = nvme_lsize(ns); /* Make sure that the values of ZNS properties are sane */ if (ns->params.zone_size_bs) { @@ -188,14 +183,14 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) "zone size %"PRIu64"B", zone_cap, zone_size); return -1; } - if (zone_size < lbasz) { + if (zone_size < ns->lbasz) { error_setg(errp, "zone size %"PRIu64"B too small, " - "must be at least %"PRIu32"B", zone_size, lbasz); + "must be at least %zuB", zone_size, ns->lbasz); return -1; } - if (zone_cap < lbasz) { + if (zone_cap < ns->lbasz) { error_setg(errp, "zone capacity %"PRIu64"B too small, " - "must be at least %"PRIu32"B", zone_cap, lbasz); + "must be at least %zuB", zone_cap, ns->lbasz); return -1; } @@ -203,9 +198,9 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) * Save the main zone geometry values to avoid * calculating them later again. */ - ns->zone_size = zone_size / lbasz; - ns->zone_capacity = zone_cap / lbasz; - ns->num_zones = nvme_ns_nlbas(ns) / ns->zone_size; + ns->zone_size = zone_size / ns->lbasz; + ns->zone_capacity = zone_cap / ns->lbasz; + ns->num_zones = le64_to_cpu(ns->id_ns.nsze) / ns->zone_size; /* Do a few more sanity checks of ZNS properties */ if (!ns->num_zones) { @@ -215,43 +210,6 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) return -1; } - if (ns->params.max_open_zones > ns->num_zones) { - error_setg(errp, - "max_open_zones value %u exceeds the number of zones %u", - ns->params.max_open_zones, ns->num_zones); - return -1; - } - if (ns->params.max_active_zones > ns->num_zones) { - error_setg(errp, - "max_active_zones value %u exceeds the number of zones %u", - ns->params.max_active_zones, ns->num_zones); - return -1; - } - - if (ns->params.max_active_zones) { - if (ns->params.max_open_zones > ns->params.max_active_zones) { - error_setg(errp, "max_open_zones (%u) exceeds max_active_zones (%u)", - ns->params.max_open_zones, ns->params.max_active_zones); - return -1; - } - - if (!ns->params.max_open_zones) { - ns->params.max_open_zones = ns->params.max_active_zones; - } - } - - if (ns->params.zd_extension_size) { - if (ns->params.zd_extension_size & 0x3f) { - error_setg(errp, - "zone descriptor extension size must be a multiple of 64B"); - return -1; - } - if ((ns->params.zd_extension_size >> 6) > 0xff) { - error_setg(errp, "zone descriptor extension size is too large"); - return -1; - } - } - return 0; } @@ -303,7 +261,7 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) id_ns_z = g_malloc0(sizeof(NvmeIdNsZoned)); - /* MAR/MOR are zeroes-based, 0xffffffff means no limit */ + /* MAR/MOR are zeroes-based, FFFFFFFFFh means no limit */ id_ns_z->mar = cpu_to_le32(ns->params.max_active_zones - 1); id_ns_z->mor = cpu_to_le32(ns->params.max_open_zones - 1); id_ns_z->zoc = 0; @@ -421,6 +379,34 @@ static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns, } } + if (ns->params.zoned) { + if (ns->params.max_active_zones) { + if (ns->params.max_open_zones > ns->params.max_active_zones) { + error_setg(errp, "max_open_zones (%u) exceeds " + "max_active_zones (%u)", ns->params.max_open_zones, + ns->params.max_active_zones); + return -1; + } + + if (!ns->params.max_open_zones) { + ns->params.max_open_zones = ns->params.max_active_zones; + } + } + + if (ns->params.zd_extension_size) { + if (ns->params.zd_extension_size & 0x3f) { + error_setg(errp, "zone descriptor extension size must be a " + "multiple of 64B"); + return -1; + } + if ((ns->params.zd_extension_size >> 6) > 0xff) { + error_setg(errp, + "zone descriptor extension size is too large"); + return -1; + } + } + } + return 0; } diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h new file mode 100644 index 0000000000..81a35cda14 --- /dev/null +++ b/hw/nvme/nvme.h @@ -0,0 +1,547 @@ +/* + * QEMU NVM Express + * + * Copyright (c) 2012 Intel Corporation + * Copyright (c) 2021 Minwoo Im + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Authors: + * Keith Busch <kbusch@kernel.org> + * Klaus Jensen <k.jensen@samsung.com> + * Gollu Appalanaidu <anaidu.gollu@samsung.com> + * Dmitry Fomichev <dmitry.fomichev@wdc.com> + * Minwoo Im <minwoo.im.dev@gmail.com> + * + * This code is licensed under the GNU GPL v2 or later. + */ + +#ifndef HW_NVME_INTERNAL_H +#define HW_NVME_INTERNAL_H + +#include "qemu/uuid.h" +#include "hw/pci/pci.h" +#include "hw/block/block.h" + +#include "block/nvme.h" + +#define NVME_MAX_CONTROLLERS 32 +#define NVME_MAX_NAMESPACES 256 + +typedef struct NvmeCtrl NvmeCtrl; +typedef struct NvmeNamespace NvmeNamespace; + +#define TYPE_NVME_SUBSYS "nvme-subsys" +#define NVME_SUBSYS(obj) \ + OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS) + +typedef struct NvmeSubsystem { + DeviceState parent_obj; + uint8_t subnqn[256]; + + NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS]; + NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; + + struct { + char *nqn; + } params; +} NvmeSubsystem; + +int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp); + +static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys, + uint32_t cntlid) +{ + if (!subsys || cntlid >= NVME_MAX_CONTROLLERS) { + return NULL; + } + + return subsys->ctrls[cntlid]; +} + +static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys, + uint32_t nsid) +{ + if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) { + return NULL; + } + + return subsys->namespaces[nsid]; +} + +#define TYPE_NVME_NS "nvme-ns" +#define NVME_NS(obj) \ + OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS) + +typedef struct NvmeZone { + NvmeZoneDescr d; + uint64_t w_ptr; + QTAILQ_ENTRY(NvmeZone) entry; +} NvmeZone; + +typedef struct NvmeNamespaceParams { + bool detached; + bool shared; + uint32_t nsid; + QemuUUID uuid; + + uint16_t ms; + uint8_t mset; + uint8_t pi; + uint8_t pil; + + uint16_t mssrl; + uint32_t mcl; + uint8_t msrc; + + bool zoned; + bool cross_zone_read; + uint64_t zone_size_bs; + uint64_t zone_cap_bs; + uint32_t max_active_zones; + uint32_t max_open_zones; + uint32_t zd_extension_size; +} NvmeNamespaceParams; + +typedef struct NvmeNamespace { + DeviceState parent_obj; + BlockConf blkconf; + int32_t bootindex; + int64_t size; + int64_t moff; + NvmeIdNs id_ns; + NvmeLBAF lbaf; + size_t lbasz; + const uint32_t *iocs; + uint8_t csi; + uint16_t status; + int attached; + + QTAILQ_ENTRY(NvmeNamespace) entry; + + NvmeIdNsZoned *id_ns_zoned; + NvmeZone *zone_array; + QTAILQ_HEAD(, NvmeZone) exp_open_zones; + QTAILQ_HEAD(, NvmeZone) imp_open_zones; + QTAILQ_HEAD(, NvmeZone) closed_zones; + QTAILQ_HEAD(, NvmeZone) full_zones; + uint32_t num_zones; + uint64_t zone_size; + uint64_t zone_capacity; + uint32_t zone_size_log2; + uint8_t *zd_extensions; + int32_t nr_open_zones; + int32_t nr_active_zones; + + NvmeNamespaceParams params; + + struct { + uint32_t err_rec; + } features; +} NvmeNamespace; + +static inline uint32_t nvme_nsid(NvmeNamespace *ns) +{ + if (ns) { + return ns->params.nsid; + } + + return 0; +} + +static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) +{ + return lba << ns->lbaf.ds; +} + +static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) +{ + return ns->lbaf.ms * lba; +} + +static inline int64_t nvme_moff(NvmeNamespace *ns, uint64_t lba) +{ + return ns->moff + nvme_m2b(ns, lba); +} + +static inline bool nvme_ns_ext(NvmeNamespace *ns) +{ + return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); +} + +static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone) +{ + return zone->d.zs >> 4; +} + +static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state) +{ + zone->d.zs = state << 4; +} + +static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone) +{ + return zone->d.zslba + ns->zone_size; +} + +static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone) +{ + return zone->d.zslba + zone->d.zcap; +} + +static inline bool nvme_wp_is_valid(NvmeZone *zone) +{ + uint8_t st = nvme_get_zone_state(zone); + + return st != NVME_ZONE_STATE_FULL && + st != NVME_ZONE_STATE_READ_ONLY && + st != NVME_ZONE_STATE_OFFLINE; +} + +static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns, + uint32_t zone_idx) +{ + return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size]; +} + +static inline void nvme_aor_inc_open(NvmeNamespace *ns) +{ + assert(ns->nr_open_zones >= 0); + if (ns->params.max_open_zones) { + ns->nr_open_zones++; + assert(ns->nr_open_zones <= ns->params.max_open_zones); + } +} + +static inline void nvme_aor_dec_open(NvmeNamespace *ns) +{ + if (ns->params.max_open_zones) { + assert(ns->nr_open_zones > 0); + ns->nr_open_zones--; + } + assert(ns->nr_open_zones >= 0); +} + +static inline void nvme_aor_inc_active(NvmeNamespace *ns) +{ + assert(ns->nr_active_zones >= 0); + if (ns->params.max_active_zones) { + ns->nr_active_zones++; + assert(ns->nr_active_zones <= ns->params.max_active_zones); + } +} + +static inline void nvme_aor_dec_active(NvmeNamespace *ns) +{ + if (ns->params.max_active_zones) { + assert(ns->nr_active_zones > 0); + ns->nr_active_zones--; + assert(ns->nr_active_zones >= ns->nr_open_zones); + } + assert(ns->nr_active_zones >= 0); +} + +void nvme_ns_init_format(NvmeNamespace *ns); +int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); +void nvme_ns_drain(NvmeNamespace *ns); +void nvme_ns_shutdown(NvmeNamespace *ns); +void nvme_ns_cleanup(NvmeNamespace *ns); + +typedef struct NvmeAsyncEvent { + QTAILQ_ENTRY(NvmeAsyncEvent) entry; + NvmeAerResult result; +} NvmeAsyncEvent; + +enum { + NVME_SG_ALLOC = 1 << 0, + NVME_SG_DMA = 1 << 1, +}; + +typedef struct NvmeSg { + int flags; + + union { + QEMUSGList qsg; + QEMUIOVector iov; + }; +} NvmeSg; + +typedef enum NvmeTxDirection { + NVME_TX_DIRECTION_TO_DEVICE = 0, + NVME_TX_DIRECTION_FROM_DEVICE = 1, +} NvmeTxDirection; + +typedef struct NvmeRequest { + struct NvmeSQueue *sq; + struct NvmeNamespace *ns; + BlockAIOCB *aiocb; + uint16_t status; + void *opaque; + NvmeCqe cqe; + NvmeCmd cmd; + BlockAcctCookie acct; + NvmeSg sg; + QTAILQ_ENTRY(NvmeRequest)entry; +} NvmeRequest; + +typedef struct NvmeBounceContext { + NvmeRequest *req; + + struct { + QEMUIOVector iov; + uint8_t *bounce; + } data, mdata; +} NvmeBounceContext; + +static inline const char *nvme_adm_opc_str(uint8_t opc) +{ + switch (opc) { + case NVME_ADM_CMD_DELETE_SQ: return "NVME_ADM_CMD_DELETE_SQ"; + case NVME_ADM_CMD_CREATE_SQ: return "NVME_ADM_CMD_CREATE_SQ"; + case NVME_ADM_CMD_GET_LOG_PAGE: return "NVME_ADM_CMD_GET_LOG_PAGE"; + case NVME_ADM_CMD_DELETE_CQ: return "NVME_ADM_CMD_DELETE_CQ"; + case NVME_ADM_CMD_CREATE_CQ: return "NVME_ADM_CMD_CREATE_CQ"; + case NVME_ADM_CMD_IDENTIFY: return "NVME_ADM_CMD_IDENTIFY"; + case NVME_ADM_CMD_ABORT: return "NVME_ADM_CMD_ABORT"; + case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES"; + case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES"; + case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ"; + case NVME_ADM_CMD_NS_ATTACHMENT: return "NVME_ADM_CMD_NS_ATTACHMENT"; + case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM"; + default: return "NVME_ADM_CMD_UNKNOWN"; + } +} + +static inline const char *nvme_io_opc_str(uint8_t opc) +{ + switch (opc) { + case NVME_CMD_FLUSH: return "NVME_NVM_CMD_FLUSH"; + case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE"; + case NVME_CMD_READ: return "NVME_NVM_CMD_READ"; + case NVME_CMD_COMPARE: return "NVME_NVM_CMD_COMPARE"; + case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES"; + case NVME_CMD_DSM: return "NVME_NVM_CMD_DSM"; + case NVME_CMD_VERIFY: return "NVME_NVM_CMD_VERIFY"; + case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY"; + case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND"; + case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV"; + case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND"; + default: return "NVME_NVM_CMD_UNKNOWN"; + } +} + +typedef struct NvmeSQueue { + struct NvmeCtrl *ctrl; + uint16_t sqid; + uint16_t cqid; + uint32_t head; + uint32_t tail; + uint32_t size; + uint64_t dma_addr; + QEMUTimer *timer; + NvmeRequest *io_req; + QTAILQ_HEAD(, NvmeRequest) req_list; + QTAILQ_HEAD(, NvmeRequest) out_req_list; + QTAILQ_ENTRY(NvmeSQueue) entry; +} NvmeSQueue; + +typedef struct NvmeCQueue { + struct NvmeCtrl *ctrl; + uint8_t phase; + uint16_t cqid; + uint16_t irq_enabled; + uint32_t head; + uint32_t tail; + uint32_t vector; + uint32_t size; + uint64_t dma_addr; + QEMUTimer *timer; + QTAILQ_HEAD(, NvmeSQueue) sq_list; + QTAILQ_HEAD(, NvmeRequest) req_list; +} NvmeCQueue; + +#define TYPE_NVME_BUS "nvme-bus" +#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS) + +typedef struct NvmeBus { + BusState parent_bus; +} NvmeBus; + +#define TYPE_NVME "nvme" +#define NVME(obj) \ + OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME) + +typedef struct NvmeParams { + char *serial; + uint32_t num_queues; /* deprecated since 5.1 */ + uint32_t max_ioqpairs; + uint16_t msix_qsize; + uint32_t cmb_size_mb; + uint8_t aerl; + uint32_t aer_max_queued; + uint8_t mdts; + uint8_t vsl; + bool use_intel_id; + uint8_t zasl; + bool legacy_cmb; +} NvmeParams; + +typedef struct NvmeCtrl { + PCIDevice parent_obj; + MemoryRegion bar0; + MemoryRegion iomem; + NvmeBar bar; + NvmeParams params; + NvmeBus bus; + + uint16_t cntlid; + bool qs_created; + uint32_t page_size; + uint16_t page_bits; + uint16_t max_prp_ents; + uint16_t cqe_size; + uint16_t sqe_size; + uint32_t reg_size; + uint32_t max_q_ents; + uint8_t outstanding_aers; + uint32_t irq_status; + uint64_t host_timestamp; /* Timestamp sent by the host */ + uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ + uint64_t starttime_ms; + uint16_t temperature; + uint8_t smart_critical_warning; + + struct { + MemoryRegion mem; + uint8_t *buf; + bool cmse; + hwaddr cba; + } cmb; + + struct { + HostMemoryBackend *dev; + bool cmse; + hwaddr cba; + } pmr; + + uint8_t aer_mask; + NvmeRequest **aer_reqs; + QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue; + int aer_queued; + + uint32_t dmrsl; + + /* Namespace ID is started with 1 so bitmap should be 1-based */ +#define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1) + DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE); + + NvmeSubsystem *subsys; + + NvmeNamespace namespace; + NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; + NvmeSQueue **sq; + NvmeCQueue **cq; + NvmeSQueue admin_sq; + NvmeCQueue admin_cq; + NvmeIdCtrl id_ctrl; + + struct { + struct { + uint16_t temp_thresh_hi; + uint16_t temp_thresh_low; + }; + uint32_t async_config; + } features; +} NvmeCtrl; + +static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid) +{ + if (!nsid || nsid > NVME_MAX_NAMESPACES) { + return NULL; + } + + return n->namespaces[nsid]; +} + +static inline NvmeCQueue *nvme_cq(NvmeRequest *req) +{ + NvmeSQueue *sq = req->sq; + NvmeCtrl *n = sq->ctrl; + + return n->cq[sq->cqid]; +} + +static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req) +{ + NvmeSQueue *sq = req->sq; + return sq->ctrl; +} + +static inline uint16_t nvme_cid(NvmeRequest *req) +{ + if (!req) { + return 0xffff; + } + + return le16_to_cpu(req->cqe.cid); +} + +void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns); +uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req); +uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req); +void nvme_rw_complete_cb(void *opaque, int ret); +uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, + NvmeCmd *cmd); + +/* from Linux kernel (crypto/crct10dif_common.c) */ +static const uint16_t t10_dif_crc_table[256] = { + 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B, + 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6, + 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6, + 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B, + 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1, + 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C, + 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C, + 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781, + 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8, + 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255, + 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925, + 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698, + 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472, + 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF, + 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF, + 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02, + 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA, + 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067, + 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17, + 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA, + 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640, + 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD, + 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D, + 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30, + 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759, + 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4, + 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394, + 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29, + 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3, + 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E, + 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E, + 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3 +}; + +uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, + uint32_t reftag); +uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, + uint64_t slba); +void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t apptag, + uint32_t reftag); +uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t ctrl, + uint64_t slba, uint16_t apptag, + uint16_t appmask, uint32_t reftag); +uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req); + + +#endif /* HW_NVME_INTERNAL_H */ diff --git a/hw/block/nvme-subsys.c b/hw/nvme/subsys.c index 9604c19117..192223d17c 100644 --- a/hw/block/nvme-subsys.c +++ b/hw/nvme/subsys.c @@ -6,20 +6,10 @@ * This code is licensed under the GNU GPL v2. Refer COPYING. */ -#include "qemu/units.h" #include "qemu/osdep.h" -#include "qemu/uuid.h" -#include "qemu/iov.h" -#include "qemu/cutils.h" #include "qapi/error.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-core.h" -#include "hw/block/block.h" -#include "block/aio.h" -#include "block/accounting.h" -#include "hw/pci/pci.h" + #include "nvme.h" -#include "nvme-subsys.h" int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) { diff --git a/hw/nvme/trace-events b/hw/nvme/trace-events new file mode 100644 index 0000000000..ea33d0ccc3 --- /dev/null +++ b/hw/nvme/trace-events @@ -0,0 +1,204 @@ +# successful events +pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" +pci_nvme_irq_pin(void) "pulsing IRQ pin" +pci_nvme_irq_masked(void) "IRQ is masked" +pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" +pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" +pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" +pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d" +pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64"" +pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" +pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" +pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" +pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" +pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" +pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" +pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8"" +pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16"" +pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16"" +pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16"" +pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32"" +pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8"" +pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" +pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d" +pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32"" +pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32"" +pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32"" +pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64"" +pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" +pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" +pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" +pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" +pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid %"PRIu16" cns 0x%"PRIx8" ctrlid %"PRIu16" csi 0x%"PRIx8"" +pci_nvme_identify_ctrl(void) "identify controller" +pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8"" +pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_identify_ns_attached_list(uint16_t cntid) "cntid=%"PRIu16"" +pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8"" +pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8"" +pci_nvme_identify_cmd_set(void) "identify i/o command set" +pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64"" +pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" +pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" +pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" +pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d" +pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" +pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64"" +pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64"" +pci_nvme_process_aers(int queued) "queued %d" +pci_nvme_aer(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aer_aerl_exceeded(void) "aerl exceeded" +pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8"" +pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" +pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8"" +pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32"" +pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" +pci_nvme_enqueue_event_noqueue(int queued) "queued %d" +pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" +pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" +pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16"" +pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d" +pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" +pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" +pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16"" +pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" +pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" +pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" +pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" +pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" +pci_nvme_mmio_stopped(void) "cleared controller enable bit" +pci_nvme_mmio_shutdown_set(void) "shutdown bit set" +pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" +pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_reset_zone(uint64_t slba, uint32_t zone_idx, int all) "reset zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_offline_zone(uint64_t slba, uint32_t zone_idx, int all) "offline zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone descriptor extension, slba=%"PRIu64", idx=%"PRIu32"" +pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32"" +pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state" +pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state" + +# error conditions +pci_nvme_err_mdts(size_t len) "len %zu" +pci_nvme_err_zasl(size_t len) "len %zu" +pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" +pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" +pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" +pci_nvme_err_cfs(void) "controller fatal status" +pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16"" +pci_nvme_err_copy_invalid_format(uint8_t format) "format 0x%"PRIx8"" +pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" +pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" +pci_nvme_err_invalid_sgl_excess_length(uint32_t residual) "residual %"PRIu32"" +pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" +pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64"" +pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" +pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" +pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" +pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" +pci_nvme_err_invalid_log_page_offset(uint64_t ofs, uint64_t size) "must be <= %"PRIu64", got %"PRIu64"" +pci_nvme_err_cmb_invalid_cba(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" +pci_nvme_err_cmb_not_enabled(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" +pci_nvme_err_unaligned_zone_cmd(uint8_t action, uint64_t slba, uint64_t zslba) "unaligned zone op 0x%"PRIx32", got slba=%"PRIu64", zslba=%"PRIu64"" +pci_nvme_err_invalid_zone_state_transition(uint8_t action, uint64_t slba, uint8_t attrs) "action=0x%"PRIx8", slba=%"PRIu64", attrs=0x%"PRIx32"" +pci_nvme_err_write_not_at_wp(uint64_t slba, uint64_t zone, uint64_t wp) "writing at slba=%"PRIu64", zone=%"PRIu64", but wp=%"PRIu64"" +pci_nvme_err_append_not_at_start(uint64_t slba, uint64_t zone) "appending at slba=%"PRIu64", but zone=%"PRIu64"" +pci_nvme_err_zone_is_full(uint64_t zslba) "zslba 0x%"PRIx64"" +pci_nvme_err_zone_is_read_only(uint64_t zslba) "zslba 0x%"PRIx64"" +pci_nvme_err_zone_is_offline(uint64_t zslba) "zslba 0x%"PRIx64"" +pci_nvme_err_zone_boundary(uint64_t slba, uint32_t nlb, uint64_t zcap) "lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64"" +pci_nvme_err_zone_invalid_write(uint64_t slba, uint64_t wp) "lba 0x%"PRIx64" wp 0x%"PRIx64"" +pci_nvme_err_zone_write_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" +pci_nvme_err_zone_read_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" +pci_nvme_err_insuff_active_res(uint32_t max_active) "max_active=%"PRIu32" zone limit exceeded" +pci_nvme_err_insuff_open_res(uint32_t max_open) "max_open=%"PRIu32" zone limit exceeded" +pci_nvme_err_zd_extension_map_error(uint32_t zone_idx) "can't map descriptor extension for zone_idx=%"PRIu32"" +pci_nvme_err_invalid_iocsci(uint32_t idx) "unsupported command set combination index %"PRIu32"" +pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" +pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" +pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" +pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" +pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" +pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" +pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" +pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" +pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" +pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" +pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" +pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" +pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" +pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16"" +pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" +pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" +pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" +pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" +pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" +pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" +pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u" +pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" +pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" +pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32"" +pci_nvme_err_startfail(void) "setting controller enable bit failed" +pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8"" + +# undefined behavior +pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" +pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" +pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" +pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" +pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" +pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" +pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" +pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" +pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" +pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" +pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" +pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" +pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" +pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" +pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" +pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" +pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" +pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" +pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" +pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field" diff --git a/hw/nvme/trace.h b/hw/nvme/trace.h new file mode 100644 index 0000000000..b398ea107f --- /dev/null +++ b/hw/nvme/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_nvme.h" diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 34b3538beb..1698d3a192 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -3,7 +3,7 @@ pci_ss.add(when: 'CONFIG_PAM', if_true: files('pam.c')) pci_ss.add(when: 'CONFIG_PCI_BONITO', if_true: files('bonito.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_DESIGNWARE', if_true: files('designware.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', if_true: files('gpex.c')) -pci_ss.add(when: 'CONFIG_ACPI', if_true: files('gpex-acpi.c')) +pci_ss.add(when: ['CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', 'CONFIG_ACPI'], if_true: files('gpex-acpi.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_Q35', if_true: files('q35.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_XILINX', if_true: files('xilinx-pcie.c')) pci_ss.add(when: 'CONFIG_PCI_I440FX', if_true: files('i440fx.c')) diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index e51e0e5e5a..66e0b15d9e 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -3,6 +3,7 @@ config PSERIES imply PCI_DEVICES imply TEST_DEVICES imply VIRTIO_VGA + imply NVDIMM select DIMM select PCI select SPAPR_VSCSI diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index 86d6f379d1..597d974dd4 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -29,6 +29,9 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files( 'spapr_numa.c', 'pef.c', )) +ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_TCG'], if_true: files( + 'spapr_softmmu.c', +)) ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c')) ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_LINUX'], if_true: files( 'spapr_pci_vfio.c', diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index ffe01977cd..d16dd2d080 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -196,7 +196,7 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); - if (env->spr_cb[SPR_PURR].oea_read) { + if (ppc_has_spr(cpu, SPR_PURR)) { _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8f40319aee..c23bcc4490 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -703,10 +703,10 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); - if (env->spr_cb[SPR_PURR].oea_read) { + if (ppc_has_spr(cpu, SPR_PURR)) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1))); } - if (env->spr_cb[SPR_SPURR].oea_read) { + if (ppc_has_spr(cpu, SPR_PURR)) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1))); } @@ -979,6 +979,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt, */ val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */ val[3] = 0x00; /* Hash */ + spapr_check_mmu_mode(false); } else if (kvm_enabled()) { if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) { val[3] = 0x80; /* OV5_MMU_BOTH */ @@ -1556,6 +1557,22 @@ void spapr_setup_hpt(SpaprMachineState *spapr) } } +void spapr_check_mmu_mode(bool guest_radix) +{ + if (guest_radix) { + if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) { + error_report("Guest requested unavailable MMU mode (radix)."); + exit(EXIT_FAILURE); + } + } else { + if (kvm_enabled() && kvmppc_has_cap_mmu_radix() + && !kvmppc_has_cap_mmu_hash_v3()) { + error_report("Guest requested unavailable MMU mode (hash)."); + exit(EXIT_FAILURE); + } + } +} + static void spapr_machine_reset(MachineState *machine) { SpaprMachineState *spapr = SPAPR_MACHINE(machine); diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 9ea7ddd1e9..d0c419b392 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -371,6 +371,65 @@ static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift, return true; } +static void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, + bool (*cb)(void *, uint32_t, uint32_t), + void *opaque) +{ + PPCHash64Options *opts = cpu->hash64_opts; + int i; + int n = 0; + bool ci_largepage = false; + + assert(opts); + + n = 0; + for (i = 0; i < ARRAY_SIZE(opts->sps); i++) { + PPCHash64SegmentPageSizes *sps = &opts->sps[i]; + int j; + int m = 0; + + assert(n <= i); + + if (!sps->page_shift) { + break; + } + + for (j = 0; j < ARRAY_SIZE(sps->enc); j++) { + PPCHash64PageSize *ps = &sps->enc[j]; + + assert(m <= j); + if (!ps->page_shift) { + break; + } + + if (cb(opaque, sps->page_shift, ps->page_shift)) { + if (ps->page_shift >= 16) { + ci_largepage = true; + } + sps->enc[m++] = *ps; + } + } + + /* Clear rest of the row */ + for (j = m; j < ARRAY_SIZE(sps->enc); j++) { + memset(&sps->enc[j], 0, sizeof(sps->enc[j])); + } + + if (m) { + n++; + } + } + + /* Clear the rest of the table */ + for (i = n; i < ARRAY_SIZE(opts->sps); i++) { + memset(&opts->sps[i], 0, sizeof(opts->sps[i])); + } + + if (!ci_largepage) { + opts->flags &= ~PPC_HASH64_CI_LARGEPAGE; + } +} + static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu, uint8_t val, Error **errp) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 16c719c3de..f25014afda 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -20,24 +20,7 @@ #include "mmu-book3s-v3.h" #include "hw/mem/memory-device.h" -static bool has_spr(PowerPCCPU *cpu, int spr) -{ - /* We can test whether the SPR is defined by checking for a valid name */ - return cpu->env.spr_cb[spr].name != NULL; -} - -static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) -{ - /* - * hash value/pteg group index is normalized by HPT mask - */ - if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { - return false; - } - return true; -} - -static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr) +bool is_ram_address(SpaprMachineState *spapr, hwaddr addr) { MachineState *machine = MACHINE(spapr); DeviceMemoryState *dms = machine->device_memory; @@ -53,355 +36,6 @@ static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr) return false; } -static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - target_ulong pteh = args[2]; - target_ulong ptel = args[3]; - unsigned apshift; - target_ulong raddr; - target_ulong slot; - const ppc_hash_pte64_t *hptes; - - apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); - if (!apshift) { - /* Bad page size encoding */ - return H_PARAMETER; - } - - raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1); - - if (is_ram_address(spapr, raddr)) { - /* Regular RAM - should have WIMG=0010 */ - if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { - return H_PARAMETER; - } - } else { - target_ulong wimg_flags; - /* Looks like an IO address */ - /* FIXME: What WIMG combinations could be sensible for IO? - * For now we allow WIMG=010x, but are there others? */ - /* FIXME: Should we check against registered IO addresses? */ - wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); - - if (wimg_flags != HPTE64_R_I && - wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { - return H_PARAMETER; - } - } - - pteh &= ~0x60ULL; - - if (!valid_ptex(cpu, ptex)) { - return H_PARAMETER; - } - - slot = ptex & 7ULL; - ptex = ptex & ~7ULL; - - if (likely((flags & H_EXACT) == 0)) { - hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); - for (slot = 0; slot < 8; slot++) { - if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { - break; - } - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); - if (slot == 8) { - return H_PTEG_FULL; - } - } else { - hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); - if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { - ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); - return H_PTEG_FULL; - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); - } - - spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); - - args[0] = ptex + slot; - return H_SUCCESS; -} - -typedef enum { - REMOVE_SUCCESS = 0, - REMOVE_NOT_FOUND = 1, - REMOVE_PARM = 2, - REMOVE_HW = 3, -} RemoveResult; - -static RemoveResult remove_hpte(PowerPCCPU *cpu - , target_ulong ptex, - target_ulong avpn, - target_ulong flags, - target_ulong *vp, target_ulong *rp) -{ - const ppc_hash_pte64_t *hptes; - target_ulong v, r; - - if (!valid_ptex(cpu, ptex)) { - return REMOVE_PARM; - } - - hptes = ppc_hash64_map_hptes(cpu, ptex, 1); - v = ppc_hash64_hpte0(cpu, hptes, 0); - r = ppc_hash64_hpte1(cpu, hptes, 0); - ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); - - if ((v & HPTE64_V_VALID) == 0 || - ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || - ((flags & H_ANDCOND) && (v & avpn) != 0)) { - return REMOVE_NOT_FOUND; - } - *vp = v; - *rp = r; - spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0); - ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); - return REMOVE_SUCCESS; -} - -static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - target_ulong avpn = args[2]; - RemoveResult ret; - - ret = remove_hpte(cpu, ptex, avpn, flags, - &args[0], &args[1]); - - switch (ret) { - case REMOVE_SUCCESS: - check_tlb_flush(env, true); - return H_SUCCESS; - - case REMOVE_NOT_FOUND: - return H_NOT_FOUND; - - case REMOVE_PARM: - return H_PARAMETER; - - case REMOVE_HW: - return H_HARDWARE; - } - - g_assert_not_reached(); -} - -#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL -#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL -#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL -#define H_BULK_REMOVE_END 0xc000000000000000ULL -#define H_BULK_REMOVE_CODE 0x3000000000000000ULL -#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL -#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL -#define H_BULK_REMOVE_PARM 0x2000000000000000ULL -#define H_BULK_REMOVE_HW 0x3000000000000000ULL -#define H_BULK_REMOVE_RC 0x0c00000000000000ULL -#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL -#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL -#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL -#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL -#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL - -#define H_BULK_REMOVE_MAX_BATCH 4 - -static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - int i; - target_ulong rc = H_SUCCESS; - - for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { - target_ulong *tsh = &args[i*2]; - target_ulong tsl = args[i*2 + 1]; - target_ulong v, r, ret; - - if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { - break; - } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { - return H_PARAMETER; - } - - *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; - *tsh |= H_BULK_REMOVE_RESPONSE; - - if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { - *tsh |= H_BULK_REMOVE_PARM; - return H_PARAMETER; - } - - ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl, - (*tsh & H_BULK_REMOVE_FLAGS) >> 26, - &v, &r); - - *tsh |= ret << 60; - - switch (ret) { - case REMOVE_SUCCESS: - *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; - break; - - case REMOVE_PARM: - rc = H_PARAMETER; - goto exit; - - case REMOVE_HW: - rc = H_HARDWARE; - goto exit; - } - } - exit: - check_tlb_flush(env, true); - - return rc; -} - -static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - target_ulong avpn = args[2]; - const ppc_hash_pte64_t *hptes; - target_ulong v, r; - - if (!valid_ptex(cpu, ptex)) { - return H_PARAMETER; - } - - hptes = ppc_hash64_map_hptes(cpu, ptex, 1); - v = ppc_hash64_hpte0(cpu, hptes, 0); - r = ppc_hash64_hpte1(cpu, hptes, 0); - ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); - - if ((v & HPTE64_V_VALID) == 0 || - ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { - return H_NOT_FOUND; - } - - r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | - HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); - r |= (flags << 55) & HPTE64_R_PP0; - r |= (flags << 48) & HPTE64_R_KEY_HI; - r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); - spapr_store_hpte(cpu, ptex, - (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); - ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); - /* Flush the tlb */ - check_tlb_flush(env, true); - /* Don't need a memory barrier, due to qemu's global lock */ - spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); - return H_SUCCESS; -} - -static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - int i, ridx, n_entries = 1; - const ppc_hash_pte64_t *hptes; - - if (!valid_ptex(cpu, ptex)) { - return H_PARAMETER; - } - - if (flags & H_READ_4) { - /* Clear the two low order bits */ - ptex &= ~(3ULL); - n_entries = 4; - } - - hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries); - for (i = 0, ridx = 0; i < n_entries; i++) { - args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i); - args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i); - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries); - - return H_SUCCESS; -} - -struct SpaprPendingHpt { - /* These fields are read-only after initialization */ - int shift; - QemuThread thread; - - /* These fields are protected by the BQL */ - bool complete; - - /* These fields are private to the preparation thread if - * !complete, otherwise protected by the BQL */ - int ret; - void *hpt; -}; - -static void free_pending_hpt(SpaprPendingHpt *pending) -{ - if (pending->hpt) { - qemu_vfree(pending->hpt); - } - - g_free(pending); -} - -static void *hpt_prepare_thread(void *opaque) -{ - SpaprPendingHpt *pending = opaque; - size_t size = 1ULL << pending->shift; - - pending->hpt = qemu_try_memalign(size, size); - if (pending->hpt) { - memset(pending->hpt, 0, size); - pending->ret = H_SUCCESS; - } else { - pending->ret = H_NO_MEM; - } - - qemu_mutex_lock_iothread(); - - if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) { - /* Ready to go */ - pending->complete = true; - } else { - /* We've been cancelled, clean ourselves up */ - free_pending_hpt(pending); - } - - qemu_mutex_unlock_iothread(); - return NULL; -} - -/* Must be called with BQL held */ -static void cancel_hpt_prepare(SpaprMachineState *spapr) -{ - SpaprPendingHpt *pending = spapr->pending_hpt; - - /* Let the thread know it's cancelled */ - spapr->pending_hpt = NULL; - - if (!pending) { - /* Nothing to do */ - return; - } - - if (!pending->complete) { - /* thread will clean itself up */ - return; - } - - free_pending_hpt(pending); -} - /* Convert a return code from the KVM ioctl()s implementing resize HPT * into a PAPR hypercall return code */ static target_ulong resize_hpt_convert_rc(int ret) @@ -447,7 +81,6 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, { target_ulong flags = args[0]; int shift = args[1]; - SpaprPendingHpt *pending = spapr->pending_hpt; uint64_t current_ram_size; int rc; @@ -484,182 +117,11 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, return resize_hpt_convert_rc(rc); } - if (pending) { - /* something already in progress */ - if (pending->shift == shift) { - /* and it's suitable */ - if (pending->complete) { - return pending->ret; - } else { - return H_LONG_BUSY_ORDER_100_MSEC; - } - } - - /* not suitable, cancel and replace */ - cancel_hpt_prepare(spapr); - } - - if (!shift) { - /* nothing to do */ - return H_SUCCESS; - } - - /* start new prepare */ - - pending = g_new0(SpaprPendingHpt, 1); - pending->shift = shift; - pending->ret = H_HARDWARE; - - qemu_thread_create(&pending->thread, "sPAPR HPT prepare", - hpt_prepare_thread, pending, QEMU_THREAD_DETACHED); - - spapr->pending_hpt = pending; - - /* In theory we could estimate the time more accurately based on - * the new size, but there's not much point */ - return H_LONG_BUSY_ORDER_100_MSEC; -} - -static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot) -{ - uint8_t *addr = htab; - - addr += pteg * HASH_PTEG_SIZE_64; - addr += slot * HASH_PTE_SIZE_64; - return ldq_p(addr); -} - -static void new_hpte_store(void *htab, uint64_t pteg, int slot, - uint64_t pte0, uint64_t pte1) -{ - uint8_t *addr = htab; - - addr += pteg * HASH_PTEG_SIZE_64; - addr += slot * HASH_PTE_SIZE_64; - - stq_p(addr, pte0); - stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1); -} - -static int rehash_hpte(PowerPCCPU *cpu, - const ppc_hash_pte64_t *hptes, - void *old_hpt, uint64_t oldsize, - void *new_hpt, uint64_t newsize, - uint64_t pteg, int slot) -{ - uint64_t old_hash_mask = (oldsize >> 7) - 1; - uint64_t new_hash_mask = (newsize >> 7) - 1; - target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot); - target_ulong pte1; - uint64_t avpn; - unsigned base_pg_shift; - uint64_t hash, new_pteg, replace_pte0; - - if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) { - return H_SUCCESS; - } - - pte1 = ppc_hash64_hpte1(cpu, hptes, slot); - - base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1); - assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */ - avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23); - - if (pte0 & HPTE64_V_SECONDARY) { - pteg = ~pteg; - } - - if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) { - uint64_t offset, vsid; - - /* We only have 28 - 23 bits of offset in avpn */ - offset = (avpn & 0x1f) << 23; - vsid = avpn >> 5; - /* We can find more bits from the pteg value */ - if (base_pg_shift < 23) { - offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift; - } - - hash = vsid ^ (offset >> base_pg_shift); - } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) { - uint64_t offset, vsid; - - /* We only have 40 - 23 bits of seg_off in avpn */ - offset = (avpn & 0x1ffff) << 23; - vsid = avpn >> 17; - if (base_pg_shift < 23) { - offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask) - << base_pg_shift; - } - - hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift); - } else { - error_report("rehash_pte: Bad segment size in HPTE"); + if (kvm_enabled()) { return H_HARDWARE; } - new_pteg = hash & new_hash_mask; - if (pte0 & HPTE64_V_SECONDARY) { - assert(~pteg == (hash & old_hash_mask)); - new_pteg = ~new_pteg; - } else { - assert(pteg == (hash & old_hash_mask)); - } - assert((oldsize != newsize) || (pteg == new_pteg)); - replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot); - /* - * Strictly speaking, we don't need all these tests, since we only - * ever rehash bolted HPTEs. We might in future handle non-bolted - * HPTEs, though so make the logic correct for those cases as - * well. - */ - if (replace_pte0 & HPTE64_V_VALID) { - assert(newsize < oldsize); - if (replace_pte0 & HPTE64_V_BOLTED) { - if (pte0 & HPTE64_V_BOLTED) { - /* Bolted collision, nothing we can do */ - return H_PTEG_FULL; - } else { - /* Discard this hpte */ - return H_SUCCESS; - } - } - } - - new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1); - return H_SUCCESS; -} - -static int rehash_hpt(PowerPCCPU *cpu, - void *old_hpt, uint64_t oldsize, - void *new_hpt, uint64_t newsize) -{ - uint64_t n_ptegs = oldsize >> 7; - uint64_t pteg; - int slot; - int rc; - - for (pteg = 0; pteg < n_ptegs; pteg++) { - hwaddr ptex = pteg * HPTES_PER_GROUP; - const ppc_hash_pte64_t *hptes - = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); - - if (!hptes) { - return H_HARDWARE; - } - - for (slot = 0; slot < HPTES_PER_GROUP; slot++) { - rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize, - pteg, slot); - if (rc != H_SUCCESS) { - ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); - return rc; - } - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); - } - - return H_SUCCESS; + return softmmu_resize_hpt_prepare(cpu, spapr, shift); } static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data) @@ -675,7 +137,7 @@ static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data) } } -static void push_sregs_to_kvm_pr(SpaprMachineState *spapr) +void push_sregs_to_kvm_pr(SpaprMachineState *spapr) { CPUState *cs; @@ -700,9 +162,7 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, { target_ulong flags = args[0]; target_ulong shift = args[1]; - SpaprPendingHpt *pending = spapr->pending_hpt; int rc; - size_t newsize; if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { return H_AUTHORITY; @@ -725,42 +185,14 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, return rc; } - if (flags != 0) { - return H_PARAMETER; - } - - if (!pending || (pending->shift != shift)) { - /* no matching prepare */ - return H_CLOSED; - } - - if (!pending->complete) { - /* prepare has not completed */ - return H_BUSY; + if (kvm_enabled()) { + return H_HARDWARE; } - /* Shouldn't have got past PREPARE without an HPT */ - g_assert(spapr->htab_shift); - - newsize = 1ULL << pending->shift; - rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr), - pending->hpt, newsize); - if (rc == H_SUCCESS) { - qemu_vfree(spapr->htab); - spapr->htab = pending->hpt; - spapr->htab_shift = pending->shift; - - push_sregs_to_kvm_pr(spapr); - - pending->hpt = NULL; /* so it's not free()d */ - } + return softmmu_resize_hpt_commit(cpu, spapr, flags, shift); +} - /* Clean up */ - spapr->pending_hpt = NULL; - free_pending_hpt(pending); - return rc; -} static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) @@ -774,12 +206,12 @@ static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr, static target_ulong h_set_dabr(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) { - if (!has_spr(cpu, SPR_DABR)) { + if (!ppc_has_spr(cpu, SPR_DABR)) { return H_HARDWARE; /* DABR register not available */ } cpu_synchronize_state(CPU(cpu)); - if (has_spr(cpu, SPR_DABRX)) { + if (ppc_has_spr(cpu, SPR_DABRX)) { cpu->env.spr[SPR_DABRX] = 0x3; /* Use Problem and Privileged state */ } else if (!(args[0] & 0x4)) { /* Breakpoint Translation set? */ return H_RESERVED_DABR; @@ -794,7 +226,7 @@ static target_ulong h_set_xdabr(PowerPCCPU *cpu, SpaprMachineState *spapr, { target_ulong dabrx = args[1]; - if (!has_spr(cpu, SPR_DABR) || !has_spr(cpu, SPR_DABRX)) { + if (!ppc_has_spr(cpu, SPR_DABR) || !ppc_has_spr(cpu, SPR_DABRX)) { return H_HARDWARE; } @@ -1760,18 +1192,8 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); spapr_ovec_cleanup(ov5_guest); - if (guest_radix) { - if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) { - error_report("Guest requested unavailable MMU mode (radix)."); - exit(EXIT_FAILURE); - } - } else { - if (kvm_enabled() && kvmppc_has_cap_mmu_radix() - && !kvmppc_has_cap_mmu_hash_v3()) { - error_report("Guest requested unavailable MMU mode (hash)."); - exit(EXIT_FAILURE); - } - } + spapr_check_mmu_mode(guest_radix); + spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); spapr_ovec_cleanup(ov1_guest); @@ -2023,16 +1445,34 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, return H_FUNCTION; } -static void hypercall_register_types(void) +#ifndef CONFIG_TCG +static target_ulong h_softmmu(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + g_assert_not_reached(); +} + +static void hypercall_register_softmmu(void) { /* hcall-pft */ - spapr_register_hypercall(H_ENTER, h_enter); - spapr_register_hypercall(H_REMOVE, h_remove); - spapr_register_hypercall(H_PROTECT, h_protect); - spapr_register_hypercall(H_READ, h_read); + spapr_register_hypercall(H_ENTER, h_softmmu); + spapr_register_hypercall(H_REMOVE, h_softmmu); + spapr_register_hypercall(H_PROTECT, h_softmmu); + spapr_register_hypercall(H_READ, h_softmmu); /* hcall-bulk */ - spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); + spapr_register_hypercall(H_BULK_REMOVE, h_softmmu); +} +#else +static void hypercall_register_softmmu(void) +{ + /* DO NOTHING */ +} +#endif + +static void hypercall_register_types(void) +{ + hypercall_register_softmmu(); /* hcall-hpt-resize */ spapr_register_hypercall(H_RESIZE_HPT_PREPARE, h_resize_hpt_prepare); diff --git a/hw/ppc/spapr_softmmu.c b/hw/ppc/spapr_softmmu.c new file mode 100644 index 0000000000..6c6b86dd3c --- /dev/null +++ b/hw/ppc/spapr_softmmu.c @@ -0,0 +1,627 @@ +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qapi/error.h" +#include "sysemu/hw_accel.h" +#include "sysemu/runstate.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "helper_regs.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_cpu_core.h" +#include "mmu-hash64.h" +#include "cpu-models.h" +#include "trace.h" +#include "kvm_ppc.h" +#include "hw/ppc/fdt.h" +#include "hw/ppc/spapr_ovec.h" +#include "mmu-book3s-v3.h" +#include "hw/mem/memory-device.h" + +static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) +{ + /* + * hash value/pteg group index is normalized by HPT mask + */ + if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { + return false; + } + return true; +} + +static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + target_ulong pteh = args[2]; + target_ulong ptel = args[3]; + unsigned apshift; + target_ulong raddr; + target_ulong slot; + const ppc_hash_pte64_t *hptes; + + apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); + if (!apshift) { + /* Bad page size encoding */ + return H_PARAMETER; + } + + raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1); + + if (is_ram_address(spapr, raddr)) { + /* Regular RAM - should have WIMG=0010 */ + if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { + return H_PARAMETER; + } + } else { + target_ulong wimg_flags; + /* Looks like an IO address */ + /* FIXME: What WIMG combinations could be sensible for IO? + * For now we allow WIMG=010x, but are there others? */ + /* FIXME: Should we check against registered IO addresses? */ + wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); + + if (wimg_flags != HPTE64_R_I && + wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { + return H_PARAMETER; + } + } + + pteh &= ~0x60ULL; + + if (!valid_ptex(cpu, ptex)) { + return H_PARAMETER; + } + + slot = ptex & 7ULL; + ptex = ptex & ~7ULL; + + if (likely((flags & H_EXACT) == 0)) { + hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); + for (slot = 0; slot < 8; slot++) { + if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { + break; + } + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + if (slot == 8) { + return H_PTEG_FULL; + } + } else { + hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); + if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { + ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); + return H_PTEG_FULL; + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); + } + + spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); + + args[0] = ptex + slot; + return H_SUCCESS; +} + +typedef enum { + REMOVE_SUCCESS = 0, + REMOVE_NOT_FOUND = 1, + REMOVE_PARM = 2, + REMOVE_HW = 3, +} RemoveResult; + +static RemoveResult remove_hpte(PowerPCCPU *cpu + , target_ulong ptex, + target_ulong avpn, + target_ulong flags, + target_ulong *vp, target_ulong *rp) +{ + const ppc_hash_pte64_t *hptes; + target_ulong v, r; + + if (!valid_ptex(cpu, ptex)) { + return REMOVE_PARM; + } + + hptes = ppc_hash64_map_hptes(cpu, ptex, 1); + v = ppc_hash64_hpte0(cpu, hptes, 0); + r = ppc_hash64_hpte1(cpu, hptes, 0); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); + + if ((v & HPTE64_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || + ((flags & H_ANDCOND) && (v & avpn) != 0)) { + return REMOVE_NOT_FOUND; + } + *vp = v; + *rp = r; + spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0); + ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); + return REMOVE_SUCCESS; +} + +static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + target_ulong avpn = args[2]; + RemoveResult ret; + + ret = remove_hpte(cpu, ptex, avpn, flags, + &args[0], &args[1]); + + switch (ret) { + case REMOVE_SUCCESS: + check_tlb_flush(env, true); + return H_SUCCESS; + + case REMOVE_NOT_FOUND: + return H_NOT_FOUND; + + case REMOVE_PARM: + return H_PARAMETER; + + case REMOVE_HW: + return H_HARDWARE; + } + + g_assert_not_reached(); +} + +#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL +#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL +#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL +#define H_BULK_REMOVE_END 0xc000000000000000ULL +#define H_BULK_REMOVE_CODE 0x3000000000000000ULL +#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL +#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL +#define H_BULK_REMOVE_PARM 0x2000000000000000ULL +#define H_BULK_REMOVE_HW 0x3000000000000000ULL +#define H_BULK_REMOVE_RC 0x0c00000000000000ULL +#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL +#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL +#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL +#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL +#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL + +#define H_BULK_REMOVE_MAX_BATCH 4 + +static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + int i; + target_ulong rc = H_SUCCESS; + + for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { + target_ulong *tsh = &args[i*2]; + target_ulong tsl = args[i*2 + 1]; + target_ulong v, r, ret; + + if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { + break; + } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { + return H_PARAMETER; + } + + *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; + *tsh |= H_BULK_REMOVE_RESPONSE; + + if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { + *tsh |= H_BULK_REMOVE_PARM; + return H_PARAMETER; + } + + ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl, + (*tsh & H_BULK_REMOVE_FLAGS) >> 26, + &v, &r); + + *tsh |= ret << 60; + + switch (ret) { + case REMOVE_SUCCESS: + *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; + break; + + case REMOVE_PARM: + rc = H_PARAMETER; + goto exit; + + case REMOVE_HW: + rc = H_HARDWARE; + goto exit; + } + } + exit: + check_tlb_flush(env, true); + + return rc; +} + +static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + target_ulong avpn = args[2]; + const ppc_hash_pte64_t *hptes; + target_ulong v, r; + + if (!valid_ptex(cpu, ptex)) { + return H_PARAMETER; + } + + hptes = ppc_hash64_map_hptes(cpu, ptex, 1); + v = ppc_hash64_hpte0(cpu, hptes, 0); + r = ppc_hash64_hpte1(cpu, hptes, 0); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); + + if ((v & HPTE64_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { + return H_NOT_FOUND; + } + + r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | + HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); + r |= (flags << 55) & HPTE64_R_PP0; + r |= (flags << 48) & HPTE64_R_KEY_HI; + r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); + spapr_store_hpte(cpu, ptex, + (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); + ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); + /* Flush the tlb */ + check_tlb_flush(env, true); + /* Don't need a memory barrier, due to qemu's global lock */ + spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); + return H_SUCCESS; +} + +static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + int i, ridx, n_entries = 1; + const ppc_hash_pte64_t *hptes; + + if (!valid_ptex(cpu, ptex)) { + return H_PARAMETER; + } + + if (flags & H_READ_4) { + /* Clear the two low order bits */ + ptex &= ~(3ULL); + n_entries = 4; + } + + hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries); + for (i = 0, ridx = 0; i < n_entries; i++) { + args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i); + args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i); + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries); + + return H_SUCCESS; +} + +struct SpaprPendingHpt { + /* These fields are read-only after initialization */ + int shift; + QemuThread thread; + + /* These fields are protected by the BQL */ + bool complete; + + /* These fields are private to the preparation thread if + * !complete, otherwise protected by the BQL */ + int ret; + void *hpt; +}; + +static void free_pending_hpt(SpaprPendingHpt *pending) +{ + if (pending->hpt) { + qemu_vfree(pending->hpt); + } + + g_free(pending); +} + +static void *hpt_prepare_thread(void *opaque) +{ + SpaprPendingHpt *pending = opaque; + size_t size = 1ULL << pending->shift; + + pending->hpt = qemu_try_memalign(size, size); + if (pending->hpt) { + memset(pending->hpt, 0, size); + pending->ret = H_SUCCESS; + } else { + pending->ret = H_NO_MEM; + } + + qemu_mutex_lock_iothread(); + + if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) { + /* Ready to go */ + pending->complete = true; + } else { + /* We've been cancelled, clean ourselves up */ + free_pending_hpt(pending); + } + + qemu_mutex_unlock_iothread(); + return NULL; +} + +/* Must be called with BQL held */ +static void cancel_hpt_prepare(SpaprMachineState *spapr) +{ + SpaprPendingHpt *pending = spapr->pending_hpt; + + /* Let the thread know it's cancelled */ + spapr->pending_hpt = NULL; + + if (!pending) { + /* Nothing to do */ + return; + } + + if (!pending->complete) { + /* thread will clean itself up */ + return; + } + + free_pending_hpt(pending); +} + +target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong shift) +{ + SpaprPendingHpt *pending = spapr->pending_hpt; + + if (pending) { + /* something already in progress */ + if (pending->shift == shift) { + /* and it's suitable */ + if (pending->complete) { + return pending->ret; + } else { + return H_LONG_BUSY_ORDER_100_MSEC; + } + } + + /* not suitable, cancel and replace */ + cancel_hpt_prepare(spapr); + } + + if (!shift) { + /* nothing to do */ + return H_SUCCESS; + } + + /* start new prepare */ + + pending = g_new0(SpaprPendingHpt, 1); + pending->shift = shift; + pending->ret = H_HARDWARE; + + qemu_thread_create(&pending->thread, "sPAPR HPT prepare", + hpt_prepare_thread, pending, QEMU_THREAD_DETACHED); + + spapr->pending_hpt = pending; + + /* In theory we could estimate the time more accurately based on + * the new size, but there's not much point */ + return H_LONG_BUSY_ORDER_100_MSEC; +} + +static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot) +{ + uint8_t *addr = htab; + + addr += pteg * HASH_PTEG_SIZE_64; + addr += slot * HASH_PTE_SIZE_64; + return ldq_p(addr); +} + +static void new_hpte_store(void *htab, uint64_t pteg, int slot, + uint64_t pte0, uint64_t pte1) +{ + uint8_t *addr = htab; + + addr += pteg * HASH_PTEG_SIZE_64; + addr += slot * HASH_PTE_SIZE_64; + + stq_p(addr, pte0); + stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1); +} + +static int rehash_hpte(PowerPCCPU *cpu, + const ppc_hash_pte64_t *hptes, + void *old_hpt, uint64_t oldsize, + void *new_hpt, uint64_t newsize, + uint64_t pteg, int slot) +{ + uint64_t old_hash_mask = (oldsize >> 7) - 1; + uint64_t new_hash_mask = (newsize >> 7) - 1; + target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot); + target_ulong pte1; + uint64_t avpn; + unsigned base_pg_shift; + uint64_t hash, new_pteg, replace_pte0; + + if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) { + return H_SUCCESS; + } + + pte1 = ppc_hash64_hpte1(cpu, hptes, slot); + + base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1); + assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */ + avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23); + + if (pte0 & HPTE64_V_SECONDARY) { + pteg = ~pteg; + } + + if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) { + uint64_t offset, vsid; + + /* We only have 28 - 23 bits of offset in avpn */ + offset = (avpn & 0x1f) << 23; + vsid = avpn >> 5; + /* We can find more bits from the pteg value */ + if (base_pg_shift < 23) { + offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift; + } + + hash = vsid ^ (offset >> base_pg_shift); + } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) { + uint64_t offset, vsid; + + /* We only have 40 - 23 bits of seg_off in avpn */ + offset = (avpn & 0x1ffff) << 23; + vsid = avpn >> 17; + if (base_pg_shift < 23) { + offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask) + << base_pg_shift; + } + + hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift); + } else { + error_report("rehash_pte: Bad segment size in HPTE"); + return H_HARDWARE; + } + + new_pteg = hash & new_hash_mask; + if (pte0 & HPTE64_V_SECONDARY) { + assert(~pteg == (hash & old_hash_mask)); + new_pteg = ~new_pteg; + } else { + assert(pteg == (hash & old_hash_mask)); + } + assert((oldsize != newsize) || (pteg == new_pteg)); + replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot); + /* + * Strictly speaking, we don't need all these tests, since we only + * ever rehash bolted HPTEs. We might in future handle non-bolted + * HPTEs, though so make the logic correct for those cases as + * well. + */ + if (replace_pte0 & HPTE64_V_VALID) { + assert(newsize < oldsize); + if (replace_pte0 & HPTE64_V_BOLTED) { + if (pte0 & HPTE64_V_BOLTED) { + /* Bolted collision, nothing we can do */ + return H_PTEG_FULL; + } else { + /* Discard this hpte */ + return H_SUCCESS; + } + } + } + + new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1); + return H_SUCCESS; +} + +static int rehash_hpt(PowerPCCPU *cpu, + void *old_hpt, uint64_t oldsize, + void *new_hpt, uint64_t newsize) +{ + uint64_t n_ptegs = oldsize >> 7; + uint64_t pteg; + int slot; + int rc; + + for (pteg = 0; pteg < n_ptegs; pteg++) { + hwaddr ptex = pteg * HPTES_PER_GROUP; + const ppc_hash_pte64_t *hptes + = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); + + if (!hptes) { + return H_HARDWARE; + } + + for (slot = 0; slot < HPTES_PER_GROUP; slot++) { + rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize, + pteg, slot); + if (rc != H_SUCCESS) { + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + return rc; + } + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + } + + return H_SUCCESS; +} + +target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong flags, + target_ulong shift) +{ + SpaprPendingHpt *pending = spapr->pending_hpt; + int rc; + size_t newsize; + + if (flags != 0) { + return H_PARAMETER; + } + + if (!pending || (pending->shift != shift)) { + /* no matching prepare */ + return H_CLOSED; + } + + if (!pending->complete) { + /* prepare has not completed */ + return H_BUSY; + } + + /* Shouldn't have got past PREPARE without an HPT */ + g_assert(spapr->htab_shift); + + newsize = 1ULL << pending->shift; + rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr), + pending->hpt, newsize); + if (rc == H_SUCCESS) { + qemu_vfree(spapr->htab); + spapr->htab = pending->hpt; + spapr->htab_shift = pending->shift; + + push_sregs_to_kvm_pr(spapr); + + pending->hpt = NULL; /* so it's not free()d */ + } + + /* Clean up */ + spapr->pending_hpt = NULL; + free_pending_hpt(pending); + + return rc; +} + +static void hypercall_register_types(void) +{ + /* hcall-pft */ + spapr_register_hypercall(H_ENTER, h_enter); + spapr_register_hypercall(H_REMOVE, h_remove); + spapr_register_hypercall(H_PROTECT, h_protect); + spapr_register_hypercall(H_READ, h_read); + + /* hcall-bulk */ + spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); + +} + +type_init(hypercall_register_types) diff --git a/hw/remote/memory.c b/hw/remote/memory.c index 2d4174614a..472ed2a272 100644 --- a/hw/remote/memory.c +++ b/hw/remote/memory.c @@ -41,10 +41,9 @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp) remote_sysmem_reset(); - for (region = 0; region < msg->num_fds; region++) { - g_autofree char *name; + for (region = 0; region < msg->num_fds; region++, suffix++) { + g_autofree char *name = g_strdup_printf("remote-mem-%u", suffix); subregion = g_new(MemoryRegion, 1); - name = g_strdup_printf("remote-mem-%u", suffix++); memory_region_init_ram_from_fd(subregion, NULL, name, sysmem_info->sizes[region], true, msg->fds[region], diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index 9ce31526e8..e67a5de72c 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -218,7 +218,7 @@ uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev, bool mpqemu_msg_valid(MPQemuMsg *msg) { - if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) { + if (msg->cmd >= MPQEMU_CMD_MAX || msg->cmd < 0) { return false; } diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 4fa4be079d..6dda705fc2 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -347,13 +347,12 @@ static void probe_pci_info(PCIDevice *dev, Error **errp) PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY; if (size) { - g_autofree char *name; + g_autofree char *name = g_strdup_printf("bar-region-%d", i); pdev->region[i].dev = pdev; pdev->region[i].present = true; if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { pdev->region[i].memory = true; } - name = g_strdup_printf("bar-region-%d", i); memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev), &proxy_mr_ops, &pdev->region[i], name, size); diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 1de18cdcf1..86957ec7b0 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -19,9 +19,20 @@ config OPENTITAN select IBEX select UNIMP +config SHAKTI + bool + +config SHAKTI_C + bool + select UNIMP + select SHAKTI + select SIFIVE_CLINT + select SIFIVE_PLIC + config RISCV_VIRT bool imply PCI_DEVICES + imply VIRTIO_VGA imply TEST_DEVICES select GOLDFISH_RTC select MSI_NONBROKEN diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 275c0f7eb7..a97454661c 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -4,6 +4,7 @@ riscv_ss.add(files('numa.c')) riscv_ss.add(files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) +riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index dc9dea117e..7545dcda9c 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -119,7 +119,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); - object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort); + object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); /* Boot ROM */ @@ -148,16 +148,16 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_DEV_UART].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_TX_WATERMARK_IRQ)); + IBEX_UART0_TX_WATERMARK_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 1, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_RX_WATERMARK_IRQ)); + IBEX_UART0_RX_WATERMARK_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 2, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_TX_EMPTY_IRQ)); + IBEX_UART0_TX_EMPTY_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 3, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_RX_OVERFLOW_IRQ)); + IBEX_UART0_RX_OVERFLOW_IRQ)); create_unimplemented_device("riscv.lowrisc.ibex.gpio", memmap[IBEX_DEV_GPIO].base, memmap[IBEX_DEV_GPIO].size); diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c new file mode 100644 index 0000000000..18f70fadaa --- /dev/null +++ b/hw/riscv/shakti_c.c @@ -0,0 +1,181 @@ +/* + * Shakti C-class SoC emulation + * + * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/boards.h" +#include "hw/riscv/shakti_c.h" +#include "qapi/error.h" +#include "hw/intc/sifive_plic.h" +#include "hw/intc/sifive_clint.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "hw/riscv/boot.h" + + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} shakti_c_memmap[] = { + [SHAKTI_C_ROM] = { 0x00001000, 0x2000 }, + [SHAKTI_C_RAM] = { 0x80000000, 0x0 }, + [SHAKTI_C_UART] = { 0x00011300, 0x00040 }, + [SHAKTI_C_GPIO] = { 0x020d0000, 0x00100 }, + [SHAKTI_C_PLIC] = { 0x0c000000, 0x20000 }, + [SHAKTI_C_CLINT] = { 0x02000000, 0xc0000 }, + [SHAKTI_C_I2C] = { 0x20c00000, 0x00100 }, +}; + +static void shakti_c_machine_state_init(MachineState *mstate) +{ + ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate); + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *main_mem = g_new(MemoryRegion, 1); + + /* Allow only Shakti C CPU for this platform */ + if (strcmp(mstate->cpu_type, TYPE_RISCV_CPU_SHAKTI_C) != 0) { + error_report("This board can only be used with Shakti C CPU"); + exit(1); + } + + /* Initialize SoC */ + object_initialize_child(OBJECT(mstate), "soc", &sms->soc, + TYPE_RISCV_SHAKTI_SOC); + qdev_realize(DEVICE(&sms->soc), NULL, &error_abort); + + /* register RAM */ + memory_region_init_ram(main_mem, NULL, "riscv.shakti.c.ram", + mstate->ram_size, &error_fatal); + memory_region_add_subregion(system_memory, + shakti_c_memmap[SHAKTI_C_RAM].base, + main_mem); + + /* ROM reset vector */ + riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, + shakti_c_memmap[SHAKTI_C_RAM].base, + shakti_c_memmap[SHAKTI_C_ROM].base, + shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0, + NULL); + if (mstate->firmware) { + riscv_load_firmware(mstate->firmware, + shakti_c_memmap[SHAKTI_C_RAM].base, + NULL); + } +} + +static void shakti_c_machine_instance_init(Object *obj) +{ +} + +static void shakti_c_machine_class_init(ObjectClass *klass, void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + mc->desc = "RISC-V Board compatible with Shakti SDK"; + mc->init = shakti_c_machine_state_init; + mc->default_cpu_type = TYPE_RISCV_CPU_SHAKTI_C; +} + +static const TypeInfo shakti_c_machine_type_info = { + .name = TYPE_RISCV_SHAKTI_MACHINE, + .parent = TYPE_MACHINE, + .class_init = shakti_c_machine_class_init, + .instance_init = shakti_c_machine_instance_init, + .instance_size = sizeof(ShaktiCMachineState), +}; + +static void shakti_c_machine_type_info_register(void) +{ + type_register_static(&shakti_c_machine_type_info); +} +type_init(shakti_c_machine_type_info_register) + +static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp) +{ + ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(dev); + MemoryRegion *system_memory = get_system_memory(); + + sysbus_realize(SYS_BUS_DEVICE(&sss->cpus), &error_abort); + + sss->plic = sifive_plic_create(shakti_c_memmap[SHAKTI_C_PLIC].base, + (char *)SHAKTI_C_PLIC_HART_CONFIG, 0, + SHAKTI_C_PLIC_NUM_SOURCES, + SHAKTI_C_PLIC_NUM_PRIORITIES, + SHAKTI_C_PLIC_PRIORITY_BASE, + SHAKTI_C_PLIC_PENDING_BASE, + SHAKTI_C_PLIC_ENABLE_BASE, + SHAKTI_C_PLIC_ENABLE_STRIDE, + SHAKTI_C_PLIC_CONTEXT_BASE, + SHAKTI_C_PLIC_CONTEXT_STRIDE, + shakti_c_memmap[SHAKTI_C_PLIC].size); + + sifive_clint_create(shakti_c_memmap[SHAKTI_C_CLINT].base, + shakti_c_memmap[SHAKTI_C_CLINT].size, 0, 1, + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + SIFIVE_CLINT_TIMEBASE_FREQ, false); + + qdev_prop_set_chr(DEVICE(&(sss->uart)), "chardev", serial_hd(0)); + if (!sysbus_realize(SYS_BUS_DEVICE(&sss->uart), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&sss->uart), 0, + shakti_c_memmap[SHAKTI_C_UART].base); + + /* ROM */ + memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.shakti.c.rom", + shakti_c_memmap[SHAKTI_C_ROM].size, &error_fatal); + memory_region_add_subregion(system_memory, + shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom); +} + +static void shakti_c_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = shakti_c_soc_state_realize; +} + +static void shakti_c_soc_instance_init(Object *obj) +{ + ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(obj); + + object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY); + object_initialize_child(obj, "uart", &sss->uart, TYPE_SHAKTI_UART); + + /* + * CPU type is fixed and we are not supporting passing from commandline yet. + * So let it be in instance_init. When supported should use ms->cpu_type + * instead of TYPE_RISCV_CPU_SHAKTI_C + */ + object_property_set_str(OBJECT(&sss->cpus), "cpu-type", + TYPE_RISCV_CPU_SHAKTI_C, &error_abort); + object_property_set_int(OBJECT(&sss->cpus), "num-harts", 1, + &error_abort); +} + +static const TypeInfo shakti_c_type_info = { + .name = TYPE_RISCV_SHAKTI_SOC, + .parent = TYPE_DEVICE, + .class_init = shakti_c_soc_class_init, + .instance_init = shakti_c_soc_instance_init, + .instance_size = sizeof(ShaktiCSoCState), +}; + +static void shakti_c_type_info_register(void) +{ + type_register_static(&shakti_c_type_info); +} +type_init(shakti_c_type_info_register) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 3e8b44b2c0..ddc658c8d6 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -48,7 +48,7 @@ #include "sysemu/arch_init.h" #include "sysemu/sysemu.h" -static MemMapEntry sifive_e_memmap[] = { +static const MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 }, diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 3d2d3854e7..4fbafddb22 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -871,22 +871,6 @@ static void rtc_notify_suspend(Notifier *notifier, void *data) rtc_set_memory(ISA_DEVICE(s), 0xF, 0xFE); } -static void rtc_reset(void *opaque) -{ - RTCState *s = opaque; - - s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); - s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); - check_update_timer(s); - - qemu_irq_lower(s->irq); - - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - s->irq_coalesced = 0; - s->irq_reinject_on_ack_count = 0; - } -} - static const MemoryRegionOps cmos_ops = { .read = cmos_ioport_read, .write = cmos_ioport_write, @@ -961,7 +945,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) memory_region_add_coalescing(&s->coalesced_io, 0, 1); qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3); - qemu_register_reset(rtc_reset, s); object_property_add_tm(OBJECT(s), "date", rtc_get_date); @@ -997,15 +980,32 @@ static Property mc146818rtc_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void rtc_resetdev(DeviceState *d) +static void rtc_reset_enter(Object *obj, ResetType type) { - RTCState *s = MC146818_RTC(d); + RTCState *s = MC146818_RTC(obj); /* Reason: VM do suspend self will set 0xfe * Reset any values other than 0xfe(Guest suspend case) */ if (s->cmos_data[0x0f] != 0xfe) { s->cmos_data[0x0f] = 0x00; } + + s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); + s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); + check_update_timer(s); + + + if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + s->irq_coalesced = 0; + s->irq_reinject_on_ack_count = 0; + } +} + +static void rtc_reset_hold(Object *obj) +{ + RTCState *s = MC146818_RTC(obj); + + qemu_irq_lower(s->irq); } static void rtc_build_aml(ISADevice *isadev, Aml *scope) @@ -1032,11 +1032,13 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope) static void rtc_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = rtc_realizefn; - dc->reset = rtc_resetdev; dc->vmsd = &vmstate_rtc; + rc->phases.enter = rtc_reset_enter; + rc->phases.hold = rtc_reset_hold; isa->build_aml = rtc_build_aml; device_class_set_props(dc, mc146818rtc_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 25e628f575..13e93d8d8f 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -158,7 +158,6 @@ static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_props(dc, emulated_ccw_3270_properties); - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; dc->realize = emulated_ccw_3270_realize; dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c index c9707110e9..95f269ab44 100644 --- a/hw/s390x/ccw-device.c +++ b/hw/s390x/ccw-device.c @@ -59,6 +59,7 @@ static void ccw_device_class_init(ObjectClass *klass, void *data) k->refill_ids = ccw_device_refill_ids; device_class_set_props(dc, ccw_device_properties); dc->reset = ccw_device_reset; + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; } const VMStateDescription vmstate_ccw_dev = { diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h index 832c78cd42..6dff95225d 100644 --- a/hw/s390x/ccw-device.h +++ b/hw/s390x/ccw-device.h @@ -14,6 +14,7 @@ #include "qom/object.h" #include "hw/qdev-core.h" #include "hw/s390x/css.h" +#include "hw/s390x/css-bridge.h" struct CcwDevice { DeviceState parent_obj; diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 242491a1ae..c227c77984 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -176,10 +176,8 @@ static void s390_ccw_instance_init(Object *obj) static void s390_ccw_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; cdc->realize = s390_ccw_realize; cdc->unrealize = s390_ccw_unrealize; } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 92b950e09a..220b9efcf9 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1234,7 +1234,6 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) k->unplug = virtio_ccw_busdev_unplug; dc->realize = virtio_ccw_busdev_realize; dc->unrealize = virtio_ccw_busdev_unrealize; - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; device_class_set_parent_reset(dc, virtio_ccw_reset, &vdc->parent_reset); } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 3580e7ee61..e8a547dbb7 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1582,6 +1582,7 @@ invalid_field: scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); } +/* sector_num and nb_sectors expected to be in qdev blocksize */ static inline bool check_lba_range(SCSIDiskState *s, uint64_t sector_num, uint32_t nb_sectors) { @@ -1614,11 +1615,12 @@ static void scsi_unmap_complete_noio(UnmapCBData *data, int ret) assert(r->req.aiocb == NULL); if (data->count > 0) { - r->sector = ldq_be_p(&data->inbuf[0]) - * (s->qdev.blocksize / BDRV_SECTOR_SIZE); - r->sector_count = (ldl_be_p(&data->inbuf[8]) & 0xffffffffULL) - * (s->qdev.blocksize / BDRV_SECTOR_SIZE); - if (!check_lba_range(s, r->sector, r->sector_count)) { + uint64_t sector_num = ldq_be_p(&data->inbuf[0]); + uint32_t nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; + r->sector = sector_num * (s->qdev.blocksize / BDRV_SECTOR_SIZE); + r->sector_count = nb_sectors * (s->qdev.blocksize / BDRV_SECTOR_SIZE); + + if (!check_lba_range(s, sector_num, nb_sectors)) { block_acct_invalid(blk_get_stats(s->qdev.conf.blk), BLOCK_ACCT_UNMAP); scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 4ad8793406..28e003250a 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -94,8 +94,7 @@ static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev, return progress; } -static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, - VirtIOHandleAIOOutput fn) +static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); int rc; @@ -109,7 +108,6 @@ static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, return rc; } - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, fn); return 0; } @@ -154,40 +152,55 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) goto fail_guest_notifiers; } - aio_context_acquire(s->ctx); - rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0, - virtio_scsi_data_plane_handle_ctrl); - if (rc) { - goto fail_vrings; + memory_region_transaction_begin(); + + rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0); + if (rc != 0) { + goto fail_host_notifiers; } vq_init_count++; - rc = virtio_scsi_vring_init(s, vs->event_vq, 1, - virtio_scsi_data_plane_handle_event); - if (rc) { - goto fail_vrings; + rc = virtio_scsi_set_host_notifier(s, vs->event_vq, 1); + if (rc != 0) { + goto fail_host_notifiers; } vq_init_count++; + for (i = 0; i < vs->conf.num_queues; i++) { - rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2, - virtio_scsi_data_plane_handle_cmd); + rc = virtio_scsi_set_host_notifier(s, vs->cmd_vqs[i], i + 2); if (rc) { - goto fail_vrings; + goto fail_host_notifiers; } vq_init_count++; } + memory_region_transaction_commit(); + + aio_context_acquire(s->ctx); + virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, + virtio_scsi_data_plane_handle_ctrl); + virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, + virtio_scsi_data_plane_handle_event); + + for (i = 0; i < vs->conf.num_queues; i++) { + virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, + virtio_scsi_data_plane_handle_cmd); + } + s->dataplane_starting = false; s->dataplane_started = true; aio_context_release(s->ctx); return 0; -fail_vrings: - aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s); - aio_context_release(s->ctx); +fail_host_notifiers: for (i = 0; i < vq_init_count; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < vq_init_count; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); @@ -225,8 +238,15 @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev) blk_drain_all(); /* ensure there are no in-flight requests */ + memory_region_transaction_begin(); + for (i = 0; i < vs->conf.num_queues + 2; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < vs->conf.num_queues + 2; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } diff --git a/hw/sd/meson.build b/hw/sd/meson.build index 9c29691e13..f1ce357a3b 100644 --- a/hw/sd/meson.build +++ b/hw/sd/meson.build @@ -4,7 +4,6 @@ softmmu_ss.add(when: 'CONFIG_SDHCI', if_true: files('sdhci.c')) softmmu_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c')) softmmu_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-memcard.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c')) diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c deleted file mode 100644 index a1235aa46c..0000000000 --- a/hw/sd/milkymist-memcard.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * QEMU model of the Milkymist SD Card Controller. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/memcard.pdf - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qapi/error.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "hw/qdev-properties.h" -#include "hw/sd/sd.h" -#include "qom/object.h" - -enum { - ENABLE_CMD_TX = (1<<0), - ENABLE_CMD_RX = (1<<1), - ENABLE_DAT_TX = (1<<2), - ENABLE_DAT_RX = (1<<3), -}; - -enum { - PENDING_CMD_TX = (1<<0), - PENDING_CMD_RX = (1<<1), - PENDING_DAT_TX = (1<<2), - PENDING_DAT_RX = (1<<3), -}; - -enum { - START_CMD_TX = (1<<0), - START_DAT_RX = (1<<1), -}; - -enum { - R_CLK2XDIV = 0, - R_ENABLE, - R_PENDING, - R_START, - R_CMD, - R_DAT, - R_MAX -}; - -#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMemcardState, MILKYMIST_MEMCARD) - -#define TYPE_MILKYMIST_SDBUS "milkymist-sdbus" - -struct MilkymistMemcardState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - SDBus sdbus; - - int command_write_ptr; - int response_read_ptr; - int response_len; - int ignore_next_cmd; - int enabled; - uint8_t command[6]; - uint8_t response[17]; - uint32_t regs[R_MAX]; -}; - -static void update_pending_bits(MilkymistMemcardState *s) -{ - /* transmits are instantaneous, thus tx pending bits are never set */ - s->regs[R_PENDING] = 0; - /* if rx is enabled the corresponding pending bits are always set */ - if (s->regs[R_ENABLE] & ENABLE_CMD_RX) { - s->regs[R_PENDING] |= PENDING_CMD_RX; - } - if (s->regs[R_ENABLE] & ENABLE_DAT_RX) { - s->regs[R_PENDING] |= PENDING_DAT_RX; - } -} - -static void memcard_sd_command(MilkymistMemcardState *s) -{ - SDRequest req; - - req.cmd = s->command[0] & 0x3f; - req.arg = ldl_be_p(s->command + 1); - req.crc = s->command[5]; - - s->response[0] = req.cmd; - s->response_len = sdbus_do_command(&s->sdbus, &req, s->response + 1); - s->response_read_ptr = 0; - - if (s->response_len == 16) { - /* R2 response */ - s->response[0] = 0x3f; - s->response_len += 1; - } else if (s->response_len == 4) { - /* no crc calculation, insert dummy byte */ - s->response[5] = 0; - s->response_len += 2; - } - - if (req.cmd == 0) { - /* next write is a dummy byte to clock the initialization of the sd - * card */ - s->ignore_next_cmd = 1; - } -} - -static uint64_t memcard_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistMemcardState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CMD: - if (!s->enabled) { - r = 0xff; - } else { - r = s->response[s->response_read_ptr++]; - if (s->response_read_ptr > s->response_len) { - qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: " - "read more cmd bytes than available: clipping\n"); - s->response_read_ptr = 0; - } - } - break; - case R_DAT: - if (!s->enabled) { - r = 0xffffffff; - } else { - sdbus_read_data(&s->sdbus, &r, sizeof(r)); - be32_to_cpus(&r); - } - break; - case R_CLK2XDIV: - case R_ENABLE: - case R_PENDING: - case R_START: - r = s->regs[addr]; - break; - - default: - qemu_log_mask(LOG_UNIMP, "milkymist_memcard: " - "read access to unknown register 0x%" HWADDR_PRIx "\n", - addr << 2); - break; - } - - trace_milkymist_memcard_memory_read(addr << 2, r); - - return r; -} - -static void memcard_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistMemcardState *s = opaque; - uint32_t val32; - - trace_milkymist_memcard_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_PENDING: - /* clear rx pending bits */ - s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX)); - update_pending_bits(s); - break; - case R_CMD: - if (!s->enabled) { - break; - } - if (s->ignore_next_cmd) { - s->ignore_next_cmd = 0; - break; - } - s->command[s->command_write_ptr] = value & 0xff; - s->command_write_ptr = (s->command_write_ptr + 1) % 6; - if (s->command_write_ptr == 0) { - memcard_sd_command(s); - } - break; - case R_DAT: - if (!s->enabled) { - break; - } - val32 = cpu_to_be32(value); - sdbus_write_data(&s->sdbus, &val32, sizeof(val32)); - break; - case R_ENABLE: - s->regs[addr] = value; - update_pending_bits(s); - break; - case R_CLK2XDIV: - case R_START: - s->regs[addr] = value; - break; - - default: - qemu_log_mask(LOG_UNIMP, "milkymist_memcard: " - "write access to unknown register 0x%" HWADDR_PRIx " " - "(value 0x%" PRIx64 ")\n", addr << 2, value); - break; - } -} - -static const MemoryRegionOps memcard_mmio_ops = { - .read = memcard_read, - .write = memcard_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_memcard_reset(DeviceState *d) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(d); - int i; - - s->command_write_ptr = 0; - s->response_read_ptr = 0; - s->response_len = 0; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } -} - -static void milkymist_memcard_set_readonly(DeviceState *dev, bool level) -{ - qemu_log_mask(LOG_UNIMP, - "milkymist_memcard: read-only mode not supported\n"); -} - -static void milkymist_memcard_set_inserted(DeviceState *dev, bool level) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev); - - s->enabled = !!level; -} - -static void milkymist_memcard_init(Object *obj) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s, - "milkymist-memcard", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, - DEVICE(obj), "sd-bus"); -} - -static const VMStateDescription vmstate_milkymist_memcard = { - .name = "milkymist-memcard", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(command_write_ptr, MilkymistMemcardState), - VMSTATE_INT32(response_read_ptr, MilkymistMemcardState), - VMSTATE_INT32(response_len, MilkymistMemcardState), - VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState), - VMSTATE_INT32(enabled, MilkymistMemcardState), - VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6), - VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17), - VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_memcard_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = milkymist_memcard_reset; - dc->vmsd = &vmstate_milkymist_memcard; - /* Reason: output IRQs should be wired up */ - dc->user_creatable = false; -} - -static const TypeInfo milkymist_memcard_info = { - .name = TYPE_MILKYMIST_MEMCARD, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistMemcardState), - .instance_init = milkymist_memcard_init, - .class_init = milkymist_memcard_class_init, -}; - -static void milkymist_sdbus_class_init(ObjectClass *klass, void *data) -{ - SDBusClass *sbc = SD_BUS_CLASS(klass); - - sbc->set_inserted = milkymist_memcard_set_inserted; - sbc->set_readonly = milkymist_memcard_set_readonly; -} - -static const TypeInfo milkymist_sdbus_info = { - .name = TYPE_MILKYMIST_SDBUS, - .parent = TYPE_SD_BUS, - .instance_size = sizeof(SDBus), - .class_init = milkymist_sdbus_class_init, -}; - -static void milkymist_memcard_register_types(void) -{ - type_register_static(&milkymist_memcard_info); - type_register_static(&milkymist_sdbus_info); -} - -type_init(milkymist_memcard_register_types) diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index 1f946908fe..b67def6381 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -318,7 +318,7 @@ void omap_mmc_reset(struct omap_mmc_s *host) * into any bus, and we must reset it manually. When omap_mmc is * QOMified this must move into the QOM reset function. */ - device_legacy_reset(DEVICE(host->card)); + device_cold_reset(DEVICE(host->card)); } static uint64_t omap_mmc_read(void *opaque, hwaddr offset, diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 4140e48540..e185d07a1d 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -55,10 +55,6 @@ sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint8_t sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t length) "%s %20s/ CMD%02d len %" PRIu32 sdcard_set_voltage(uint16_t millivolts) "%u mV" -# milkymist-memcard.c -milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" - # pxa2xx_mmci.c pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index f22c4f5b73..7397e56737 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -27,6 +27,7 @@ #include "hw/firmware/smbios.h" #include "hw/loader.h" #include "hw/boards.h" +#include "hw/pci/pci_bus.h" #include "smbios_build.h" /* legacy structures and constants for <= 2.0 machines */ @@ -118,6 +119,28 @@ static struct { uint16_t speed; } type17; +static QEnumLookup type41_kind_lookup = { + .array = (const char *const[]) { + "other", + "unknown", + "video", + "scsi", + "ethernet", + "tokenring", + "sound", + "pata", + "sata", + "sas", + }, + .size = 10 +}; +struct type41_instance { + const char *designation, *pcidev; + uint8_t instance, kind; + QTAILQ_ENTRY(type41_instance) next; +}; +static QTAILQ_HEAD(, type41_instance) type41 = QTAILQ_HEAD_INITIALIZER(type41); + static QemuOptsList qemu_smbios_opts = { .name = "smbios", .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head), @@ -358,6 +381,32 @@ static const QemuOptDesc qemu_smbios_type17_opts[] = { { /* end of list */ } }; +static const QemuOptDesc qemu_smbios_type41_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "designation", + .type = QEMU_OPT_STRING, + .help = "reference designation string", + },{ + .name = "kind", + .type = QEMU_OPT_STRING, + .help = "device type", + .def_value_str = "other", + },{ + .name = "instance", + .type = QEMU_OPT_NUMBER, + .help = "device type instance", + },{ + .name = "pcidev", + .type = QEMU_OPT_STRING, + .help = "PCI device", + }, + { /* end of list */ } +}; + static void smbios_register_config(void) { qemu_add_opts(&qemu_smbios_opts); @@ -773,6 +822,53 @@ static void smbios_build_type_32_table(void) SMBIOS_BUILD_TABLE_POST; } +static void smbios_build_type_41_table(Error **errp) +{ + unsigned instance = 0; + struct type41_instance *t41; + + QTAILQ_FOREACH(t41, &type41, next) { + SMBIOS_BUILD_TABLE_PRE(41, 0x2900 + instance, true); + + SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation); + t->device_type = t41->kind; + t->device_type_instance = t41->instance; + t->segment_group_number = cpu_to_le16(0); + t->bus_number = 0; + t->device_number = 0; + + if (t41->pcidev) { + PCIDevice *pdev = NULL; + int rc = pci_qdev_find_device(t41->pcidev, &pdev); + if (rc != 0) { + error_setg(errp, + "No PCI device %s for SMBIOS type 41 entry %s", + t41->pcidev, t41->designation); + return; + } + /* + * We only handle the case were the device is attached to + * the PCI root bus. The general case is more complex as + * bridges are enumerated later and the table would need + * to be updated at this moment. + */ + if (!pci_bus_is_root(pci_get_bus(pdev))) { + error_setg(errp, + "Cannot create type 41 entry for PCI device %s: " + "not attached to the root bus", + t41->pcidev); + return; + } + t->segment_group_number = cpu_to_le16(0); + t->bus_number = pci_dev_bus_num(pdev); + t->device_number = pdev->devfn; + } + + SMBIOS_BUILD_TABLE_POST; + instance++; + } +} + static void smbios_build_type_127_table(void) { SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */ @@ -883,7 +979,8 @@ void smbios_get_tables(MachineState *ms, const struct smbios_phys_mem_area *mem_array, const unsigned int mem_array_size, uint8_t **tables, size_t *tables_len, - uint8_t **anchor, size_t *anchor_len) + uint8_t **anchor, size_t *anchor_len, + Error **errp) { unsigned i, dimm_cnt; @@ -928,6 +1025,7 @@ void smbios_get_tables(MachineState *ms, smbios_build_type_32_table(); smbios_build_type_38_table(); + smbios_build_type_41_table(errp); smbios_build_type_127_table(); smbios_validate_table(ms); @@ -1224,6 +1322,30 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type17.part, opts, "part"); type17.speed = qemu_opt_get_number(opts, "speed", 0); return; + case 41: { + struct type41_instance *t; + Error *local_err = NULL; + + if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) { + return; + } + t = g_new0(struct type41_instance, 1); + save_opt(&t->designation, opts, "designation"); + t->kind = qapi_enum_parse(&type41_kind_lookup, + qemu_opt_get(opts, "kind"), + 0, &local_err) + 1; + t->kind |= 0x80; /* enabled */ + if (local_err != NULL) { + error_propagate(errp, local_err); + g_free(t); + return; + } + t->instance = qemu_opt_get_number(opts, "instance", 1); + save_opt(&t->pcidev, opts, "pcidev"); + + QTAILQ_INSERT_TAIL(&type41, t, next); + return; + } default: error_setg(errp, "Don't know how to build fields for SMBIOS type %ld", diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index eb5d2a6792..7b4dec1721 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -136,7 +136,36 @@ static void main_cpu_reset(void *opaque) env->regbase[6] = s->sp; } -void leon3_irq_ack(void *irq_manager, int intno) +static void leon3_cache_control_int(CPUSPARCState *env) +{ + uint32_t state = 0; + + if (env->cache_control & CACHE_CTRL_IF) { + /* Instruction cache state */ + state = env->cache_control & CACHE_STATE_MASK; + if (state == CACHE_ENABLED) { + state = CACHE_FROZEN; + trace_int_helper_icache_freeze(); + } + + env->cache_control &= ~CACHE_STATE_MASK; + env->cache_control |= state; + } + + if (env->cache_control & CACHE_CTRL_DF) { + /* Data cache state */ + state = (env->cache_control >> 2) & CACHE_STATE_MASK; + if (state == CACHE_ENABLED) { + state = CACHE_FROZEN; + trace_int_helper_dcache_freeze(); + } + + env->cache_control &= ~(CACHE_STATE_MASK << 2); + env->cache_control |= (state << 2); + } +} + +static void leon3_irq_ack(void *irq_manager, int intno) { grlib_irqmp_ack((DeviceState *)irq_manager, intno); } @@ -180,6 +209,12 @@ static void leon3_set_pil_in(void *opaque, int n, int level) } } +static void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno) +{ + leon3_irq_ack(irq_manager, intno); + leon3_cache_control_int(env); +} + static void leon3_generic_hw_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 1a00816d9a..42e139849e 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -107,6 +107,17 @@ struct sun4m_hwdef { uint8_t nvram_machine_id; }; +struct Sun4mMachineClass { + /*< private >*/ + MachineClass parent_obj; + /*< public >*/ + const struct sun4m_hwdef *hwdef; +}; +typedef struct Sun4mMachineClass Sun4mMachineClass; + +#define TYPE_SUN4M_MACHINE MACHINE_TYPE_NAME("sun4m-common") +DECLARE_CLASS_CHECKERS(Sun4mMachineClass, SUN4M_MACHINE, TYPE_SUN4M_MACHINE) + const char *fw_cfg_arch_key_name(uint16_t key) { static const struct { @@ -159,38 +170,6 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr, } } -void cpu_check_irqs(CPUSPARCState *env) -{ - CPUState *cs; - - /* We should be holding the BQL before we mess with IRQs */ - g_assert(qemu_mutex_iothread_locked()); - - if (env->pil_in && (env->interrupt_index == 0 || - (env->interrupt_index & ~15) == TT_EXTINT)) { - unsigned int i; - - for (i = 15; i > 0; i--) { - if (env->pil_in & (1 << i)) { - int old_interrupt = env->interrupt_index; - - env->interrupt_index = TT_EXTINT | i; - if (old_interrupt != env->interrupt_index) { - cs = env_cpu(env); - trace_sun4m_cpu_interrupt(i); - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { - cs = env_cpu(env); - trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); - env->interrupt_index = 0; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - static void cpu_kick_irq(SPARCCPU *cpu) { CPUSPARCState *env = &cpu->env; @@ -837,9 +816,9 @@ static void dummy_fdc_tc(void *opaque, int irq, int level) { } -static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, - MachineState *machine) +static void sun4m_hw_init(MachineState *machine) { + const struct sun4m_hwdef *hwdef = SUN4M_MACHINE_GET_CLASS(machine)->hwdef; DeviceState *slavio_intctl; unsigned int i; Nvram *nvram; @@ -1127,9 +1106,22 @@ enum { ss600mp_id, }; -static const struct sun4m_hwdef sun4m_hwdefs[] = { - /* SS-5 */ - { +static void sun4m_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = sun4m_hw_init; + mc->block_default_type = IF_SCSI; + mc->default_boot_order = "c"; + mc->default_display = "tcx"; + mc->default_ram_id = "sun4m.ram"; +} + +static void ss5_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss5_hwdef = { .iommu_base = 0x10000000, .iommu_pad_base = 0x10004000, .iommu_pad_len = 0x0fffb000, @@ -1154,9 +1146,19 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = ss5_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* SS-10 */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 5"; + mc->is_default = true; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); + smc->hwdef = &ss5_hwdef; +} + +static void ss10_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss10_hwdef = { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, .slavio_base = 0xff0000000ULL, @@ -1170,18 +1172,28 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .dma_base = 0xef0400000ULL, .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist + .apc_base = 0xefa000000ULL, /* XXX should not exist */ .aux1_base = 0xff1800000ULL, .aux2_base = 0xff1a01000ULL, .ecc_base = 0xf00000000ULL, - .ecc_version = 0x10000000, // version 0, implementation 1 + .ecc_version = 0x10000000, /* version 0, implementation 1 */ .nvram_machine_id = 0x72, .machine_id = ss10_id, .iommu_version = 0x03000000, .max_mem = 0xf00000000ULL, - }, - /* SS-600MP */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 10"; + mc->max_cpus = 4; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); + smc->hwdef = &ss10_hwdef; +} + +static void ss600mp_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss600mp_hwdef = { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, .slavio_base = 0xff0000000ULL, @@ -1193,18 +1205,28 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .dma_base = 0xef0081000ULL, .esp_base = 0xef0080000ULL, .le_base = 0xef0060000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist + .apc_base = 0xefa000000ULL, /* XXX should not exist */ .aux1_base = 0xff1800000ULL, - .aux2_base = 0xff1a01000ULL, // XXX should not exist + .aux2_base = 0xff1a01000ULL, /* XXX should not exist */ .ecc_base = 0xf00000000ULL, - .ecc_version = 0x00000000, // version 0, implementation 0 + .ecc_version = 0x00000000, /* version 0, implementation 0 */ .nvram_machine_id = 0x71, .machine_id = ss600mp_id, .iommu_version = 0x01000000, .max_mem = 0xf00000000ULL, - }, - /* SS-20 */ - { + }; + + mc->desc = "Sun4m platform, SPARCserver 600MP"; + mc->max_cpus = 4; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); + smc->hwdef = &ss600mp_hwdef; +} + +static void ss20_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss20_hwdef = { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, .slavio_base = 0xff0000000ULL, @@ -1219,7 +1241,7 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, .bpp_base = 0xef4800000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist + .apc_base = 0xefa000000ULL, /* XXX should not exist */ .aux1_base = 0xff1800000ULL, .aux2_base = 0xff1a01000ULL, .dbri_base = 0xee0000000ULL, @@ -1238,14 +1260,24 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { } }, .ecc_base = 0xf00000000ULL, - .ecc_version = 0x20000000, // version 0, implementation 2 + .ecc_version = 0x20000000, /* version 0, implementation 2 */ .nvram_machine_id = 0x72, .machine_id = ss20_id, .iommu_version = 0x13000000, .max_mem = 0xf00000000ULL, - }, - /* Voyager */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 20"; + mc->max_cpus = 4; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); + smc->hwdef = &ss20_hwdef; +} + +static void voyager_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef voyager_hwdef = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .slavio_base = 0x70000000, @@ -1259,16 +1291,25 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .dma_base = 0x78400000, .esp_base = 0x78800000, .le_base = 0x78c00000, - .apc_base = 0x71300000, // pmc + .apc_base = 0x71300000, /* pmc */ .aux1_base = 0x71900000, .aux2_base = 0x71910000, .nvram_machine_id = 0x80, .machine_id = vger_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* LX */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation Voyager"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); + smc->hwdef = &voyager_hwdef; +} + +static void ss_lx_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss_lx_hwdef = { .iommu_base = 0x10000000, .iommu_pad_base = 0x10004000, .iommu_pad_len = 0x0fffb000, @@ -1290,9 +1331,18 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = lx_id, .iommu_version = 0x04000000, .max_mem = 0x10000000, - }, - /* SS-4 */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation LX"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); + smc->hwdef = &ss_lx_hwdef; +} + +static void ss4_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss4_hwdef = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .cs_base = 0x6c000000, @@ -1314,9 +1364,18 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = ss4_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* SPARCClassic */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 4"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); + smc->hwdef = &ss4_hwdef; +} + +static void scls_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef scls_hwdef = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .slavio_base = 0x70000000, @@ -1337,11 +1396,20 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = scls_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* SPARCbook */ - { + }; + + mc->desc = "Sun4m platform, SPARCClassic"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); + smc->hwdef = &scls_hwdef; +} + +static void sbook_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef sbook_hwdef = { .iommu_base = 0x10000000, - .tcx_base = 0x50000000, // XXX + .tcx_base = 0x50000000, /* XXX */ .slavio_base = 0x70000000, .ms_kb_base = 0x71000000, .serial_base = 0x71100000, @@ -1360,254 +1428,67 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = sbook_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, -}; - -/* SPARCstation 5 hardware initialisation */ -static void ss5_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[0], machine); -} - -/* SPARCstation 10 hardware initialisation */ -static void ss10_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[1], machine); -} - -/* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[2], machine); -} - -/* SPARCstation 20 hardware initialisation */ -static void ss20_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[3], machine); -} - -/* SPARCstation Voyager hardware initialisation */ -static void vger_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[4], machine); -} - -/* SPARCstation LX hardware initialisation */ -static void ss_lx_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[5], machine); -} - -/* SPARCstation 4 hardware initialisation */ -static void ss4_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[6], machine); -} - -/* SPARCClassic hardware initialisation */ -static void scls_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[7], machine); -} - -/* SPARCbook hardware initialisation */ -static void sbook_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[8], machine); -} - -static void ss5_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 5"; - mc->init = ss5_init; - mc->block_default_type = IF_SCSI; - mc->is_default = true; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss5_type = { - .name = MACHINE_TYPE_NAME("SS-5"), - .parent = TYPE_MACHINE, - .class_init = ss5_class_init, -}; - -static void ss10_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 10"; - mc->init = ss10_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss10_type = { - .name = MACHINE_TYPE_NAME("SS-10"), - .parent = TYPE_MACHINE, - .class_init = ss10_class_init, -}; - -static void ss600mp_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCserver 600MP"; - mc->init = ss600mp_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss600mp_type = { - .name = MACHINE_TYPE_NAME("SS-600MP"), - .parent = TYPE_MACHINE, - .class_init = ss600mp_class_init, -}; - -static void ss20_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 20"; - mc->init = ss20_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss20_type = { - .name = MACHINE_TYPE_NAME("SS-20"), - .parent = TYPE_MACHINE, - .class_init = ss20_class_init, -}; - -static void voyager_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation Voyager"; - mc->init = vger_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo voyager_type = { - .name = MACHINE_TYPE_NAME("Voyager"), - .parent = TYPE_MACHINE, - .class_init = voyager_class_init, -}; - -static void ss_lx_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation LX"; - mc->init = ss_lx_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss_lx_type = { - .name = MACHINE_TYPE_NAME("LX"), - .parent = TYPE_MACHINE, - .class_init = ss_lx_class_init, -}; - -static void ss4_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 4"; - mc->init = ss4_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss4_type = { - .name = MACHINE_TYPE_NAME("SS-4"), - .parent = TYPE_MACHINE, - .class_init = ss4_class_init, -}; - -static void scls_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCClassic"; - mc->init = scls_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo scls_type = { - .name = MACHINE_TYPE_NAME("SPARCClassic"), - .parent = TYPE_MACHINE, - .class_init = scls_class_init, -}; - -static void sbook_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); + }; mc->desc = "Sun4m platform, SPARCbook"; - mc->init = sbook_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; + smc->hwdef = &sbook_hwdef; } -static const TypeInfo sbook_type = { - .name = MACHINE_TYPE_NAME("SPARCbook"), - .parent = TYPE_MACHINE, - .class_init = sbook_class_init, +static const TypeInfo sun4m_machine_types[] = { + { + .name = MACHINE_TYPE_NAME("SS-5"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss5_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-10"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss10_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-600MP"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss600mp_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-20"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss20_class_init, + }, { + .name = MACHINE_TYPE_NAME("Voyager"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = voyager_class_init, + }, { + .name = MACHINE_TYPE_NAME("LX"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss_lx_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-4"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss4_class_init, + }, { + .name = MACHINE_TYPE_NAME("SPARCClassic"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = scls_class_init, + }, { + .name = MACHINE_TYPE_NAME("SPARCbook"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = sbook_class_init, + }, { + .name = TYPE_SUN4M_MACHINE, + .parent = TYPE_MACHINE, + .class_size = sizeof(Sun4mMachineClass), + .class_init = sun4m_machine_class_init, + .abstract = true, + } }; +DEFINE_TYPES(sun4m_machine_types) + static void sun4m_register_types(void) { type_register_static(&idreg_info); type_register_static(&afx_info); type_register_static(&prom_info); type_register_static(&ram_info); - - type_register_static(&ss5_type); - type_register_static(&ss10_type); - type_register_static(&ss600mp_type); - type_register_static(&ss20_type); - type_register_static(&voyager_type); - type_register_static(&ss_lx_type); - type_register_static(&ss4_type); - type_register_static(&scls_type); - type_register_static(&sbook_type); } type_init(sun4m_register_types) diff --git a/hw/sparc/trace-events b/hw/sparc/trace-events index 355b07ae05..d3a30a816a 100644 --- a/hw/sparc/trace-events +++ b/hw/sparc/trace-events @@ -1,8 +1,6 @@ # See docs/devel/tracing.txt for syntax documentation. # sun4m.c -sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d" -sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d" sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d" sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d" @@ -19,3 +17,5 @@ sun4m_iommu_bad_addr(uint64_t addr) "bad addr 0x%"PRIx64 # leon3.c leon3_set_irq(int intno) "Set CPU IRQ %d" leon3_reset_irq(int intno) "Reset CPU IRQ %d" +int_helper_icache_freeze(void) "Instruction cache: freeze" +int_helper_dcache_freeze(void) "Data cache: freeze" diff --git a/hw/sparc64/sparc64.c b/hw/sparc64/sparc64.c index e3f9219a10..8654e955eb 100644 --- a/hw/sparc64/sparc64.c +++ b/hw/sparc64/sparc64.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "hw/boards.h" -#include "hw/char/serial.h" #include "hw/sparc/sparc64.h" #include "qemu/timer.h" #include "sysemu/reset.h" @@ -35,68 +34,6 @@ #define TICK_MAX 0x7fffffffffffffffULL -void cpu_check_irqs(CPUSPARCState *env) -{ - CPUState *cs; - uint32_t pil = env->pil_in | - (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); - - /* We should be holding the BQL before we mess with IRQs */ - g_assert(qemu_mutex_iothread_locked()); - - /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */ - if (env->ivec_status & 0x20) { - return; - } - cs = env_cpu(env); - /* check if TM or SM in SOFTINT are set - setting these also causes interrupt 14 */ - if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { - pil |= 1 << 14; - } - - /* The bit corresponding to psrpil is (1<< psrpil), the next bit - is (2 << psrpil). */ - if (pil < (2 << env->psrpil)) { - if (cs->interrupt_request & CPU_INTERRUPT_HARD) { - trace_sparc64_cpu_check_irqs_reset_irq(env->interrupt_index); - env->interrupt_index = 0; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } - return; - } - - if (cpu_interrupts_enabled(env)) { - - unsigned int i; - - for (i = 15; i > env->psrpil; i--) { - if (pil & (1 << i)) { - int old_interrupt = env->interrupt_index; - int new_interrupt = TT_EXTINT | i; - - if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt - && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) { - trace_sparc64_cpu_check_irqs_noset_irq(env->tl, - cpu_tsptr(env)->tt, - new_interrupt); - } else if (old_interrupt != new_interrupt) { - env->interrupt_index = new_interrupt; - trace_sparc64_cpu_check_irqs_set_irq(i, old_interrupt, - new_interrupt); - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) { - trace_sparc64_cpu_check_irqs_disabled(pil, env->pil_in, env->softint, - env->interrupt_index); - env->interrupt_index = 0; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - static void cpu_kick_irq(SPARCCPU *cpu) { CPUState *cs = CPU(cpu); diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events index a0b29987d2..b85d14c30c 100644 --- a/hw/sparc64/trace-events +++ b/hw/sparc64/trace-events @@ -9,10 +9,6 @@ sun4u_iommu_mem_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" sun4u_iommu_translate(uint64_t addr, uint64_t trans_addr, uint64_t tte) "xlate 0x%"PRIx64" => pa 0x%"PRIx64" tte: 0x%"PRIx64 # sparc64.c -sparc64_cpu_check_irqs_reset_irq(int intno) "Reset CPU IRQ (current interrupt 0x%x)" -sparc64_cpu_check_irqs_noset_irq(uint32_t tl, uint32_t tt, int intno) "Not setting CPU IRQ: TL=%d current 0x%x >= pending 0x%x" -sparc64_cpu_check_irqs_set_irq(unsigned int i, int old, int new) "Set CPU IRQ %d old=0x%x new=0x%x" -sparc64_cpu_check_irqs_disabled(uint32_t pil, uint32_t pil_in, uint32_t softint, int intno) "Interrupts disabled, pil=0x%08x pil_in=0x%08x softint=0x%08x current interrupt 0x%x" sparc64_cpu_ivec_raise_irq(int irq) "Raise IVEC IRQ %d" sparc64_cpu_ivec_lower_irq(int irq) "Lower IVEC IRQ %d" sparc64_cpu_tick_irq_disabled(void) "tick_irq: softint disabled" diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 5379006086..4ba662190d 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -309,9 +309,9 @@ static const MemoryRegionOps timer_ops = { } }; -static void etraxfs_timer_reset(void *opaque) +static void etraxfs_timer_reset_enter(Object *obj, ResetType type) { - ETRAXTimerState *t = opaque; + ETRAXTimerState *t = ETRAX_TIMER(obj); ptimer_transaction_begin(t->ptimer_t0); ptimer_stop(t->ptimer_t0); @@ -325,6 +325,12 @@ static void etraxfs_timer_reset(void *opaque) t->rw_wd_ctrl = 0; t->r_intr = 0; t->rw_intr_mask = 0; +} + +static void etraxfs_timer_reset_hold(Object *obj) +{ + ETRAXTimerState *t = ETRAX_TIMER(obj); + qemu_irq_lower(t->irq); } @@ -343,14 +349,16 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp) memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "etraxfs-timer", 0x5c); sysbus_init_mmio(sbd, &t->mmio); - qemu_register_reset(etraxfs_timer_reset, t); } static void etraxfs_timer_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); dc->realize = etraxfs_timer_realize; + rc->phases.enter = etraxfs_timer_reset_enter; + rc->phases.hold = etraxfs_timer_reset_hold; } static const TypeInfo etraxfs_timer_info = { diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c deleted file mode 100644 index eeaf0ada5f..0000000000 --- a/hw/timer/lm32_timer.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * QEMU model of the LatticeMico32 timer block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://www.latticesemi.com/documents/mico32timer.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -#define DEFAULT_FREQUENCY (50*1000000) - -enum { - R_SR = 0, - R_CR, - R_PERIOD, - R_SNAPSHOT, - R_MAX -}; - -enum { - SR_TO = (1 << 0), - SR_RUN = (1 << 1), -}; - -enum { - CR_ITO = (1 << 0), - CR_CONT = (1 << 1), - CR_START = (1 << 2), - CR_STOP = (1 << 3), -}; - -#define TYPE_LM32_TIMER "lm32-timer" -OBJECT_DECLARE_SIMPLE_TYPE(LM32TimerState, LM32_TIMER) - -struct LM32TimerState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - ptimer_state *ptimer; - - qemu_irq irq; - uint32_t freq_hz; - - uint32_t regs[R_MAX]; -}; - -static void timer_update_irq(LM32TimerState *s) -{ - int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO); - - trace_lm32_timer_irq_state(state); - qemu_set_irq(s->irq, state); -} - -static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) -{ - LM32TimerState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SR: - case R_CR: - case R_PERIOD: - r = s->regs[addr]; - break; - case R_SNAPSHOT: - r = (uint32_t)ptimer_get_count(s->ptimer); - break; - default: - error_report("lm32_timer: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_lm32_timer_memory_read(addr << 2, r); - return r; -} - -static void timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32TimerState *s = opaque; - - trace_lm32_timer_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_SR: - 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); - } - 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" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_timer: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - timer_update_irq(s); -} - -static const MemoryRegionOps timer_ops = { - .read = timer_read, - .write = timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void timer_hit(void *opaque) -{ - LM32TimerState *s = opaque; - - trace_lm32_timer_hit(); - - s->regs[R_SR] |= SR_TO; - - if (s->regs[R_CR] & CR_CONT) { - ptimer_set_count(s->ptimer, s->regs[R_PERIOD]); - ptimer_run(s->ptimer, 1); - } - timer_update_irq(s); -} - -static void timer_reset(DeviceState *d) -{ - LM32TimerState *s = LM32_TIMER(d); - int i; - - 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) -{ - LM32TimerState *s = LM32_TIMER(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, obj, &timer_ops, s, - "timer", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); -} - -static void lm32_timer_realize(DeviceState *dev, Error **errp) -{ - LM32TimerState *s = LM32_TIMER(dev); - - 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 = { - .name = "lm32-timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PTIMER(ptimer, LM32TimerState), - VMSTATE_UINT32(freq_hz, LM32TimerState), - VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_timer_properties[] = { - DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = lm32_timer_realize; - dc->reset = timer_reset; - dc->vmsd = &vmstate_lm32_timer; - device_class_set_props(dc, lm32_timer_properties); -} - -static const TypeInfo lm32_timer_info = { - .name = TYPE_LM32_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32TimerState), - .instance_init = lm32_timer_init, - .class_init = lm32_timer_class_init, -}; - -static void lm32_timer_register_types(void) -{ - type_register_static(&lm32_timer_info); -} - -type_init(lm32_timer_register_types) diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 598d058506..157f540ecd 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -19,15 +19,12 @@ softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c')) softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_timer.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-sysctl.c')) softmmu_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c')) softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c')) -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_ost.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c')) softmmu_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c')) diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c deleted file mode 100644 index 9ecea63861..0000000000 --- a/hw/timer/milkymist-sysctl.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * QEMU model of the Milkymist System Controller. - * - * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/sysctl.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/timer.h" -#include "sysemu/runstate.h" -#include "hw/ptimer.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - CTRL_ENABLE = (1<<0), - CTRL_AUTORESTART = (1<<1), -}; - -enum { - ICAP_READY = (1<<0), -}; - -enum { - R_GPIO_IN = 0, - R_GPIO_OUT, - R_GPIO_INTEN, - R_TIMER0_CONTROL = 4, - R_TIMER0_COMPARE, - R_TIMER0_COUNTER, - R_TIMER1_CONTROL = 8, - R_TIMER1_COMPARE, - R_TIMER1_COUNTER, - R_ICAP = 16, - R_DBG_SCRATCHPAD = 20, - R_DBG_WRITE_LOCK, - R_CLK_FREQUENCY = 29, - R_CAPABILITIES, - R_SYSTEM_ID, - R_MAX -}; - -#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSysctlState, MILKYMIST_SYSCTL) - -struct MilkymistSysctlState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - ptimer_state *ptimer0; - ptimer_state *ptimer1; - - uint32_t freq_hz; - uint32_t capabilities; - uint32_t systemid; - uint32_t strappings; - - uint32_t regs[R_MAX]; - - qemu_irq gpio_irq; - qemu_irq timer0_irq; - qemu_irq timer1_irq; -}; - -static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value) -{ - trace_milkymist_sysctl_icap_write(value); - switch (value & 0xffff) { - case 0x000e: - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); - break; - } -} - -static uint64_t sysctl_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistSysctlState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_TIMER0_COUNTER: - r = (uint32_t)ptimer_get_count(s->ptimer0); - /* milkymist timer counts up */ - r = s->regs[R_TIMER0_COMPARE] - r; - break; - case R_TIMER1_COUNTER: - r = (uint32_t)ptimer_get_count(s->ptimer1); - /* milkymist timer counts up */ - r = s->regs[R_TIMER1_COMPARE] - r; - break; - case R_GPIO_IN: - case R_GPIO_OUT: - case R_GPIO_INTEN: - case R_TIMER0_CONTROL: - case R_TIMER0_COMPARE: - case R_TIMER1_CONTROL: - case R_TIMER1_COMPARE: - case R_ICAP: - case R_DBG_SCRATCHPAD: - case R_DBG_WRITE_LOCK: - case R_CLK_FREQUENCY: - case R_CAPABILITIES: - case R_SYSTEM_ID: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_sysctl: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_sysctl_memory_read(addr << 2, r); - - return r; -} - -static void sysctl_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistSysctlState *s = opaque; - - trace_milkymist_sysctl_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_GPIO_OUT: - case R_GPIO_INTEN: - case R_TIMER0_COUNTER: - case R_TIMER1_COUNTER: - case R_DBG_SCRATCHPAD: - 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(); - ptimer_set_count(s->ptimer0, - s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]); - ptimer_run(s->ptimer0, 0); - } else { - 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(); - ptimer_set_count(s->ptimer1, - s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]); - ptimer_run(s->ptimer1, 0); - } else { - trace_milkymist_sysctl_stop_timer1(); - ptimer_stop(s->ptimer1); - } - ptimer_transaction_commit(s->ptimer1); - break; - case R_ICAP: - sysctl_icap_write(s, value); - break; - case R_DBG_WRITE_LOCK: - s->regs[addr] = 1; - break; - case R_SYSTEM_ID: - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - break; - - case R_GPIO_IN: - case R_CLK_FREQUENCY: - case R_CAPABILITIES: - error_report("milkymist_sysctl: write to read-only register 0x" - TARGET_FMT_plx, addr << 2); - break; - - default: - error_report("milkymist_sysctl: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps sysctl_mmio_ops = { - .read = sysctl_read, - .write = sysctl_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void timer0_hit(void *opaque) -{ - MilkymistSysctlState *s = opaque; - - if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) { - s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE; - trace_milkymist_sysctl_stop_timer0(); - ptimer_stop(s->ptimer0); - } - - trace_milkymist_sysctl_pulse_irq_timer0(); - qemu_irq_pulse(s->timer0_irq); -} - -static void timer1_hit(void *opaque) -{ - MilkymistSysctlState *s = opaque; - - if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) { - s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE; - trace_milkymist_sysctl_stop_timer1(); - ptimer_stop(s->ptimer1); - } - - trace_milkymist_sysctl_pulse_irq_timer1(); - qemu_irq_pulse(s->timer1_irq); -} - -static void milkymist_sysctl_reset(DeviceState *d) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(d); - int i; - - for (i = 0; i < R_MAX; i++) { - 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; - s->regs[R_SYSTEM_ID] = s->systemid; - s->regs[R_CLK_FREQUENCY] = s->freq_hz; - s->regs[R_CAPABILITIES] = s->capabilities; - s->regs[R_GPIO_IN] = s->strappings; -} - -static void milkymist_sysctl_init(Object *obj) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->gpio_irq); - sysbus_init_irq(dev, &s->timer0_irq); - sysbus_init_irq(dev, &s->timer1_irq); - - memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, - "milkymist-sysctl", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); - - 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 = { - .name = "milkymist-sysctl", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX), - VMSTATE_PTIMER(ptimer0, MilkymistSysctlState), - VMSTATE_PTIMER(ptimer1, MilkymistSysctlState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_sysctl_properties[] = { - DEFINE_PROP_UINT32("frequency", MilkymistSysctlState, - freq_hz, 80000000), - DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState, - capabilities, 0x00000000), - DEFINE_PROP_UINT32("systemid", MilkymistSysctlState, - systemid, 0x10014d31), - DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState, - strappings, 0x00000001), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_sysctl_realize; - dc->reset = milkymist_sysctl_reset; - dc->vmsd = &vmstate_milkymist_sysctl; - device_class_set_props(dc, milkymist_sysctl_properties); -} - -static const TypeInfo milkymist_sysctl_info = { - .name = TYPE_MILKYMIST_SYSCTL, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistSysctlState), - .instance_init = milkymist_sysctl_init, - .class_init = milkymist_sysctl_class_init, -}; - -static void milkymist_sysctl_register_types(void) -{ - type_register_static(&milkymist_sysctl_info); -} - -type_init(milkymist_sysctl_register_types) diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c deleted file mode 100644 index d5bf26b56b..0000000000 --- a/hw/timer/puv3_ost.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * OSTimer device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/irq.h" -#include "hw/ptimer.h" -#include "qemu/module.h" -#include "qemu/log.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" - -#define TYPE_PUV3_OST "puv3_ost" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3OSTState, PUV3_OST) - -/* puv3 ostimer implementation. */ -struct PUV3OSTState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - ptimer_state *ptimer; - - uint32_t reg_OSMR0; - uint32_t reg_OSCR; - uint32_t reg_OSSR; - uint32_t reg_OIER; -}; - -static uint64_t puv3_ost_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3OSTState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x10: /* Counter Register */ - ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer); - break; - case 0x14: /* Status Register */ - ret = s->reg_OSSR; - break; - case 0x1c: /* Interrupt Enable Register */ - ret = s->reg_OIER; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - return ret; -} - -static void puv3_ost_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3OSTState *s = opaque; - - 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); - } else { - ptimer_set_count(s->ptimer, s->reg_OSMR0 + - (0xffffffff - s->reg_OSCR)); - } - ptimer_run(s->ptimer, 2); - ptimer_transaction_commit(s->ptimer); - break; - case 0x14: /* Status Register */ - assert(value == 0); - if (s->reg_OSSR) { - s->reg_OSSR = value; - qemu_irq_lower(s->irq); - } - break; - case 0x1c: /* Interrupt Enable Register */ - s->reg_OIER = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } -} - -static const MemoryRegionOps puv3_ost_ops = { - .read = puv3_ost_read, - .write = puv3_ost_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_ost_tick(void *opaque) -{ - PUV3OSTState *s = opaque; - - DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n", - s->reg_OSCR, s->reg_OSMR0); - - s->reg_OSCR = s->reg_OSMR0; - if (s->reg_OIER) { - s->reg_OSSR = 1; - qemu_irq_raise(s->irq); - } -} - -static void puv3_ost_realize(DeviceState *dev, Error **errp) -{ - PUV3OSTState *s = PUV3_OST(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - s->reg_OIER = 0; - s->reg_OSSR = 0; - s->reg_OSMR0 = 0; - s->reg_OSCR = 0; - - sysbus_init_irq(sbd, &s->irq); - - 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); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void puv3_ost_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_ost_realize; -} - -static const TypeInfo puv3_ost_info = { - .name = TYPE_PUV3_OST, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3OSTState), - .class_init = puv3_ost_class_init, -}; - -static void puv3_ost_register_type(void) -{ - type_register_static(&puv3_ost_info); -} - -type_init(puv3_ost_register_type) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index f8b9db25c2..029fb56280 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -24,23 +24,6 @@ grlib_gptimer_hit(int id) "timer:%d HIT" grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" -# lm32_timer.c -lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_timer_hit(void) "timer hit" -lm32_timer_irq_state(int level) "irq state %d" - -# milkymist-sysctl.c -milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_sysctl_icap_write(uint32_t value) "value 0x%08x" -milkymist_sysctl_start_timer0(void) "Start timer0" -milkymist_sysctl_stop_timer0(void) "Stop timer0" -milkymist_sysctl_start_timer1(void) "Start timer1" -milkymist_sysctl_stop_timer1(void) "Stop timer1" -milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0" -milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1" - # aspeed_timer.c aspeed_timer_ctrl_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" aspeed_timer_ctrl_external_clock(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" diff --git a/hw/tricore/meson.build b/hw/tricore/meson.build index 77ff6fd137..47e36bb077 100644 --- a/hw/tricore/meson.build +++ b/hw/tricore/meson.build @@ -1,5 +1,6 @@ tricore_ss = ss.source_set() tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testboard.c')) +tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testdevice.c')) tricore_ss.add(when: 'CONFIG_TRIBOARD', if_true: files('triboard.c')) tricore_ss.add(when: 'CONFIG_TC27X_SOC', if_true: files('tc27x_soc.c')) diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c index 51658d9e37..b6810e3be0 100644 --- a/hw/tricore/tricore_testboard.c +++ b/hw/tricore/tricore_testboard.c @@ -27,6 +27,7 @@ #include "hw/loader.h" #include "elf.h" #include "hw/tricore/tricore.h" +#include "hw/tricore/tricore_testdevice.h" #include "qemu/error-report.h" @@ -56,6 +57,7 @@ static void tricore_testboard_init(MachineState *machine, int board_id) { TriCoreCPU *cpu; CPUTriCoreState *env; + TriCoreTestDeviceState *test_dev; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ext_cram = g_new(MemoryRegion, 1); @@ -87,6 +89,12 @@ static void tricore_testboard_init(MachineState *machine, int board_id) memory_region_add_subregion(sysmem, 0xf0050000, pcp_data); memory_region_add_subregion(sysmem, 0xf0060000, pcp_text); + test_dev = g_new(TriCoreTestDeviceState, 1); + object_initialize(test_dev, sizeof(TriCoreTestDeviceState), + TYPE_TRICORE_TESTDEVICE); + memory_region_add_subregion(sysmem, 0xf0000000, &test_dev->iomem); + + tricoretb_binfo.ram_size = machine->ram_size; tricoretb_binfo.kernel_filename = machine->kernel_filename; diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c new file mode 100644 index 0000000000..a1563aa568 --- /dev/null +++ b/hw/tricore/tricore_testdevice.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2021 Bastian Koppelmann Paderborn University + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/qdev-properties.h" +#include "hw/tricore/tricore_testdevice.h" + +static void tricore_testdevice_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + exit(value); +} + +static uint64_t tricore_testdevice_read(void *opaque, hwaddr offset, + unsigned size) +{ + return 0xdeadbeef; +} + +static void tricore_testdevice_reset(DeviceState *dev) +{ +} + +static const MemoryRegionOps tricore_testdevice_ops = { + .read = tricore_testdevice_read, + .write = tricore_testdevice_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void tricore_testdevice_init(Object *obj) +{ + TriCoreTestDeviceState *s = TRICORE_TESTDEVICE(obj); + /* map memory */ + memory_region_init_io(&s->iomem, OBJECT(s), &tricore_testdevice_ops, s, + "tricore_testdevice", 0x4); +} + +static Property tricore_testdevice_properties[] = { + DEFINE_PROP_END_OF_LIST() +}; + +static void tricore_testdevice_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, tricore_testdevice_properties); + dc->reset = tricore_testdevice_reset; +} + +static const TypeInfo tricore_testdevice_info = { + .name = TYPE_TRICORE_TESTDEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TriCoreTestDeviceState), + .instance_init = tricore_testdevice_init, + .class_init = tricore_testdevice_class_init, +}; + +static void tricore_testdevice_register_types(void) +{ + type_register_static(&tricore_testdevice_info); +} + +type_init(tricore_testdevice_register_types) diff --git a/hw/unicore32/Kconfig b/hw/unicore32/Kconfig deleted file mode 100644 index 4443a29dd2..0000000000 --- a/hw/unicore32/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config PUV3 - bool - select ISA_BUS - select PCKBD - select PTIMER diff --git a/hw/unicore32/meson.build b/hw/unicore32/meson.build deleted file mode 100644 index fc26d6bcab..0000000000 --- a/hw/unicore32/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -unicore32_ss = ss.source_set() -# PKUnity-v3 SoC and board information -unicore32_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3.c')) - -hw_arch += {'unicore32': unicore32_ss} diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c deleted file mode 100644 index eacacb4249..0000000000 --- a/hw/unicore32/puv3.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Generic PKUnity SoC machine and board descriptor - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "ui/console.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "sysemu/qtest.h" -#include "hw/unicore32/puv3.h" -#include "hw/input/i8042.h" -#include "hw/irq.h" - -#define KERNEL_LOAD_ADDR 0x03000000 -#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ - -/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */ -#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */ - -/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */ -#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */ -#define PUV3_INTC_BASE (0xee600000) /* APB-6 */ -#define PUV3_OST_BASE (0xee800000) /* APB-8 */ -#define PUV3_PM_BASE (0xeea00000) /* APB-10 */ -#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */ - -static void puv3_intc_cpu_handler(void *opaque, int irq, int level) -{ - UniCore32CPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - assert(irq == 0); - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - -static void puv3_soc_init(CPUUniCore32State *env) -{ - qemu_irq cpu_intc, irqs[PUV3_IRQS_NR]; - DeviceState *dev; - MemoryRegion *i8042 = g_new(MemoryRegion, 1); - int i; - - /* Initialize interrupt controller */ - cpu_intc = qemu_allocate_irq(puv3_intc_cpu_handler, - env_archcpu(env), 0); - dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, cpu_intc); - for (i = 0; i < PUV3_IRQS_NR; i++) { - irqs[i] = qdev_get_gpio_in(dev, i); - } - - /* Initialize minimal necessary devices for kernel booting */ - sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL); - sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL); - sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]); - sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE, - irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1], - irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3], - irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5], - irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7], - irqs[PUV3_IRQS_GPIOHIGH], NULL); - - /* Keyboard (i8042), mouse disabled for nographic */ - i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4); - memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042); -} - -static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size) -{ - MemoryRegion *ram_memory = g_new(MemoryRegion, 1); - - /* SDRAM at address zero. */ - memory_region_init_ram(ram_memory, NULL, "puv3.ram", ram_size, - &error_fatal); - memory_region_add_subregion(get_system_memory(), 0, ram_memory); -} - -static const GraphicHwOps no_ops; - -static void puv3_load_kernel(const char *kernel_filename) -{ - int size; - - if (kernel_filename == NULL && qtest_enabled()) { - return; - } - if (kernel_filename == NULL) { - error_report("kernel parameter cannot be empty"); - exit(1); - } - - /* only zImage format supported */ - size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, - KERNEL_MAX_SIZE); - if (size < 0) { - error_report("Load kernel error: '%s'", kernel_filename); - exit(1); - } - - /* cheat curses that we have a graphic console, only under ocd console */ - graphic_console_init(NULL, 0, &no_ops, NULL); -} - -static void puv3_init(MachineState *machine) -{ - ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *initrd_filename = machine->initrd_filename; - CPUUniCore32State *env; - UniCore32CPU *cpu; - - if (initrd_filename) { - error_report("Please use kernel built-in initramdisk"); - exit(1); - } - - cpu = UNICORE32_CPU(cpu_create(machine->cpu_type)); - env = &cpu->env; - - puv3_soc_init(env); - puv3_board_init(env, ram_size); - puv3_load_kernel(kernel_filename); -} - -static void puv3_machine_init(MachineClass *mc) -{ - mc->desc = "PKUnity Version-3 based on UniCore32"; - mc->init = puv3_init; - mc->is_default = true; - mc->default_cpu_type = UNICORE32_CPU_TYPE_NAME("UniCore-II"); -} - -DEFINE_MACHINE("puv3", puv3_machine_init) diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c index 5d57e883dc..e56802f89a 100644 --- a/hw/usb/combined-packet.c +++ b/hw/usb/combined-packet.c @@ -171,7 +171,9 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok || next == NULL || /* Work around for Linux usbfs bulk splitting + migration */ - (totalsize == (16 * KiB - 36) && p->int_req)) { + (totalsize == (16 * KiB - 36) && p->int_req) || + /* Next package may grow combined package over 1MiB */ + totalsize > 1 * MiB - ep->max_packet_size) { usb_device_handle_data(ep->dev, first); assert(first->status == USB_RET_ASYNC); if (first->combined) { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index fc39bab79f..1c7ae97c30 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -656,7 +656,7 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) { USBHIDState *us = USB_HID(dev); HIDState *hs = &us->hid; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); int len = 0; switch (p->pid) { diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index bbb8274344..2a895a73b0 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -907,7 +907,8 @@ static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c, MTPObject *o) { MTPData *d = usb_mtp_data_alloc(c); - uint32_t i = 0, handles[o->nchildren]; + uint32_t i = 0; + g_autofree uint32_t *handles = g_new(uint32_t, o->nchildren); MTPObject *iter; trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path); diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index b595048635..ed687bc9f1 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -301,7 +301,7 @@ static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p) { USBWacomState *s = (USBWacomState *) dev; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); int len = 0; switch (p->pid) { diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c index 538ed29684..80809ceba5 100644 --- a/hw/usb/host-stub.c +++ b/hw/usb/host-stub.c @@ -31,7 +31,6 @@ */ #include "qemu/osdep.h" -#include "ui/console.h" #include "hw/usb.h" #include "monitor/monitor.h" diff --git a/hw/usb/meson.build b/hw/usb/meson.build index fb7a74e73a..f357270d0b 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -1,17 +1,14 @@ hw_usb_modules = {} # usb subsystem core -softmmu_ss.add(files( +softmmu_ss.add(when: 'CONFIG_USB', if_true: files( 'bus.c', 'combined-packet.c', 'core.c', - 'pcap.c', - 'libhw.c' -)) - -softmmu_ss.add(when: 'CONFIG_USB', if_true: files( 'desc.c', 'desc-msos.c', + 'libhw.c', + 'pcap.c', )) # usb host adapters diff --git a/hw/usb/quirks-ftdi-ids.h b/hw/usb/quirks-ftdi-ids.h index 57c12ef662..01aca55ca7 100644 --- a/hw/usb/quirks-ftdi-ids.h +++ b/hw/usb/quirks-ftdi-ids.h @@ -1222,12 +1222,6 @@ #define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D /* - * Milkymist One JTAG/Serial - */ -#define QIHARDWARE_VID 0x20B7 -#define MILKYMISTONE_JTAGSERIAL_PID 0x0713 - -/* * CTI GmbH RS485 Converter http://www.cti-lean.com/ */ /* USB-485-Mini*/ diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h index 50ef2f9c2e..c3e595f40b 100644 --- a/hw/usb/quirks.h +++ b/hw/usb/quirks.h @@ -904,7 +904,6 @@ static const struct usb_device_id usbredir_ftdi_serial_ids[] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, - { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) }, { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) }, diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 17f06f3417..6a75b0dc4a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -620,7 +620,7 @@ static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, .endpoint = ep, .length = p->iov.size }; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); /* No id, we look at the ep when receiving a status back */ usb_packet_copy(p, buf, p->iov.size); usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet, @@ -818,7 +818,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, usbredirparser_send_bulk_packet(dev->parser, p->id, &bulk_packet, NULL, 0); } else { - uint8_t buf[size]; + g_autofree uint8_t *buf = g_malloc(size); usb_packet_copy(p, buf, size); usbredir_log_data(dev, "bulk data out:", buf, size); usbredirparser_send_bulk_packet(dev->parser, p->id, @@ -923,7 +923,7 @@ static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_interrupt_packet_header interrupt_packet; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index e752c845e9..139a3d9d1b 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -411,8 +411,8 @@ static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, } if (vdev->num_irqs < irq + 1) { - error_setg(errp, "vfio: unexpected number of irqs %u", - vdev->num_irqs); + error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)", + irq, vdev->num_irqs); return; } @@ -469,7 +469,7 @@ static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, if (vfio_set_irq_signaling(&vcdev->vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { - error_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); + warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); } qemu_set_fd_handler(event_notifier_get_fd(notifier), @@ -689,20 +689,24 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) if (vcdev->crw_region) { vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX, &err); if (err) { - goto out_crw_notifier_err; + goto out_irq_notifier_err; } } vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX, &err); if (err) { - goto out_req_notifier_err; + /* + * Report this error, but do not make it a failing condition. + * Lack of this IRQ in the host does not prevent normal operation. + */ + error_report_err(err); } return; -out_req_notifier_err: +out_irq_notifier_err: + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); -out_crw_notifier_err: vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); out_io_notifier_err: vfio_ccw_put_region(vcdev); diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index ded0c10453..ee57abe045 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1909,6 +1909,11 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque) return err; } } + if (dev->num_queues && dev->max_queues < dev->num_queues) { + error_report("The maximum number of queues supported by the " + "backend is %" PRIu64, dev->max_queues); + return -EINVAL; + } if (virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM) && !(virtio_has_feature(dev->protocol_features, diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 01d2101d09..8f2fb9f10b 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -371,8 +371,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) return 0; } -int vhost_vdpa_get_device_id(struct vhost_dev *dev, - uint32_t *device_id) +static int vhost_vdpa_get_device_id(struct vhost_dev *dev, + uint32_t *device_id) { int ret; ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index d120bf8f43..4b5d9e5e50 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -663,9 +663,6 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data) } switch (pnd->reason) { - case PRECOPY_NOTIFY_SETUP: - precopy_enable_free_page_optimization(); - break; case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC: virtio_balloon_free_page_stop(dev); break; @@ -685,6 +682,7 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data) */ virtio_balloon_free_page_done(dev); break; + case PRECOPY_NOTIFY_SETUP: case PRECOPY_NOTIFY_COMPLETE: break; default: diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index d6332d45c3..859978d248 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -69,6 +69,11 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) return; } + if (has_iommu && !virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { + error_setg(errp, "iommu_platform=true is not supported by the device"); + return; + } + if (klass->device_plugged != NULL) { klass->device_plugged(qbus->parent, &local_err); } diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 655824ff81..75aa7d6f1b 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -902,9 +902,6 @@ static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data) PrecopyNotifyData *pnd = data; switch (pnd->reason) { - case PRECOPY_NOTIFY_SETUP: - precopy_enable_free_page_optimization(); - break; case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC: virtio_mem_precopy_exclude_unplugged(vmem); break; diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 342c918ea7..5952471b38 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -36,7 +36,9 @@ static bool virtio_mmio_ioeventfd_enabled(DeviceState *d) { - return kvm_eventfds_enabled(); + VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); + + return (proxy->flags & VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD) != 0; } static int virtio_mmio_ioeventfd_assign(DeviceState *d, @@ -720,6 +722,8 @@ static Property virtio_mmio_properties[] = { DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy, format_transport_address, true), DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true), + DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags, + VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), }; @@ -731,6 +735,11 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp) qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS, d, NULL); sysbus_init_irq(sbd, &proxy->irq); + + if (!kvm_eventfds_enabled()) { + proxy->flags &= ~VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD; + } + if (proxy->legacy) { memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_legacy_mem_ops, proxy, diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 9e13cb9e3a..ab516ac614 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1972,9 +1972,7 @@ static enum virtio_device_endian virtio_default_endian(void) static enum virtio_device_endian virtio_current_cpu_endian(void) { - CPUClass *cc = CPU_GET_CLASS(current_cpu); - - if (cc->virtio_is_big_endian(current_cpu)) { + if (cpu_virtio_is_big_endian(current_cpu)) { return VIRTIO_DEVICE_ENDIAN_BIG; } else { return VIRTIO_DEVICE_ENDIAN_LITTLE; @@ -2981,7 +2979,7 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } -size_t virtio_feature_get_config_size(VirtIOFeature *feature_sizes, +size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes, uint64_t host_features) { size_t config_size = 0; |