diff options
Diffstat (limited to 'hw')
119 files changed, 2561 insertions, 328 deletions
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index c1681d3c8a..4dc0d2bed1 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -22,6 +22,7 @@ #include "qemu/xattr.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include <linux/fs.h> #ifdef CONFIG_LINUX_MAGIC_H #include <linux/magic.h> diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index b25c185ff0..b37b1db453 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -8,7 +8,6 @@ * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. - * */ #include "qemu/osdep.h" @@ -23,8 +22,10 @@ #include <sys/socket.h> #include <sys/un.h> #include "qemu/xattr.h" +#include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include <libgen.h> #include <linux/fs.h> #ifdef CONFIG_LINUX_MAGIC_H diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index f030c6a428..e2e03292de 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -9,12 +9,15 @@ * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. */ + #include "qemu/osdep.h" #include <sys/socket.h> #include <sys/un.h> #include "9p.h" +#include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "fsdev/qemu-fsdev.h" #include "9p-proxy.h" diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 14f0d6a50e..95e50c4dfc 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -15,6 +15,7 @@ #include "hw/xen/xen_backend.h" #include "hw/9pfs/xen-9pfs.h" #include "qemu/config-file.h" +#include "qemu/option.h" #include "fsdev/qemu-fsdev.h" #define VERSIONS "1" diff --git a/hw/acpi/acpi-stub.c b/hw/acpi/acpi-stub.c index 26bd22f7ec..4c9d081ed4 100644 --- a/hw/acpi/acpi-stub.c +++ b/hw/acpi/acpi-stub.c @@ -19,8 +19,8 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qapi/qmp/qerror.h" -#include "qmp-commands.h" #include "hw/acpi/acpi.h" void acpi_table_add(const QemuOpts *opts, Error **errp) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index eb9b76f70b..b50b3ca772 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -18,16 +18,19 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ + #include "qemu/osdep.h" #include "sysemu/sysemu.h" #include "hw/hw.h" #include "hw/acpi/acpi.h" #include "hw/nvram/fw_cfg.h" #include "qemu/config-file.h" +#include "qapi/error.h" #include "qapi/opts-visitor.h" #include "qapi-visit.h" #include "qapi-event.h" #include "qemu/error-report.h" +#include "qemu/option.h" struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index cda2c9dd06..ea958a0e99 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -6,6 +6,7 @@ #include "hw/qdev-core.h" #include "trace.h" #include "qapi-event.h" +#include "qapi/error.h" #define MEMORY_SLOTS_NUMBER "MDNR" #define MEMORY_HOTPLUG_IO_REGION "HPMR" diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c index ba6f47b67b..f25eafc0ec 100644 --- a/hw/acpi/vmgenid.c +++ b/hw/acpi/vmgenid.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qmp-commands.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c index 13f31ad2f7..329a8aa673 100644 --- a/hw/adc/stm32f2xx_adc.c +++ b/hw/adc/stm32f2xx_adc.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/hw.h" -#include "qapi/error.h" #include "qemu/log.h" #include "hw/adc/stm32f2xx_adc.h" diff --git a/hw/arm/boot.c b/hw/arm/boot.c index bb244ec359..05108bc42f 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -22,6 +22,7 @@ #include "elf.h" #include "sysemu/device_tree.h" #include "qemu/config-file.h" +#include "qemu/option.h" #include "exec/address-spaces.h" /* Kernel boot protocol is specified in the kernel docs @@ -385,6 +386,69 @@ static void set_kernel_args_old(const struct arm_boot_info *info) } } +static void fdt_add_psci_node(void *fdt) +{ + uint32_t cpu_suspend_fn; + uint32_t cpu_off_fn; + uint32_t cpu_on_fn; + uint32_t migrate_fn; + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); + const char *psci_method; + int64_t psci_conduit; + + psci_conduit = object_property_get_int(OBJECT(armcpu), + "psci-conduit", + &error_abort); + switch (psci_conduit) { + case QEMU_PSCI_CONDUIT_DISABLED: + return; + case QEMU_PSCI_CONDUIT_HVC: + psci_method = "hvc"; + break; + case QEMU_PSCI_CONDUIT_SMC: + psci_method = "smc"; + break; + default: + g_assert_not_reached(); + } + + qemu_fdt_add_subnode(fdt, "/psci"); + if (armcpu->psci_version == 2) { + const char comp[] = "arm,psci-0.2\0arm,psci"; + qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); + + cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF; + if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) { + cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND; + cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON; + migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE; + } else { + cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND; + cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON; + migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE; + } + } else { + qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); + + cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND; + cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF; + cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON; + migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE; + } + + /* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer + * to the instruction that should be used to invoke PSCI functions. + * However, the device tree binding uses 'method' instead, so that is + * what we should use here. + */ + qemu_fdt_setprop_string(fdt, "/psci", "method", psci_method); + + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); +} + /** * load_dtb() - load a device tree binary image into memory * @addr: the address to load the image at @@ -541,6 +605,8 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, } } + fdt_add_psci_node(fdt); + if (binfo->modify_dtb) { binfo->modify_dtb(binfo, fdt); } diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index b0d4088290..e6559a8b12 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -93,7 +93,7 @@ static void fsl_imx6_init(Object *obj) } for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) { - object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_SYSBUS_SDHCI); + object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_IMX_USDHC); qdev_set_parent_bus(DEVICE(&s->esdhc[i]), sysbus_get_default()); snprintf(name, NAME_SIZE, "sdhc%d", i + 1); object_property_add_child(obj, name, OBJECT(&s->esdhc[i]), NULL); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index b334c82eda..dbb3c8036a 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -244,66 +244,6 @@ static void create_fdt(VirtMachineState *vms) } } -static void fdt_add_psci_node(const VirtMachineState *vms) -{ - uint32_t cpu_suspend_fn; - uint32_t cpu_off_fn; - uint32_t cpu_on_fn; - uint32_t migrate_fn; - void *fdt = vms->fdt; - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); - const char *psci_method; - - switch (vms->psci_conduit) { - case QEMU_PSCI_CONDUIT_DISABLED: - return; - case QEMU_PSCI_CONDUIT_HVC: - psci_method = "hvc"; - break; - case QEMU_PSCI_CONDUIT_SMC: - psci_method = "smc"; - break; - default: - g_assert_not_reached(); - } - - qemu_fdt_add_subnode(fdt, "/psci"); - if (armcpu->psci_version == 2) { - const char comp[] = "arm,psci-0.2\0arm,psci"; - qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); - - cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF; - if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) { - cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND; - cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON; - migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE; - } else { - cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND; - cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON; - migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE; - } - } else { - qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); - - cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND; - cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF; - cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON; - migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE; - } - - /* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer - * to the instruction that should be used to invoke PSCI functions. - * However, the device tree binding uses 'method' instead, so that is - * what we should use here. - */ - qemu_fdt_setprop_string(fdt, "/psci", "method", psci_method); - - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn); - qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); -} - static void fdt_add_timer_nodes(const VirtMachineState *vms) { /* On real hardware these interrupts are level-triggered. @@ -1409,7 +1349,6 @@ static void machvirt_init(MachineState *machine) } fdt_add_timer_nodes(vms); fdt_add_cpu_nodes(vms); - fdt_add_psci_node(vms); memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram", machine->ram_size); diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index b53b4c9c57..f840f07dfe 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qemu/typedefs.h" #include "qemu/cutils.h" #include "qom/object.h" #include "hw/qdev-core.h" diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c index 56fa402b58..faae083e78 100644 --- a/hw/char/mcf_uart.c +++ b/hw/char/mcf_uart.c @@ -11,7 +11,6 @@ #include "hw/m68k/mcf.h" #include "chardev/char-fe.h" #include "exec/address-spaces.h" -#include "qapi/error.h" typedef struct { SysBusDevice parent_obj; diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 172c72d06c..4be5d4ee52 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -16,6 +16,7 @@ #include "trace.h" #include "hw/virtio/virtio-serial.h" #include "qapi-event.h" +#include "qapi/error.h" #define TYPE_VIRTIO_CONSOLE_SERIAL_PORT "virtserialport" #define VIRTIO_CONSOLE(obj) \ diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index 46012673c3..cb0e68486d 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -105,7 +105,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) error_setg(errp, "data can not be specified when setting a " "program counter"); return; - } else if (!s->cpu_num) { + } else if (s->cpu_num == CPU_NONE) { error_setg(errp, "cpu_num must be specified when setting a " "program counter"); return; diff --git a/hw/core/machine.c b/hw/core/machine.c index cdc1163dc6..5d445839e8 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -520,7 +520,7 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "accel", "Accelerator list", &error_abort); - object_class_property_add(oc, "kernel-irqchip", "OnOffSplit", + object_class_property_add(oc, "kernel-irqchip", "on|off|split", NULL, machine_set_kernel_irqchip, NULL, NULL, &error_abort); object_class_property_set_description(oc, "kernel-irqchip", diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 11f8a27a69..7ed1f431f0 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -28,10 +28,11 @@ #include "qemu/osdep.h" #include "hw/qdev.h" #include "sysemu/sysemu.h" +#include "qapi/error.h" #include "qapi/qmp/qerror.h" #include "qapi/visitor.h" -#include "qapi/qmp/qjson.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "hw/hotplug.h" #include "hw/boards.h" #include "hw/sysbus.h" diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index 59120ddb67..3ce44fdfce 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -28,6 +28,7 @@ #include "hw/hw.h" #include "hw/sysbus.h" #include "trace.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qapi/error.h" diff --git a/hw/display/qxl.c b/hw/display/qxl.c index b9fa067f6e..a71714ccb4 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include <zlib.h> +#include "qapi/error.h" #include "qemu-common.h" #include "qemu/timer.h" #include "qemu/queue.h" diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index 8c106a662d..7db84efe89 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -17,7 +17,6 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" -#include "qapi/error.h" #ifdef CONFIG_VIRGL diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 3519dc80b1..cece4aa495 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -10,7 +10,9 @@ * See the COPYING file in the top-level directory. * */ + #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/pci/pci.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-bus.h" diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index ead4e1a0e4..6715b9cc2b 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/log.h" #include "hw/display/xlnx_dp.h" diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c index e873a445da..ab64d196be 100644 --- a/hw/i2c/ppc4xx_i2c.c +++ b/hw/i2c/ppc4xx_i2c.c @@ -25,7 +25,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu-common.h" #include "qemu/log.h" #include "cpu.h" diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ed78c4ed9f..deb440f286 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qmp/qnum.h" #include "acpi-build.h" #include "qemu-common.h" #include "qemu/bitmap.h" diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index c7b70c91d5..46d9c68bf5 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/option.h" #include "cpu.h" #include "hw/hw.h" #include "hw/nvram/fw_cfg.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index ccc50baa85..55e69d66fe 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/i386/pc.h" @@ -58,12 +59,14 @@ #include "qemu/bitmap.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "hw/acpi/acpi.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/boards.h" #include "hw/pci/pci_host.h" #include "acpi-build.h" #include "hw/mem/pc-dimm.h" +#include "qapi/error.h" #include "qapi/visitor.h" #include "qapi-visit.h" #include "qom/cpu.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a25619dfbf..456dc9e9f0 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -47,6 +47,7 @@ #include "exec/address-spaces.h" #include "hw/acpi/acpi.h" #include "cpu.h" +#include "qapi/error.h" #include "qemu/error-report.h" #ifdef CONFIG_XEN #include <xen/hvm/hvm_info_table.h> diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index ed3a0b8ff7..aba7541a82 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -27,6 +27,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/loader.h" @@ -48,6 +49,7 @@ #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/numa.h" diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 6b183747fc..4325575e7d 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "sysemu/block-backend.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "hw/sysbus.h" #include "hw/hw.h" #include "hw/i386/pc.h" diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 8028bed6fd..bfdbe55580 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -17,7 +17,7 @@ #include "hw/xen/xen_common.h" #include "hw/xen/xen_backend.h" #include "qmp-commands.h" - +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/range.h" #include "sysemu/xen-mapcache.h" diff --git a/hw/ide/core.c b/hw/ide/core.c index 5be72d41dc..257b429381 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -22,6 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/pci.h" @@ -33,6 +34,7 @@ #include "sysemu/dma.h" #include "hw/block/block.h" #include "sysemu/block-backend.h" +#include "qapi/error.h" #include "qemu/cutils.h" #include "hw/ide/internal.h" diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c index 17aa930e39..e3896c65b4 100644 --- a/hw/ide/sii3112.c +++ b/hw/ide/sii3112.c @@ -12,8 +12,8 @@ * http://wiki.osdev.org/User:Quok/Silicon_Image_Datasheets */ -#include <qemu/osdep.h> -#include <hw/ide/pci.h> +#include "qemu/osdep.h" +#include "hw/ide/pci.h" #include "trace.h" #define TYPE_SII3112_PCI "sii3112" diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 571e094a14..0e9963f5ee 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -6,7 +6,7 @@ common-obj-$(CONFIG_XILINX) += xilinx_intc.o common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-pmu-iomod-intc.o common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-ipi.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_pic.o -common-obj-$(CONFIG_IMX) += imx_avic.o +common-obj-$(CONFIG_IMX) += imx_avic.o imx_gpcv2.o common-obj-$(CONFIG_LM32) += lm32_pic.o common-obj-$(CONFIG_REALVIEW) += realview_gic.o common-obj-$(CONFIG_SLAVIO) += slavio_intctl.o diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 8ca6ceeb9b..360889d30b 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -503,8 +503,25 @@ static void armv7m_nvic_clear_pending(void *opaque, int irq, bool secure) } } -void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) +static void do_armv7m_nvic_set_pending(void *opaque, int irq, bool secure, + bool derived) { + /* Pend an exception, including possibly escalating it to HardFault. + * + * This function handles both "normal" pending of interrupts and + * exceptions, and also derived exceptions (ones which occur as + * a result of trying to take some other exception). + * + * If derived == true, the caller guarantees that we are part way through + * trying to take an exception (but have not yet called + * armv7m_nvic_acknowledge_irq() to make it active), and so: + * - s->vectpending is the "original exception" we were trying to take + * - irq is the "derived exception" + * - nvic_exec_prio(s) gives the priority before exception entry + * Here we handle the prioritization logic which the pseudocode puts + * in the DerivedLateArrival() function. + */ + NVICState *s = (NVICState *)opaque; bool banked = exc_is_banked(irq); VecInfo *vec; @@ -514,7 +531,44 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) vec = (banked && secure) ? &s->sec_vectors[irq] : &s->vectors[irq]; - trace_nvic_set_pending(irq, secure, vec->enabled, vec->prio); + trace_nvic_set_pending(irq, secure, derived, vec->enabled, vec->prio); + + if (derived) { + /* Derived exceptions are always synchronous. */ + assert(irq >= ARMV7M_EXCP_HARD && irq < ARMV7M_EXCP_PENDSV); + + if (irq == ARMV7M_EXCP_DEBUG && + exc_group_prio(s, vec->prio, secure) >= nvic_exec_prio(s)) { + /* DebugMonitorFault, but its priority is lower than the + * preempted exception priority: just ignore it. + */ + return; + } + + if (irq == ARMV7M_EXCP_HARD && vec->prio >= s->vectpending_prio) { + /* If this is a terminal exception (one which means we cannot + * take the original exception, like a failure to read its + * vector table entry), then we must take the derived exception. + * If the derived exception can't take priority over the + * original exception, then we go into Lockup. + * + * For QEMU, we rely on the fact that a derived exception is + * terminal if and only if it's reported to us as HardFault, + * which saves having to have an extra argument is_terminal + * that we'd only use in one place. + */ + cpu_abort(&s->cpu->parent_obj, + "Lockup: can't take terminal derived exception " + "(original exception priority %d)\n", + s->vectpending_prio); + } + /* We now continue with the same code as for a normal pending + * exception, which will cause us to pend the derived exception. + * We'll then take either the original or the derived exception + * based on which is higher priority by the usual mechanism + * for selecting the highest priority pending interrupt. + */ + } if (irq >= ARMV7M_EXCP_HARD && irq < ARMV7M_EXCP_PENDSV) { /* If a synchronous exception is pending then it may be @@ -585,25 +639,31 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) } } +void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) +{ + do_armv7m_nvic_set_pending(opaque, irq, secure, false); +} + +void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure) +{ + do_armv7m_nvic_set_pending(opaque, irq, secure, true); +} + /* Make pending IRQ active. */ -bool armv7m_nvic_acknowledge_irq(void *opaque) +void armv7m_nvic_acknowledge_irq(void *opaque) { NVICState *s = (NVICState *)opaque; CPUARMState *env = &s->cpu->env; const int pending = s->vectpending; const int running = nvic_exec_prio(s); VecInfo *vec; - bool targets_secure; assert(pending > ARMV7M_EXCP_RESET && pending < s->num_irq); if (s->vectpending_is_s_banked) { vec = &s->sec_vectors[pending]; - targets_secure = true; } else { vec = &s->vectors[pending]; - targets_secure = !exc_is_banked(s->vectpending) && - exc_targets_secure(s, s->vectpending); } assert(vec->enabled); @@ -611,7 +671,7 @@ bool armv7m_nvic_acknowledge_irq(void *opaque) assert(s->vectpending_prio < running); - trace_nvic_acknowledge_irq(pending, s->vectpending_prio, targets_secure); + trace_nvic_acknowledge_irq(pending, s->vectpending_prio); vec->active = 1; vec->pending = 0; @@ -619,8 +679,28 @@ bool armv7m_nvic_acknowledge_irq(void *opaque) write_v7m_exception(env, s->vectpending); nvic_irq_update(s); +} + +void armv7m_nvic_get_pending_irq_info(void *opaque, + int *pirq, bool *ptargets_secure) +{ + NVICState *s = (NVICState *)opaque; + const int pending = s->vectpending; + bool targets_secure; + + assert(pending > ARMV7M_EXCP_RESET && pending < s->num_irq); + + if (s->vectpending_is_s_banked) { + targets_secure = true; + } else { + targets_secure = !exc_is_banked(pending) && + exc_targets_secure(s, pending); + } + + trace_nvic_get_pending_irq_info(pending, targets_secure); - return targets_secure; + *ptargets_secure = targets_secure; + *pirq = pending; } int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) diff --git a/hw/intc/imx_gpcv2.c b/hw/intc/imx_gpcv2.c new file mode 100644 index 0000000000..4eb9ce2668 --- /dev/null +++ b/hw/intc/imx_gpcv2.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * i.MX7 GPCv2 block emulation code + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/intc/imx_gpcv2.h" +#include "qemu/log.h" + +#define GPC_PU_PGC_SW_PUP_REQ 0x0f8 +#define GPC_PU_PGC_SW_PDN_REQ 0x104 + +#define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) +#define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) +#define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) +#define PCIE_PHY_SW_Pxx_REQ BIT(1) +#define MIPI_PHY_SW_Pxx_REQ BIT(0) + + +static void imx_gpcv2_reset(DeviceState *dev) +{ + IMXGPCv2State *s = IMX_GPCV2(dev); + + memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx_gpcv2_read(void *opaque, hwaddr offset, + unsigned size) +{ + IMXGPCv2State *s = opaque; + + return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx_gpcv2_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + IMXGPCv2State *s = opaque; + const size_t idx = offset / sizeof(uint32_t); + + s->regs[idx] = value; + + /* + * Real HW will clear those bits once as a way to indicate that + * power up request is complete + */ + if (offset == GPC_PU_PGC_SW_PUP_REQ || + offset == GPC_PU_PGC_SW_PDN_REQ) { + s->regs[idx] &= ~(USB_HSIC_PHY_SW_Pxx_REQ | + USB_OTG2_PHY_SW_Pxx_REQ | + USB_OTG1_PHY_SW_Pxx_REQ | + PCIE_PHY_SW_Pxx_REQ | + MIPI_PHY_SW_Pxx_REQ); + } +} + +static const struct MemoryRegionOps imx_gpcv2_ops = { + .read = imx_gpcv2_read, + .write = imx_gpcv2_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx_gpcv2_init(Object *obj) +{ + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + IMXGPCv2State *s = IMX_GPCV2(obj); + + memory_region_init_io(&s->iomem, + obj, + &imx_gpcv2_ops, + s, + TYPE_IMX_GPCV2 ".iomem", + sizeof(s->regs)); + sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx_gpcv2 = { + .name = TYPE_IMX_GPCV2, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, IMXGPCv2State, GPC_NUM), + VMSTATE_END_OF_LIST() + }, +}; + +static void imx_gpcv2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = imx_gpcv2_reset; + dc->vmsd = &vmstate_imx_gpcv2; + dc->desc = "i.MX GPCv2 Module"; +} + +static const TypeInfo imx_gpcv2_info = { + .name = TYPE_IMX_GPCV2, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMXGPCv2State), + .instance_init = imx_gpcv2_init, + .class_init = imx_gpcv2_class_init, +}; + +static void imx_gpcv2_register_type(void) +{ + type_register_static(&imx_gpcv2_info); +} +type_init(imx_gpcv2_register_type) diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index 6eaf178d79..a85a149c6d 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -22,16 +22,36 @@ #include "qapi/error.h" #include "hw/s390x/s390-virtio-ccw.h" +S390FLICStateClass *s390_get_flic_class(S390FLICState *fs) +{ + static S390FLICStateClass *class; + + if (!class) { + /* we only have one flic device, so this is fine to cache */ + class = S390_FLIC_COMMON_GET_CLASS(fs); + } + return class; +} + +QEMUS390FLICState *s390_get_qemu_flic(S390FLICState *fs) +{ + static QEMUS390FLICState *flic; + + if (!flic) { + /* we only have one flic device, so this is fine to cache */ + flic = QEMU_S390_FLIC(fs); + } + return flic; +} + S390FLICState *s390_get_flic(void) { static S390FLICState *fs; if (!fs) { - fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL)); - if (!fs) { - fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, - NULL)); - } + fs = S390_FLIC_COMMON(object_resolve_path_type("", + TYPE_S390_FLIC_COMMON, + NULL)); } return fs; } @@ -40,8 +60,11 @@ void s390_flic_init(void) { DeviceState *dev; - dev = s390_flic_kvm_create(); - if (!dev) { + if (kvm_enabled()) { + dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); + object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, + OBJECT(dev), NULL); + } else { dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC); object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, OBJECT(dev), NULL); @@ -78,14 +101,41 @@ static void qemu_s390_release_adapter_routes(S390FLICState *fs, static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, uint16_t subchannel_nr) { - /* Fixme TCG */ - return -ENOSYS; + QEMUS390FLICState *flic = s390_get_qemu_flic(fs); + QEMUS390FlicIO *cur, *next; + uint8_t isc; + + g_assert(qemu_mutex_iothread_locked()); + if (!(flic->pending & FLIC_PENDING_IO)) { + return 0; + } + + /* check all iscs */ + for (isc = 0; isc < 8; isc++) { + if (QLIST_EMPTY(&flic->io[isc])) { + continue; + } + + /* search and delete any matching one */ + QLIST_FOREACH_SAFE(cur, &flic->io[isc], next, next) { + if (cur->id == subchannel_id && cur->nr == subchannel_nr) { + QLIST_REMOVE(cur, next); + g_free(cur); + } + } + + /* update our indicator bit */ + if (QLIST_EMPTY(&flic->io[isc])) { + flic->pending &= ~ISC_TO_PENDING_IO(isc); + } + } + return 0; } static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, uint16_t mode) { - QEMUS390FLICState *flic = QEMU_S390_FLIC(fs); + QEMUS390FLICState *flic = s390_get_qemu_flic(fs); switch (mode) { case SIC_IRQ_MODE_ALL: @@ -106,7 +156,8 @@ static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type, uint8_t isc, uint8_t flags) { - QEMUS390FLICState *flic = QEMU_S390_FLIC(fs); + QEMUS390FLICState *flic = s390_get_qemu_flic(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); bool flag = flags & S390_ADAPTER_SUPPRESSIBLE; uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; @@ -115,7 +166,7 @@ static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type, return 0; } - s390_io_interrupt(0, 0, 0, io_int_word); + fsc->inject_io(fs, 0, 0, 0, io_int_word); if (flag && (flic->simm & AIS_MODE_MASK(isc))) { flic->nimm |= AIS_MODE_MASK(isc); @@ -126,12 +177,180 @@ static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type, return 0; } +static void qemu_s390_flic_notify(uint32_t type) +{ + CPUState *cs; + + /* + * We have to make all CPUs see CPU_INTERRUPT_HARD, so they might + * consider it. We will kick all running CPUs and only relevant + * sleeping ones. + */ + CPU_FOREACH(cs) { + S390CPU *cpu = S390_CPU(cs); + + cs->interrupt_request |= CPU_INTERRUPT_HARD; + + /* ignore CPUs that are not sleeping */ + if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING && + s390_cpu_get_state(cpu) != CPU_STATE_LOAD) { + continue; + } + + /* we always kick running CPUs for now, this is tricky */ + if (cs->halted) { + /* don't check for subclasses, CPUs double check when waking up */ + if (type & FLIC_PENDING_SERVICE) { + if (!(cpu->env.psw.mask & PSW_MASK_EXT)) { + continue; + } + } else if (type & FLIC_PENDING_IO) { + if (!(cpu->env.psw.mask & PSW_MASK_IO)) { + continue; + } + } else if (type & FLIC_PENDING_MCHK_CR) { + if (!(cpu->env.psw.mask & PSW_MASK_MCHECK)) { + continue; + } + } + } + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +uint32_t qemu_s390_flic_dequeue_service(QEMUS390FLICState *flic) +{ + uint32_t tmp; + + g_assert(qemu_mutex_iothread_locked()); + g_assert(flic->pending & FLIC_PENDING_SERVICE); + tmp = flic->service_param; + flic->service_param = 0; + flic->pending &= ~FLIC_PENDING_SERVICE; + + return tmp; +} + +/* caller has to free the returned object */ +QEMUS390FlicIO *qemu_s390_flic_dequeue_io(QEMUS390FLICState *flic, uint64_t cr6) +{ + QEMUS390FlicIO *io; + uint8_t isc; + + g_assert(qemu_mutex_iothread_locked()); + if (!(flic->pending & CR6_TO_PENDING_IO(cr6))) { + return NULL; + } + + for (isc = 0; isc < 8; isc++) { + if (QLIST_EMPTY(&flic->io[isc]) || !(cr6 & ISC_TO_ISC_BITS(isc))) { + continue; + } + io = QLIST_FIRST(&flic->io[isc]); + QLIST_REMOVE(io, next); + + /* update our indicator bit */ + if (QLIST_EMPTY(&flic->io[isc])) { + flic->pending &= ~ISC_TO_PENDING_IO(isc); + } + return io; + } + + return NULL; +} + +void qemu_s390_flic_dequeue_crw_mchk(QEMUS390FLICState *flic) +{ + g_assert(qemu_mutex_iothread_locked()); + g_assert(flic->pending & FLIC_PENDING_MCHK_CR); + flic->pending &= ~FLIC_PENDING_MCHK_CR; +} + +static void qemu_s390_inject_service(S390FLICState *fs, uint32_t parm) +{ + QEMUS390FLICState *flic = s390_get_qemu_flic(fs); + + g_assert(qemu_mutex_iothread_locked()); + /* multiplexing is good enough for sclp - kvm does it internally as well */ + flic->service_param |= parm; + flic->pending |= FLIC_PENDING_SERVICE; + + qemu_s390_flic_notify(FLIC_PENDING_SERVICE); +} + +static void qemu_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word) +{ + const uint8_t isc = IO_INT_WORD_ISC(io_int_word); + QEMUS390FLICState *flic = s390_get_qemu_flic(fs); + QEMUS390FlicIO *io; + + g_assert(qemu_mutex_iothread_locked()); + io = g_new0(QEMUS390FlicIO, 1); + io->id = subchannel_id; + io->nr = subchannel_nr; + io->parm = io_int_parm; + io->word = io_int_word; + + QLIST_INSERT_HEAD(&flic->io[isc], io, next); + flic->pending |= ISC_TO_PENDING_IO(isc); + + qemu_s390_flic_notify(ISC_TO_PENDING_IO(isc)); +} + +static void qemu_s390_inject_crw_mchk(S390FLICState *fs) +{ + QEMUS390FLICState *flic = s390_get_qemu_flic(fs); + + g_assert(qemu_mutex_iothread_locked()); + flic->pending |= FLIC_PENDING_MCHK_CR; + + qemu_s390_flic_notify(FLIC_PENDING_MCHK_CR); +} + +bool qemu_s390_flic_has_service(QEMUS390FLICState *flic) +{ + /* called without lock via cc->has_work, will be validated under lock */ + return !!(flic->pending & FLIC_PENDING_SERVICE); +} + +bool qemu_s390_flic_has_io(QEMUS390FLICState *flic, uint64_t cr6) +{ + /* called without lock via cc->has_work, will be validated under lock */ + return !!(flic->pending & CR6_TO_PENDING_IO(cr6)); +} + +bool qemu_s390_flic_has_crw_mchk(QEMUS390FLICState *flic) +{ + /* called without lock via cc->has_work, will be validated under lock */ + return !!(flic->pending & FLIC_PENDING_MCHK_CR); +} + +bool qemu_s390_flic_has_any(QEMUS390FLICState *flic) +{ + g_assert(qemu_mutex_iothread_locked()); + return !!flic->pending; +} + static void qemu_s390_flic_reset(DeviceState *dev) { QEMUS390FLICState *flic = QEMU_S390_FLIC(dev); + QEMUS390FlicIO *cur, *next; + int isc; + g_assert(qemu_mutex_iothread_locked()); flic->simm = 0; flic->nimm = 0; + flic->pending = 0; + + /* remove all pending io interrupts */ + for (isc = 0; isc < 8; isc++) { + QLIST_FOREACH_SAFE(cur, &flic->io[isc], next, next) { + QLIST_REMOVE(cur, next); + g_free(cur); + } + } } bool ais_needed(void *opaque) @@ -153,6 +372,16 @@ static const VMStateDescription qemu_s390_flic_vmstate = { } }; +static void qemu_s390_flic_instance_init(Object *obj) +{ + QEMUS390FLICState *flic = QEMU_S390_FLIC(obj); + int isc; + + for (isc = 0; isc < 8; isc++) { + QLIST_INIT(&flic->io[isc]); + } +} + static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -167,6 +396,9 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) fsc->clear_io_irq = qemu_s390_clear_io_flic; fsc->modify_ais_mode = qemu_s390_modify_ais_mode; fsc->inject_airq = qemu_s390_inject_airq; + fsc->inject_service = qemu_s390_inject_service; + fsc->inject_io = qemu_s390_inject_io; + fsc->inject_crw_mchk = qemu_s390_inject_crw_mchk; } static Property s390_flic_common_properties[] = { @@ -201,6 +433,7 @@ static const TypeInfo qemu_s390_flic_info = { .name = TYPE_QEMU_S390_FLIC, .parent = TYPE_S390_FLIC_COMMON, .instance_size = sizeof(QEMUS390FLICState), + .instance_init = qemu_s390_flic_instance_init, .class_init = qemu_s390_flic_class_init, }; diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index d208cb81c4..3f804ad52e 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -35,16 +35,15 @@ typedef struct KVMS390FLICState { bool clear_io_supported; } KVMS390FLICState; -DeviceState *s390_flic_kvm_create(void) +static KVMS390FLICState *s390_get_kvm_flic(S390FLICState *fs) { - DeviceState *dev = NULL; + static KVMS390FLICState *flic; - if (kvm_enabled()) { - dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); - object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, - OBJECT(dev), NULL); + if (!flic) { + /* we only have one flic device, so this is fine to cache */ + flic = KVM_S390_FLIC(fs); } - return dev; + return flic; } /** @@ -123,20 +122,70 @@ static int flic_enqueue_irqs(void *buf, uint64_t len, return rc ? -errno : 0; } -int kvm_s390_inject_flic(struct kvm_s390_irq *irq) +static void kvm_s390_inject_flic(S390FLICState *fs, struct kvm_s390_irq *irq) { - static KVMS390FLICState *flic; + static bool use_flic = true; + int r; + + if (use_flic) { + r = flic_enqueue_irqs(irq, sizeof(*irq), s390_get_kvm_flic(fs)); + if (r == -ENOSYS) { + use_flic = false; + } + if (!r) { + return; + } + } + /* fallback to legacy KVM IOCTL in case FLIC fails */ + kvm_s390_floating_interrupt_legacy(irq); +} + +static void kvm_s390_inject_service(S390FLICState *fs, uint32_t parm) +{ + struct kvm_s390_irq irq = { + .type = KVM_S390_INT_SERVICE, + .u.ext.ext_params = parm, + }; + + kvm_s390_inject_flic(fs, &irq); +} - if (unlikely(!flic)) { - flic = KVM_S390_FLIC(s390_get_flic()); +static void kvm_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word) +{ + struct kvm_s390_irq irq = { + .u.io.subchannel_id = subchannel_id, + .u.io.subchannel_nr = subchannel_nr, + .u.io.io_int_parm = io_int_parm, + .u.io.io_int_word = io_int_word, + }; + + if (io_int_word & IO_INT_WORD_AI) { + irq.type = KVM_S390_INT_IO(1, 0, 0, 0); + } else { + irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8, + (subchannel_id & 0x0006), + subchannel_nr); } - return flic_enqueue_irqs(irq, sizeof(*irq), flic); + kvm_s390_inject_flic(fs, &irq); +} + +static void kvm_s390_inject_crw_mchk(S390FLICState *fs) +{ + struct kvm_s390_irq irq = { + .type = KVM_S390_MCHK, + .u.mchk.cr14 = CR14_CHANNEL_REPORT_SC, + .u.mchk.mcic = s390_build_validity_mcic() | MCIC_SC_CP, + }; + + kvm_s390_inject_flic(fs, &irq); } static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, uint16_t subchannel_nr) { - KVMS390FLICState *flic = KVM_S390_FLIC(fs); + KVMS390FLICState *flic = s390_get_kvm_flic(fs); int rc; uint32_t sid = subchannel_id << 16 | subchannel_nr; struct kvm_device_attr attr = { @@ -154,7 +203,7 @@ static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, uint16_t mode) { - KVMS390FLICState *flic = KVM_S390_FLIC(fs); + KVMS390FLICState *flic = s390_get_kvm_flic(fs); struct kvm_s390_ais_req req = { .isc = isc, .mode = mode, @@ -174,7 +223,7 @@ static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type, uint8_t isc, uint8_t flags) { - KVMS390FLICState *flic = KVM_S390_FLIC(fs); + KVMS390FLICState *flic = s390_get_kvm_flic(fs); uint32_t id = css_get_adapter_id(type, isc); struct kvm_device_attr attr = { .group = KVM_DEV_FLIC_AIRQ_INJECT, @@ -263,7 +312,7 @@ static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id, .group = KVM_DEV_FLIC_ADAPTER_MODIFY, .addr = (uint64_t)&req, }; - KVMS390FLICState *flic = KVM_S390_FLIC(fs); + KVMS390FLICState *flic = s390_get_kvm_flic(fs); int r; if (!kvm_gsi_routing_enabled()) { @@ -614,6 +663,9 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) fsc->clear_io_irq = kvm_s390_clear_io_flic; fsc->modify_ais_mode = kvm_s390_modify_ais_mode; fsc->inject_airq = kvm_s390_inject_airq; + fsc->inject_service = kvm_s390_inject_service; + fsc->inject_io = kvm_s390_inject_io; + fsc->inject_crw_mchk = kvm_s390_inject_crw_mchk; } static const TypeInfo kvm_s390_flic_info = { diff --git a/hw/intc/trace-events b/hw/intc/trace-events index be769186fc..4092d2825e 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -177,10 +177,11 @@ nvic_set_prio(int irq, bool secure, uint8_t prio) "NVIC set irq %d secure-bank % nvic_irq_update(int vectpending, int pendprio, int exception_prio, int level) "NVIC vectpending %d pending prio %d exception_prio %d: setting irq line to %d" nvic_escalate_prio(int irq, int irqprio, int runprio) "NVIC escalating irq %d to HardFault: insufficient priority %d >= %d" nvic_escalate_disabled(int irq) "NVIC escalating irq %d to HardFault: disabled" -nvic_set_pending(int irq, bool secure, int en, int prio) "NVIC set pending irq %d secure-bank %d (enabled: %d priority %d)" +nvic_set_pending(int irq, bool secure, bool derived, int en, int prio) "NVIC set pending irq %d secure-bank %d derived %d (enabled: %d priority %d)" nvic_clear_pending(int irq, bool secure, int en, int prio) "NVIC clear pending irq %d secure-bank %d (enabled: %d priority %d)" nvic_set_pending_level(int irq) "NVIC set pending: irq %d higher prio than vectpending: setting irq line to 1" -nvic_acknowledge_irq(int irq, int prio, bool targets_secure) "NVIC acknowledge IRQ: %d now active (prio %d targets_secure %d)" +nvic_acknowledge_irq(int irq, int prio) "NVIC acknowledge IRQ: %d now active (prio %d)" +nvic_get_pending_irq_info(int irq, bool secure) "NVIC next IRQ %d: targets_secure: %d" nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)" nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d" nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" diff --git a/hw/intc/xics_pnv.c b/hw/intc/xics_pnv.c index 2a955a8946..c87de2189c 100644 --- a/hw/intc/xics_pnv.c +++ b/hw/intc/xics_pnv.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" -#include "qapi/error.h" #include "qemu/log.h" #include "hw/ppc/xics.h" diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 5a0967caf4..2e27b92b87 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -34,7 +34,6 @@ #include "hw/ppc/xics.h" #include "hw/ppc/fdt.h" #include "qapi/visitor.h" -#include "qapi/error.h" /* * Guest interfaces diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c index b27babd504..adbbf6e4a6 100644 --- a/hw/ipmi/ipmi.c +++ b/hw/ipmi/ipmi.c @@ -28,6 +28,7 @@ #include "sysemu/sysemu.h" #include "qmp-commands.h" #include "qom/object_interfaces.h" +#include "qapi/error.h" #include "qapi/visitor.h" static uint32_t ipmi_current_uuid = 1; diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 596f3c210e..b09871a814 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -45,6 +45,7 @@ #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/help_option.h" diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 7ca8ba2086..6f0deb99e7 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -51,6 +51,7 @@ #include "hw/sysbus.h" /* SysBusDevice */ #include "qemu/host-utils.h" #include "sysemu/qtest.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "hw/empty_slot.h" #include "sysemu/kvm.h" diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index d517f83e81..f33b37a8e5 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -17,6 +17,9 @@ common-obj-$(CONFIG_INTEGRATOR_DEBUG) += arm_integrator_debug.o common-obj-$(CONFIG_A9SCU) += a9scu.o common-obj-$(CONFIG_ARM11SCU) += arm11scu.o +# Mac devices +common-obj-$(CONFIG_MOS6522) += mos6522.o + # PKUnity SoC devices common-obj-$(CONFIG_PUV3) += puv3_pm.o @@ -33,6 +36,10 @@ obj-$(CONFIG_IMX) += imx31_ccm.o obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o +obj-$(CONFIG_IMX) += imx7_ccm.o +obj-$(CONFIG_IMX) += imx2_wdt.o +obj-$(CONFIG_IMX) += imx7_snvs.o +obj-$(CONFIG_IMX) += imx7_gpr.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/exynos4210_rng.c b/hw/misc/exynos4210_rng.c index 31ebe38e26..4ecbebd2d7 100644 --- a/hw/misc/exynos4210_rng.c +++ b/hw/misc/exynos4210_rng.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "crypto/random.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "qemu/log.h" #define DEBUG_EXYNOS_RNG 0 diff --git a/hw/misc/imx2_wdt.c b/hw/misc/imx2_wdt.c new file mode 100644 index 0000000000..e47e442592 --- /dev/null +++ b/hw/misc/imx2_wdt.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "sysemu/watchdog.h" + +#include "hw/misc/imx2_wdt.h" + +#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */ +#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */ + +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, + unsigned int size) +{ + return 0; +} + +static void imx2_wdt_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + if (addr == IMX2_WDT_WCR && + (value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) { + watchdog_perform_action(); + } +} + +static const MemoryRegionOps imx2_wdt_ops = { + .read = imx2_wdt_read, + .write = imx2_wdt_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx2_wdt_realize(DeviceState *dev, Error **errp) +{ + IMX2WdtState *s = IMX2_WDT(dev); + + memory_region_init_io(&s->mmio, OBJECT(dev), + &imx2_wdt_ops, s, + TYPE_IMX2_WDT".mmio", + IMX2_WDT_REG_NUM * sizeof(uint16_t)); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void imx2_wdt_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = imx2_wdt_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo imx2_wdt_info = { + .name = TYPE_IMX2_WDT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX2WdtState), + .class_init = imx2_wdt_class_init, +}; + +static WatchdogTimerModel model = { + .wdt_name = "imx2-watchdog", + .wdt_description = "i.MX2 Watchdog", +}; + +static void imx2_wdt_register_type(void) +{ + watchdog_add_model(&model); + type_register_static(&imx2_wdt_info); +} +type_init(imx2_wdt_register_type) diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c new file mode 100644 index 0000000000..d90c48bfec --- /dev/null +++ b/hw/misc/imx7_ccm.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * i.MX7 CCM, PMU and ANALOG IP blocks emulation code + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" + +#include "hw/misc/imx7_ccm.h" + +static void imx7_analog_reset(DeviceState *dev) +{ + IMX7AnalogState *s = IMX7_ANALOG(dev); + + memset(s->pmu, 0, sizeof(s->pmu)); + memset(s->analog, 0, sizeof(s->analog)); + + s->analog[ANALOG_PLL_ARM] = 0x00002042; + s->analog[ANALOG_PLL_DDR] = 0x0060302c; + s->analog[ANALOG_PLL_DDR_SS] = 0x00000000; + s->analog[ANALOG_PLL_DDR_NUM] = 0x06aaac4d; + s->analog[ANALOG_PLL_DDR_DENOM] = 0x100003ec; + s->analog[ANALOG_PLL_480] = 0x00002000; + s->analog[ANALOG_PLL_480A] = 0x52605a56; + s->analog[ANALOG_PLL_480B] = 0x52525216; + s->analog[ANALOG_PLL_ENET] = 0x00001fc0; + s->analog[ANALOG_PLL_AUDIO] = 0x0001301b; + s->analog[ANALOG_PLL_AUDIO_SS] = 0x00000000; + s->analog[ANALOG_PLL_AUDIO_NUM] = 0x05f5e100; + s->analog[ANALOG_PLL_AUDIO_DENOM] = 0x2964619c; + s->analog[ANALOG_PLL_VIDEO] = 0x0008201b; + s->analog[ANALOG_PLL_VIDEO_SS] = 0x00000000; + s->analog[ANALOG_PLL_VIDEO_NUM] = 0x0000f699; + s->analog[ANALOG_PLL_VIDEO_DENOM] = 0x000f4240; + s->analog[ANALOG_PLL_MISC0] = 0x00000000; + + /* all PLLs need to be locked */ + s->analog[ANALOG_PLL_ARM] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_DDR] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_480] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_480A] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_480B] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_ENET] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_AUDIO] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_VIDEO] |= ANALOG_PLL_LOCK; + s->analog[ANALOG_PLL_MISC0] |= ANALOG_PLL_LOCK; + + /* + * Since I couldn't find any info about this in the reference + * manual the value of this register is based strictly on matching + * what Linux kernel expects it to be. + */ + s->analog[ANALOG_DIGPROG] = 0x720000; + /* + * Set revision to be 1.0 (Arbitrary choice, no particular + * reason). + */ + s->analog[ANALOG_DIGPROG] |= 0x000010; +} + +static void imx7_ccm_reset(DeviceState *dev) +{ + IMX7CCMState *s = IMX7_CCM(dev); + + memset(s->ccm, 0, sizeof(s->ccm)); +} + +#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t)) +#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF) + +enum { + CCM_BITOP_NONE = 0x00, + CCM_BITOP_SET = 0x04, + CCM_BITOP_CLR = 0x08, + CCM_BITOP_TOG = 0x0C, +}; + +static uint64_t imx7_set_clr_tog_read(void *opaque, hwaddr offset, + unsigned size) +{ + const uint32_t *mmio = opaque; + + return mmio[CCM_INDEX(offset)]; +} + +static void imx7_set_clr_tog_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + const uint8_t bitop = CCM_BITOP(offset); + const uint32_t index = CCM_INDEX(offset); + uint32_t *mmio = opaque; + + switch (bitop) { + case CCM_BITOP_NONE: + mmio[index] = value; + break; + case CCM_BITOP_SET: + mmio[index] |= value; + break; + case CCM_BITOP_CLR: + mmio[index] &= ~value; + break; + case CCM_BITOP_TOG: + mmio[index] ^= value; + break; + }; +} + +static const struct MemoryRegionOps imx7_set_clr_tog_ops = { + .read = imx7_set_clr_tog_read, + .write = imx7_set_clr_tog_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static const struct MemoryRegionOps imx7_digprog_ops = { + .read = imx7_set_clr_tog_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx7_ccm_init(Object *obj) +{ + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + IMX7CCMState *s = IMX7_CCM(obj); + + memory_region_init_io(&s->iomem, + obj, + &imx7_set_clr_tog_ops, + s->ccm, + TYPE_IMX7_CCM ".ccm", + sizeof(s->ccm)); + + sysbus_init_mmio(sd, &s->iomem); +} + +static void imx7_analog_init(Object *obj) +{ + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + IMX7AnalogState *s = IMX7_ANALOG(obj); + + memory_region_init(&s->mmio.container, obj, TYPE_IMX7_ANALOG, + 0x10000); + + memory_region_init_io(&s->mmio.analog, + obj, + &imx7_set_clr_tog_ops, + s->analog, + TYPE_IMX7_ANALOG, + sizeof(s->analog)); + + memory_region_add_subregion(&s->mmio.container, + 0x60, &s->mmio.analog); + + memory_region_init_io(&s->mmio.pmu, + obj, + &imx7_set_clr_tog_ops, + s->pmu, + TYPE_IMX7_ANALOG ".pmu", + sizeof(s->pmu)); + + memory_region_add_subregion(&s->mmio.container, + 0x200, &s->mmio.pmu); + + memory_region_init_io(&s->mmio.digprog, + obj, + &imx7_digprog_ops, + &s->analog[ANALOG_DIGPROG], + TYPE_IMX7_ANALOG ".digprog", + sizeof(uint32_t)); + + memory_region_add_subregion_overlap(&s->mmio.container, + 0x800, &s->mmio.digprog, 10); + + + sysbus_init_mmio(sd, &s->mmio.container); +} + +static const VMStateDescription vmstate_imx7_ccm = { + .name = TYPE_IMX7_CCM, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(ccm, IMX7CCMState, CCM_MAX), + VMSTATE_END_OF_LIST() + }, +}; + +static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) +{ + /* + * This function is "consumed" by GPT emulation code, however on + * i.MX7 each GPT block can have their own clock root. This means + * that this functions needs somehow to know requester's identity + * and the way to pass it: be it via additional IMXClk constants + * or by adding another argument to this method needs to be + * figured out + */ + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n", + TYPE_IMX7_CCM, __func__); + return 0; +} + +static void imx7_ccm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + IMXCCMClass *ccm = IMX_CCM_CLASS(klass); + + dc->reset = imx7_ccm_reset; + dc->vmsd = &vmstate_imx7_ccm; + dc->desc = "i.MX7 Clock Control Module"; + + ccm->get_clock_frequency = imx7_ccm_get_clock_frequency; +} + +static const TypeInfo imx7_ccm_info = { + .name = TYPE_IMX7_CCM, + .parent = TYPE_IMX_CCM, + .instance_size = sizeof(IMX7CCMState), + .instance_init = imx7_ccm_init, + .class_init = imx7_ccm_class_init, +}; + +static const VMStateDescription vmstate_imx7_analog = { + .name = TYPE_IMX7_ANALOG, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(analog, IMX7AnalogState, ANALOG_MAX), + VMSTATE_UINT32_ARRAY(pmu, IMX7AnalogState, PMU_MAX), + VMSTATE_END_OF_LIST() + }, +}; + +static void imx7_analog_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = imx7_analog_reset; + dc->vmsd = &vmstate_imx7_analog; + dc->desc = "i.MX7 Analog Module"; +} + +static const TypeInfo imx7_analog_info = { + .name = TYPE_IMX7_ANALOG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX7AnalogState), + .instance_init = imx7_analog_init, + .class_init = imx7_analog_class_init, +}; + +static void imx7_ccm_register_type(void) +{ + type_register_static(&imx7_ccm_info); + type_register_static(&imx7_analog_info); +} +type_init(imx7_ccm_register_type) diff --git a/hw/misc/imx7_gpr.c b/hw/misc/imx7_gpr.c new file mode 100644 index 0000000000..c2a9df29c6 --- /dev/null +++ b/hw/misc/imx7_gpr.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * i.MX7 GPR IP block emulation code + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Bare minimum emulation code needed to support being able to shut + * down linux guest gracefully. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_gpr.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +#include "trace.h" + +enum IMX7GPRRegisters { + IOMUXC_GPR0 = 0x00, + IOMUXC_GPR1 = 0x04, + IOMUXC_GPR2 = 0x08, + IOMUXC_GPR3 = 0x0c, + IOMUXC_GPR4 = 0x10, + IOMUXC_GPR5 = 0x14, + IOMUXC_GPR6 = 0x18, + IOMUXC_GPR7 = 0x1c, + IOMUXC_GPR8 = 0x20, + IOMUXC_GPR9 = 0x24, + IOMUXC_GPR10 = 0x28, + IOMUXC_GPR11 = 0x2c, + IOMUXC_GPR12 = 0x30, + IOMUXC_GPR13 = 0x34, + IOMUXC_GPR14 = 0x38, + IOMUXC_GPR15 = 0x3c, + IOMUXC_GPR16 = 0x40, + IOMUXC_GPR17 = 0x44, + IOMUXC_GPR18 = 0x48, + IOMUXC_GPR19 = 0x4c, + IOMUXC_GPR20 = 0x50, + IOMUXC_GPR21 = 0x54, + IOMUXC_GPR22 = 0x58, +}; + +#define IMX7D_GPR1_IRQ_MASK BIT(12) +#define IMX7D_GPR1_ENET1_TX_CLK_SEL_MASK BIT(13) +#define IMX7D_GPR1_ENET2_TX_CLK_SEL_MASK BIT(14) +#define IMX7D_GPR1_ENET_TX_CLK_SEL_MASK (0x3 << 13) +#define IMX7D_GPR1_ENET1_CLK_DIR_MASK BIT(17) +#define IMX7D_GPR1_ENET2_CLK_DIR_MASK BIT(18) +#define IMX7D_GPR1_ENET_CLK_DIR_MASK (0x3 << 17) + +#define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI BIT(4) +#define IMX7D_GPR12_PCIE_PHY_REFCLK_SEL BIT(5) +#define IMX7D_GPR22_PCIE_PHY_PLL_LOCKED BIT(31) + + +static uint64_t imx7_gpr_read(void *opaque, hwaddr offset, unsigned size) +{ + trace_imx7_gpr_read(offset); + + if (offset == IOMUXC_GPR22) { + return IMX7D_GPR22_PCIE_PHY_PLL_LOCKED; + } + + return 0; +} + +static void imx7_gpr_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + trace_imx7_gpr_write(offset, v); +} + +static const struct MemoryRegionOps imx7_gpr_ops = { + .read = imx7_gpr_read, + .write = imx7_gpr_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx7_gpr_init(Object *obj) +{ + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + IMX7GPRState *s = IMX7_GPR(obj); + + memory_region_init_io(&s->mmio, obj, &imx7_gpr_ops, s, + TYPE_IMX7_GPR, 64 * 1024); + sysbus_init_mmio(sd, &s->mmio); +} + +static void imx7_gpr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "i.MX7 General Purpose Registers Module"; +} + +static const TypeInfo imx7_gpr_info = { + .name = TYPE_IMX7_GPR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX7GPRState), + .instance_init = imx7_gpr_init, + .class_init = imx7_gpr_class_init, +}; + +static void imx7_gpr_register_type(void) +{ + type_register_static(&imx7_gpr_info); +} +type_init(imx7_gpr_register_type) diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c new file mode 100644 index 0000000000..4df482b282 --- /dev/null +++ b/hw/misc/imx7_snvs.c @@ -0,0 +1,83 @@ +/* + * IMX7 Secure Non-Volatile Storage + * + * Copyright (c) 2018, Impinj, Inc. + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Bare minimum emulation code needed to support being able to shut + * down linux guest gracefully. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_snvs.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size) +{ + return 0; +} + +static void imx7_snvs_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + const uint32_t value = v; + const uint32_t mask = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN; + + if (offset == SNVS_LPCR && ((value & mask) == mask)) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } +} + +static const struct MemoryRegionOps imx7_snvs_ops = { + .read = imx7_snvs_read, + .write = imx7_snvs_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx7_snvs_init(Object *obj) +{ + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + IMX7SNVSState *s = IMX7_SNVS(obj); + + memory_region_init_io(&s->mmio, obj, &imx7_snvs_ops, s, + TYPE_IMX7_SNVS, 0x1000); + + sysbus_init_mmio(sd, &s->mmio); +} + +static void imx7_snvs_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "i.MX7 Secure Non-Volatile Storage Module"; +} + +static const TypeInfo imx7_snvs_info = { + .name = TYPE_IMX7_SNVS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX7SNVSState), + .instance_init = imx7_snvs_init, + .class_init = imx7_snvs_class_init, +}; + +static void imx7_snvs_register_type(void) +{ + type_register_static(&imx7_snvs_info); +} +type_init(imx7_snvs_register_type) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 008d8bd4d5..a185252144 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -145,21 +145,29 @@ static void cuda_update_irq(CUDAState *s) } } -static uint64_t get_tb(uint64_t time, uint64_t freq) +static uint64_t get_counter_value(CUDAState *s, CUDATimer *ti) { - return muldiv64(time, freq, NANOSECONDS_PER_SECOND); + /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup */ + uint64_t tb_diff = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + s->tb_frequency, NANOSECONDS_PER_SECOND) - + ti->load_time; + + return (tb_diff * 0xBF401675E5DULL) / (s->tb_frequency << 24); } -static unsigned int get_counter(CUDATimer *ti) +static uint64_t get_counter_load_time(CUDAState *s, CUDATimer *ti) +{ + uint64_t load_time = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + s->tb_frequency, NANOSECONDS_PER_SECOND); + return load_time; +} + +static unsigned int get_counter(CUDAState *s, CUDATimer *ti) { int64_t d; unsigned int counter; - uint64_t tb_diff; - uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */ - tb_diff = get_tb(current_time, ti->frequency) - ti->load_time; - d = (tb_diff * 0xBF401675E5DULL) / (ti->frequency << 24); + d = get_counter_value(s, ti); if (ti->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ @@ -178,42 +186,42 @@ static unsigned int get_counter(CUDATimer *ti) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { CUDA_DPRINTF("T%d.counter=%d\n", 1 + ti->index, val); - ti->load_time = get_tb(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - s->frequency); + ti->load_time = get_counter_load_time(s, ti); ti->counter_value = val; cuda_timer_update(s, ti, ti->load_time); } -static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) +static int64_t get_next_irq_time(CUDATimer *ti, int64_t current_time) { int64_t d, next_time; unsigned int counter; /* current counter value */ - d = muldiv64(current_time - s->load_time, - CUDA_TIMER_FREQ, NANOSECONDS_PER_SECOND); + d = muldiv64(current_time - ti->load_time, + ti->frequency, NANOSECONDS_PER_SECOND); /* the timer goes down from latch to -1 (period of latch + 2) */ - if (d <= (s->counter_value + 1)) { - counter = (s->counter_value - d) & 0xffff; + if (d <= (ti->counter_value + 1)) { + counter = (ti->counter_value - d) & 0xffff; } else { - counter = (d - (s->counter_value + 1)) % (s->latch + 2); - counter = (s->latch - counter) & 0xffff; + counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); + counter = (ti->latch - counter) & 0xffff; } /* Note: we consider the irq is raised on 0 */ if (counter == 0xffff) { - next_time = d + s->latch + 1; + next_time = d + ti->latch + 1; } else if (counter == 0) { - next_time = d + s->latch + 2; + next_time = d + ti->latch + 2; } else { next_time = d + counter; } CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", - s->latch, d, next_time - d); - next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, CUDA_TIMER_FREQ) + - s->load_time; - if (next_time <= current_time) + ti->latch, d, next_time - d); + next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) + + ti->load_time; + if (next_time <= current_time) { next_time = current_time + 1; + } return next_time; } @@ -275,7 +283,7 @@ static void cuda_delay_set_sr_int(CUDAState *s) timer_mod(s->sr_delay_timer, expire); } -static uint32_t cuda_readb(void *opaque, hwaddr addr) +static uint64_t cuda_read(void *opaque, hwaddr addr, unsigned size) { CUDAState *s = opaque; uint32_t val; @@ -295,12 +303,12 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) val = s->dira; break; case CUDA_REG_T1CL: - val = get_counter(&s->timers[0]) & 0xff; + val = get_counter(s, &s->timers[0]) & 0xff; s->ifr &= ~T1_INT; cuda_update_irq(s); break; case CUDA_REG_T1CH: - val = get_counter(&s->timers[0]) >> 8; + val = get_counter(s, &s->timers[0]) >> 8; cuda_update_irq(s); break; case CUDA_REG_T1LL: @@ -311,12 +319,12 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) val = (s->timers[0].latch >> 8) & 0xff; break; case CUDA_REG_T2CL: - val = get_counter(&s->timers[1]) & 0xff; + val = get_counter(s, &s->timers[1]) & 0xff; s->ifr &= ~T2_INT; cuda_update_irq(s); break; case CUDA_REG_T2CH: - val = get_counter(&s->timers[1]) >> 8; + val = get_counter(s, &s->timers[1]) >> 8; break; case CUDA_REG_SR: val = s->sr; @@ -350,7 +358,7 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) return val; } -static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) +static void cuda_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { CUDAState *s = opaque; @@ -359,11 +367,11 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) switch(addr) { case CUDA_REG_B: - s->b = val; + s->b = (s->b & ~s->dirb) | (val & s->dirb); cuda_update(s); break; case CUDA_REG_A: - s->a = val; + s->a = (s->a & ~s->dira) | (val & s->dira); break; case CUDA_REG_DIRB: s->dirb = val; @@ -406,7 +414,6 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) case CUDA_REG_ACR: s->acr = val; cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); - cuda_update(s); break; case CUDA_REG_PCR: s->pcr = val; @@ -780,38 +787,14 @@ static void cuda_receive_packet_from_host(CUDAState *s, } } -static void cuda_writew (void *opaque, hwaddr addr, uint32_t value) -{ -} - -static void cuda_writel (void *opaque, hwaddr addr, uint32_t value) -{ -} - -static uint32_t cuda_readw (void *opaque, hwaddr addr) -{ - return 0; -} - -static uint32_t cuda_readl (void *opaque, hwaddr addr) -{ - return 0; -} - static const MemoryRegionOps cuda_ops = { - .old_mmio = { - .write = { - cuda_writeb, - cuda_writew, - cuda_writel, - }, - .read = { - cuda_readb, - cuda_readw, - cuda_readl, - }, + .read = cuda_read, + .write = cuda_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, }, - .endianness = DEVICE_NATIVE_ENDIAN, }; static bool cuda_timer_exist(void *opaque, int version_id) @@ -903,7 +886,7 @@ static void cuda_realizefn(DeviceState *dev, Error **errp) struct tm tm; s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s); - s->timers[0].frequency = s->frequency; + s->timers[0].frequency = CUDA_TIMER_FREQ; s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer2, s); s->timers[1].frequency = (SCALE_US * 6000) / 4700; @@ -934,7 +917,7 @@ static void cuda_initfn(Object *obj) } static Property cuda_properties[] = { - DEFINE_PROP_UINT64("frequency", CUDAState, frequency, 0), + DEFINE_PROP_UINT64("timebase-frequency", CUDAState, tb_frequency, 0), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 44f91d1e7f..a639b09e00 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -451,7 +451,7 @@ void macio_init(PCIDevice *d, macio_state->escc_mem = escc_mem; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ - qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency", + qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "timebase-frequency", macio_state->frequency); qdev_init_nofail(DEVICE(d)); diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c index 211f6097fd..d019d41a3c 100644 --- a/hw/misc/mips_cmgcr.c +++ b/hw/misc/mips_cmgcr.c @@ -10,7 +10,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu/log.h" #include "hw/hw.h" #include "hw/sysbus.h" diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c new file mode 100644 index 0000000000..8ad9fc831e --- /dev/null +++ b/hw/misc/mos6522.c @@ -0,0 +1,505 @@ +/* + * QEMU MOS6522 VIA emulation + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * Copyright (c) 2018 Mark Cave-Ayland + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/input/adb.h" +#include "hw/misc/mos6522.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "trace.h" + +/* XXX: implement all timer modes */ + +static void mos6522_timer_update(MOS6522State *s, MOS6522Timer *ti, + int64_t current_time); + +static void mos6522_update_irq(MOS6522State *s) +{ + if (s->ifr & s->ier & (SR_INT | T1_INT | T2_INT)) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti) +{ + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + if (ti->index == 0) { + return mdc->get_timer1_counter_value(s, ti); + } else { + return mdc->get_timer2_counter_value(s, ti); + } +} + +static uint64_t get_load_time(MOS6522State *s, MOS6522Timer *ti) +{ + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + if (ti->index == 0) { + return mdc->get_timer1_load_time(s, ti); + } else { + return mdc->get_timer2_load_time(s, ti); + } +} + +static unsigned int get_counter(MOS6522State *s, MOS6522Timer *ti) +{ + int64_t d; + unsigned int counter; + + d = get_counter_value(s, ti); + + if (ti->index == 0) { + /* the timer goes down from latch to -1 (period of latch + 2) */ + if (d <= (ti->counter_value + 1)) { + counter = (ti->counter_value - d) & 0xffff; + } else { + counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); + counter = (ti->latch - counter) & 0xffff; + } + } else { + counter = (ti->counter_value - d) & 0xffff; + } + return counter; +} + +static void set_counter(MOS6522State *s, MOS6522Timer *ti, unsigned int val) +{ + trace_mos6522_set_counter(1 + ti->index, val); + ti->load_time = get_load_time(s, ti); + ti->counter_value = val; + mos6522_timer_update(s, ti, ti->load_time); +} + +static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti, + int64_t current_time) +{ + int64_t d, next_time; + unsigned int counter; + + /* current counter value */ + d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time, + ti->frequency, NANOSECONDS_PER_SECOND); + + /* the timer goes down from latch to -1 (period of latch + 2) */ + if (d <= (ti->counter_value + 1)) { + counter = (ti->counter_value - d) & 0xffff; + } else { + counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); + counter = (ti->latch - counter) & 0xffff; + } + + /* Note: we consider the irq is raised on 0 */ + if (counter == 0xffff) { + next_time = d + ti->latch + 1; + } else if (counter == 0) { + next_time = d + ti->latch + 2; + } else { + next_time = d + counter; + } + trace_mos6522_get_next_irq_time(ti->latch, d, next_time - d); + next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, ti->frequency) + + ti->load_time; + if (next_time <= current_time) { + next_time = current_time + 1; + } + return next_time; +} + +static void mos6522_timer_update(MOS6522State *s, MOS6522Timer *ti, + int64_t current_time) +{ + if (!ti->timer) { + return; + } + if (ti->index == 0 && (s->acr & T1MODE) != T1MODE_CONT) { + timer_del(ti->timer); + } else { + ti->next_irq_time = get_next_irq_time(s, ti, current_time); + timer_mod(ti->timer, ti->next_irq_time); + } +} + +static void mos6522_timer1(void *opaque) +{ + MOS6522State *s = opaque; + MOS6522Timer *ti = &s->timers[0]; + + mos6522_timer_update(s, ti, ti->next_irq_time); + s->ifr |= T1_INT; + mos6522_update_irq(s); +} + +static void mos6522_timer2(void *opaque) +{ + MOS6522State *s = opaque; + MOS6522Timer *ti = &s->timers[1]; + + mos6522_timer_update(s, ti, ti->next_irq_time); + s->ifr |= T2_INT; + mos6522_update_irq(s); +} + +static void mos6522_set_sr_int(MOS6522State *s) +{ + trace_mos6522_set_sr_int(); + s->ifr |= SR_INT; + mos6522_update_irq(s); +} + +static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti) +{ + uint64_t d; + + d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time, + ti->frequency, NANOSECONDS_PER_SECOND); + + return d; +} + +static uint64_t mos6522_get_load_time(MOS6522State *s, MOS6522Timer *ti) +{ + uint64_t load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + return load_time; +} + +static void mos6522_portA_write(MOS6522State *s) +{ + qemu_log_mask(LOG_UNIMP, "portA_write unimplemented"); +} + +static void mos6522_portB_write(MOS6522State *s) +{ + qemu_log_mask(LOG_UNIMP, "portB_write unimplemented"); +} + +uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size) +{ + MOS6522State *s = opaque; + uint32_t val; + + switch (addr) { + case VIA_REG_B: + val = s->b; + break; + case VIA_REG_A: + val = s->a; + break; + case VIA_REG_DIRB: + val = s->dirb; + break; + case VIA_REG_DIRA: + val = s->dira; + break; + case VIA_REG_T1CL: + val = get_counter(s, &s->timers[0]) & 0xff; + s->ifr &= ~T1_INT; + mos6522_update_irq(s); + break; + case VIA_REG_T1CH: + val = get_counter(s, &s->timers[0]) >> 8; + mos6522_update_irq(s); + break; + case VIA_REG_T1LL: + val = s->timers[0].latch & 0xff; + break; + case VIA_REG_T1LH: + /* XXX: check this */ + val = (s->timers[0].latch >> 8) & 0xff; + break; + case VIA_REG_T2CL: + val = get_counter(s, &s->timers[1]) & 0xff; + s->ifr &= ~T2_INT; + mos6522_update_irq(s); + break; + case VIA_REG_T2CH: + val = get_counter(s, &s->timers[1]) >> 8; + break; + case VIA_REG_SR: + val = s->sr; + s->ifr &= ~(SR_INT | CB1_INT | CB2_INT); + mos6522_update_irq(s); + break; + case VIA_REG_ACR: + val = s->acr; + break; + case VIA_REG_PCR: + val = s->pcr; + break; + case VIA_REG_IFR: + val = s->ifr; + if (s->ifr & s->ier) { + val |= 0x80; + } + break; + case VIA_REG_IER: + val = s->ier | 0x80; + break; + default: + case VIA_REG_ANH: + val = s->anh; + break; + } + + if (addr != VIA_REG_IFR || val != 0) { + trace_mos6522_read(addr, val); + } + + return val; +} + +void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + MOS6522State *s = opaque; + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + trace_mos6522_write(addr, val); + + switch (addr) { + case VIA_REG_B: + s->b = (s->b & ~s->dirb) | (val & s->dirb); + mdc->portB_write(s); + break; + case VIA_REG_A: + s->a = (s->a & ~s->dira) | (val & s->dira); + mdc->portA_write(s); + break; + case VIA_REG_DIRB: + s->dirb = val; + break; + case VIA_REG_DIRA: + s->dira = val; + break; + case VIA_REG_T1CL: + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; + mos6522_timer_update(s, &s->timers[0], + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + break; + case VIA_REG_T1CH: + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + s->ifr &= ~T1_INT; + set_counter(s, &s->timers[0], s->timers[0].latch); + break; + case VIA_REG_T1LL: + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; + mos6522_timer_update(s, &s->timers[0], + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + break; + case VIA_REG_T1LH: + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + s->ifr &= ~T1_INT; + mos6522_timer_update(s, &s->timers[0], + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + break; + case VIA_REG_T2CL: + s->timers[1].latch = (s->timers[1].latch & 0xff00) | val; + break; + case VIA_REG_T2CH: + /* To ensure T2 generates an interrupt on zero crossing with the + common timer code, write the value directly from the latch to + the counter */ + s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8); + s->ifr &= ~T2_INT; + set_counter(s, &s->timers[1], s->timers[1].latch); + break; + case VIA_REG_SR: + s->sr = val; + break; + case VIA_REG_ACR: + s->acr = val; + mos6522_timer_update(s, &s->timers[0], + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + break; + case VIA_REG_PCR: + s->pcr = val; + break; + case VIA_REG_IFR: + /* reset bits */ + s->ifr &= ~val; + mos6522_update_irq(s); + break; + case VIA_REG_IER: + if (val & IER_SET) { + /* set bits */ + s->ier |= val & 0x7f; + } else { + /* reset bits */ + s->ier &= ~val; + } + mos6522_update_irq(s); + break; + default: + case VIA_REG_ANH: + s->anh = val; + break; + } +} + +static const MemoryRegionOps mos6522_ops = { + .read = mos6522_read, + .write = mos6522_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static bool mos6522_timer_exist(void *opaque, int version_id) +{ + MOS6522Timer *s = opaque; + + return s->timer != NULL; +} + +static const VMStateDescription vmstate_mos6522_timer = { + .name = "mos6522_timer", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT16(latch, MOS6522Timer), + VMSTATE_UINT16(counter_value, MOS6522Timer), + VMSTATE_INT64(load_time, MOS6522Timer), + VMSTATE_INT64(next_irq_time, MOS6522Timer), + VMSTATE_TIMER_PTR_TEST(timer, MOS6522Timer, mos6522_timer_exist), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_mos6522 = { + .name = "mos6522", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(a, MOS6522State), + VMSTATE_UINT8(b, MOS6522State), + VMSTATE_UINT8(dira, MOS6522State), + VMSTATE_UINT8(dirb, MOS6522State), + VMSTATE_UINT8(sr, MOS6522State), + VMSTATE_UINT8(acr, MOS6522State), + VMSTATE_UINT8(pcr, MOS6522State), + VMSTATE_UINT8(ifr, MOS6522State), + VMSTATE_UINT8(ier, MOS6522State), + VMSTATE_UINT8(anh, MOS6522State), + VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 1, + vmstate_mos6522_timer, MOS6522Timer), + VMSTATE_END_OF_LIST() + } +}; + +static void mos6522_reset(DeviceState *dev) +{ + MOS6522State *s = MOS6522(dev); + + s->b = 0; + s->a = 0; + s->dirb = 0xff; + s->dira = 0; + s->sr = 0; + s->acr = 0; + s->pcr = 0; + s->ifr = 0; + s->ier = 0; + /* s->ier = T1_INT | SR_INT; */ + s->anh = 0; + + s->timers[0].latch = 0xffff; + set_counter(s, &s->timers[0], 0xffff); + + s->timers[1].latch = 0xffff; +} + +static void mos6522_realize(DeviceState *dev, Error **errp) +{ + MOS6522State *s = MOS6522(dev); + + s->timers[0].frequency = s->frequency; + s->timers[1].frequency = s->frequency; +} + +static void mos6522_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + MOS6522State *s = MOS6522(obj); + int i; + + memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522", 0x10); + sysbus_init_mmio(sbd, &s->mem); + sysbus_init_irq(sbd, &s->irq); + + for (i = 0; i < ARRAY_SIZE(s->timers); i++) { + s->timers[i].index = i; + } + + s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer1, s); + s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer2, s); +} + +static Property mos6522_properties[] = { + DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void mos6522_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); + + dc->realize = mos6522_realize; + dc->reset = mos6522_reset; + dc->vmsd = &vmstate_mos6522; + dc->props = mos6522_properties; + mdc->parent_realize = dc->realize; + mdc->set_sr_int = mos6522_set_sr_int; + mdc->portB_write = mos6522_portB_write; + mdc->portA_write = mos6522_portA_write; + mdc->get_timer1_counter_value = mos6522_get_counter_value; + mdc->get_timer2_counter_value = mos6522_get_counter_value; + mdc->get_timer1_load_time = mos6522_get_load_time; + mdc->get_timer2_load_time = mos6522_get_load_time; +} + +static const TypeInfo mos6522_type_info = { + .name = TYPE_MOS6522, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MOS6522State), + .instance_init = mos6522_init, + .abstract = true, + .class_size = sizeof(MOS6522DeviceClass), + .class_init = mos6522_class_init, +}; + +static void mos6522_register_types(void) +{ + type_register_static(&mos6522_type_info); +} + +type_init(mos6522_register_types) diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c index 32be2a9df1..6a9d251f18 100644 --- a/hw/misc/mps2-scc.c +++ b/hw/misc/mps2-scc.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "qapi/error.h" #include "trace.h" #include "hw/sysbus.h" #include "hw/registerfields.h" diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 616579a403..b340d4e81c 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -66,3 +66,14 @@ mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC msf2_sysreg_write(uint64_t offset, uint32_t val, uint32_t prev) "msf2-sysreg write: addr 0x%08" HWADDR_PRIx " data 0x%" PRIx32 " prev 0x%" PRIx32 msf2_sysreg_read(uint64_t offset, uint32_t val) "msf2-sysreg read: addr 0x%08" HWADDR_PRIx " data 0x%08" PRIx32 msf2_sysreg_write_pll_status(void) "Invalid write to read only PLL status register" + +#hw/misc/imx7_gpr.c +imx7_gpr_read(uint64_t offset) "addr 0x%08" HWADDR_PRIx +imx7_gpr_write(uint64_t offset, uint64_t value) "addr 0x%08" HWADDR_PRIx "value 0x%08" HWADDR_PRIx + +# hw/misc/mos6522.c +mos6522_set_counter(int index, unsigned int val) "T%d.counter=%d" +mos6522_get_next_irq_time(uint16_t latch, int64_t d, int64_t delta) "latch=%d counter=0x%"PRId64 " delta_next=0x%"PRId64 +mos6522_set_sr_int(void) "set sr_int" +mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 +mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" diff --git a/hw/net/rocker/qmp-norocker.c b/hw/net/rocker/qmp-norocker.c index 6acbcdb02b..94c1e480ae 100644 --- a/hw/net/rocker/qmp-norocker.c +++ b/hw/net/rocker/qmp-norocker.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qmp-commands.h" +#include "qapi/error.h" #include "qapi/qmp/qerror.h" RockerSwitch *qmp_query_rocker(const char *name, Error **errp) diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 823a29df03..a2a76c2a74 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -21,6 +21,7 @@ #include "hw/pci/msix.h" #include "net/net.h" #include "net/eth.h" +#include "qapi/error.h" #include "qemu/iov.h" #include "qemu/bitops.h" #include "qmp-commands.h" diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 191a58e0a7..9339df2d09 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -16,6 +16,7 @@ #include "qemu/osdep.h" #include "net/eth.h" +#include "qapi/error.h" #include "qemu/iov.h" #include "qemu/timer.h" #include "qmp-commands.h" diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 38674b08aa..369d40b378 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -22,7 +22,7 @@ #include "hw/virtio/virtio-net.h" #include "net/vhost_net.h" #include "hw/virtio/virtio-bus.h" -#include "qapi/qmp/qjson.h" +#include "qapi/error.h" #include "qapi-event.h" #include "hw/virtio/virtio-access.h" #include "migration/misc.h" diff --git a/hw/nios2/cpu_pic.c b/hw/nios2/cpu_pic.c index 0f95987ef3..6bccce2f32 100644 --- a/hw/nios2/cpu_pic.c +++ b/hw/nios2/cpu_pic.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index efa3621ac6..22183f5360 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -7,9 +7,8 @@ * the LICENSE file in the top-level directory. */ -#include <string.h> - #include "qemu/osdep.h" + #include "qapi/error.h" #include "hw/hw.h" #include "hw/i2c/i2c.h" diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 4313484b21..2a0739d0e9 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "hw/hw.h" #include "sysemu/sysemu.h" @@ -31,6 +32,7 @@ #include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/cutils.h" #include "qapi/error.h" diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index 620b43518e..10e590e5c6 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -44,8 +44,6 @@ #include "qemu/osdep.h" #include "hw/pci/pci.h" #include "hw/i386/ich9.h" -#include "qapi/error.h" - /*****************************************************************************/ /* ICH9 DMI-to-PCI bridge */ diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index a7bfbdd238..a451d74ee6 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -25,7 +25,6 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "ioh3420.h" -#include "qapi/error.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ #define PCI_DEVICE_ID_IOH_REV 0x2 diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 556f471a83..bca2f9a5ea 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -24,7 +24,6 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "xio3130_upstream.h" -#include "qapi/error.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ #define XIO3130_REVISION 0x2 diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index 2268a41dd9..e2f4ee480e 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -34,7 +34,6 @@ #include "hw/pci-host/sabre.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -#include "qapi/error.h" #include "qemu/log.h" #include "trace.h" diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c index d5ce00748e..74ce7316da 100644 --- a/hw/pci/pci-stub.c +++ b/hw/pci/pci-stub.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" #include "monitor/monitor.h" +#include "qapi/error.h" #include "qapi/qmp/qerror.h" #include "hw/pci/pci.h" #include "qmp-commands.h" diff --git a/hw/pci/pci.c b/hw/pci/pci.c index ef4342293e..e006b6ac71 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/pci.h" @@ -40,6 +41,7 @@ #include "exec/address-spaces.h" #include "hw/hotplug.h" #include "hw/boards.h" +#include "qapi/error.h" #include "qemu/cutils.h" //#define DEBUG_PCI diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index b009be7f17..939da0b778 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -20,8 +20,7 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" -#include "qapi/qmp/types.h" -#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qdict.h" #include "monitor/monitor.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pcie.h" diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 343bba93ce..a40d3ec3e3 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -16,7 +16,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "e500.h" #include "e500-ccsr.h" #include "net/net.h" @@ -36,6 +35,7 @@ #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "qemu/host-utils.h" +#include "qemu/option.h" #include "hw/pci-host/ppce500.h" #include "qemu/error-report.h" #include "hw/platform-bus.h" diff --git a/hw/ppc/fdt.c b/hw/ppc/fdt.c index 38a7234b46..2ffc5866e4 100644 --- a/hw/ppc/fdt.c +++ b/hw/ppc/fdt.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "target/ppc/cpu.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index b501af1653..fa78115c95 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -99,7 +99,7 @@ typedef struct CUDAState { CUDATimer timers[2]; uint32_t tick_offset; - uint64_t frequency; + uint64_t tb_frequency; uint8_t last_b; uint8_t last_acr; diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index b2cf441ee7..4b76d34f0a 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -20,7 +20,6 @@ #include "hw/hw.h" #include "sysemu/sysemu.h" #include "target/ppc/cpu.h" -#include "qapi/error.h" #include "qemu/log.h" #include "hw/ipmi/ipmi.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 99c40efecd..46fae41f32 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -17,7 +17,6 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "hw/hw.h" #include "qemu/log.h" #include "sysemu/hw_accel.h" diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 7ec35de5ae..ec4be25f49 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -33,7 +33,6 @@ #include "hw/timer/m48t59.h" #include "qemu/log.h" #include "qemu/error-report.h" -#include "qapi/error.h" #include "hw/loader.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 32a876be56..9f29434819 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -74,7 +74,6 @@ #include "hw/compat.h" #include "qemu/cutils.h" #include "hw/ppc/spapr_cpu_core.h" -#include "qmp-commands.h" #include <libfdt.h> @@ -465,7 +464,8 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt) } } if (!mem_start) { - /* ppc_spapr_init() checks for rma_size <= node0_size already */ + /* spapr_machine_init() checks for rma_size <= node0_size + * already */ spapr_populate_memory_node(fdt, i, 0, spapr->rma_size); mem_start += spapr->rma_size; node_size -= spapr->rma_size; @@ -2310,7 +2310,7 @@ static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) * the value that we'd get with KVM on POWER8, the * overwhelmingly common case in production systems. */ - spapr->vsmt = 8; + spapr->vsmt = MAX(8, smp_threads); } /* KVM: If necessary, set the SMT mode: */ diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index e3b122968e..aa251133de 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qmp/qnull.h" #include "cpu.h" #include "qemu/cutils.h" #include "hw/ppc/spapr_drc.h" diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 4d0e6eb0cf..76422cfac1 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1635,7 +1635,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); if (!spapr->cas_reboot) { - /* If ppc_spapr_reset() did not set up a HPT but one is necessary + /* If spapr_machine_reset() did not set up a HPT but one is necessary * (because the guest isn't going to use radix) then set it up here. */ if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) { /* legacy hash or new hash: */ @@ -1697,6 +1697,7 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, switch (safe_indirect_branch) { case SPAPR_CAP_FIXED: characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED; + break; default: /* broken */ assert(safe_indirect_branch == SPAPR_CAP_BROKEN); break; diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 053efb03bd..71491dbd28 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include <linux/vfio.h> -#include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" #include "hw/ppc/spapr.h" diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c index 9ec3078691..cfdb274bfd 100644 --- a/hw/ppc/spapr_rtc.c +++ b/hw/ppc/spapr_rtc.c @@ -23,14 +23,15 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * */ + #include "qemu/osdep.h" #include "cpu.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "hw/ppc/spapr.h" #include "qapi-event.h" +#include "qapi/error.h" #include "qemu/cutils.h" void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns) diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 485d9affb2..77a1778e07 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -37,6 +37,7 @@ #include "elf.h" #include "qemu/error-report.h" #include "qemu/log.h" +#include "qemu/option.h" #include "exec/address-spaces.h" #include "hw/ppc/ppc.h" diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 1c526fd7e2..301bf1772f 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -439,7 +439,7 @@ static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr, bool do_map) { S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map); } @@ -520,7 +520,7 @@ void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable, int ret, isc; IoAdapter *adapter; S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); /* * Disallow multiple registrations for the same device type. @@ -566,7 +566,7 @@ static void css_clear_io_interrupt(uint16_t subchannel_id, Error *err = NULL; static bool no_clear_irq; S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); int r; if (unlikely(no_clear_irq)) { @@ -640,7 +640,7 @@ void css_conditional_io_interrupt(SubchDev *sch) int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode) { S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); int r; if (env->psw.mask & PSW_MASK_PSTATE) { @@ -666,7 +666,7 @@ out: void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc) { S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; IoAdapter *adapter = channel_subsys.io_adapters[type][isc]; diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index b0f71f4554..155a69467b 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -293,10 +293,10 @@ static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb) ef->receive_mask = be32_to_cpu(tmp_mask); /* return the SCLP's capability masks to the guest */ - tmp_mask = cpu_to_be32(get_host_send_mask(ef)); + tmp_mask = cpu_to_be32(get_host_receive_mask(ef)); copy_mask(WEM_RECEIVE_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask, mask_length, sizeof(tmp_mask)); - tmp_mask = cpu_to_be32(get_host_receive_mask(ef)); + tmp_mask = cpu_to_be32(get_host_send_mask(ef)); copy_mask(WEM_SEND_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask, mask_length, sizeof(tmp_mask)); diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 4a9d4d2534..7fc1c603c0 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -10,10 +10,11 @@ * or (at your option) any later version. See the COPYING file in the * top-level directory. */ + #include "qemu/osdep.h" +#include <libgen.h> #include "qapi/error.h" #include "hw/sysbus.h" -#include "libgen.h" #include "hw/s390x/css.h" #include "hw/s390x/css-bridge.h" #include "hw/s390x/s390-ccw.h" diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 7d9c65e719..77a50cab36 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -309,49 +309,187 @@ static uint64_t get_st_pto(uint64_t entry) : 0; } -static uint64_t s390_guest_io_table_walk(uint64_t guest_iota, - uint64_t guest_dma_address) +static bool rt_entry_isvalid(uint64_t entry) { - uint64_t sto_a, pto_a, px_a; - uint64_t sto, pto, pte; - uint32_t rtx, sx, px; - - rtx = calc_rtx(guest_dma_address); - sx = calc_sx(guest_dma_address); - px = calc_px(guest_dma_address); - - sto_a = guest_iota + rtx * sizeof(uint64_t); - sto = address_space_ldq(&address_space_memory, sto_a, - MEMTXATTRS_UNSPECIFIED, NULL); - sto = get_rt_sto(sto); - if (!sto) { - pte = 0; + return (entry & ZPCI_TABLE_VALID_MASK) == ZPCI_TABLE_VALID; +} + +static bool pt_entry_isvalid(uint64_t entry) +{ + return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID; +} + +static bool entry_isprotected(uint64_t entry) +{ + return (entry & ZPCI_TABLE_PROT_MASK) == ZPCI_TABLE_PROTECTED; +} + +/* ett is expected table type, -1 page table, 0 segment table, 1 region table */ +static uint64_t get_table_index(uint64_t iova, int8_t ett) +{ + switch (ett) { + case ZPCI_ETT_PT: + return calc_px(iova); + case ZPCI_ETT_ST: + return calc_sx(iova); + case ZPCI_ETT_RT: + return calc_rtx(iova); + } + + return -1; +} + +static bool entry_isvalid(uint64_t entry, int8_t ett) +{ + switch (ett) { + case ZPCI_ETT_PT: + return pt_entry_isvalid(entry); + case ZPCI_ETT_ST: + case ZPCI_ETT_RT: + return rt_entry_isvalid(entry); + } + + return false; +} + +/* Return true if address translation is done */ +static bool translate_iscomplete(uint64_t entry, int8_t ett) +{ + switch (ett) { + case 0: + return (entry & ZPCI_TABLE_FC) ? true : false; + case 1: + return false; + } + + return true; +} + +static uint64_t get_frame_size(int8_t ett) +{ + switch (ett) { + case ZPCI_ETT_PT: + return 1ULL << 12; + case ZPCI_ETT_ST: + return 1ULL << 20; + case ZPCI_ETT_RT: + return 1ULL << 31; + } + + return 0; +} + +static uint64_t get_next_table_origin(uint64_t entry, int8_t ett) +{ + switch (ett) { + case ZPCI_ETT_PT: + return entry & ZPCI_PTE_ADDR_MASK; + case ZPCI_ETT_ST: + return get_st_pto(entry); + case ZPCI_ETT_RT: + return get_rt_sto(entry); + } + + return 0; +} + +/** + * table_translate: do translation within one table and return the following + * table origin + * + * @entry: the entry being translated, the result is stored in this. + * @to: the address of table origin. + * @ett: expected table type, 1 region table, 0 segment table and -1 page table. + * @error: error code + */ +static uint64_t table_translate(S390IOTLBEntry *entry, uint64_t to, int8_t ett, + uint16_t *error) +{ + uint64_t tx, te, nto = 0; + uint16_t err = 0; + + tx = get_table_index(entry->iova, ett); + te = address_space_ldq(&address_space_memory, to + tx * sizeof(uint64_t), + MEMTXATTRS_UNSPECIFIED, NULL); + + if (!te) { + err = ERR_EVENT_INVALTE; + goto out; + } + + if (!entry_isvalid(te, ett)) { + entry->perm &= IOMMU_NONE; + goto out; + } + + if (ett == ZPCI_ETT_RT && ((te & ZPCI_TABLE_LEN_RTX) != ZPCI_TABLE_LEN_RTX + || te & ZPCI_TABLE_OFFSET_MASK)) { + err = ERR_EVENT_INVALTL; goto out; } - pto_a = sto + sx * sizeof(uint64_t); - pto = address_space_ldq(&address_space_memory, pto_a, - MEMTXATTRS_UNSPECIFIED, NULL); - pto = get_st_pto(pto); - if (!pto) { - pte = 0; + nto = get_next_table_origin(te, ett); + if (!nto) { + err = ERR_EVENT_TT; goto out; } - px_a = pto + px * sizeof(uint64_t); - pte = address_space_ldq(&address_space_memory, px_a, - MEMTXATTRS_UNSPECIFIED, NULL); + if (entry_isprotected(te)) { + entry->perm &= IOMMU_RO; + } else { + entry->perm &= IOMMU_RW; + } + if (translate_iscomplete(te, ett)) { + switch (ett) { + case ZPCI_ETT_PT: + entry->translated_addr = te & ZPCI_PTE_ADDR_MASK; + break; + case ZPCI_ETT_ST: + entry->translated_addr = (te & ZPCI_SFAA_MASK) | + (entry->iova & ~ZPCI_SFAA_MASK); + break; + } + nto = 0; + } out: - return pte; + if (err) { + entry->perm = IOMMU_NONE; + *error = err; + } + entry->len = get_frame_size(ett); + return nto; +} + +uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, + S390IOTLBEntry *entry) +{ + uint64_t to = s390_pci_get_table_origin(g_iota); + int8_t ett = 1; + uint16_t error = 0; + + entry->iova = addr & PAGE_MASK; + entry->translated_addr = 0; + entry->perm = IOMMU_RW; + + if (entry_isprotected(g_iota)) { + entry->perm &= IOMMU_RO; + } + + while (to) { + to = table_translate(entry, to, ett--, &error); + } + + return error; } static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag) { - uint64_t pte; - uint32_t flags; S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + S390IOTLBEntry *entry; + uint64_t iova = addr & PAGE_MASK; + uint16_t error = 0; IOMMUTLBEntry ret = { .target_as = &address_space_memory, .iova = 0, @@ -374,26 +512,31 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr); if (addr < iommu->pba || addr > iommu->pal) { - return ret; + error = ERR_EVENT_OORANGE; + goto err; } - pte = s390_guest_io_table_walk(s390_pci_get_table_origin(iommu->g_iota), - addr); - if (!pte) { - return ret; - } - - flags = pte & ZPCI_PTE_FLAG_MASK; - ret.iova = addr; - ret.translated_addr = pte & ZPCI_PTE_ADDR_MASK; - ret.addr_mask = 0xfff; - - if (flags & ZPCI_PTE_INVALID) { - ret.perm = IOMMU_NONE; + entry = g_hash_table_lookup(iommu->iotlb, &iova); + if (entry) { + ret.iova = entry->iova; + ret.translated_addr = entry->translated_addr; + ret.addr_mask = entry->len - 1; + ret.perm = entry->perm; } else { - ret.perm = IOMMU_RW; + ret.iova = iova; + ret.addr_mask = ~PAGE_MASK; + ret.perm = IOMMU_NONE; } + if (flag != IOMMU_NONE && !(flag & ret.perm)) { + error = ERR_EVENT_TPROTE; + } +err: + if (error) { + iommu->pbdev->state = ZPCI_FS_ERROR; + s390_pci_generate_error_event(error, iommu->pbdev->fh, + iommu->pbdev->fid, addr, 0); + } return ret; } @@ -435,6 +578,8 @@ static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, PCI_FUNC(devfn)); memory_region_init(&iommu->mr, OBJECT(iommu), mr_name, UINT64_MAX); address_space_init(&iommu->as, &iommu->mr, as_name); + iommu->iotlb = g_hash_table_new_full(g_int64_hash, g_int64_equal, + NULL, g_free); table->iommu[PCI_SLOT(devfn)] = iommu; g_free(mr_name); @@ -524,6 +669,7 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu) void s390_pci_iommu_disable(S390PCIIOMMU *iommu) { iommu->enabled = false; + g_hash_table_remove_all(iommu->iotlb); memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr)); object_unparent(OBJECT(&iommu->iommu_mr)); } @@ -539,6 +685,7 @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn) } table->iommu[PCI_SLOT(devfn)] = NULL; + g_hash_table_destroy(iommu->iotlb); address_space_destroy(&iommu->as); object_unparent(OBJECT(&iommu->mr)); object_unparent(OBJECT(iommu)); diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 2993f0ddef..1f7f9b5814 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -148,6 +148,8 @@ enum ZpciIoatDtype { #define ZPCI_STE_FLAG_MASK 0x7ffULL #define ZPCI_STE_ADDR_MASK (~ZPCI_STE_FLAG_MASK) +#define ZPCI_SFAA_MASK (~((1ULL << 20) - 1)) + /* I/O Page tables */ #define ZPCI_PTE_VALID_MASK 0x400 #define ZPCI_PTE_INVALID 0x400 @@ -165,10 +167,15 @@ enum ZpciIoatDtype { #define ZPCI_TABLE_INVALID 0x20 #define ZPCI_TABLE_PROTECTED 0x200 #define ZPCI_TABLE_UNPROTECTED 0x000 +#define ZPCI_TABLE_FC 0x400 #define ZPCI_TABLE_VALID_MASK 0x20 #define ZPCI_TABLE_PROT_MASK 0x200 +#define ZPCI_ETT_RT 1 +#define ZPCI_ETT_ST 0 +#define ZPCI_ETT_PT -1 + /* PCI Function States * * reserved: default; device has just been plugged or is in progress of being @@ -253,6 +260,13 @@ typedef struct S390MsixInfo { uint32_t pba_offset; } S390MsixInfo; +typedef struct S390IOTLBEntry { + uint64_t iova; + uint64_t translated_addr; + uint64_t len; + uint64_t perm; +} S390IOTLBEntry; + typedef struct S390PCIBusDevice S390PCIBusDevice; typedef struct S390PCIIOMMU { Object parent_obj; @@ -264,6 +278,7 @@ typedef struct S390PCIIOMMU { uint64_t g_iota; uint64_t pba; uint64_t pal; + GHashTable *iotlb; } S390PCIIOMMU; typedef struct S390PCIIOMMUTable { @@ -320,6 +335,8 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu); void s390_pci_iommu_disable(S390PCIIOMMU *iommu); void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e); +uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, + S390IOTLBEntry *entry); S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx); S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh); S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index be449210d9..3fcc330fe3 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -571,27 +571,65 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } +static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry) +{ + S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); + IOMMUTLBEntry notify = { + .target_as = &address_space_memory, + .iova = entry->iova, + .translated_addr = entry->translated_addr, + .perm = entry->perm, + .addr_mask = ~PAGE_MASK, + }; + + if (entry->perm == IOMMU_NONE) { + if (!cache) { + return; + } + g_hash_table_remove(iommu->iotlb, &entry->iova); + } else { + if (cache) { + if (cache->perm == entry->perm && + cache->translated_addr == entry->translated_addr) { + return; + } + + notify.perm = IOMMU_NONE; + memory_region_notify_iommu(&iommu->iommu_mr, notify); + notify.perm = entry->perm; + } + + cache = g_new(S390IOTLBEntry, 1); + cache->iova = entry->iova; + cache->translated_addr = entry->translated_addr; + cache->len = PAGE_SIZE; + cache->perm = entry->perm; + g_hash_table_replace(iommu->iotlb, &cache->iova, cache); + } + + memory_region_notify_iommu(&iommu->iommu_mr, notify); +} + int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; uint32_t fh; + uint16_t error = 0; S390PCIBusDevice *pbdev; S390PCIIOMMU *iommu; + S390IOTLBEntry entry; hwaddr start, end; - IOMMUTLBEntry entry; - IOMMUMemoryRegion *iommu_mr; - IOMMUMemoryRegionClass *imrc; cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); - goto out; + return 0; } if (r2 & 0x1) { s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); - goto out; + return 0; } fh = env->regs[r1] >> 32; @@ -602,7 +640,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) if (!pbdev) { DPRINTF("rpcit no pci dev\n"); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - goto out; + return 0; } switch (pbdev->state) { @@ -622,44 +660,37 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) iommu = pbdev->iommu; if (!iommu->g_iota) { - pbdev->state = ZPCI_FS_ERROR; - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); - s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid, - start, 0); - goto out; + error = ERR_EVENT_INVALAS; + goto err; } if (end < iommu->pba || start > iommu->pal) { - pbdev->state = ZPCI_FS_ERROR; - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); - s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid, - start, 0); - goto out; + error = ERR_EVENT_OORANGE; + goto err; } - iommu_mr = &iommu->iommu_mr; - imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr); - while (start < end) { - entry = imrc->translate(iommu_mr, start, IOMMU_NONE); - - if (!entry.translated_addr) { - pbdev->state = ZPCI_FS_ERROR; - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); - s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid, - start, ERR_EVENT_Q_BIT); - goto out; + error = s390_guest_io_table_walk(iommu->g_iota, start, &entry); + if (error) { + break; } - memory_region_notify_iommu(iommu_mr, entry); - start += entry.addr_mask + 1; + start += entry.len; + while (entry.iova < start && entry.iova < end) { + s390_pci_update_iotlb(iommu, &entry); + entry.iova += PAGE_SIZE; + entry.translated_addr += PAGE_SIZE; + } + } +err: + if (error) { + pbdev->state = ZPCI_FS_ERROR; + setcc(cpu, ZPCI_PCI_LS_ERR); + s390_set_status_code(env, r1, ZPCI_PCI_ST_FUNC_IN_ERR); + s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, start, 0); + } else { + setcc(cpu, ZPCI_PCI_LS_OK); } - - setcc(cpu, ZPCI_PCI_LS_OK); -out: return 0; } @@ -834,6 +865,8 @@ static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib, uint8_t dt = (g_iota >> 2) & 0x7; uint8_t t = (g_iota >> 11) & 0x1; + pba &= ~0xfff; + pal |= 0xfff; if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return -EINVAL; diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 53ad5d38d4..bdb6c18a0f 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -13,6 +13,8 @@ #include "hw/boards.h" #include "qmp-commands.h" #include "hw/s390x/storage-keys.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" #include "migration/register.h" diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 2902f54f11..a1d2135a60 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -12,13 +12,13 @@ #include "qemu/osdep.h" #include "hw/boards.h" #include "cpu.h" -#include "qmp-commands.h" #include "migration/qemu-file.h" #include "migration/register.h" #include "hw/s390x/storage-attributes.h" #include "qemu/error-report.h" #include "exec/ram_addr.h" #include "qapi/error.h" +#include "qapi/qmp/qdict.h" #define CMMA_BLOCK_SIZE (1 << 10) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 3807dcb097..4abbe89847 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "cpu.h" #include "hw/boards.h" #include "exec/address-spaces.h" @@ -24,6 +23,7 @@ #include "virtio-ccw.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "s390-pci-bus.h" #include "hw/s390x/storage-keys.h" #include "hw/s390x/storage-attributes.h" @@ -33,7 +33,6 @@ #include "hw/s390x/css-bridge.h" #include "migration/register.h" #include "cpu_models.h" -#include "qapi/qmp/qerror.h" #include "hw/nmi.h" S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) @@ -78,10 +77,6 @@ static void s390_init_cpus(MachineState *machine) MachineClass *mc = MACHINE_GET_CLASS(machine); int i; - if (tcg_enabled() && max_cpus > 1) { - error_report("WARNING: SMP support on s390x is experimental!"); - } - /* initialize possible_cpus */ mc->possible_cpu_arch_ids(machine); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 3d8f26949b..8f7fbc2ab7 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1111,7 +1111,7 @@ static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs) VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); int ret; S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); ret = virtio_ccw_get_mappings(dev); if (ret) { @@ -1129,7 +1129,7 @@ static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs) static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs) { S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + S390FLICStateClass *fsc = s390_get_flic_class(fs); fsc->release_adapter_routes(fs, &dev->routes); } diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index ee586e7d6c..45975c21e8 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -27,7 +27,6 @@ #include "hw/sysbus.h" #include "hw/scsi/esp.h" #include "trace.h" -#include "qapi/error.h" #include "qemu/log.h" /* diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 05e501efd3..b7bafbed6e 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -2,6 +2,7 @@ #include "hw/hw.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "hw/scsi/scsi.h" #include "scsi/constants.h" #include "hw/qdev.h" diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c index d434b3e99a..77e9897244 100644 --- a/hw/scsi/vhost-scsi-common.c +++ b/hw/scsi/vhost-scsi-common.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu/error-report.h" #include "migration/migration.h" #include "hw/virtio/vhost.h" diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index fc807f08f3..0991acd724 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -84,12 +84,18 @@ /* R/W Host control Register 0x0 */ #define SDHC_HOSTCTL 0x28 +#define SDHC_CTRL_LED 0x01 #define SDHC_CTRL_DMA_CHECK_MASK 0x18 #define SDHC_CTRL_SDMA 0x00 #define SDHC_CTRL_ADMA1_32 0x08 #define SDHC_CTRL_ADMA2_32 0x10 #define SDHC_CTRL_ADMA2_64 0x18 #define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) +#define SDHC_CTRL_4BITBUS 0x02 +#define SDHC_CTRL_8BITBUS 0x20 +#define SDHC_CTRL_CDTEST_INS 0x40 +#define SDHC_CTRL_CDTEST_EN 0x80 + /* R/W Power Control Register 0x0 */ #define SDHC_PWRCON 0x29 @@ -226,4 +232,21 @@ enum { sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ }; +extern const VMStateDescription sdhci_vmstate; + + +#define ESDHC_MIX_CTRL 0x48 +#define ESDHC_VENDOR_SPEC 0xc0 +#define ESDHC_DLL_CTRL 0x60 + +#define ESDHC_TUNING_CTRL 0xcc +#define ESDHC_TUNE_CTRL_STATUS 0x68 +#define ESDHC_WTMK_LVL 0x44 + +/* Undocumented register used by guests working around erratum ERR004536 */ +#define ESDHC_UNDOCUMENTED_REG27 0x6c + +#define ESDHC_CTRL_4BITBUS (0x1 << 1) +#define ESDHC_CTRL_8BITBUS (0x2 << 1) + #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index fac7fa5c72..ee95e78aeb 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -32,7 +32,6 @@ #include "qemu/bitops.h" #include "hw/sd/sdhci.h" #include "sdhci-internal.h" -#include "qapi/error.h" #include "qemu/log.h" #include "trace.h" @@ -244,7 +243,8 @@ static void sdhci_send_command(SDHCIState *s) } } - if ((s->norintstsen & SDHC_NISEN_TRSCMP) && + if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && + (s->norintstsen & SDHC_NISEN_TRSCMP) && (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { s->norintsts |= SDHC_NIS_TRSCMP; } @@ -1189,6 +1189,8 @@ static void sdhci_initfn(SDHCIState *s) s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); + + s->io_ops = &sdhci_mmio_ops; } static void sdhci_uninitfn(SDHCIState *s) @@ -1396,6 +1398,10 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) } sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci", + SDHC_REGISTERS_MAP_SIZE); + sysbus_init_mmio(sbd, &s->iomem); } @@ -1447,11 +1453,232 @@ static const TypeInfo sdhci_bus_info = { .class_init = sdhci_bus_class_init, }; +static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) +{ + SDHCIState *s = SYSBUS_SDHCI(opaque); + uint32_t ret; + uint16_t hostctl; + + switch (offset) { + default: + return sdhci_read(opaque, offset, size); + + case SDHC_HOSTCTL: + /* + * For a detailed explanation on the following bit + * manipulation code see comments in a similar part of + * usdhc_write() + */ + hostctl = SDHC_DMA_TYPE(s->hostctl) << (8 - 3); + + if (s->hostctl & SDHC_CTRL_8BITBUS) { + hostctl |= ESDHC_CTRL_8BITBUS; + } + + if (s->hostctl & SDHC_CTRL_4BITBUS) { + hostctl |= ESDHC_CTRL_4BITBUS; + } + + ret = hostctl; + ret |= (uint32_t)s->blkgap << 16; + ret |= (uint32_t)s->wakcon << 24; + + break; + + case ESDHC_DLL_CTRL: + case ESDHC_TUNE_CTRL_STATUS: + case ESDHC_UNDOCUMENTED_REG27: + case ESDHC_TUNING_CTRL: + case ESDHC_VENDOR_SPEC: + case ESDHC_MIX_CTRL: + case ESDHC_WTMK_LVL: + ret = 0; + break; + } + + return ret; +} + +static void +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ + SDHCIState *s = SYSBUS_SDHCI(opaque); + uint8_t hostctl; + uint32_t value = (uint32_t)val; + + switch (offset) { + case ESDHC_DLL_CTRL: + case ESDHC_TUNE_CTRL_STATUS: + case ESDHC_UNDOCUMENTED_REG27: + case ESDHC_TUNING_CTRL: + case ESDHC_WTMK_LVL: + case ESDHC_VENDOR_SPEC: + break; + + case SDHC_HOSTCTL: + /* + * Here's What ESDHCI has at offset 0x28 (SDHC_HOSTCTL) + * + * 7 6 5 4 3 2 1 0 + * |-----------+--------+--------+-----------+----------+---------| + * | Card | Card | Endian | DATA3 | Data | Led | + * | Detect | Detect | Mode | as Card | Transfer | Control | + * | Signal | Test | | Detection | Width | | + * | Selection | Level | | Pin | | | + * |-----------+--------+--------+-----------+----------+---------| + * + * and 0x29 + * + * 15 10 9 8 + * |----------+------| + * | Reserved | DMA | + * | | Sel. | + * | | | + * |----------+------| + * + * and here's what SDCHI spec expects those offsets to be: + * + * 0x28 (Host Control Register) + * + * 7 6 5 4 3 2 1 0 + * |--------+--------+----------+------+--------+----------+---------| + * | Card | Card | Extended | DMA | High | Data | LED | + * | Detect | Detect | Data | Sel. | Speed | Transfer | Control | + * | Signal | Test | Transfer | | Enable | Width | | + * | Sel. | Level | Width | | | | | + * |--------+--------+----------+------+--------+----------+---------| + * + * and 0x29 (Power Control Register) + * + * |----------------------------------| + * | Power Control Register | + * | | + * | Description omitted, | + * | since it has no analog in ESDHCI | + * | | + * |----------------------------------| + * + * Since offsets 0x2A and 0x2B should be compatible between + * both IP specs we only need to reconcile least 16-bit of the + * word we've been given. + */ + + /* + * First, save bits 7 6 and 0 since they are identical + */ + hostctl = value & (SDHC_CTRL_LED | + SDHC_CTRL_CDTEST_INS | + SDHC_CTRL_CDTEST_EN); + /* + * Second, split "Data Transfer Width" from bits 2 and 1 in to + * bits 5 and 1 + */ + if (value & ESDHC_CTRL_8BITBUS) { + hostctl |= SDHC_CTRL_8BITBUS; + } + + if (value & ESDHC_CTRL_4BITBUS) { + hostctl |= ESDHC_CTRL_4BITBUS; + } + + /* + * Third, move DMA select from bits 9 and 8 to bits 4 and 3 + */ + hostctl |= SDHC_DMA_TYPE(value >> (8 - 3)); + + /* + * Now place the corrected value into low 16-bit of the value + * we are going to give standard SDHCI write function + * + * NOTE: This transformation should be the inverse of what can + * be found in drivers/mmc/host/sdhci-esdhc-imx.c in Linux + * kernel + */ + value &= ~UINT16_MAX; + value |= hostctl; + value |= (uint16_t)s->pwrcon << 8; + + sdhci_write(opaque, offset, value, size); + break; + + case ESDHC_MIX_CTRL: + /* + * So, when SD/MMC stack in Linux tries to write to "Transfer + * Mode Register", ESDHC i.MX quirk code will translate it + * into a write to ESDHC_MIX_CTRL, so we do the opposite in + * order to get where we started + * + * Note that Auto CMD23 Enable bit is located in a wrong place + * on i.MX, but since it is not used by QEMU we do not care. + * + * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...) + * here becuase it will result in a call to + * sdhci_send_command(s) which we don't want. + * + */ + s->trnmod = value & UINT16_MAX; + break; + case SDHC_TRNMOD: + /* + * Similar to above, but this time a write to "Command + * Register" will be translated into a 4-byte write to + * "Transfer Mode register" where lower 16-bit of value would + * be set to zero. So what we do is fill those bits with + * cached value from s->trnmod and let the SDHCI + * infrastructure handle the rest + */ + sdhci_write(opaque, offset, val | s->trnmod, size); + break; + case SDHC_BLKSIZE: + /* + * ESDHCI does not implement "Host SDMA Buffer Boundary", and + * Linux driver will try to zero this field out which will + * break the rest of SDHCI emulation. + * + * Linux defaults to maximum possible setting (512K boundary) + * and it seems to be the only option that i.MX IP implements, + * so we artificially set it to that value. + */ + val |= 0x7 << 12; + /* FALLTHROUGH */ + default: + sdhci_write(opaque, offset, val, size); + break; + } +} + + +static const MemoryRegionOps usdhc_mmio_ops = { + .read = usdhc_read, + .write = usdhc_write, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void imx_usdhc_init(Object *obj) +{ + SDHCIState *s = SYSBUS_SDHCI(obj); + + s->io_ops = &usdhc_mmio_ops; + s->quirks = SDHCI_QUIRK_NO_BUSY_IRQ; +} + +static const TypeInfo imx_usdhc_info = { + .name = TYPE_IMX_USDHC, + .parent = TYPE_SYSBUS_SDHCI, + .instance_init = imx_usdhc_init, +}; + static void sdhci_register_types(void) { type_register_static(&sdhci_pci_info); type_register_static(&sdhci_sysbus_info); type_register_static(&sdhci_bus_info); + type_register_static(&imx_usdhc_info); } type_init(sdhci_register_types) diff --git a/hw/smbios/smbios-stub.c b/hw/smbios/smbios-stub.c index 308739410f..d3a385441a 100644 --- a/hw/smbios/smbios-stub.c +++ b/hw/smbios/smbios-stub.c @@ -21,8 +21,8 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qapi/qmp/qerror.h" -#include "qmp-commands.h" #include "hw/smbios/smbios.h" void smbios_entry_add(QemuOpts *opts, Error **errp) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 5d11f01874..27a07e96f4 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -19,6 +19,7 @@ #include "qapi/error.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "sysemu/sysemu.h" #include "qemu/uuid.h" #include "sysemu/cpus.h" diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index 996ce2ada0..1874477ef6 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" #include "hw/hw.h" diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index 4cf8e69be9..eb3aaa87e6 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -28,7 +28,6 @@ #include "hw/sysbus.h" #include "hw/sparc/sun4u_iommu.h" #include "exec/address-spaces.h" -#include "qapi/error.h" #include "qemu/log.h" #include "trace.h" diff --git a/hw/ssi/stm32f2xx_spi.c b/hw/ssi/stm32f2xx_spi.c index 69514da9fb..930c616de3 100644 --- a/hw/ssi/stm32f2xx_spi.c +++ b/hw/ssi/stm32f2xx_spi.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu/log.h" #include "hw/ssi/stm32f2xx_spi.h" diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 4b9b54bf2e..65e4ee6bcf 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -113,6 +113,17 @@ static const IMXClk imx6_gpt_clocks[] = { CLK_HIGH, /* 111 reference clock */ }; +static const IMXClk imx7_gpt_clocks[] = { + CLK_NONE, /* 000 No clock source */ + CLK_IPG, /* 001 ipg_clk, 532MHz*/ + CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ + CLK_EXT, /* 011 External clock */ + CLK_32k, /* 100 ipg_clk_32k */ + CLK_HIGH, /* 101 reference clock */ + CLK_NONE, /* 110 not defined */ + CLK_NONE, /* 111 not defined */ +}; + static void imx_gpt_set_freq(IMXGPTState *s) { uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); @@ -512,6 +523,13 @@ static void imx6_gpt_init(Object *obj) s->clocks = imx6_gpt_clocks; } +static void imx7_gpt_init(Object *obj) +{ + IMXGPTState *s = IMX_GPT(obj); + + s->clocks = imx7_gpt_clocks; +} + static const TypeInfo imx25_gpt_info = { .name = TYPE_IMX25_GPT, .parent = TYPE_SYS_BUS_DEVICE, @@ -532,11 +550,18 @@ static const TypeInfo imx6_gpt_info = { .instance_init = imx6_gpt_init, }; +static const TypeInfo imx7_gpt_info = { + .name = TYPE_IMX7_GPT, + .parent = TYPE_IMX25_GPT, + .instance_init = imx7_gpt_init, +}; + static void imx_gpt_register_types(void) { type_register_static(&imx25_gpt_info); type_register_static(&imx31_gpt_info); type_register_static(&imx6_gpt_info); + type_register_static(&imx7_gpt_info); } type_init(imx_gpt_register_types) diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c index 844aad540e..742c576443 100644 --- a/hw/timer/m48t59.c +++ b/hw/timer/m48t59.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/timer/m48t59.h" -#include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 35a05a64cc..9d93a16e0f 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/bcd.h" @@ -29,6 +30,7 @@ #include "sysemu/sysemu.h" #include "sysemu/replay.h" #include "hw/timer/mc146818rtc.h" +#include "qapi/error.h" #include "qapi/visitor.h" #include "qapi-event.h" #include "qmp-commands.h" diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 710a9ec718..b787aee13b 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -40,11 +40,6 @@ #include "qapi/clone-visitor.h" #include "chardev/char-fe.h" -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <stdio.h> - #define DEBUG_TPM 0 #define DPRINTF(fmt, ...) do { \ diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index abbca5191a..a4c77fbd7e 100644 --- a/hw/tpm/tpm_int.h +++ b/hw/tpm/tpm_int.h @@ -12,8 +12,6 @@ #ifndef TPM_TPM_INT_H #define TPM_TPM_INT_H -#include "qemu/osdep.h" - #define TPM_STANDARD_CMDLINE_OPTS \ { \ .name = "type", \ diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h index 54c8d345ad..59a0b0595d 100644 --- a/hw/tpm/tpm_ioctl.h +++ b/hw/tpm/tpm_ioctl.h @@ -8,9 +8,7 @@ #ifndef _TPM_IOCTL_H_ #define _TPM_IOCTL_H_ -#include <stdint.h> #include <sys/uio.h> -#include <sys/types.h> #include <sys/ioctl.h> /* diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index fbcd498c59..41be700812 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -12,6 +12,7 @@ common-obj-$(CONFIG_USB_XHCI_NEC) += hcd-xhci-nec.o common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o obj-$(CONFIG_TUSB6010) += tusb6010.o +obj-$(CONFIG_IMX) += chipidea.o # emulated usb devices common-obj-$(CONFIG_USB) += dev-hub.o diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index 085ed2c667..b7dd3602dc 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include <cacard/vscard_common.h> #include "chardev/char-fe.h" #include "qemu/error-report.h" diff --git a/hw/usb/chipidea.c b/hw/usb/chipidea.c new file mode 100644 index 0000000000..60d67f88b8 --- /dev/null +++ b/hw/usb/chipidea.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * Chipidea USB block emulation code + * + * Author: Andrey Smirnov <andrew.smirnov@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/usb/hcd-ehci.h" +#include "hw/usb/chipidea.h" +#include "qemu/log.h" + +enum { + CHIPIDEA_USBx_DCIVERSION = 0x000, + CHIPIDEA_USBx_DCCPARAMS = 0x004, + CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8), +}; + +static uint64_t chipidea_read(void *opaque, hwaddr offset, + unsigned size) +{ + return 0; +} + +static void chipidea_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +} + +static const struct MemoryRegionOps chipidea_ops = { + .read = chipidea_read, + .write = chipidea_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static uint64_t chipidea_dc_read(void *opaque, hwaddr offset, + unsigned size) +{ + switch (offset) { + case CHIPIDEA_USBx_DCIVERSION: + return 0x1; + case CHIPIDEA_USBx_DCCPARAMS: + /* + * Real hardware (at least i.MX7) will also report the + * controller as "Device Capable" (and 8 supported endpoints), + * but there doesn't seem to be much point in doing so, since + * we don't emulate that part. + */ + return CHIPIDEA_USBx_DCCPARAMS_HC; + } + + return 0; +} + +static void chipidea_dc_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +} + +static const struct MemoryRegionOps chipidea_dc_ops = { + .read = chipidea_dc_read, + .write = chipidea_dc_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void chipidea_init(Object *obj) +{ + EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci; + ChipideaState *ci = CHIPIDEA(obj); + int i; + + for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) { + const struct { + const char *name; + hwaddr offset; + uint64_t size; + const struct MemoryRegionOps *ops; + } regions[ARRAY_SIZE(ci->iomem)] = { + /* + * Registers located between offsets 0x000 and 0xFC + */ + { + .name = TYPE_CHIPIDEA ".misc", + .offset = 0x000, + .size = 0x100, + .ops = &chipidea_ops, + }, + /* + * Registers located between offsets 0x1A4 and 0x1DC + */ + { + .name = TYPE_CHIPIDEA ".endpoints", + .offset = 0x1A4, + .size = 0x1DC - 0x1A4 + 4, + .ops = &chipidea_ops, + }, + /* + * USB_x_DCIVERSION and USB_x_DCCPARAMS + */ + { + .name = TYPE_CHIPIDEA ".dc", + .offset = 0x120, + .size = 8, + .ops = &chipidea_dc_ops, + }, + }; + + memory_region_init_io(&ci->iomem[i], + obj, + regions[i].ops, + ci, + regions[i].name, + regions[i].size); + + memory_region_add_subregion(&ehci->mem, + regions[i].offset, + &ci->iomem[i]); + } +} + +static void chipidea_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); + + /* + * Offsets used were taken from i.MX7Dual Applications Processor + * Reference Manual, Rev 0.1, p. 3177, Table 11-59 + */ + sec->capsbase = 0x100; + sec->opregbase = 0x140; + sec->portnr = 1; + + set_bit(DEVICE_CATEGORY_USB, dc->categories); + dc->desc = "Chipidea USB Module"; +} + +static const TypeInfo chipidea_info = { + .name = TYPE_CHIPIDEA, + .parent = TYPE_SYS_BUS_EHCI, + .instance_size = sizeof(ChipideaState), + .instance_init = chipidea_init, + .class_init = chipidea_class_init, +}; + +static void chipidea_register_type(void) +{ + type_register_static(&chipidea_info); +} +type_init(chipidea_register_type) diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 584a6f2442..3beeb0d170 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -23,13 +23,13 @@ #include <libusb.h> #include <sys/user.h> -#include "qemu-common.h" #include "qemu/config-file.h" +#include "qemu/option.h" #include "hw/sysbus.h" #include "hw/usb.h" #include "hw/xen/xen_backend.h" #include "monitor/qdev.h" -#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" #include "hw/xen/io/ring.h" diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b33c5e8a03..033cc8dea1 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -26,6 +26,7 @@ #include "hw/pci/msix.h" #include "hw/pci/pci_bridge.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "qemu/range.h" #include "sysemu/kvm.h" #include "sysemu/sysemu.h" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 179c8f5768..48224493a0 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -23,6 +23,7 @@ #include "hw/virtio/virtio-balloon.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" +#include "qapi/error.h" #include "qapi/visitor.h" #include "qapi-event.h" #include "trace.h" diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 670114ecfe..98a5dd6689 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -23,7 +23,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/queue.h" -#include "qapi/qmp/types.h" +#include "qapi/error.h" #include "sysemu/sysemu.h" #include "sysemu/watchdog.h" #include "qapi-event.h" diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index afa1e3f404..83099dd1b1 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "hw/xen/xen_backend.h" -#include "qmp-commands.h" #include "chardev/char.h" #include "sysemu/accel.h" #include "migration/misc.h" diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c index a80e78c0dc..fac9d3fcdc 100644 --- a/hw/xen/xen_devconfig.c +++ b/hw/xen/xen_devconfig.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "hw/xen/xen_backend.h" +#include "qemu/option.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" diff --git a/hw/xtensa/xtensa_memory.h b/hw/xtensa/xtensa_memory.h index cab4d172d4..e9aa08749d 100644 --- a/hw/xtensa/xtensa_memory.h +++ b/hw/xtensa/xtensa_memory.h @@ -28,7 +28,6 @@ #ifndef _XTENSA_MEMORY_H #define _XTENSA_MEMORY_H -#include "qemu/osdep.h" #include "qemu-common.h" #include "cpu.h" #include "exec/memory.h" diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 76ea970215..70686a2eb1 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "cpu.h" #include "sysemu/sysemu.h" #include "hw/boards.h" @@ -43,6 +42,7 @@ #include "chardev/char.h" #include "sysemu/device_tree.h" #include "qemu/error-report.h" +#include "qemu/option.h" #include "bootparam.h" #include "xtensa_memory.h" |