diff options
Diffstat (limited to 'hw')
50 files changed, 1446 insertions, 860 deletions
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 25bc023882..8a64ffb38f 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -152,6 +152,7 @@ static const VMStateDescription vmstate_memhp_state = { .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, + .needed = vmstate_test_use_memhp, .fields = (VMStateField[]) { VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs), VMSTATE_END_OF_LIST() @@ -175,12 +176,9 @@ const VMStateDescription vmstate_ich9_pm = { VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_memhp_state, - .needed = vmstate_test_use_memhp, - }, - VMSTATE_END_OF_LIST() + .subsections = (const VMStateDescription*[]) { + &vmstate_memhp_state, + NULL } }; diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index b730ca6ced..3bd1d5a865 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -260,6 +260,7 @@ static const VMStateDescription vmstate_memhp_state = { .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, + .needed = vmstate_test_use_memhp, .fields = (VMStateField[]) { VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState), VMSTATE_END_OF_LIST() @@ -298,12 +299,9 @@ static const VMStateDescription vmstate_acpi = { vmstate_test_use_acpi_pci_hotplug), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_memhp_state, - .needed = vmstate_test_use_memhp, - }, - VMSTATE_END_OF_LIST() + .subsections = (const VMStateDescription*[]) { + &vmstate_memhp_state, + NULL } }; diff --git a/hw/arm/boot.c b/hw/arm/boot.c index d036624948..1e7fd28daa 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -574,15 +574,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) struct arm_boot_info *info = container_of(n, struct arm_boot_info, load_kernel_notifier); - /* CPU objects (unlike devices) are not automatically reset on system - * reset, so we must always register a handler to do so. If we're - * actually loading a kernel, the handler is also responsible for - * arranging that we start it correctly. - */ - for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) { - qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); - } - /* Load the kernel. */ if (!info->kernel_filename || info->firmware_loaded) { @@ -783,7 +774,18 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) { + CPUState *cs; + info->load_kernel_notifier.cpu = cpu; info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify; qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier); + + /* CPU objects (unlike devices) are not automatically reset on system + * reset, so we must always register a handler to do so. If we're + * actually loading a kernel, the handler is also responsible for + * arranging that we start it correctly. + */ + for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) { + qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); + } } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index f921a5680c..ec353f79c4 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -334,10 +334,10 @@ static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri) static const ARMCPRegInfo pxa_cp_reginfo[] = { /* cp14 crm==1: perf registers */ { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, @@ -356,11 +356,11 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, /* cp14 crn==6: CLKCFG */ { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, /* cp14 crn==7: PWRMODE */ { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, REGINFO_SENTINEL }; @@ -457,7 +457,7 @@ typedef struct { MemoryRegion iomem; qemu_irq irq; - int enable; + uint32_t enable; SSIBus *bus; uint32_t sscr[2]; @@ -470,10 +470,39 @@ typedef struct { uint8_t ssacd; uint32_t rx_fifo[16]; - int rx_level; - int rx_start; + uint32_t rx_level; + uint32_t rx_start; } PXA2xxSSPState; +static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id) +{ + PXA2xxSSPState *s = opaque; + + return s->rx_start < sizeof(s->rx_fifo); +} + +static const VMStateDescription vmstate_pxa2xx_ssp = { + .name = "pxa2xx-ssp", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(enable, PXA2xxSSPState), + VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2), + VMSTATE_UINT32(sspsp, PXA2xxSSPState), + VMSTATE_UINT32(ssto, PXA2xxSSPState), + VMSTATE_UINT32(ssitr, PXA2xxSSPState), + VMSTATE_UINT32(sssr, PXA2xxSSPState), + VMSTATE_UINT8(sstsa, PXA2xxSSPState), + VMSTATE_UINT8(ssrsa, PXA2xxSSPState), + VMSTATE_UINT8(ssacd, PXA2xxSSPState), + VMSTATE_UINT32(rx_level, PXA2xxSSPState), + VMSTATE_UINT32(rx_start, PXA2xxSSPState), + VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate), + VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16), + VMSTATE_END_OF_LIST() + } +}; + #define SSCR0 0x00 /* SSP Control register 0 */ #define SSCR1 0x04 /* SSP Control register 1 */ #define SSSR 0x08 /* SSP Status register */ @@ -705,55 +734,20 @@ static const MemoryRegionOps pxa2xx_ssp_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) +static void pxa2xx_ssp_reset(DeviceState *d) { - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i; - - qemu_put_be32(f, s->enable); + PXA2xxSSPState *s = PXA2XX_SSP(d); - qemu_put_be32s(f, &s->sscr[0]); - qemu_put_be32s(f, &s->sscr[1]); - qemu_put_be32s(f, &s->sspsp); - qemu_put_be32s(f, &s->ssto); - qemu_put_be32s(f, &s->ssitr); - qemu_put_be32s(f, &s->sssr); - qemu_put_8s(f, &s->sstsa); - qemu_put_8s(f, &s->ssrsa); - qemu_put_8s(f, &s->ssacd); - - qemu_put_byte(f, s->rx_level); - for (i = 0; i < s->rx_level; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]); -} - -static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i, v; - - s->enable = qemu_get_be32(f); - - qemu_get_be32s(f, &s->sscr[0]); - qemu_get_be32s(f, &s->sscr[1]); - qemu_get_be32s(f, &s->sspsp); - qemu_get_be32s(f, &s->ssto); - qemu_get_be32s(f, &s->ssitr); - qemu_get_be32s(f, &s->sssr); - qemu_get_8s(f, &s->sstsa); - qemu_get_8s(f, &s->ssrsa); - qemu_get_8s(f, &s->ssacd); - - v = qemu_get_byte(f); - if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) { - return -EINVAL; - } - s->rx_level = v; - s->rx_start = 0; - for (i = 0; i < s->rx_level; i ++) - s->rx_fifo[i] = qemu_get_byte(f); - - return 0; + s->enable = 0; + s->sscr[0] = s->sscr[1] = 0; + s->sspsp = 0; + s->ssto = 0; + s->ssitr = 0; + s->sssr = 0; + s->sstsa = 0; + s->ssrsa = 0; + s->ssacd = 0; + s->rx_start = s->rx_level = 0; } static int pxa2xx_ssp_init(SysBusDevice *sbd) @@ -766,8 +760,6 @@ static int pxa2xx_ssp_init(SysBusDevice *sbd) memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000); sysbus_init_mmio(sbd, &s->iomem); - register_savevm(dev, "pxa2xx_ssp", -1, 0, - pxa2xx_ssp_save, pxa2xx_ssp_load, s); s->bus = ssi_create_bus(dev, "ssi"); return 0; @@ -1759,24 +1751,33 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, } /* PXA Fast Infra-red Communications Port */ +#define TYPE_PXA2XX_FIR "pxa2xx-fir" +#define PXA2XX_FIR(obj) OBJECT_CHECK(PXA2xxFIrState, (obj), TYPE_PXA2XX_FIR) + struct PXA2xxFIrState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; qemu_irq irq; qemu_irq rx_dma; qemu_irq tx_dma; - int enable; + uint32_t enable; CharDriverState *chr; uint8_t control[3]; uint8_t status[2]; - int rx_len; - int rx_start; + uint32_t rx_len; + uint32_t rx_start; uint8_t rx_fifo[64]; }; -static void pxa2xx_fir_reset(PXA2xxFIrState *s) +static void pxa2xx_fir_reset(DeviceState *d) { + PXA2xxFIrState *s = PXA2XX_FIR(d); + s->control[0] = 0x00; s->control[1] = 0x00; s->control[2] = 0x00; @@ -1953,73 +1954,94 @@ static void pxa2xx_fir_event(void *opaque, int event) { } -static void pxa2xx_fir_save(QEMUFile *f, void *opaque) +static void pxa2xx_fir_instance_init(Object *obj) { - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - int i; + PXA2xxFIrState *s = PXA2XX_FIR(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - qemu_put_be32(f, s->enable); - - qemu_put_8s(f, &s->control[0]); - qemu_put_8s(f, &s->control[1]); - qemu_put_8s(f, &s->control[2]); - qemu_put_8s(f, &s->status[0]); - qemu_put_8s(f, &s->status[1]); - - qemu_put_byte(f, s->rx_len); - for (i = 0; i < s->rx_len; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]); + memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, + "pxa2xx-fir", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->rx_dma); + sysbus_init_irq(sbd, &s->tx_dma); } -static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) +static void pxa2xx_fir_realize(DeviceState *dev, Error **errp) { - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - int i; - - s->enable = qemu_get_be32(f); + PXA2xxFIrState *s = PXA2XX_FIR(dev); - qemu_get_8s(f, &s->control[0]); - qemu_get_8s(f, &s->control[1]); - qemu_get_8s(f, &s->control[2]); - qemu_get_8s(f, &s->status[0]); - qemu_get_8s(f, &s->status[1]); + if (s->chr) { + qemu_chr_fe_claim_no_fail(s->chr); + qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty, + pxa2xx_fir_rx, pxa2xx_fir_event, s); + } +} - s->rx_len = qemu_get_byte(f); - s->rx_start = 0; - for (i = 0; i < s->rx_len; i ++) - s->rx_fifo[i] = qemu_get_byte(f); +static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id) +{ + PXA2xxFIrState *s = opaque; - return 0; + return s->rx_start < ARRAY_SIZE(s->rx_fifo); } -static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, - CharDriverState *chr) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) - g_malloc0(sizeof(PXA2xxFIrState)); +static const VMStateDescription pxa2xx_fir_vmsd = { + .name = "pxa2xx-fir", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(enable, PXA2xxFIrState), + VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3), + VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2), + VMSTATE_UINT32(rx_len, PXA2xxFIrState), + VMSTATE_UINT32(rx_start, PXA2xxFIrState), + VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate), + VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64), + VMSTATE_END_OF_LIST() + } +}; - s->irq = irq; - s->rx_dma = rx_dma; - s->tx_dma = tx_dma; - s->chr = chr; +static Property pxa2xx_fir_properties[] = { + DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr), + DEFINE_PROP_END_OF_LIST(), +}; - pxa2xx_fir_reset(s); +static void pxa2xx_fir_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); - memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); - memory_region_add_subregion(sysmem, base, &s->iomem); + dc->realize = pxa2xx_fir_realize; + dc->vmsd = &pxa2xx_fir_vmsd; + dc->props = pxa2xx_fir_properties; + dc->reset = pxa2xx_fir_reset; +} - if (chr) { - qemu_chr_fe_claim_no_fail(chr); - qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, - pxa2xx_fir_rx, pxa2xx_fir_event, s); - } +static const TypeInfo pxa2xx_fir_info = { + .name = TYPE_PXA2XX_FIR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxFIrState), + .class_init = pxa2xx_fir_class_init, + .instance_init = pxa2xx_fir_instance_init, +}; - register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, - pxa2xx_fir_load, s); +static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + hwaddr base, + qemu_irq irq, qemu_irq rx_dma, + qemu_irq tx_dma, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *sbd; - return s; + dev = qdev_create(NULL, TYPE_PXA2XX_FIR); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sbd = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sbd, 0, base); + sysbus_connect_irq(sbd, 0, irq); + sysbus_connect_irq(sbd, 1, rx_dma); + sysbus_connect_irq(sbd, 2, tx_dma); + return PXA2XX_FIR(dev); } static void pxa2xx_reset(void *opaque, int line, int level) @@ -2306,8 +2328,11 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); sdc->init = pxa2xx_ssp_init; + dc->reset = pxa2xx_ssp_reset; + dc->vmsd = &vmstate_pxa2xx_ssp; } static const TypeInfo pxa2xx_ssp_info = { @@ -2323,6 +2348,7 @@ static void pxa2xx_register_types(void) type_register_static(&pxa2xx_ssp_info); type_register_static(&pxa2xx_i2c_info); type_register_static(&pxa2xx_rtc_sysbus_info); + type_register_static(&pxa2xx_fir_info); } type_init(pxa2xx_register_types) diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 9cfc714874..d41ac93416 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -232,7 +232,7 @@ static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri, #define REGINFO_FOR_PIC_CP(NAME, CRN) \ { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \ - .access = PL1_RW, \ + .access = PL1_RW, .type = ARM_CP_IO, \ .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write } static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index a9373ccaca..d5a8b9c017 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -84,6 +84,12 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, AML_EXCLUSIVE, uart_irq)); aml_append(dev, aml_name_decl("_CRS", crs)); + + /* The _ADR entry is used to link this device to the UART described + * in the SPCR table, i.e. SPCR.base_address.address == _ADR. + */ + aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base))); + aml_append(scope, dev); } @@ -334,6 +340,38 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) } static void +build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) +{ + AcpiSerialPortConsoleRedirection *spcr; + const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART]; + int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE; + + spcr = acpi_data_push(table_data, sizeof(*spcr)); + + spcr->interface_type = 0x3; /* ARM PL011 UART */ + + spcr->base_address.space_id = AML_SYSTEM_MEMORY; + spcr->base_address.bit_width = 8; + spcr->base_address.bit_offset = 0; + spcr->base_address.access_width = 1; + spcr->base_address.address = cpu_to_le64(uart_memmap->base); + + spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */ + spcr->gsi = cpu_to_le32(irq); /* Global System Interrupt */ + + spcr->baud = 3; /* Baud Rate: 3 = 9600 */ + spcr->parity = 0; /* No Parity */ + spcr->stopbits = 1; /* 1 Stop bit */ + spcr->flowctrl = (1 << 1); /* Bit[1] = RTS/CTS hardware flow control */ + spcr->term_type = 0; /* Terminal Type: 0 = VT100 */ + + spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */ + spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ + + build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2); +} + +static void build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) { AcpiTableMcfg *mcfg; @@ -514,7 +552,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) dsdt = tables_blob->len; build_dsdt(tables_blob, tables->linker, guest_info); - /* FADT MADT GTDT pointed to by RSDT */ + /* FADT MADT GTDT SPCR pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables->linker, dsdt); @@ -527,6 +565,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_mcfg(tables_blob, tables->linker, guest_info); + acpi_add_table(table_offsets, tables_blob); + build_spcr(tables_blob, tables->linker, guest_info); + /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; build_rsdt(tables_blob, tables->linker, table_offsets); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 1b1cc716ad..f1e85c8e92 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -145,6 +145,11 @@ static VirtBoardInfo machines[] = { .irqmap = a15irqmap, }, { + .cpu_model = "cortex-a53", + .memmap = a15memmap, + .irqmap = a15irqmap, + }, + { .cpu_model = "cortex-a57", .memmap = a15memmap, .irqmap = a15irqmap, @@ -306,7 +311,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) "enable-method", "psci"); } - qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", cpu); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity); g_free(nodename); } } diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 6e794597dc..5e1b67ee43 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -699,6 +699,7 @@ static const VMStateDescription vmstate_fdrive_media_changed = { .name = "fdrive/media_changed", .version_id = 1, .minimum_version_id = 1, + .needed = fdrive_media_changed_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(media_changed, FDrive), VMSTATE_END_OF_LIST() @@ -716,6 +717,7 @@ static const VMStateDescription vmstate_fdrive_media_rate = { .name = "fdrive/media_rate", .version_id = 1, .minimum_version_id = 1, + .needed = fdrive_media_rate_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(media_rate, FDrive), VMSTATE_END_OF_LIST() @@ -733,6 +735,7 @@ static const VMStateDescription vmstate_fdrive_perpendicular = { .name = "fdrive/perpendicular", .version_id = 1, .minimum_version_id = 1, + .needed = fdrive_perpendicular_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(perpendicular, FDrive), VMSTATE_END_OF_LIST() @@ -756,19 +759,11 @@ static const VMStateDescription vmstate_fdrive = { VMSTATE_UINT8(sect, FDrive), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_fdrive_media_changed, - .needed = &fdrive_media_changed_needed, - } , { - .vmsd = &vmstate_fdrive_media_rate, - .needed = &fdrive_media_rate_needed, - } , { - .vmsd = &vmstate_fdrive_perpendicular, - .needed = &fdrive_perpendicular_needed, - } , { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_fdrive_media_changed, + &vmstate_fdrive_media_rate, + &vmstate_fdrive_perpendicular, + NULL } }; @@ -833,6 +828,7 @@ static const VMStateDescription vmstate_fdc_reset_sensei = { .name = "fdc/reset_sensei", .version_id = 1, .minimum_version_id = 1, + .needed = fdc_reset_sensei_needed, .fields = (VMStateField[]) { VMSTATE_INT32(reset_sensei, FDCtrl), VMSTATE_END_OF_LIST() @@ -850,6 +846,7 @@ static const VMStateDescription vmstate_fdc_result_timer = { .name = "fdc/result_timer", .version_id = 1, .minimum_version_id = 1, + .needed = fdc_result_timer_needed, .fields = (VMStateField[]) { VMSTATE_TIMER_PTR(result_timer, FDCtrl), VMSTATE_END_OF_LIST() @@ -867,6 +864,7 @@ static const VMStateDescription vmstate_fdc_phase = { .name = "fdc/phase", .version_id = 1, .minimum_version_id = 1, + .needed = fdc_phase_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(phase, FDCtrl), VMSTATE_END_OF_LIST() @@ -911,19 +909,11 @@ static const VMStateDescription vmstate_fdc = { vmstate_fdrive, FDrive), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_fdc_reset_sensei, - .needed = fdc_reset_sensei_needed, - } , { - .vmsd = &vmstate_fdc_result_timer, - .needed = fdc_result_timer_needed, - } , { - .vmsd = &vmstate_fdc_phase, - .needed = fdc_phase_needed, - } , { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_fdc_reset_sensei, + &vmstate_fdc_result_timer, + &vmstate_fdc_phase, + NULL } }; diff --git a/hw/char/serial.c b/hw/char/serial.c index 55011cfd26..513d73c27f 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -662,6 +662,7 @@ static const VMStateDescription vmstate_serial_thr_ipending = { .name = "serial/thr_ipending", .version_id = 1, .minimum_version_id = 1, + .needed = serial_thr_ipending_needed, .fields = (VMStateField[]) { VMSTATE_INT32(thr_ipending, SerialState), VMSTATE_END_OF_LIST() @@ -678,6 +679,7 @@ static const VMStateDescription vmstate_serial_tsr = { .name = "serial/tsr", .version_id = 1, .minimum_version_id = 1, + .needed = serial_tsr_needed, .fields = (VMStateField[]) { VMSTATE_INT32(tsr_retry, SerialState), VMSTATE_UINT8(thr, SerialState), @@ -697,6 +699,7 @@ static const VMStateDescription vmstate_serial_recv_fifo = { .name = "serial/recv_fifo", .version_id = 1, .minimum_version_id = 1, + .needed = serial_recv_fifo_needed, .fields = (VMStateField[]) { VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8), VMSTATE_END_OF_LIST() @@ -713,6 +716,7 @@ static const VMStateDescription vmstate_serial_xmit_fifo = { .name = "serial/xmit_fifo", .version_id = 1, .minimum_version_id = 1, + .needed = serial_xmit_fifo_needed, .fields = (VMStateField[]) { VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8), VMSTATE_END_OF_LIST() @@ -729,6 +733,7 @@ static const VMStateDescription vmstate_serial_fifo_timeout_timer = { .name = "serial/fifo_timeout_timer", .version_id = 1, .minimum_version_id = 1, + .needed = serial_fifo_timeout_timer_needed, .fields = (VMStateField[]) { VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState), VMSTATE_END_OF_LIST() @@ -745,6 +750,7 @@ static const VMStateDescription vmstate_serial_timeout_ipending = { .name = "serial/timeout_ipending", .version_id = 1, .minimum_version_id = 1, + .needed = serial_timeout_ipending_needed, .fields = (VMStateField[]) { VMSTATE_INT32(timeout_ipending, SerialState), VMSTATE_END_OF_LIST() @@ -760,6 +766,7 @@ static bool serial_poll_needed(void *opaque) static const VMStateDescription vmstate_serial_poll = { .name = "serial/poll", .version_id = 1, + .needed = serial_poll_needed, .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_INT32(poll_msl, SerialState), @@ -788,31 +795,15 @@ const VMStateDescription vmstate_serial = { VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_serial_thr_ipending, - .needed = &serial_thr_ipending_needed, - } , { - .vmsd = &vmstate_serial_tsr, - .needed = &serial_tsr_needed, - } , { - .vmsd = &vmstate_serial_recv_fifo, - .needed = &serial_recv_fifo_needed, - } , { - .vmsd = &vmstate_serial_xmit_fifo, - .needed = &serial_xmit_fifo_needed, - } , { - .vmsd = &vmstate_serial_fifo_timeout_timer, - .needed = &serial_fifo_timeout_timer_needed, - } , { - .vmsd = &vmstate_serial_timeout_ipending, - .needed = &serial_timeout_ipending_needed, - } , { - .vmsd = &vmstate_serial_poll, - .needed = &serial_poll_needed, - } , { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_serial_thr_ipending, + &vmstate_serial_tsr, + &vmstate_serial_recv_fifo, + &vmstate_serial_xmit_fifo, + &vmstate_serial_fifo_timeout_timer, + &vmstate_serial_timeout_ipending, + &vmstate_serial_poll, + NULL } }; diff --git a/hw/core/nmi.c b/hw/core/nmi.c index 3dff020659..5260d6c1ec 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -21,6 +21,7 @@ #include "hw/nmi.h" #include "qapi/qmp/qerror.h" +#include "monitor/monitor.h" struct do_nmi_s { int cpu_index; @@ -70,6 +71,25 @@ void nmi_monitor_handle(int cpu_index, Error **errp) } } +void inject_nmi(void) +{ +#if defined(TARGET_I386) + CPUState *cs; + + CPU_FOREACH(cs) { + X86CPU *cpu = X86_CPU(cs); + + if (!cpu->apic_state) { + cpu_interrupt(cs, CPU_INTERRUPT_NMI); + } else { + apic_deliver_nmi(cpu->apic_state); + } + } +#else + nmi_monitor_handle(0, NULL); +#endif +} + static const TypeInfo nmi_info = { .name = TYPE_NMI, .parent = TYPE_INTERFACE, diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 72b3a1d063..603ef50568 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -337,7 +337,7 @@ static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data) if (swap_ctl & FIMD_WINCON_SWAP_BITS) { res = 0; for (i = 0; i < 64; i++) { - if (x & (1ULL << (64 - i))) { + if (x & (1ULL << (63 - i))) { res |= (1ULL << i); } } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index b220e2d5d2..722146ec3a 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2220,6 +2220,7 @@ static VMStateDescription qxl_vmstate_monitors_config = { .name = "qxl/monitors-config", .version_id = 1, .minimum_version_id = 1, + .needed = qxl_monitors_config_needed, .fields = (VMStateField[]) { VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice), VMSTATE_END_OF_LIST() @@ -2253,13 +2254,9 @@ static VMStateDescription qxl_vmstate = { VMSTATE_UINT64(guest_cursor, PCIQXLDevice), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &qxl_vmstate_monitors_config, - .needed = qxl_monitors_config_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &qxl_vmstate_monitors_config, + NULL } }; diff --git a/hw/display/vga.c b/hw/display/vga.c index d1d296c74e..b35d523e65 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -2035,6 +2035,7 @@ static const VMStateDescription vmstate_vga_endian = { .name = "vga.endian", .version_id = 1, .minimum_version_id = 1, + .needed = vga_endian_state_needed, .fields = (VMStateField[]) { VMSTATE_BOOL(big_endian_fb, VGACommonState), VMSTATE_END_OF_LIST() @@ -2078,13 +2079,9 @@ const VMStateDescription vmstate_vga_common = { VMSTATE_UINT32(vbe_bank_mask, VGACommonState), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_vga_endian, - .needed = vga_endian_state_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_vga_endian, + NULL } }; diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index af2663256e..3efa6de352 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -1,7 +1,7 @@ /* * QEMU JAZZ RC4030 chipset * - * Copyright (c) 2007-2009 Herve Poussineau + * Copyright (c) 2007-2013 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,29 +24,16 @@ #include "hw/hw.h" #include "hw/mips/mips.h" +#include "hw/sysbus.h" #include "qemu/timer.h" - -/********************************************************/ -/* debug rc4030 */ - -//#define DEBUG_RC4030 -//#define DEBUG_RC4030_DMA - -#ifdef DEBUG_RC4030 -#define DPRINTF(fmt, ...) \ -do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0) -static const char* irq_names[] = { "parallel", "floppy", "sound", "video", - "network", "scsi", "keyboard", "mouse", "serial0", "serial1" }; -#else -#define DPRINTF(fmt, ...) -#endif - -#define RC4030_ERROR(fmt, ...) \ -do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) +#include "exec/address-spaces.h" +#include "trace.h" /********************************************************/ /* rc4030 emulation */ +#define MAX_TL_ENTRIES 512 + typedef struct dma_pagetable_entry { int32_t frame; int32_t owner; @@ -63,8 +50,14 @@ typedef struct dma_pagetable_entry { #define DMA_FLAG_MEM_INTR 0x0200 #define DMA_FLAG_ADDR_INTR 0x0400 +#define TYPE_RC4030 "rc4030" +#define RC4030(obj) \ + OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030) + typedef struct rc4030State { + SysBusDevice parent; + uint32_t config; /* 0x0000: RC4030 config register */ uint32_t revision; /* 0x0008: RC4030 Revision register */ uint32_t invalid_address_register; /* 0x0010: Invalid Address register */ @@ -83,7 +76,7 @@ typedef struct rc4030State uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */ uint32_t nmi_interrupt; /* 0x0200: interrupt source */ - uint32_t offset210; + uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */ uint32_t nvram_protect; /* 0x0220: NV ram protect register */ uint32_t rem_speed[16]; uint32_t imr_jazz; /* Local bus int enable mask */ @@ -96,6 +89,16 @@ typedef struct rc4030State qemu_irq timer_irq; qemu_irq jazz_bus_irq; + /* biggest translation table */ + MemoryRegion dma_tt; + /* translation table memory region alias, added to system RAM */ + MemoryRegion dma_tt_alias; + /* whole DMA memory region, root of DMA address space */ + MemoryRegion dma_mr; + /* translation table entry aliases, added to DMA memory region */ + MemoryRegion dma_mrs[MAX_TL_ENTRIES]; + AddressSpace dma_as; + MemoryRegion iomem_chipset; MemoryRegion iomem_jazzio; } rc4030State; @@ -112,7 +115,7 @@ static void set_next_tick(rc4030State *s) } /* called for accesses to rc4030 */ -static uint32_t rc4030_readl(void *opaque, hwaddr addr) +static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size) { rc4030State *s = opaque; uint32_t val; @@ -220,9 +223,9 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr) case 0x0208: val = 0; break; - /* Offset 0x0210 */ + /* Memory refresh rate */ case 0x0210: - val = s->offset210; + val = s->memory_refresh_rate; break; /* NV ram protect register */ case 0x0220: @@ -238,39 +241,117 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr) val = 7; /* FIXME: should be read from EISA controller */ break; default: - RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030: invalid read at 0x%x", (int)addr); val = 0; break; } if ((addr & ~3) != 0x230) { - DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr); + trace_rc4030_read(addr, val); } return val; } -static uint32_t rc4030_readw(void *opaque, hwaddr addr) +static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame) { - uint32_t v = rc4030_readl(opaque, addr & ~0x3); - if (addr & 0x2) - return v >> 16; - else - return v & 0xffff; + if (index < MAX_TL_ENTRIES) { + memory_region_set_enabled(&s->dma_mrs[index], false); + } + + if (!frame) { + return; + } + + if (index >= MAX_TL_ENTRIES) { + qemu_log_mask(LOG_UNIMP, + "rc4030: trying to use too high " + "translation table entry %d (max allowed=%d)", + index, MAX_TL_ENTRIES); + return; + } + memory_region_set_alias_offset(&s->dma_mrs[index], frame); + memory_region_set_enabled(&s->dma_mrs[index], true); } -static uint32_t rc4030_readb(void *opaque, hwaddr addr) +static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - uint32_t v = rc4030_readl(opaque, addr & ~0x3); - return (v >> (8 * (addr & 0x3))) & 0xff; + rc4030State *s = opaque; + + /* write memory */ + memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size); + + /* update dma address space (only if frame field has been written) */ + if (addr % sizeof(dma_pagetable_entry) == 0) { + int index = addr / sizeof(dma_pagetable_entry); + memory_region_transaction_begin(); + rc4030_dma_as_update_one(s, index, (uint32_t)data); + memory_region_transaction_commit(); + } } -static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) +static const MemoryRegionOps rc4030_dma_tt_ops = { + .write = rc4030_dma_tt_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base, + uint32_t new_tl_limit) +{ + int entries, i; + dma_pagetable_entry *dma_tl_contents; + + if (s->dma_tl_limit) { + /* write old dma tl table to physical memory */ + memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias); + cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff, + memory_region_get_ram_ptr(&s->dma_tt), + memory_region_size(&s->dma_tt_alias)); + } + object_unparent(OBJECT(&s->dma_tt_alias)); + + s->dma_tl_base = new_tl_base; + s->dma_tl_limit = new_tl_limit; + new_tl_base &= 0x7fffffff; + + if (s->dma_tl_limit) { + uint64_t dma_tt_size; + if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) { + dma_tt_size = s->dma_tl_limit; + } else { + dma_tt_size = memory_region_size(&s->dma_tt); + } + memory_region_init_alias(&s->dma_tt_alias, OBJECT(s), + "dma-table-alias", + &s->dma_tt, 0, dma_tt_size); + dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt); + cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size); + + memory_region_transaction_begin(); + entries = dma_tt_size / sizeof(dma_pagetable_entry); + for (i = 0; i < entries; i++) { + rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame); + } + memory_region_add_subregion(get_system_memory(), new_tl_base, + &s->dma_tt_alias); + memory_region_transaction_commit(); + } else { + memory_region_init(&s->dma_tt_alias, OBJECT(s), + "dma-table-alias", 0); + } +} + +static void rc4030_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { rc4030State *s = opaque; + uint32_t val = data; addr &= 0x3fff; - DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr); + trace_rc4030_write(addr, val); switch (addr & ~0x3) { /* Global config register */ @@ -279,11 +360,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) break; /* DMA transl. table base */ case 0x0018: - s->dma_tl_base = val; + rc4030_dma_tt_update(s, val, s->dma_tl_limit); break; /* DMA transl. table limit */ case 0x0020: - s->dma_tl_limit = val; + rc4030_dma_tt_update(s, s->dma_tl_base, val); break; /* DMA transl. table invalidated */ case 0x0028: @@ -371,9 +452,9 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) s->dma_regs[entry][idx] = val; } break; - /* Offset 0x0210 */ + /* Memory refresh rate */ case 0x0210: - s->offset210 = val; + s->memory_refresh_rate = val; break; /* Interval timer reload */ case 0x0228: @@ -385,48 +466,18 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) case 0x0238: break; default: - RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr); - break; - } -} - -static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); - - if (addr & 0x2) - val = (val << 16) | (old_val & 0x0000ffff); - else - val = val | (old_val & 0xffff0000); - rc4030_writel(opaque, addr & ~0x3, val); -} - -static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xffffff00); - break; - case 1: - val = (val << 8) | (old_val & 0xffff00ff); - break; - case 2: - val = (val << 16) | (old_val & 0xff00ffff); - break; - case 3: - val = (val << 24) | (old_val & 0x00ffffff); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030: invalid write of 0x%02x at 0x%x", + val, (int)addr); break; } - rc4030_writel(opaque, addr & ~0x3, val); } static const MemoryRegionOps rc4030_ops = { - .old_mmio = { - .read = { rc4030_readb, rc4030_readw, rc4030_readl, }, - .write = { rc4030_writeb, rc4030_writew, rc4030_writel, }, - }, + .read = rc4030_read, + .write = rc4030_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -436,22 +487,6 @@ static void update_jazz_irq(rc4030State *s) pending = s->isr_jazz & s->imr_jazz; -#ifdef DEBUG_RC4030 - if (s->isr_jazz != 0) { - uint32_t irq = 0; - DPRINTF("pending irqs:"); - for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) { - if (s->isr_jazz & (1 << irq)) { - printf(" %s", irq_names[irq]); - if (!(s->imr_jazz & (1 << irq))) { - printf("(ignored)"); - } - } - } - printf("\n"); - } -#endif - if (pending != 0) qemu_irq_raise(s->jazz_bus_irq); else @@ -479,7 +514,7 @@ static void rc4030_periodic_timer(void *opaque) qemu_irq_raise(s->timer_irq); } -static uint32_t jazzio_readw(void *opaque, hwaddr addr) +static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size) { rc4030State *s = opaque; uint32_t val; @@ -494,7 +529,6 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr) irq = 0; while (pending) { if (pending & 1) { - DPRINTF("returning irq %s\n", irq_names[irq]); val = (irq + 1) << 2; break; } @@ -508,36 +542,25 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr) val = s->imr_jazz; break; default: - RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030/jazzio: invalid read at 0x%x", (int)addr); val = 0; + break; } - DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr); + trace_jazzio_read(addr, val); return val; } -static uint32_t jazzio_readb(void *opaque, hwaddr addr) -{ - uint32_t v; - v = jazzio_readw(opaque, addr & ~0x1); - return (v >> (8 * (addr & 0x1))) & 0xff; -} - -static uint32_t jazzio_readl(void *opaque, hwaddr addr) -{ - uint32_t v; - v = jazzio_readw(opaque, addr); - v |= jazzio_readw(opaque, addr + 2) << 16; - return v; -} - -static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) +static void jazzio_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { rc4030State *s = opaque; + uint32_t val = data; addr &= 0xfff; - DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr); + trace_jazzio_write(addr, val); switch (addr) { /* Local bus int enable mask */ @@ -546,43 +569,24 @@ static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) update_jazz_irq(s); break; default: - RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030/jazzio: invalid write of 0x%02x at 0x%x", + val, (int)addr); break; } } -static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = jazzio_readw(opaque, addr & ~0x1); - - switch (addr & 1) { - case 0: - val = val | (old_val & 0xff00); - break; - case 1: - val = (val << 8) | (old_val & 0x00ff); - break; - } - jazzio_writew(opaque, addr & ~0x1, val); -} - -static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val) -{ - jazzio_writew(opaque, addr, val & 0xffff); - jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff); -} - static const MemoryRegionOps jazzio_ops = { - .old_mmio = { - .read = { jazzio_readb, jazzio_readw, jazzio_readl, }, - .write = { jazzio_writeb, jazzio_writew, jazzio_writel, }, - }, + .read = jazzio_read, + .write = jazzio_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, .endianness = DEVICE_NATIVE_ENDIAN, }; -static void rc4030_reset(void *opaque) +static void rc4030_reset(DeviceState *dev) { - rc4030State *s = opaque; + rc4030State *s = RC4030(dev); int i; s->config = 0x410; /* some boards seem to accept 0x104 too */ @@ -590,14 +594,14 @@ static void rc4030_reset(void *opaque) s->invalid_address_register = 0; memset(s->dma_regs, 0, sizeof(s->dma_regs)); - s->dma_tl_base = s->dma_tl_limit = 0; + rc4030_dma_tt_update(s, 0, 0); s->remote_failed_address = s->memory_failed_address = 0; s->cache_maint = 0; s->cache_ptag = s->cache_ltag = 0; s->cache_bmask = 0; - s->offset210 = 0x18186; + s->memory_refresh_rate = 0x18186; s->nvram_protect = 7; for (i = 0; i < 15; i++) s->rem_speed[i] = 7; @@ -631,7 +635,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) s->cache_ptag = qemu_get_be32(f); s->cache_ltag = qemu_get_be32(f); s->cache_bmask = qemu_get_be32(f); - s->offset210 = qemu_get_be32(f); + s->memory_refresh_rate = qemu_get_be32(f); s->nvram_protect = qemu_get_be32(f); for (i = 0; i < 15; i++) s->rem_speed[i] = qemu_get_be32(f); @@ -663,7 +667,7 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->cache_ptag); qemu_put_be32(f, s->cache_ltag); qemu_put_be32(f, s->cache_bmask); - qemu_put_be32(f, s->offset210); + qemu_put_be32(f, s->memory_refresh_rate); qemu_put_be32(f, s->nvram_protect); for (i = 0; i < 15; i++) qemu_put_be32(f, s->rem_speed[i]); @@ -672,44 +676,6 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->itr); } -void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write) -{ - rc4030State *s = opaque; - hwaddr entry_addr; - hwaddr phys_addr; - dma_pagetable_entry entry; - int index; - int ncpy, i; - - i = 0; - for (;;) { - if (i == len) { - break; - } - - ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1)); - if (ncpy > len - i) - ncpy = len - i; - - /* Get DMA translation table entry */ - index = addr / DMA_PAGESIZE; - if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) { - break; - } - entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry); - /* XXX: not sure. should we really use only lowest bits? */ - entry_addr &= 0x7fffffff; - cpu_physical_memory_read(entry_addr, &entry, sizeof(entry)); - - /* Read/write data at right place */ - phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); - cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write); - - i += ncpy; - addr += ncpy; - } -} - static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) { rc4030State *s = opaque; @@ -733,32 +699,11 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; /* Read/write data at right place */ - rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write); + address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED, + buf, len, is_write); s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; s->dma_regs[n][DMA_REG_COUNT] -= len; - -#ifdef DEBUG_RC4030_DMA - { - int i, j; - printf("rc4030 dma: Copying %d bytes %s host %p\n", - len, is_write ? "from" : "to", buf); - for (i = 0; i < len; i += 16) { - int n = 16; - if (n > len - i) { - n = len - i; - } - for (j = 0; j < n; j++) - printf("%02x ", buf[i + j]); - while (j++ < 16) - printf(" "); - printf("| "); - for (j = 0; j < n; j++) - printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.'); - printf("\n"); - } - } -#endif } struct rc4030DMAState { @@ -795,31 +740,102 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n) return s; } -void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, - qemu_irq **irqs, rc4030_dma **dmas, - MemoryRegion *sysmem) +static void rc4030_initfn(Object *obj) { - rc4030State *s; + DeviceState *dev = DEVICE(obj); + rc4030State *s = RC4030(obj); + SysBusDevice *sysbus = SYS_BUS_DEVICE(obj); - s = g_malloc0(sizeof(rc4030State)); + qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16); - *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16); - *dmas = rc4030_allocate_dmas(s, 4); + sysbus_init_irq(sysbus, &s->timer_irq); + sysbus_init_irq(sysbus, &s->jazz_bus_irq); - s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s); - s->timer_irq = timer; - s->jazz_bus_irq = jazz_bus; - - qemu_register_reset(rc4030_reset, s); register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s); - rc4030_reset(s); + + sysbus_init_mmio(sysbus, &s->iomem_chipset); + sysbus_init_mmio(sysbus, &s->iomem_jazzio); +} + +static void rc4030_realize(DeviceState *dev, Error **errp) +{ + rc4030State *s = RC4030(dev); + Object *o = OBJECT(dev); + int i; + + s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + rc4030_periodic_timer, s); memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s, "rc4030.chipset", 0x300); - memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset); memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s, "rc4030.jazzio", 0x00001000); - memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio); - return s; + memory_region_init_rom_device(&s->dma_tt, o, + &rc4030_dma_tt_ops, s, "dma-table", + MAX_TL_ENTRIES * sizeof(dma_pagetable_entry), + NULL); + memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0); + memory_region_init(&s->dma_mr, o, "dma", INT32_MAX); + for (i = 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias", + get_system_memory(), 0, DMA_PAGESIZE); + memory_region_set_enabled(&s->dma_mrs[i], false); + memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE, + &s->dma_mrs[i]); + } + address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma"); +} + +static void rc4030_unrealize(DeviceState *dev, Error **errp) +{ + rc4030State *s = RC4030(dev); + int i; + + timer_free(s->periodic_timer); + + address_space_destroy(&s->dma_as); + object_unparent(OBJECT(&s->dma_tt)); + object_unparent(OBJECT(&s->dma_tt_alias)); + object_unparent(OBJECT(&s->dma_mr)); + for (i = 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]); + object_unparent(OBJECT(&s->dma_mrs[i])); + } +} + +static void rc4030_class_init(ObjectClass *klass, void *class_data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rc4030_realize; + dc->unrealize = rc4030_unrealize; + dc->reset = rc4030_reset; +} + +static const TypeInfo rc4030_info = { + .name = TYPE_RC4030, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(rc4030State), + .instance_init = rc4030_initfn, + .class_init = rc4030_class_init, +}; + +static void rc4030_register_types(void) +{ + type_register_static(&rc4030_info); +} + +type_init(rc4030_register_types) + +DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_RC4030); + qdev_init_nofail(dev); + + *dmas = rc4030_allocate_dmas(dev, 4); + *dma_mr = &RC4030(dev)->dma_mr; + return dev; } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5253e6d4fa..e142f75649 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -52,6 +52,7 @@ #ifdef CONFIG_XEN # include <xen/hvm/hvm_info_table.h> #endif +#include "migration/migration.h" #define MAX_IDE_BUS 2 @@ -305,6 +306,7 @@ static void pc_init1(MachineState *machine) static void pc_compat_2_3(MachineState *machine) { + savevm_skip_section_footers(); } static void pc_compat_2_2(MachineState *machine) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 110dfb78a8..b68263d231 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -45,6 +45,7 @@ #include "hw/usb.h" #include "hw/cpu/icc_bus.h" #include "qemu/error-report.h" +#include "migration/migration.h" /* ICH9 AHCI has 6 ports */ #define MAX_SATA_PORTS 6 @@ -289,6 +290,7 @@ static void pc_q35_init(MachineState *machine) static void pc_compat_2_3(MachineState *machine) { + savevm_skip_section_footers(); } static void pc_compat_2_2(MachineState *machine) diff --git a/hw/ide/core.c b/hw/ide/core.c index fcb908061c..1efd98af63 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2561,6 +2561,7 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = { .name ="ide_drive/atapi/gesn_state", .version_id = 1, .minimum_version_id = 1, + .needed = ide_atapi_gesn_needed, .fields = (VMStateField[]) { VMSTATE_BOOL(events.new_media, IDEState), VMSTATE_BOOL(events.eject_request, IDEState), @@ -2572,6 +2573,7 @@ static const VMStateDescription vmstate_ide_tray_state = { .name = "ide_drive/tray_state", .version_id = 1, .minimum_version_id = 1, + .needed = ide_tray_state_needed, .fields = (VMStateField[]) { VMSTATE_BOOL(tray_open, IDEState), VMSTATE_BOOL(tray_locked, IDEState), @@ -2585,6 +2587,7 @@ static const VMStateDescription vmstate_ide_drive_pio_state = { .minimum_version_id = 1, .pre_save = ide_drive_pio_pre_save, .post_load = ide_drive_pio_post_load, + .needed = ide_drive_pio_state_needed, .fields = (VMStateField[]) { VMSTATE_INT32(req_nb_sectors, IDEState), VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1, @@ -2626,19 +2629,11 @@ const VMStateDescription vmstate_ide_drive = { VMSTATE_UINT8_V(cdrom_changed, IDEState, 3), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_ide_drive_pio_state, - .needed = ide_drive_pio_state_needed, - }, { - .vmsd = &vmstate_ide_tray_state, - .needed = ide_tray_state_needed, - }, { - .vmsd = &vmstate_ide_atapi_gesn_state, - .needed = ide_atapi_gesn_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_ide_drive_pio_state, + &vmstate_ide_tray_state, + &vmstate_ide_atapi_gesn_state, + NULL } }; @@ -2646,6 +2641,7 @@ static const VMStateDescription vmstate_ide_error_status = { .name ="ide_bus/error", .version_id = 2, .minimum_version_id = 1, + .needed = ide_error_needed, .fields = (VMStateField[]) { VMSTATE_INT32(error_status, IDEBus), VMSTATE_INT64_V(retry_sector_num, IDEBus, 2), @@ -2664,13 +2660,9 @@ const VMStateDescription vmstate_ide_bus = { VMSTATE_UINT8(unit, IDEBus), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_ide_error_status, - .needed = ide_error_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_ide_error_status, + NULL } }; diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 4b5e32dcbe..4afd0cfe8c 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -350,6 +350,7 @@ static const VMStateDescription vmstate_bmdma_current = { .name = "ide bmdma_current", .version_id = 1, .minimum_version_id = 1, + .needed = ide_bmdma_current_needed, .fields = (VMStateField[]) { VMSTATE_UINT32(cur_addr, BMDMAState), VMSTATE_UINT32(cur_prd_last, BMDMAState), @@ -363,6 +364,7 @@ static const VMStateDescription vmstate_bmdma_status = { .name ="ide bmdma/status", .version_id = 1, .minimum_version_id = 1, + .needed = ide_bmdma_status_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(status, BMDMAState), VMSTATE_END_OF_LIST() @@ -383,16 +385,10 @@ static const VMStateDescription vmstate_bmdma = { VMSTATE_UINT8(migration_retry_unit, BMDMAState), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_bmdma_current, - .needed = ide_bmdma_current_needed, - }, { - .vmsd = &vmstate_bmdma_status, - .needed = ide_bmdma_status_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_bmdma_current, + &vmstate_bmdma_status, + NULL } }; diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 9b9a7d7a8a..ddac69df6f 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -391,23 +391,24 @@ static int kbd_outport_post_load(void *opaque, int version_id) return 0; } +static bool kbd_outport_needed(void *opaque) +{ + KBDState *s = opaque; + return s->outport != kbd_outport_default(s); +} + static const VMStateDescription vmstate_kbd_outport = { .name = "pckbd_outport", .version_id = 1, .minimum_version_id = 1, .post_load = kbd_outport_post_load, + .needed = kbd_outport_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(outport, KBDState), VMSTATE_END_OF_LIST() } }; -static bool kbd_outport_needed(void *opaque) -{ - KBDState *s = opaque; - return s->outport != kbd_outport_default(s); -} - static int kbd_post_load(void *opaque, int version_id) { KBDState *s = opaque; @@ -430,12 +431,9 @@ static const VMStateDescription vmstate_kbd = { VMSTATE_UINT8(pending, KBDState), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_kbd_outport, - .needed = kbd_outport_needed, - }, - VMSTATE_END_OF_LIST() + .subsections = (const VMStateDescription*[]) { + &vmstate_kbd_outport, + NULL } }; diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 4baeea2b56..fdbe565e62 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -677,6 +677,7 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = { .version_id = 3, .minimum_version_id = 2, .post_load = ps2_kbd_ledstate_post_load, + .needed = ps2_keyboard_ledstate_needed, .fields = (VMStateField[]) { VMSTATE_INT32(ledstate, PS2KbdState), VMSTATE_END_OF_LIST() @@ -717,13 +718,9 @@ static const VMStateDescription vmstate_ps2_keyboard = { VMSTATE_INT32_V(scancode_set, PS2KbdState,3), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_ps2_keyboard_ledstate, - .needed = ps2_keyboard_ledstate_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_ps2_keyboard_ledstate, + NULL } }; diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index d595d63a51..0032b97c5f 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -369,6 +369,7 @@ static const VMStateDescription vmstate_apic_common_sipi = { .name = "apic_sipi", .version_id = 1, .minimum_version_id = 1, + .needed = apic_common_sipi_needed, .fields = (VMStateField[]) { VMSTATE_INT32(sipi_vector, APICCommonState), VMSTATE_INT32(wait_for_sipi, APICCommonState), @@ -408,12 +409,9 @@ static const VMStateDescription vmstate_apic_common = { APICCommonState), /* open-coded timer state */ VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_apic_common_sipi, - .needed = apic_common_sipi_needed, - }, - VMSTATE_END_OF_LIST() + .subsections = (const VMStateDescription*[]) { + &vmstate_apic_common_sipi, + NULL } }; diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index c1d2e704ec..454bfd7df5 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -71,7 +71,7 @@ void gic_update(GICState *s) || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { qemu_irq_lower(s->parent_irq[cpu]); qemu_irq_lower(s->parent_fiq[cpu]); - return; + continue; } best_prio = 0x100; best_irq = 1023; diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 71a9f7a716..b3e0b1fd52 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -650,6 +650,7 @@ static const VMStateDescription vmstate_ich9_rst_cnt = { .name = "ICH9LPC/rst_cnt", .version_id = 1, .minimum_version_id = 1, + .needed = ich9_rst_cnt_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(rst_cnt, ICH9LPCState), VMSTATE_END_OF_LIST() @@ -669,12 +670,9 @@ static const VMStateDescription vmstate_ich9_lpc = { VMSTATE_UINT32(sci_level, ICH9LPCState), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_ich9_rst_cnt, - .needed = ich9_rst_cnt_needed - }, - { 0 } + .subsections = (const VMStateDescription*[]) { + &vmstate_ich9_rst_cnt, + NULL } }; diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 0a652f8521..9633f3a57d 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -1,4 +1,5 @@ -obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +obj-y += mips_r4k.o mips_malta.o mips_mipssim.o obj-y += addr.o cputimer.o mips_int.o +obj-$(CONFIG_JAZZ) += mips_jazz.o obj-$(CONFIG_FULONG) += mips_fulong2e.o obj-y += gt64xxx_pci.o diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 2c153e092f..9d60633efb 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -135,16 +135,16 @@ static void mips_jazz_init(MachineState *machine, MIPSCPU *cpu; CPUClass *cc; CPUMIPSState *env; - qemu_irq *rc4030, *i8259; + qemu_irq *i8259; rc4030_dma *dmas; - void* rc4030_opaque; + MemoryRegion *rc4030_dma_mr; MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); NICInfo *nd; - DeviceState *dev; + DeviceState *dev, *rc4030; SysBusDevice *sysbus; ISABus *isa_bus; ISADevice *pit; @@ -157,12 +157,7 @@ static void mips_jazz_init(MachineState *machine, /* init CPUs */ if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 cpu_model = "R4000"; -#else - /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */ - cpu_model = "24Kf"; -#endif } cpu = cpu_mips_init(cpu_model); if (cpu == NULL) { @@ -218,8 +213,14 @@ static void mips_jazz_init(MachineState *machine, cpu_mips_clock_init(env); /* Chipset */ - rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas, - address_space); + rc4030 = rc4030_init(&dmas, &rc4030_dma_mr); + sysbus = SYS_BUS_DEVICE(rc4030); + sysbus_connect_irq(sysbus, 0, env->irq[6]); + sysbus_connect_irq(sysbus, 1, env->irq[3]); + memory_region_add_subregion(address_space, 0x80000000, + sysbus_mmio_get_region(sysbus, 0)); + memory_region_add_subregion(address_space, 0xf0000000, + sysbus_mmio_get_region(sysbus, 1)); memory_region_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000); memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); @@ -246,7 +247,7 @@ static void mips_jazz_init(MachineState *machine, sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 1, 0x40000000); - sysbus_connect_irq(sysbus, 0, rc4030[3]); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3)); { /* Simple ROM, so user doesn't have to provide one */ MemoryRegion *rom_mr = g_new(MemoryRegion, 1); @@ -272,8 +273,17 @@ static void mips_jazz_init(MachineState *machine, if (!nd->model) nd->model = g_strdup("dp83932"); if (strcmp(nd->model, "dp83932") == 0) { - dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4], - rc4030_opaque, rc4030_dma_memory_rw); + qemu_check_nic_model(nd, "dp83932"); + + dev = qdev_create(NULL, "dp8393x"); + qdev_set_nic_properties(dev, nd); + qdev_prop_set_uint8(dev, "it_shift", 2); + qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sysbus, 0, 0x80001000); + sysbus_mmio_map(sysbus, 1, 0x8000b000); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4)); break; } else if (is_help_option(nd->model)) { fprintf(stderr, "qemu: Supported NICs: dp83932\n"); @@ -287,7 +297,7 @@ static void mips_jazz_init(MachineState *machine, /* SCSI adapter */ esp_init(0x80002000, 0, rc4030_dma_read, rc4030_dma_write, dmas[0], - rc4030[5], &esp_reset, &dma_enable); + qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable); /* Floppy */ if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { @@ -297,7 +307,7 @@ static void mips_jazz_init(MachineState *machine, for (n = 0; n < MAX_FD; n++) { fds[n] = drive_get(IF_FLOPPY, 0, n); } - fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); + fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0, 0x80003000, fds); /* Real time clock */ rtc_init(isa_bus, 1980, NULL); @@ -305,23 +315,26 @@ static void mips_jazz_init(MachineState *machine, memory_region_add_subregion(address_space, 0x80004000, rtc); /* Keyboard (i8042) */ - i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1); + i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7), + i8042, 0x1000, 0x1); memory_region_add_subregion(address_space, 0x80005000, i8042); /* Serial ports */ if (serial_hds[0]) { - serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16, + serial_mm_init(address_space, 0x80006000, 0, + qdev_get_gpio_in(rc4030, 8), 8000000/16, serial_hds[0], DEVICE_NATIVE_ENDIAN); } if (serial_hds[1]) { - serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16, + serial_mm_init(address_space, 0x80007000, 0, + qdev_get_gpio_in(rc4030, 9), 8000000/16, serial_hds[1], DEVICE_NATIVE_ENDIAN); } /* Parallel port */ if (parallel_hds[0]) - parallel_mm_init(address_space, 0x80008000, 0, rc4030[0], - parallel_hds[0]); + parallel_mm_init(address_space, 0x80008000, 0, + qdev_get_gpio_in(rc4030, 0), parallel_hds[0]); /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 5140882c00..786a8f0638 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -97,7 +97,7 @@ typedef struct { static ISADevice *pit; static struct _loaderparams { - int ram_size; + int ram_size, ram_low_size; const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; @@ -641,8 +641,8 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */ - stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ + stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */ + stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */ /* Load BAR registers as done by YAMON */ stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */ @@ -851,8 +851,10 @@ static int64_t load_kernel (void) } prom_set(prom_buf, prom_index++, "memsize"); - prom_set(prom_buf, prom_index++, "%i", - MIN(loaderparams.ram_size, 256 << 20)); + prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size); + + prom_set(prom_buf, prom_index++, "ememsize"); + prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size); prom_set(prom_buf, prom_index++, "modetty0"); prom_set(prom_buf, prom_index++, "38400n8r"); @@ -1054,7 +1056,8 @@ void mips_malta_init(MachineState *machine) } /* Write a small bootloader to the flash location. */ - loaderparams.ram_size = ram_low_size; + loaderparams.ram_size = ram_size; + loaderparams.ram_low_size = ram_low_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs index 7b91c4e51d..98801739ef 100644 --- a/hw/net/Makefile.objs +++ b/hw/net/Makefile.objs @@ -39,3 +39,4 @@ obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \ common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \ rocker/rocker_desc.o rocker/rocker_world.o \ rocker/rocker_of_dpa.o +obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 7ce13d2b46..cd889bce86 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -17,20 +17,15 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "hw/hw.h" -#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/devices.h" #include "net/net.h" -#include "hw/mips/mips.h" +#include "qemu/timer.h" +#include <zlib.h> //#define DEBUG_SONIC -/* Calculate CRCs properly on Rx packets */ -#define SONIC_CALCULATE_RXCRC - -#if defined(SONIC_CALCULATE_RXCRC) -/* For crc32 */ -#include <zlib.h> -#endif +#define SONIC_PROM_SIZE 0x1000 #ifdef DEBUG_SONIC #define DPRINTF(fmt, ...) \ @@ -145,9 +140,14 @@ do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) #define SONIC_ISR_PINT 0x0800 #define SONIC_ISR_LCD 0x1000 +#define TYPE_DP8393X "dp8393x" +#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X) + typedef struct dp8393xState { + SysBusDevice parent_obj; + /* Hardware */ - int it_shift; + uint8_t it_shift; qemu_irq irq; #ifdef DEBUG_SONIC int irq_level; @@ -156,8 +156,8 @@ typedef struct dp8393xState { int64_t wt_last_update; NICConf conf; NICState *nic; - MemoryRegion *address_space; MemoryRegion mmio; + MemoryRegion prom; /* Registers */ uint8_t cam[16][6]; @@ -168,8 +168,8 @@ typedef struct dp8393xState { int loopback_packet; /* Memory access */ - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); - void* mem_opaque; + void *dma_mr; + AddressSpace as; } dp8393xState; static void dp8393x_update_irq(dp8393xState *s) @@ -190,7 +190,7 @@ static void dp8393x_update_irq(dp8393xState *s) qemu_set_irq(s->irq, level); } -static void do_load_cam(dp8393xState *s) +static void dp8393x_do_load_cam(dp8393xState *s) { uint16_t data[8]; int width, size; @@ -201,9 +201,9 @@ static void do_load_cam(dp8393xState *s) while (s->regs[SONIC_CDC] & 0x1f) { /* Fill current entry */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->cam[index][0] = data[1 * width] & 0xff; s->cam[index][1] = data[1 * width] >> 8; s->cam[index][2] = data[2 * width] & 0xff; @@ -220,9 +220,9 @@ static void do_load_cam(dp8393xState *s) } /* Read CAM enable */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CE] = data[0 * width]; DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); @@ -232,7 +232,7 @@ static void do_load_cam(dp8393xState *s) dp8393x_update_irq(s); } -static void do_read_rra(dp8393xState *s) +static void dp8393x_do_read_rra(dp8393xState *s) { uint16_t data[8]; int width, size; @@ -240,9 +240,9 @@ static void do_read_rra(dp8393xState *s) /* Read memory */ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); /* Update SONIC registers */ s->regs[SONIC_CRBA0] = data[0 * width]; @@ -272,7 +272,7 @@ static void do_read_rra(dp8393xState *s) s->regs[SONIC_CR] &= ~SONIC_CR_RRRA; } -static void do_software_reset(dp8393xState *s) +static void dp8393x_do_software_reset(dp8393xState *s) { timer_del(s->watchdog); @@ -280,7 +280,7 @@ static void do_software_reset(dp8393xState *s) s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS; } -static void set_next_tick(dp8393xState *s) +static void dp8393x_set_next_tick(dp8393xState *s) { uint32_t ticks; int64_t delay; @@ -296,7 +296,7 @@ static void set_next_tick(dp8393xState *s) timer_mod(s->watchdog, s->wt_last_update + delay); } -static void update_wt_regs(dp8393xState *s) +static void dp8393x_update_wt_regs(dp8393xState *s) { int64_t elapsed; uint32_t val; @@ -311,33 +311,33 @@ static void update_wt_regs(dp8393xState *s) val -= elapsed / 5000000; s->regs[SONIC_WT1] = (val >> 16) & 0xffff; s->regs[SONIC_WT0] = (val >> 0) & 0xffff; - set_next_tick(s); + dp8393x_set_next_tick(s); } -static void do_start_timer(dp8393xState *s) +static void dp8393x_do_start_timer(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_STP; - set_next_tick(s); + dp8393x_set_next_tick(s); } -static void do_stop_timer(dp8393xState *s) +static void dp8393x_do_stop_timer(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_ST; - update_wt_regs(s); + dp8393x_update_wt_regs(s); } -static void do_receiver_enable(dp8393xState *s) +static void dp8393x_do_receiver_enable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS; } -static void do_receiver_disable(dp8393xState *s) +static void dp8393x_do_receiver_disable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXEN; } -static void do_transmit_packets(dp8393xState *s) +static void dp8393x_do_transmit_packets(dp8393xState *s) { NetClientState *nc = qemu_get_queue(s->nic); uint16_t data[12]; @@ -353,9 +353,9 @@ static void do_transmit_packets(dp8393xState *s) (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]); size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); tx_len = 0; /* Update registers */ @@ -379,18 +379,18 @@ static void do_transmit_packets(dp8393xState *s) if (tx_len + len > sizeof(s->tx_buffer)) { len = sizeof(s->tx_buffer) - tx_len; } - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0], - &s->tx_buffer[tx_len], len, 0); + MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0); tx_len += len; i++; if (i != s->regs[SONIC_TFC]) { /* Read next fragment details */ size = sizeof(uint16_t) * 3 * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_TSA0] = data[0 * width]; s->regs[SONIC_TSA1] = data[1 * width]; s->regs[SONIC_TFS] = data[2 * width]; @@ -422,16 +422,16 @@ static void do_transmit_packets(dp8393xState *s) /* Write status */ data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA], - (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { /* Read footer of packet */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; if (data[0 * width] & 0x1) { /* EOL detected */ @@ -446,12 +446,12 @@ static void do_transmit_packets(dp8393xState *s) dp8393x_update_irq(s); } -static void do_halt_transmission(dp8393xState *s) +static void dp8393x_do_halt_transmission(dp8393xState *s) { /* Nothing to do */ } -static void do_command(dp8393xState *s, uint16_t command) +static void dp8393x_do_command(dp8393xState *s, uint16_t command) { if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) { s->regs[SONIC_CR] &= ~SONIC_CR_RST; @@ -461,34 +461,36 @@ static void do_command(dp8393xState *s, uint16_t command) s->regs[SONIC_CR] |= (command & SONIC_CR_MASK); if (command & SONIC_CR_HTX) - do_halt_transmission(s); + dp8393x_do_halt_transmission(s); if (command & SONIC_CR_TXP) - do_transmit_packets(s); + dp8393x_do_transmit_packets(s); if (command & SONIC_CR_RXDIS) - do_receiver_disable(s); + dp8393x_do_receiver_disable(s); if (command & SONIC_CR_RXEN) - do_receiver_enable(s); + dp8393x_do_receiver_enable(s); if (command & SONIC_CR_STP) - do_stop_timer(s); + dp8393x_do_stop_timer(s); if (command & SONIC_CR_ST) - do_start_timer(s); + dp8393x_do_start_timer(s); if (command & SONIC_CR_RST) - do_software_reset(s); + dp8393x_do_software_reset(s); if (command & SONIC_CR_RRRA) - do_read_rra(s); + dp8393x_do_read_rra(s); if (command & SONIC_CR_LCAM) - do_load_cam(s); + dp8393x_do_load_cam(s); } -static uint16_t read_register(dp8393xState *s, int reg) +static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size) { + dp8393xState *s = opaque; + int reg = addr >> s->it_shift; uint16_t val = 0; switch (reg) { /* Update data before reading it */ case SONIC_WT0: case SONIC_WT1: - update_wt_regs(s); + dp8393x_update_wt_regs(s); val = s->regs[reg]; break; /* Accept read to some registers only when in reset mode */ @@ -510,14 +512,18 @@ static uint16_t read_register(dp8393xState *s, int reg) return val; } -static void write_register(dp8393xState *s, int reg, uint16_t val) +static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]); + dp8393xState *s = opaque; + int reg = addr >> s->it_shift; + + DPRINTF("write 0x%04x to reg %s\n", (uint16_t)data, reg_names[reg]); switch (reg) { /* Command register */ case SONIC_CR: - do_command(s, val); + dp8393x_do_command(s, data); break; /* Prevent write to read-only registers */ case SONIC_CAP2: @@ -530,37 +536,37 @@ static void write_register(dp8393xState *s, int reg, uint16_t val) /* Accept write to some registers only when in reset mode */ case SONIC_DCR: if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xbfff; + s->regs[reg] = data & 0xbfff; } else { DPRINTF("writing to DCR invalid\n"); } break; case SONIC_DCR2: if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xf017; + s->regs[reg] = data & 0xf017; } else { DPRINTF("writing to DCR2 invalid\n"); } break; /* 12 lower bytes are Read Only */ case SONIC_TCR: - s->regs[reg] = val & 0xf000; + s->regs[reg] = data & 0xf000; break; /* 9 lower bytes are Read Only */ case SONIC_RCR: - s->regs[reg] = val & 0xffe0; + s->regs[reg] = data & 0xffe0; break; /* Ignore most significant bit */ case SONIC_IMR: - s->regs[reg] = val & 0x7fff; + s->regs[reg] = data & 0x7fff; dp8393x_update_irq(s); break; /* Clear bits by writing 1 to them */ case SONIC_ISR: - val &= s->regs[reg]; - s->regs[reg] &= ~val; - if (val & SONIC_ISR_RBE) { - do_read_rra(s); + data &= s->regs[reg]; + s->regs[reg] &= ~data; + if (data & SONIC_ISR_RBE) { + dp8393x_do_read_rra(s); } dp8393x_update_irq(s); break; @@ -569,24 +575,32 @@ static void write_register(dp8393xState *s, int reg, uint16_t val) case SONIC_REA: case SONIC_RRP: case SONIC_RWP: - s->regs[reg] = val & 0xfffe; + s->regs[reg] = data & 0xfffe; break; /* Invert written value for some registers */ case SONIC_CRCT: case SONIC_FAET: case SONIC_MPT: - s->regs[reg] = val ^ 0xffff; + s->regs[reg] = data ^ 0xffff; break; /* All other registers have no special contrainst */ default: - s->regs[reg] = val; + s->regs[reg] = data; } if (reg == SONIC_WT0 || reg == SONIC_WT1) { - set_next_tick(s); + dp8393x_set_next_tick(s); } } +static const MemoryRegionOps dp8393x_ops = { + .read = dp8393x_read, + .write = dp8393x_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + static void dp8393x_watchdog(void *opaque) { dp8393xState *s = opaque; @@ -597,84 +611,14 @@ static void dp8393x_watchdog(void *opaque) s->regs[SONIC_WT1] = 0xffff; s->regs[SONIC_WT0] = 0xffff; - set_next_tick(s); + dp8393x_set_next_tick(s); /* Signal underflow */ s->regs[SONIC_ISR] |= SONIC_ISR_TC; dp8393x_update_irq(s); } -static uint32_t dp8393x_readw(void *opaque, hwaddr addr) -{ - dp8393xState *s = opaque; - int reg; - - if ((addr & ((1 << s->it_shift) - 1)) != 0) { - return 0; - } - - reg = addr >> s->it_shift; - return read_register(s, reg); -} - -static uint32_t dp8393x_readb(void *opaque, hwaddr addr) -{ - uint16_t v = dp8393x_readw(opaque, addr & ~0x1); - return (v >> (8 * (addr & 0x1))) & 0xff; -} - -static uint32_t dp8393x_readl(void *opaque, hwaddr addr) -{ - uint32_t v; - v = dp8393x_readw(opaque, addr); - v |= dp8393x_readw(opaque, addr + 2) << 16; - return v; -} - -static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val) -{ - dp8393xState *s = opaque; - int reg; - - if ((addr & ((1 << s->it_shift) - 1)) != 0) { - return; - } - - reg = addr >> s->it_shift; - - write_register(s, reg, (uint16_t)val); -} - -static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xff00); - break; - case 1: - val = (val << 8) | (old_val & 0x00ff); - break; - } - dp8393x_writew(opaque, addr & ~0x1, val); -} - -static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val) -{ - dp8393x_writew(opaque, addr, val & 0xffff); - dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff); -} - -static const MemoryRegionOps dp8393x_ops = { - .old_mmio = { - .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, }, - .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int nic_can_receive(NetClientState *nc) +static int dp8393x_can_receive(NetClientState *nc) { dp8393xState *s = qemu_get_nic_opaque(nc); @@ -685,7 +629,8 @@ static int nic_can_receive(NetClientState *nc) return 1; } -static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) +static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf, + int size) { static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int i; @@ -723,7 +668,8 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) +static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, + size_t size) { dp8393xState *s = qemu_get_nic_opaque(nc); uint16_t data[10]; @@ -737,7 +683,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER | SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC); - packet_type = receive_filter(s, buf, size); + packet_type = dp8393x_receive_filter(s, buf, size); if (packet_type < 0) { DPRINTF("packet not for netcard\n"); return -1; @@ -750,7 +696,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) /* Are we still in resource exhaustion? */ size = sizeof(uint16_t) * 1 * width; address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width; - s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0); + address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)data, size, 0); if (data[0 * width] & 0x1) { /* Still EOL ; stop reception */ return -1; @@ -764,18 +711,16 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0]; /* Calculate the ethernet checksum */ -#ifdef SONIC_CALCULATE_RXCRC checksum = cpu_to_le32(crc32(0, buf, rx_len)); -#else - checksum = 0; -#endif /* Put packet into RBA */ DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]); address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]; - s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1); + address_space_rw(&s->as, address, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1); address += rx_len; - s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1); + address_space_rw(&s->as, address, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1); rx_len += 4; s->regs[SONIC_CRBA1] = address >> 16; s->regs[SONIC_CRBA0] = address & 0xffff; @@ -803,29 +748,30 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ size = sizeof(uint16_t) * 5 * width; - s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1); + address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); /* Move to next descriptor */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_LLFA] = data[0 * width]; if (s->regs[SONIC_LLFA] & 0x1) { /* EOL detected */ s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { data[0 * width] = 0; /* in_use */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width, - (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) { /* Read next RRA */ - do_read_rra(s); + dp8393x_do_read_rra(s); } } @@ -835,11 +781,12 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) return size; } -static void nic_reset(void *opaque) +static void dp8393x_reset(DeviceState *dev) { - dp8393xState *s = opaque; + dp8393xState *s = DP8393X(dev); timer_del(s->watchdog); + memset(s->regs, 0, sizeof(s->regs)); s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS; s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT); @@ -862,39 +809,91 @@ static void nic_reset(void *opaque) static NetClientInfo net_dp83932_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = nic_can_receive, - .receive = nic_receive, + .can_receive = dp8393x_can_receive, + .receive = dp8393x_receive, }; -void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, - MemoryRegion *address_space, - qemu_irq irq, void* mem_opaque, - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)) +static void dp8393x_instance_init(Object *obj) { - dp8393xState *s; + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + dp8393xState *s = DP8393X(obj); + + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_mmio(sbd, &s->prom); + sysbus_init_irq(sbd, &s->irq); +} - qemu_check_nic_model(nd, "dp83932"); +static void dp8393x_realize(DeviceState *dev, Error **errp) +{ + dp8393xState *s = DP8393X(dev); + int i, checksum; + uint8_t *prom; - s = g_malloc0(sizeof(dp8393xState)); + address_space_init(&s->as, s->dma_mr, "dp8393x"); + memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s, + "dp8393x-regs", 0x40 << s->it_shift); + + s->nic = qemu_new_nic(&net_dp83932_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); - s->address_space = address_space; - s->mem_opaque = mem_opaque; - s->memory_rw = memory_rw; - s->it_shift = it_shift; - s->irq = irq; s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->conf.macaddr = nd->macaddr; - s->conf.peers.ncs[0] = nd->netdev; + memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL, + "dp8393x-prom", SONIC_PROM_SIZE, NULL); + prom = memory_region_get_ram_ptr(&s->prom); + checksum = 0; + for (i = 0; i < 6; i++) { + prom[i] = s->conf.macaddr.a[i]; + checksum += prom[i]; + if (checksum > 0xff) { + checksum = (checksum + 1) & 0xff; + } + } + prom[7] = 0xff - checksum; +} - s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); +static const VMStateDescription vmstate_dp8393x = { + .name = "dp8393x", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField []) { + VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6), + VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40), + VMSTATE_END_OF_LIST() + } +}; - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - qemu_register_reset(nic_reset, s); - nic_reset(s); +static Property dp8393x_properties[] = { + DEFINE_NIC_PROPERTIES(dp8393xState, conf), + DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr), + DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void dp8393x_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); - memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s, - "dp8393x", 0x40 << it_shift); - memory_region_add_subregion(address_space, base, &s->mmio); + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->realize = dp8393x_realize; + dc->reset = dp8393x_reset; + dc->vmsd = &vmstate_dp8393x; + dc->props = dp8393x_properties; } + +static const TypeInfo dp8393x_info = { + .name = TYPE_DP8393X, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(dp8393xState), + .instance_init = dp8393x_instance_init, + .class_init = dp8393x_class_init, +}; + +static void dp8393x_register_types(void) +{ + type_register_static(&dp8393x_info); +} + +type_init(dp8393x_register_types) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 091d61acc3..bab8e2abfb 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1370,6 +1370,7 @@ static const VMStateDescription vmstate_e1000_mit_state = { .name = "e1000/mit_state", .version_id = 1, .minimum_version_id = 1, + .needed = e1000_mit_state_needed, .fields = (VMStateField[]) { VMSTATE_UINT32(mac_reg[RDTR], E1000State), VMSTATE_UINT32(mac_reg[RADV], E1000State), @@ -1457,13 +1458,9 @@ static const VMStateDescription vmstate_e1000 = { VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_e1000_mit_state, - .needed = e1000_mit_state_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_e1000_mit_state, + NULL } }; diff --git a/hw/net/rocker/qmp-norocker.c b/hw/net/rocker/qmp-norocker.c new file mode 100644 index 0000000000..f253747361 --- /dev/null +++ b/hw/net/rocker/qmp-norocker.c @@ -0,0 +1,50 @@ +/* + * QMP Target options - Commands handled based on a target config + * versus a host config + * + * Copyright (c) 2015 David Ahern <dsahern@gmail.com> + * + * 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-common.h" +#include "qmp-commands.h" +#include "qapi/qmp/qerror.h" + +RockerSwitch *qmp_query_rocker(const char *name, Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; + +RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; + +RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, + bool has_tbl_id, + uint32_t tbl_id, + Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; + +RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, + bool has_type, + uint8_t type, + Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 55b6c46157..4d25842509 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -94,6 +94,51 @@ World *rocker_get_world(Rocker *r, enum rocker_world_type type) return NULL; } +RockerSwitch *qmp_query_rocker(const char *name, Error **errp) +{ + RockerSwitch *rocker = g_malloc0(sizeof(*rocker)); + Rocker *r; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + rocker->name = g_strdup(r->name); + rocker->id = r->switch_id; + rocker->ports = r->fp_ports; + + return rocker; +} + +RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) +{ + RockerPortList *list = NULL; + Rocker *r; + int i; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + for (i = r->fp_ports - 1; i >= 0; i--) { + RockerPortList *info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + struct fp_port *port = r->fp_port[i]; + + fp_port_get_info(port, info); + info->next = list; + list = info; + } + + return list; +} + uint32_t rocker_fp_ports(Rocker *r) { return r->fp_ports; @@ -238,6 +283,7 @@ static int cmd_get_port_settings(Rocker *r, uint8_t duplex; uint8_t autoneg; uint8_t learning; + char *phys_name; MACAddr macaddr; enum rocker_world_type mode; size_t tlv_size; @@ -265,6 +311,7 @@ static int cmd_get_port_settings(Rocker *r, fp_port_get_macaddr(fp_port, &macaddr); mode = world_type(fp_port_get_world(fp_port)); learning = fp_port_get_learning(fp_port); + phys_name = fp_port_get_name(fp_port); tlv_size = rocker_tlv_total_size(0) + /* nest */ rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ @@ -273,7 +320,8 @@ static int cmd_get_port_settings(Rocker *r, rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */ rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */ rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */ - rocker_tlv_total_size(sizeof(uint8_t)); /* learning */ + rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */ + rocker_tlv_total_size(strlen(phys_name)); if (tlv_size > desc_buf_size(info)) { return -ROCKER_EMSGSIZE; @@ -290,6 +338,8 @@ static int cmd_get_port_settings(Rocker *r, rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode); rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, learning); + rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, + strlen(phys_name), phys_name); rocker_tlv_nest_end(buf, &pos, nest); return desc_set_buf(info, tlv_size); @@ -1277,6 +1327,22 @@ static int pci_rocker_init(PCIDevice *dev) goto err_duplicate; } + /* Rocker name is passed in port name requests to OS with the intention + * that the name is used in interface names. Limit the length of the + * rocker name to avoid naming problems in the OS. Also, adding the + * port number as p# and unganged breakout b#, where # is at most 2 + * digits, so leave room for it too (-1 for string terminator, -3 for + * p# and -3 for b#) + */ +#define ROCKER_IFNAMSIZ 16 +#define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3) + if (strlen(r->name) > MAX_ROCKER_NAME_LEN) { + fprintf(stderr, + "rocker: name too long; please shorten to at most %d chars\n", + MAX_ROCKER_NAME_LEN); + return -EINVAL; + } + if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) { memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt)); r->fp_start_macaddr.a[4] += (sw_index++); diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c index 2f1e3b348a..d8d934c396 100644 --- a/hw/net/rocker/rocker_fp.c +++ b/hw/net/rocker/rocker_fp.c @@ -41,11 +41,26 @@ struct fp_port { NICConf conf; }; +char *fp_port_get_name(FpPort *port) +{ + return port->name; +} + bool fp_port_get_link_up(FpPort *port) { return !qemu_get_queue(port->nic)->link_down; } +void fp_port_get_info(FpPort *port, RockerPortList *info) +{ + info->value->name = g_strdup(port->name); + info->value->enabled = port->enabled; + info->value->link_up = fp_port_get_link_up(port); + info->value->speed = port->speed; + info->value->duplex = port->duplex; + info->value->autoneg = port->autoneg; +} + void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr) { memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a)); @@ -173,8 +188,19 @@ bool fp_port_enabled(FpPort *port) return port->enabled; } +static void fp_port_set_link(FpPort *port, bool up) +{ + NetClientState *nc = qemu_get_queue(port->nic); + + if (up == nc->link_down) { + nc->link_down = !up; + nc->info->link_status_changed(nc); + } +} + void fp_port_enable(FpPort *port) { + fp_port_set_link(port, true); port->enabled = true; DPRINTF("port %d enabled\n", port->index); } @@ -182,6 +208,7 @@ void fp_port_enable(FpPort *port) void fp_port_disable(FpPort *port) { port->enabled = false; + fp_port_set_link(port, false); DPRINTF("port %d disabled\n", port->index); } @@ -201,7 +228,7 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name, /* front-panel switch port names are 1-based */ - port->name = g_strdup_printf("%s.%d", sw_name, port->pport); + port->name = g_strdup_printf("%sp%d", sw_name, port->pport); memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a)); port->conf.macaddr.a[5] += index; diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h index a5f28f120d..ab80fd833c 100644 --- a/hw/net/rocker/rocker_fp.h +++ b/hw/net/rocker/rocker_fp.h @@ -26,7 +26,9 @@ typedef struct fp_port FpPort; int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt); +char *fp_port_get_name(FpPort *port); bool fp_port_get_link_up(FpPort *port); +void fp_port_get_info(FpPort *port, RockerPortList *info); void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr); void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr); uint8_t fp_port_get_learning(FpPort *port); diff --git a/hw/net/rocker/rocker_hw.h b/hw/net/rocker/rocker_hw.h index c9c85a75bd..fe639badd4 100644 --- a/hw/net/rocker/rocker_hw.h +++ b/hw/net/rocker/rocker_hw.h @@ -179,6 +179,7 @@ enum { ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */ ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */ ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */ + ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */ __ROCKER_TLV_CMD_PORT_SETTINGS_MAX, ROCKER_TLV_CMD_PORT_SETTINGS_MAX = __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 1bcb7af5ef..b25a17d6d7 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -2302,6 +2302,318 @@ static void of_dpa_uninit(World *world) g_hash_table_destroy(of_dpa->flow_tbl); } +struct of_dpa_flow_fill_context { + RockerOfDpaFlowList *list; + uint32_t tbl_id; +}; + +static void of_dpa_flow_fill(void *cookie, void *value, void *user_data) +{ + struct of_dpa_flow *flow = value; + struct of_dpa_flow_key *key = &flow->key; + struct of_dpa_flow_key *mask = &flow->mask; + struct of_dpa_flow_fill_context *flow_context = user_data; + RockerOfDpaFlowList *new; + RockerOfDpaFlow *nflow; + RockerOfDpaFlowKey *nkey; + RockerOfDpaFlowMask *nmask; + RockerOfDpaFlowAction *naction; + + if (flow_context->tbl_id != -1 && + flow_context->tbl_id != key->tbl_id) { + return; + } + + new = g_malloc0(sizeof(*new)); + nflow = new->value = g_malloc0(sizeof(*nflow)); + nkey = nflow->key = g_malloc0(sizeof(*nkey)); + nmask = nflow->mask = g_malloc0(sizeof(*nmask)); + naction = nflow->action = g_malloc0(sizeof(*naction)); + + nflow->cookie = flow->cookie; + nflow->hits = flow->stats.hits; + nkey->priority = flow->priority; + nkey->tbl_id = key->tbl_id; + + if (key->in_pport || mask->in_pport) { + nkey->has_in_pport = true; + nkey->in_pport = key->in_pport; + } + + if (nkey->has_in_pport && mask->in_pport != 0xffffffff) { + nmask->has_in_pport = true; + nmask->in_pport = mask->in_pport; + } + + if (key->eth.vlan_id || mask->eth.vlan_id) { + nkey->has_vlan_id = true; + nkey->vlan_id = ntohs(key->eth.vlan_id); + } + + if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) { + nmask->has_vlan_id = true; + nmask->vlan_id = ntohs(mask->eth.vlan_id); + } + + if (key->tunnel_id || mask->tunnel_id) { + nkey->has_tunnel_id = true; + nkey->tunnel_id = key->tunnel_id; + } + + if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) { + nmask->has_tunnel_id = true; + nmask->tunnel_id = mask->tunnel_id; + } + + if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) || + memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) { + nkey->has_eth_src = true; + nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a); + } + + if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { + nmask->has_eth_src = true; + nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a); + } + + if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) || + memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) { + nkey->has_eth_dst = true; + nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a); + } + + if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { + nmask->has_eth_dst = true; + nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a); + } + + if (key->eth.type) { + + nkey->has_eth_type = true; + nkey->eth_type = ntohs(key->eth.type); + + switch (ntohs(key->eth.type)) { + case 0x0800: + case 0x86dd: + if (key->ip.proto || mask->ip.proto) { + nkey->has_ip_proto = true; + nkey->ip_proto = key->ip.proto; + } + if (nkey->has_ip_proto && mask->ip.proto != 0xff) { + nmask->has_ip_proto = true; + nmask->ip_proto = mask->ip.proto; + } + if (key->ip.tos || mask->ip.tos) { + nkey->has_ip_tos = true; + nkey->ip_tos = key->ip.tos; + } + if (nkey->has_ip_tos && mask->ip.tos != 0xff) { + nmask->has_ip_tos = true; + nmask->ip_tos = mask->ip.tos; + } + break; + } + + switch (ntohs(key->eth.type)) { + case 0x0800: + if (key->ipv4.addr.dst || mask->ipv4.addr.dst) { + char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst); + int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst); + nkey->has_ip_dst = true; + nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len); + } + break; + } + } + + if (flow->action.goto_tbl) { + naction->has_goto_tbl = true; + naction->goto_tbl = flow->action.goto_tbl; + } + + if (flow->action.write.group_id) { + naction->has_group_id = true; + naction->group_id = flow->action.write.group_id; + } + + if (flow->action.apply.new_vlan_id) { + naction->has_new_vlan_id = true; + naction->new_vlan_id = flow->action.apply.new_vlan_id; + } + + new->next = flow_context->list; + flow_context->list = new; +} + +RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, + bool has_tbl_id, + uint32_t tbl_id, + Error **errp) +{ + struct rocker *r; + struct world *w; + struct of_dpa *of_dpa; + struct of_dpa_flow_fill_context fill_context = { + .list = NULL, + .tbl_id = tbl_id, + }; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); + if (!w) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s doesn't have OF-DPA world", name); + return NULL; + } + + of_dpa = world_private(w); + + g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context); + + return fill_context.list; +} + +struct of_dpa_group_fill_context { + RockerOfDpaGroupList *list; + uint8_t type; +}; + +static void of_dpa_group_fill(void *key, void *value, void *user_data) +{ + struct of_dpa_group *group = value; + struct of_dpa_group_fill_context *flow_context = user_data; + RockerOfDpaGroupList *new; + RockerOfDpaGroup *ngroup; + struct uint32List *id; + int i; + + if (flow_context->type != 9 && + flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) { + return; + } + + new = g_malloc0(sizeof(*new)); + ngroup = new->value = g_malloc0(sizeof(*ngroup)); + + ngroup->id = group->id; + + ngroup->type = ROCKER_GROUP_TYPE_GET(group->id); + + switch (ngroup->type) { + case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: + ngroup->has_vlan_id = true; + ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); + ngroup->has_pport = true; + ngroup->pport = ROCKER_GROUP_PORT_GET(group->id); + ngroup->has_out_pport = true; + ngroup->out_pport = group->l2_interface.out_pport; + ngroup->has_pop_vlan = true; + ngroup->pop_vlan = group->l2_interface.pop_vlan; + break; + case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: + ngroup->has_index = true; + ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); + ngroup->has_group_id = true; + ngroup->group_id = group->l2_rewrite.group_id; + if (group->l2_rewrite.vlan_id) { + ngroup->has_set_vlan_id = true; + ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id); + } + break; + if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_src = true; + ngroup->set_eth_src = + qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a); + } + if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_dst = true; + ngroup->set_eth_dst = + qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a); + } + case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: + case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: + ngroup->has_vlan_id = true; + ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); + ngroup->has_index = true; + ngroup->index = ROCKER_GROUP_INDEX_GET(group->id); + for (i = 0; i < group->l2_flood.group_count; i++) { + ngroup->has_group_ids = true; + id = g_malloc0(sizeof(*id)); + id->value = group->l2_flood.group_ids[i]; + id->next = ngroup->group_ids; + ngroup->group_ids = id; + } + break; + case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST: + ngroup->has_index = true; + ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); + ngroup->has_group_id = true; + ngroup->group_id = group->l3_unicast.group_id; + if (group->l3_unicast.vlan_id) { + ngroup->has_set_vlan_id = true; + ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id); + } + if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_src = true; + ngroup->set_eth_src = + qemu_mac_strdup_printf(group->l3_unicast.src_mac.a); + } + if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_dst = true; + ngroup->set_eth_dst = + qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a); + } + if (group->l3_unicast.ttl_check) { + ngroup->has_ttl_check = true; + ngroup->ttl_check = group->l3_unicast.ttl_check; + } + break; + } + + new->next = flow_context->list; + flow_context->list = new; +} + +RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, + bool has_type, + uint8_t type, + Error **errp) +{ + struct rocker *r; + struct world *w; + struct of_dpa *of_dpa; + struct of_dpa_group_fill_context fill_context = { + .list = NULL, + .type = type, + }; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); + if (!w) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s doesn't have OF-DPA world", name); + return NULL; + } + + of_dpa = world_private(w); + + g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context); + + return fill_context.list; +} + static WorldOps of_dpa_ops = { .init = of_dpa_init, .uninit = of_dpa_uninit, diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index f868108dfe..e0db4727ae 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3240,6 +3240,7 @@ static const VMStateDescription vmstate_rtl8139_hotplug_ready ={ .name = "rtl8139/hotplug_ready", .version_id = 1, .minimum_version_id = 1, + .needed = rtl8139_hotplug_ready_needed, .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() } @@ -3335,13 +3336,9 @@ static const VMStateDescription vmstate_rtl8139 = { VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_rtl8139_hotplug_ready, - .needed = rtl8139_hotplug_ready_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_rtl8139_hotplug_ready, + NULL } }; diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index dfb328debd..8bcdf3ed77 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2226,6 +2226,7 @@ static const VMStateDescription vmxstate_vmxnet3_mcast_list = { .version_id = 1, .minimum_version_id = 1, .pre_load = vmxnet3_mcast_list_pre_load, + .needed = vmxnet3_mc_list_needed, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, 0, mcast_list_buff_size), @@ -2470,14 +2471,9 @@ static const VMStateDescription vmstate_vmxnet3 = { VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmxstate_vmxnet3_mcast_list, - .needed = vmxnet3_mc_list_needed - }, - { - /* empty element. */ - } + .subsections = (const VMStateDescription*[]) { + &vmxstate_vmxnet3_mcast_list, + NULL } }; diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index f1712b86fe..ed2424c4cd 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -582,6 +582,7 @@ static const VMStateDescription vmstate_piix3_rcr = { .name = "PIIX3/rcr", .version_id = 1, .minimum_version_id = 1, + .needed = piix3_rcr_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(rcr, PIIX3State), VMSTATE_END_OF_LIST() @@ -600,12 +601,9 @@ static const VMStateDescription vmstate_piix3 = { PIIX_NUM_PIRQS, 3), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_piix3_rcr, - .needed = piix3_rcr_needed, - }, - { 0 } + .subsections = (const VMStateDescription*[]) { + &vmstate_piix3_rcr, + NULL } }; diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index bd2c0e4caa..f50b2f08af 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1968,6 +1968,7 @@ static const VMStateDescription vmstate_scsi_sense_state = { .name = "SCSIDevice/sense", .version_id = 1, .minimum_version_id = 1, + .needed = scsi_sense_state_needed, .fields = (VMStateField[]) { VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE_OLD, @@ -1998,13 +1999,9 @@ const VMStateDescription vmstate_scsi_device = { }, VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_scsi_sense_state, - .needed = scsi_sense_state_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_scsi_sense_state, + NULL } }; diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index ac3ab39bea..d1fe6d58e8 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -48,7 +48,6 @@ struct PXA2xxMMCIState { int resp_len; int cmdreq; - int ac_width; }; #define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ @@ -215,7 +214,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) pxa2xx_mmci_fifo_update(s); } -static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) +static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; uint32_t ret; @@ -257,8 +256,8 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) return 0; case MMC_RXFIFO: ret = 0; - while (s->ac_width -- && s->rx_len) { - ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3); + while (size-- && s->rx_len) { + ret |= s->rx_fifo[s->rx_start++] << (size << 3); s->rx_start &= 0x1f; s->rx_len --; } @@ -277,7 +276,7 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) } static void pxa2xx_mmci_write(void *opaque, - hwaddr offset, uint32_t value) + hwaddr offset, uint64_t value, unsigned size) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; @@ -370,9 +369,9 @@ static void pxa2xx_mmci_write(void *opaque, break; case MMC_TXFIFO: - while (s->ac_width -- && s->tx_len < 0x20) + while (size-- && s->tx_len < 0x20) s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] = - (value >> (s->ac_width << 3)) & 0xff; + (value >> (size << 3)) & 0xff; s->intreq &= ~INT_TXFIFO_REQ; pxa2xx_mmci_fifo_update(s); break; @@ -386,60 +385,9 @@ static void pxa2xx_mmci_write(void *opaque, } } -static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 1; - return pxa2xx_mmci_read(opaque, offset); -} - -static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 2; - return pxa2xx_mmci_read(opaque, offset); -} - -static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 4; - return pxa2xx_mmci_read(opaque, offset); -} - -static void pxa2xx_mmci_writeb(void *opaque, - hwaddr offset, uint32_t value) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 1; - pxa2xx_mmci_write(opaque, offset, value); -} - -static void pxa2xx_mmci_writeh(void *opaque, - hwaddr offset, uint32_t value) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 2; - pxa2xx_mmci_write(opaque, offset, value); -} - -static void pxa2xx_mmci_writew(void *opaque, - hwaddr offset, uint32_t value) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 4; - pxa2xx_mmci_write(opaque, offset, value); -} - static const MemoryRegionOps pxa2xx_mmci_ops = { - .old_mmio = { - .read = { pxa2xx_mmci_readb, - pxa2xx_mmci_readh, - pxa2xx_mmci_readw, }, - .write = { pxa2xx_mmci_writeb, - pxa2xx_mmci_writeh, - pxa2xx_mmci_writew, }, - }, + .read = pxa2xx_mmci_read, + .write = pxa2xx_mmci_write, .endianness = DEVICE_NATIVE_ENDIAN, }; diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index 4221060308..5e22ed79b2 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -127,7 +127,7 @@ static void r2d_fpga_irq_set(void *opaque, int n, int level) update_irl(fpga); } -static uint32_t r2d_fpga_read(void *opaque, hwaddr addr) +static uint64_t r2d_fpga_read(void *opaque, hwaddr addr, unsigned int size) { r2d_fpga_t *s = opaque; @@ -146,7 +146,7 @@ static uint32_t r2d_fpga_read(void *opaque, hwaddr addr) } static void -r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value) +r2d_fpga_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { r2d_fpga_t *s = opaque; @@ -170,10 +170,10 @@ r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value) } static const MemoryRegionOps r2d_fpga_ops = { - .old_mmio = { - .read = { r2d_fpga_read, r2d_fpga_read, NULL, }, - .write = { r2d_fpga_write, r2d_fpga_write, NULL, }, - }, + .read = r2d_fpga_read, + .write = r2d_fpga_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, .endianness = DEVICE_NATIVE_ENDIAN, }; diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index b6b8a2063d..b50071ef93 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -283,6 +283,7 @@ static const VMStateDescription vmstate_hpet_rtc_irq_level = { .name = "hpet/rtc_irq_level", .version_id = 1, .minimum_version_id = 1, + .needed = hpet_rtc_irq_level_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(rtc_irq_level, HPETState), VMSTATE_END_OF_LIST() @@ -322,13 +323,9 @@ static const VMStateDescription vmstate_hpet = { vmstate_hpet_timer, HPETTimer), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_hpet_rtc_irq_level, - .needed = hpet_rtc_irq_level_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_hpet_rtc_irq_level, + NULL } }; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index f2b77fa118..32048258c9 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -733,22 +733,23 @@ static int rtc_post_load(void *opaque, int version_id) return 0; } +static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) +{ + RTCState *s = (RTCState *)opaque; + return s->irq_reinject_on_ack_count != 0; +} + static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = { .name = "mc146818rtc/irq_reinject_on_ack_count", .version_id = 1, .minimum_version_id = 1, + .needed = rtc_irq_reinject_on_ack_count_needed, .fields = (VMStateField[]) { VMSTATE_UINT16(irq_reinject_on_ack_count, RTCState), VMSTATE_END_OF_LIST() } }; -static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) -{ - RTCState *s = (RTCState *)opaque; - return s->irq_reinject_on_ack_count != 0; -} - static const VMStateDescription vmstate_rtc = { .name = "mc146818rtc", .version_id = 3, @@ -770,13 +771,9 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_UINT64_V(next_alarm_time, RTCState, 3), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_rtc_irq_reinject_on_ack_count, - .needed = rtc_irq_reinject_on_ack_count_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_rtc_irq_reinject_on_ack_count, + NULL } }; diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 1a22c9c0cb..7d65818064 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -2034,6 +2034,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = { .version_id = 1, .minimum_version_id = 1, .pre_load = ohci_eof_timer_pre_load, + .needed = ohci_eof_timer_needed, .fields = (VMStateField[]) { VMSTATE_TIMER_PTR(eof_timer, OHCIState), VMSTATE_END_OF_LIST() @@ -2081,13 +2082,9 @@ static const VMStateDescription vmstate_ohci_state = { VMSTATE_BOOL(async_complete, OHCIState), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_ohci_eof_timer, - .needed = ohci_eof_timer_needed, - } , { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_ohci_eof_timer, + NULL } }; diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 242a654583..6b4218c037 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2257,40 +2257,42 @@ static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { /* For endp_data migration */ +static bool usbredir_bulk_receiving_needed(void *priv) +{ + struct endp_data *endp = priv; + + return endp->bulk_receiving_started; +} + static const VMStateDescription usbredir_bulk_receiving_vmstate = { .name = "usb-redir-ep/bulk-receiving", .version_id = 1, .minimum_version_id = 1, + .needed = usbredir_bulk_receiving_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(bulk_receiving_started, struct endp_data), VMSTATE_END_OF_LIST() } }; -static bool usbredir_bulk_receiving_needed(void *priv) +static bool usbredir_stream_needed(void *priv) { struct endp_data *endp = priv; - return endp->bulk_receiving_started; + return endp->max_streams; } static const VMStateDescription usbredir_stream_vmstate = { .name = "usb-redir-ep/stream-state", .version_id = 1, .minimum_version_id = 1, + .needed = usbredir_stream_needed, .fields = (VMStateField[]) { VMSTATE_UINT32(max_streams, struct endp_data), VMSTATE_END_OF_LIST() } }; -static bool usbredir_stream_needed(void *priv) -{ - struct endp_data *endp = priv; - - return endp->max_streams; -} - static const VMStateDescription usbredir_ep_vmstate = { .name = "usb-redir-ep", .version_id = 1, @@ -2318,16 +2320,10 @@ static const VMStateDescription usbredir_ep_vmstate = { VMSTATE_INT32(bufpq_target_size, struct endp_data), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &usbredir_bulk_receiving_vmstate, - .needed = usbredir_bulk_receiving_needed, - }, { - .vmsd = &usbredir_stream_vmstate, - .needed = usbredir_stream_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &usbredir_bulk_receiving_vmstate, + &usbredir_stream_vmstate, + NULL } }; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index fb49ffcb2d..ee4e07c5e7 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1053,6 +1053,7 @@ static const VMStateDescription vmstate_virtio_device_endian = { .name = "virtio/device_endian", .version_id = 1, .minimum_version_id = 1, + .needed = &virtio_device_endian_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(device_endian, VirtIODevice), VMSTATE_END_OF_LIST() @@ -1063,6 +1064,7 @@ static const VMStateDescription vmstate_virtio_64bit_features = { .name = "virtio/64bit_features", .version_id = 1, .minimum_version_id = 1, + .needed = &virtio_64bit_features_needed, .fields = (VMStateField[]) { VMSTATE_UINT64(guest_features, VirtIODevice), VMSTATE_END_OF_LIST() @@ -1077,16 +1079,10 @@ static const VMStateDescription vmstate_virtio = { .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_virtio_device_endian, - .needed = &virtio_device_endian_needed - }, - { - .vmsd = &vmstate_virtio_64bit_features, - .needed = &virtio_64bit_features_needed - }, - { 0 } + .subsections = (const VMStateDescription*[]) { + &vmstate_virtio_device_endian, + &vmstate_virtio_64bit_features, + NULL } }; diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs index 4b0374a555..72e3ffd93c 100644 --- a/hw/watchdog/Makefile.objs +++ b/hw/watchdog/Makefile.objs @@ -1,3 +1,4 @@ common-obj-y += watchdog.o common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o +common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 54440c91c5..8d4b0eeeb0 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -27,6 +27,7 @@ #include "sysemu/sysemu.h" #include "sysemu/watchdog.h" #include "qapi-event.h" +#include "hw/nmi.h" /* Possible values for action parameter. */ #define WDT_RESET 1 /* Hard reset. */ @@ -35,6 +36,7 @@ #define WDT_PAUSE 4 /* Pause. */ #define WDT_DEBUG 5 /* Prints a message and continues running. */ #define WDT_NONE 6 /* Do nothing. */ +#define WDT_NMI 7 /* Inject nmi into the guest */ static int watchdog_action = WDT_RESET; static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list; @@ -95,6 +97,8 @@ int select_watchdog_action(const char *p) watchdog_action = WDT_DEBUG; else if (strcasecmp(p, "none") == 0) watchdog_action = WDT_NONE; + else if (strcasecmp(p, "inject-nmi") == 0) + watchdog_action = WDT_NMI; else return -1; @@ -138,5 +142,11 @@ void watchdog_perform_action(void) case WDT_NONE: qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_NONE, &error_abort); break; + + case WDT_NMI: + qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_INJECT_NMI, + &error_abort); + inject_nmi(); + break; } } diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c new file mode 100644 index 0000000000..1185e0681c --- /dev/null +++ b/hw/watchdog/wdt_diag288.c @@ -0,0 +1,122 @@ +/* + * watchdog device diag288 support + * + * Copyright IBM, Corp. 2015 + * + * Authors: + * Xu Wang <gesaint@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "sysemu/watchdog.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "hw/watchdog/wdt_diag288.h" + +static WatchdogTimerModel model = { + .wdt_name = TYPE_WDT_DIAG288, + .wdt_description = "diag288 device for s390x platform", +}; + +static const VMStateDescription vmstate_diag288 = { + .name = "vmstate_diag288", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_TIMER_PTR(timer, DIAG288State), + VMSTATE_BOOL(enabled, DIAG288State), + VMSTATE_END_OF_LIST() + } +}; + +static void wdt_diag288_reset(DeviceState *dev) +{ + DIAG288State *diag288 = DIAG288(dev); + + diag288->enabled = false; + timer_del(diag288->timer); +} + +static void diag288_timer_expired(void *dev) +{ + qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n"); + watchdog_perform_action(); + wdt_diag288_reset(dev); +} + +static int wdt_diag288_handle_timer(DIAG288State *diag288, + uint64_t func, uint64_t timeout) +{ + switch (func) { + case WDT_DIAG288_INIT: + diag288->enabled = true; + /* fall through */ + case WDT_DIAG288_CHANGE: + if (!diag288->enabled) { + return -1; + } + timer_mod(diag288->timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + timeout * get_ticks_per_sec()); + break; + case WDT_DIAG288_CANCEL: + if (!diag288->enabled) { + return -1; + } + diag288->enabled = false; + timer_del(diag288->timer); + break; + default: + return -1; + } + + return 0; +} + +static void wdt_diag288_realize(DeviceState *dev, Error **errp) +{ + DIAG288State *diag288 = DIAG288(dev); + + diag288->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, diag288_timer_expired, + dev); +} + +static void wdt_diag288_unrealize(DeviceState *dev, Error **errp) +{ + DIAG288State *diag288 = DIAG288(dev); + + timer_del(diag288->timer); + timer_free(diag288->timer); +} + +static void wdt_diag288_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + DIAG288Class *diag288 = DIAG288_CLASS(klass); + + dc->realize = wdt_diag288_realize; + dc->unrealize = wdt_diag288_unrealize; + dc->reset = wdt_diag288_reset; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->vmsd = &vmstate_diag288; + diag288->handle_timer = wdt_diag288_handle_timer; +} + +static const TypeInfo wdt_diag288_info = { + .class_init = wdt_diag288_class_init, + .parent = TYPE_DEVICE, + .name = TYPE_WDT_DIAG288, + .instance_size = sizeof(DIAG288State), + .class_size = sizeof(DIAG288Class), +}; + +static void wdt_diag288_register_types(void) +{ + watchdog_add_model(&model); + type_register_static(&wdt_diag288_info); +} + +type_init(wdt_diag288_register_types) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index b2cb22b99d..2510e2e4ff 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -714,9 +714,7 @@ int xen_be_init(void) return -1; } - if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) { - goto err; - } + qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL); if (xen_xc == XC_HANDLER_INITIAL_VALUE) { /* Check if xen_init() have been called */ |