diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/block/block.h | 11 | ||||
-rw-r--r-- | include/block/block_int.h | 44 | ||||
-rw-r--r-- | include/block/throttle-groups.h | 1 | ||||
-rw-r--r-- | include/exec/exec-all.h | 108 | ||||
-rw-r--r-- | include/exec/gen-icount.h | 16 | ||||
-rw-r--r-- | include/hw/acpi/acpi-defs.h | 17 | ||||
-rw-r--r-- | include/hw/acpi/aml-build.h | 10 | ||||
-rw-r--r-- | include/hw/arm/fsl-imx6.h | 450 | ||||
-rw-r--r-- | include/hw/misc/imx6_src.h | 73 | ||||
-rw-r--r-- | include/hw/ssi/imx_spi.h | 103 | ||||
-rw-r--r-- | include/qapi/dealloc-visitor.h | 5 | ||||
-rw-r--r-- | include/qapi/opts-visitor.h | 5 | ||||
-rw-r--r-- | include/qapi/qmp-input-visitor.h | 9 | ||||
-rw-r--r-- | include/qapi/qmp/dispatch.h | 6 | ||||
-rw-r--r-- | include/qapi/string-input-visitor.h | 5 | ||||
-rw-r--r-- | include/qapi/string-output-visitor.h | 5 | ||||
-rw-r--r-- | include/qapi/visitor-impl.h | 81 | ||||
-rw-r--r-- | include/qapi/visitor.h | 493 | ||||
-rw-r--r-- | include/qemu/fifo32.h | 191 | ||||
-rw-r--r-- | include/qemu/osdep.h | 14 | ||||
-rw-r--r-- | include/qom/cpu.h | 4 | ||||
-rw-r--r-- | include/sysemu/block-backend.h | 35 | ||||
-rw-r--r-- | include/sysemu/dma.h | 4 |
23 files changed, 1536 insertions, 154 deletions
diff --git a/include/block/block.h b/include/block/block.h index 3a731377db..b210832778 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -476,6 +476,10 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs); void bdrv_ref(BlockDriverState *bs); void bdrv_unref(BlockDriverState *bs); void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); +BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, + BlockDriverState *child_bs, + const char *child_name, + const BdrvChildRole *child_role); bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); @@ -520,7 +524,8 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); void bdrv_io_plug(BlockDriverState *bs); void bdrv_io_unplug(BlockDriverState *bs); -void bdrv_flush_io_queue(BlockDriverState *bs); +void bdrv_io_unplugged_begin(BlockDriverState *bs); +void bdrv_io_unplugged_end(BlockDriverState *bs); /** * bdrv_drained_begin: @@ -541,4 +546,8 @@ void bdrv_drained_begin(BlockDriverState *bs); */ void bdrv_drained_end(BlockDriverState *bs); +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, + Error **errp); +void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); + #endif diff --git a/include/block/block_int.h b/include/block/block_int.h index 10d87595be..a029c2003f 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -38,12 +38,12 @@ #include "qemu/throttle.h" #define BLOCK_FLAG_ENCRYPT 1 -#define BLOCK_FLAG_COMPAT6 4 #define BLOCK_FLAG_LAZY_REFCOUNTS 8 #define BLOCK_OPT_SIZE "size" #define BLOCK_OPT_ENCRYPT "encryption" #define BLOCK_OPT_COMPAT6 "compat6" +#define BLOCK_OPT_HWVERSION "hwversion" #define BLOCK_OPT_BACKING_FILE "backing_file" #define BLOCK_OPT_BACKING_FMT "backing_fmt" #define BLOCK_OPT_CLUSTER_SIZE "cluster_size" @@ -127,10 +127,6 @@ struct BlockDriver { Error **errp); int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags, Error **errp); - int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); - int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); @@ -153,18 +149,20 @@ struct BlockDriver { int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); + int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags); int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags); - - int supported_write_flags; + int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags); /* * Efficiently zero a region of the disk image. Typically an image format * would use a compact metadata representation to implement this. This - * function pointer may be NULL and .bdrv_co_writev() will be called - * instead. + * function pointer may be NULL or return -ENOSUP and .bdrv_co_writev() + * will be called instead. */ int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags); @@ -294,7 +292,6 @@ struct BlockDriver { /* io queue for linux-aio */ void (*bdrv_io_plug)(BlockDriverState *bs); void (*bdrv_io_unplug)(BlockDriverState *bs); - void (*bdrv_flush_io_queue)(BlockDriverState *bs); /** * Try to get @bs's logical and physical block size. @@ -317,6 +314,11 @@ struct BlockDriver { */ void (*bdrv_drain)(BlockDriverState *bs); + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, + Error **errp); + void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, + Error **errp); + QLIST_ENTRY(BlockDriver) list; }; @@ -424,10 +426,10 @@ struct BlockDriverState { /* I/O throttling. * throttle_state tells us if this BDS has I/O limits configured. - * io_limits_enabled tells us if they are currently being - * enforced, but it can be temporarily set to false */ + * io_limits_disabled tells us if they are currently being enforced */ CoQueue throttled_reqs[2]; - bool io_limits_enabled; + unsigned int io_limits_disabled; + /* The following fields are protected by the ThrottleGroup lock. * See the ThrottleGroup documentation for details. */ ThrottleState *throttle_state; @@ -446,6 +448,11 @@ struct BlockDriverState { /* Alignment requirement for offset/length of I/O requests */ unsigned int request_alignment; + /* Flags honored during pwrite (so far: BDRV_REQ_FUA) */ + unsigned int supported_write_flags; + /* Flags honored during write_zeroes (so far: BDRV_REQ_FUA, + * BDRV_REQ_MAY_UNMAP) */ + unsigned int supported_zero_flags; /* the following member gives a name to every node on the bs graph. */ char node_name[32]; @@ -484,6 +491,10 @@ struct BlockDriverState { uint64_t write_threshold_offset; NotifierWithReturn write_threshold_notifier; + /* counters for nested bdrv_io_plug and bdrv_io_unplugged_begin */ + unsigned io_plugged; + unsigned io_plug_disabled; + int quiesce_counter; }; @@ -517,10 +528,10 @@ extern BlockDriver bdrv_qcow2; */ void bdrv_setup_io_funcs(BlockDriver *bdrv); -int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, +int coroutine_fn bdrv_co_preadv(BlockDriverState *bs, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags); -int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, +int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags); @@ -713,6 +724,9 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const BdrvChildRole *child_role); void bdrv_root_unref_child(BdrvChild *child); +void bdrv_no_throttling_begin(BlockDriverState *bs); +void bdrv_no_throttling_end(BlockDriverState *bs); + void blk_dev_change_media_cb(BlockBackend *blk, bool load); bool blk_dev_has_removable_media(BlockBackend *blk); bool blk_dev_has_tray(BlockBackend *blk); diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h index aba28f30b6..395f72d444 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -38,6 +38,7 @@ void throttle_group_get_config(BlockDriverState *bs, ThrottleConfig *cfg); void throttle_group_register_bs(BlockDriverState *bs, const char *groupname); void throttle_group_unregister_bs(BlockDriverState *bs); +void throttle_group_restart_bs(BlockDriverState *bs); void coroutine_fn throttle_group_co_io_limits_intercept(BlockDriverState *bs, unsigned int bytes, diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 736209505a..85528f9941 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -76,7 +76,8 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc); void QEMU_NORETURN cpu_resume_from_signal(CPUState *cpu, void *puc); void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); TranslationBlock *tb_gen_code(CPUState *cpu, - target_ulong pc, target_ulong cs_base, int flags, + target_ulong pc, target_ulong cs_base, + uint32_t flags, int cflags); void cpu_exec_init(CPUState *cpu, Error **errp); void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); @@ -229,13 +230,14 @@ static inline void tlb_flush_by_mmuidx(CPUState *cpu, ...) || defined(__sparc__) || defined(__aarch64__) \ || defined(__s390x__) || defined(__mips__) \ || defined(CONFIG_TCG_INTERPRETER) +/* NOTE: Direct jump patching must be atomic to be thread-safe. */ #define USE_DIRECT_JUMP #endif struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ - uint64_t flags; /* flags defining in which context the code was generated */ + uint32_t flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ uint16_t icount; @@ -257,20 +259,34 @@ struct TranslationBlock { struct TranslationBlock *page_next[2]; tb_page_addr_t page_addr[2]; - /* the following data are used to directly call another TB from - the code of this one. */ - uint16_t tb_next_offset[2]; /* offset of original jump target */ + /* The following data are used to directly call another TB from + * the code of this one. This can be done either by emitting direct or + * indirect native jump instructions. These jumps are reset so that the TB + * just continue its execution. The TB can be linked to another one by + * setting one of the jump targets (or patching the jump instruction). Only + * two of such jumps are supported. + */ + uint16_t jmp_reset_offset[2]; /* offset of original jump target */ +#define TB_JMP_RESET_OFFSET_INVALID 0xffff /* indicates no jump generated */ #ifdef USE_DIRECT_JUMP - uint16_t tb_jmp_offset[2]; /* offset of jump instruction */ + uint16_t jmp_insn_offset[2]; /* offset of native jump instruction */ #else - uintptr_t tb_next[2]; /* address of jump generated code */ + uintptr_t jmp_target_addr[2]; /* target address for indirect jump */ #endif - /* list of TBs jumping to this one. This is a circular list using - the two least significant bits of the pointers to tell what is - the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = - jmp_first */ - struct TranslationBlock *jmp_next[2]; - struct TranslationBlock *jmp_first; + /* Each TB has an assosiated circular list of TBs jumping to this one. + * jmp_list_first points to the first TB jumping to this one. + * jmp_list_next is used to point to the next TB in a list. + * Since each TB can have two jumps, it can participate in two lists. + * jmp_list_first and jmp_list_next are 4-byte aligned pointers to a + * TranslationBlock structure, but the two least significant bits of + * them are used to encode which data field of the pointed TB should + * be used to traverse the list further from that TB: + * 0 => jmp_list_next[0], 1 => jmp_list_next[1], 2 => jmp_list_first. + * In other words, 0/1 tells which jump is used in the pointed TB, + * and 2 means that this is a pointer back to the target TB of this list. + */ + uintptr_t jmp_list_next[2]; + uintptr_t jmp_list_first; }; #include "qemu/thread.h" @@ -288,8 +304,6 @@ struct TBContext { /* statistics */ int tb_flush_count; int tb_phys_invalidate_count; - - int tb_invalidated_flag; }; void tb_free(TranslationBlock *tb); @@ -302,7 +316,7 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) { /* patch the branch destination */ - *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + atomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4)); /* no need to flush icache explicitly */ } #elif defined(_ARCH_PPC) @@ -312,7 +326,7 @@ void ppc_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr); static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) { /* patch the branch destination */ - stl_le_p((void*)jmp_addr, addr - (jmp_addr + 4)); + atomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4)); /* no need to flush icache explicitly */ } #elif defined(__s390x__) @@ -320,36 +334,15 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) { /* patch the branch destination */ intptr_t disp = addr - (jmp_addr - 2); - stl_be_p((void*)jmp_addr, disp / 2); + atomic_set((int32_t *)jmp_addr, disp / 2); /* no need to flush icache explicitly */ } #elif defined(__aarch64__) void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr); #define tb_set_jmp_target1 aarch64_tb_set_jmp_target #elif defined(__arm__) -static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) -{ -#if !QEMU_GNUC_PREREQ(4, 1) - register unsigned long _beg __asm ("a1"); - register unsigned long _end __asm ("a2"); - register unsigned long _flg __asm ("a3"); -#endif - - /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ - *(uint32_t *)jmp_addr = - (*(uint32_t *)jmp_addr & ~0xffffff) - | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff); - -#if QEMU_GNUC_PREREQ(4, 1) - __builtin___clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); -#else - /* flush icache */ - _beg = jmp_addr; - _end = jmp_addr + 4; - _flg = 0; - __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); -#endif -} +void arm_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr); +#define tb_set_jmp_target1 arm_tb_set_jmp_target #elif defined(__sparc__) || defined(__mips__) void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr); #else @@ -359,7 +352,7 @@ void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr); static inline void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) { - uint16_t offset = tb->tb_jmp_offset[n]; + uint16_t offset = tb->jmp_insn_offset[n]; tb_set_jmp_target1((uintptr_t)(tb->tc_ptr + offset), addr); } @@ -369,7 +362,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, static inline void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) { - tb->tb_next[n] = addr; + tb->jmp_target_addr[n] = addr; } #endif @@ -377,20 +370,23 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb_next) { - /* NOTE: this test is only needed for thread safety */ - if (!tb->jmp_next[n]) { - qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc, - "Linking TBs %p [" TARGET_FMT_lx - "] index %d -> %p [" TARGET_FMT_lx "]\n", - tb->tc_ptr, tb->pc, n, - tb_next->tc_ptr, tb_next->pc); - /* patch the native jump address */ - tb_set_jmp_target(tb, n, (uintptr_t)tb_next->tc_ptr); - - /* add in TB jmp circular list */ - tb->jmp_next[n] = tb_next->jmp_first; - tb_next->jmp_first = (TranslationBlock *)((uintptr_t)(tb) | (n)); + if (tb->jmp_list_next[n]) { + /* Another thread has already done this while we were + * outside of the lock; nothing to do in this case */ + return; } + qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc, + "Linking TBs %p [" TARGET_FMT_lx + "] index %d -> %p [" TARGET_FMT_lx "]\n", + tb->tc_ptr, tb->pc, n, + tb_next->tc_ptr, tb_next->pc); + + /* patch the native jump address */ + tb_set_jmp_target(tb, n, (uintptr_t)tb_next->tc_ptr); + + /* add in TB jmp circular list */ + tb->jmp_list_next[n] = tb_next->jmp_list_first; + tb_next->jmp_list_first = (uintptr_t)tb | n; } /* GETRA is the true target of the return instruction that we'll execute, diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 05d89d358f..a011324b92 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -5,14 +5,13 @@ /* Helpers for instruction counting code generation. */ -static TCGArg *icount_arg; +static int icount_start_insn_idx; static TCGLabel *icount_label; static TCGLabel *exitreq_label; static inline void gen_tb_start(TranslationBlock *tb) { TCGv_i32 count, flag, imm; - int i; exitreq_label = gen_new_label(); flag = tcg_temp_new_i32(); @@ -31,13 +30,12 @@ static inline void gen_tb_start(TranslationBlock *tb) -ENV_OFFSET + offsetof(CPUState, icount_decr.u32)); imm = tcg_temp_new_i32(); + /* We emit a movi with a dummy immediate argument. Keep the insn index + * of the movi so that we later (when we know the actual insn count) + * can update the immediate argument with the actual insn count. */ + icount_start_insn_idx = tcg_op_buf_count(); tcg_gen_movi_i32(imm, 0xdeadbeef); - /* This is a horrid hack to allow fixing up the value later. */ - i = tcg_ctx.gen_last_op_idx; - i = tcg_ctx.gen_op_buf[i].args; - icount_arg = &tcg_ctx.gen_opparam_buf[i + 1]; - tcg_gen_sub_i32(count, count, imm); tcg_temp_free_i32(imm); @@ -53,7 +51,9 @@ static void gen_tb_end(TranslationBlock *tb, int num_insns) tcg_gen_exit_tb((uintptr_t)tb + TB_EXIT_REQUESTED); if (tb->cflags & CF_USE_ICOUNT) { - *icount_arg = num_insns; + /* Update the num_insn immediate parameter now that we know + * the actual insn count. */ + tcg_set_insn_param(icount_start_insn_idx, 1, num_insns); gen_set_label(icount_label); tcg_gen_exit_tb((uintptr_t)tb + TB_EXIT_ICOUNT_EXPIRED); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c7a03d43b9..850a9626b7 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -455,8 +455,10 @@ struct AcpiSystemResourceAffinityTable } QEMU_PACKED; typedef struct AcpiSystemResourceAffinityTable AcpiSystemResourceAffinityTable; -#define ACPI_SRAT_PROCESSOR 0 +#define ACPI_SRAT_PROCESSOR_APIC 0 #define ACPI_SRAT_MEMORY 1 +#define ACPI_SRAT_PROCESSOR_x2APIC 2 +#define ACPI_SRAT_PROCESSOR_GICC 3 struct AcpiSratProcessorAffinity { @@ -473,7 +475,7 @@ typedef struct AcpiSratProcessorAffinity AcpiSratProcessorAffinity; struct AcpiSratMemoryAffinity { ACPI_SUB_HEADER_DEF - uint8_t proximity[4]; + uint32_t proximity; uint16_t reserved1; uint64_t base_addr; uint64_t range_length; @@ -483,6 +485,17 @@ struct AcpiSratMemoryAffinity } QEMU_PACKED; typedef struct AcpiSratMemoryAffinity AcpiSratMemoryAffinity; +struct AcpiSratProcessorGiccAffinity +{ + ACPI_SUB_HEADER_DEF + uint32_t proximity; + uint32_t acpi_processor_uid; + uint32_t flags; + uint32_t clock_domain; +} QEMU_PACKED; + +typedef struct AcpiSratProcessorGiccAffinity AcpiSratProcessorGiccAffinity; + /* PCI fw r3.0 MCFG table. */ /* Subtable */ struct AcpiMcfgAllocation { diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 2c994b351a..7eb51c7885 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -198,6 +198,13 @@ typedef enum { AML_PULL_NONE = 3, } AmlPinConfig; +typedef enum { + MEM_AFFINITY_NOFLAGS = 0, + MEM_AFFINITY_ENABLED = (1 << 0), + MEM_AFFINITY_HOTPLUGGABLE = (1 << 1), + MEM_AFFINITY_NON_VOLATILE = (1 << 2), +} MemoryAffinityFlags; + typedef struct AcpiBuildTables { GArray *table_data; @@ -372,4 +379,7 @@ int build_append_named_dword(GArray *array, const char *name_format, ...) GCC_FMT_ATTR(2, 3); +void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, + uint64_t len, int node, MemoryAffinityFlags flags); + #endif diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h new file mode 100644 index 0000000000..d24aaee1c1 --- /dev/null +++ b/include/hw/arm/fsl-imx6.h @@ -0,0 +1,450 @@ +/* + * Freescale i.MX31 SoC emulation + * + * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef FSL_IMX6_H +#define FSL_IMX6_H + +#include "hw/arm/arm.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/misc/imx6_ccm.h" +#include "hw/misc/imx6_src.h" +#include "hw/char/imx_serial.h" +#include "hw/timer/imx_gpt.h" +#include "hw/timer/imx_epit.h" +#include "hw/i2c/imx_i2c.h" +#include "hw/gpio/imx_gpio.h" +#include "hw/sd/sdhci.h" +#include "hw/ssi/imx_spi.h" +#include "exec/memory.h" + +#define TYPE_FSL_IMX6 "fsl,imx6" +#define FSL_IMX6(obj) OBJECT_CHECK(FslIMX6State, (obj), TYPE_FSL_IMX6) + +#define FSL_IMX6_NUM_CPUS 4 +#define FSL_IMX6_NUM_UARTS 5 +#define FSL_IMX6_NUM_EPITS 2 +#define FSL_IMX6_NUM_I2CS 3 +#define FSL_IMX6_NUM_GPIOS 7 +#define FSL_IMX6_NUM_ESDHCS 4 +#define FSL_IMX6_NUM_ECSPIS 5 + +typedef struct FslIMX6State { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + ARMCPU cpu[FSL_IMX6_NUM_CPUS]; + A9MPPrivState a9mpcore; + IMX6CCMState ccm; + IMX6SRCState src; + IMXSerialState uart[FSL_IMX6_NUM_UARTS]; + IMXGPTState gpt; + IMXEPITState epit[FSL_IMX6_NUM_EPITS]; + IMXI2CState i2c[FSL_IMX6_NUM_I2CS]; + IMXGPIOState gpio[FSL_IMX6_NUM_GPIOS]; + SDHCIState esdhc[FSL_IMX6_NUM_ESDHCS]; + IMXSPIState spi[FSL_IMX6_NUM_ECSPIS]; + MemoryRegion rom; + MemoryRegion caam; + MemoryRegion ocram; + MemoryRegion ocram_alias; +} FslIMX6State; + + +#define FSL_IMX6_MMDC_ADDR 0x10000000 +#define FSL_IMX6_MMDC_SIZE 0xF0000000 +#define FSL_IMX6_EIM_MEM_ADDR 0x08000000 +#define FSL_IMX6_EIM_MEM_SIZE 0x8000000 +#define FSL_IMX6_IPU_2_ADDR 0x02800000 +#define FSL_IMX6_IPU_2_SIZE 0x400000 +#define FSL_IMX6_IPU_1_ADDR 0x02400000 +#define FSL_IMX6_IPU_1_SIZE 0x400000 +#define FSL_IMX6_MIPI_HSI_ADDR 0x02208000 +#define FSL_IMX6_MIPI_HSI_SIZE 0x4000 +#define FSL_IMX6_OPENVG_ADDR 0x02204000 +#define FSL_IMX6_OPENVG_SIZE 0x4000 +#define FSL_IMX6_SATA_ADDR 0x02200000 +#define FSL_IMX6_SATA_SIZE 0x4000 +#define FSL_IMX6_AIPS_2_ADDR 0x02100000 +#define FSL_IMX6_AIPS_2_SIZE 0x100000 +/* AIPS2 */ +#define FSL_IMX6_UART5_ADDR 0x021F4000 +#define FSL_IMX6_UART5_SIZE 0x4000 +#define FSL_IMX6_UART4_ADDR 0x021F0000 +#define FSL_IMX6_UART4_SIZE 0x4000 +#define FSL_IMX6_UART3_ADDR 0x021EC000 +#define FSL_IMX6_UART3_SIZE 0x4000 +#define FSL_IMX6_UART2_ADDR 0x021E8000 +#define FSL_IMX6_UART2_SIZE 0x4000 +#define FSL_IMX6_VDOA_ADDR 0x021E4000 +#define FSL_IMX6_VDOA_SIZE 0x4000 +#define FSL_IMX6_MIPI_DSI_ADDR 0x021E0000 +#define FSL_IMX6_MIPI_DSI_SIZE 0x4000 +#define FSL_IMX6_MIPI_CSI_ADDR 0x021DC000 +#define FSL_IMX6_MIPI_CSI_SIZE 0x4000 +#define FSL_IMX6_AUDMUX_ADDR 0x021D8000 +#define FSL_IMX6_AUDMUX_SIZE 0x4000 +#define FSL_IMX6_TZASC2_ADDR 0x021D4000 +#define FSL_IMX6_TZASC2_SIZE 0x4000 +#define FSL_IMX6_TZASC1_ADDR 0x021D0000 +#define FSL_IMX6_TZASC1_SIZE 0x4000 +#define FSL_IMX6_CSU_ADDR 0x021C0000 +#define FSL_IMX6_CSU_SIZE 0x4000 +#define FSL_IMX6_OCOTPCTRL_ADDR 0x021BC000 +#define FSL_IMX6_OCOTPCTRL_SIZE 0x4000 +#define FSL_IMX6_EIM_ADDR 0x021B8000 +#define FSL_IMX6_EIM_SIZE 0x4000 +#define FSL_IMX6_MMDC1_ADDR 0x021B4000 +#define FSL_IMX6_MMDC1_SIZE 0x4000 +#define FSL_IMX6_MMDC0_ADDR 0x021B0000 +#define FSL_IMX6_MMDC0_SIZE 0x4000 +#define FSL_IMX6_ROMCP_ADDR 0x021AC000 +#define FSL_IMX6_ROMCP_SIZE 0x4000 +#define FSL_IMX6_I2C3_ADDR 0x021A8000 +#define FSL_IMX6_I2C3_SIZE 0x4000 +#define FSL_IMX6_I2C2_ADDR 0x021A4000 +#define FSL_IMX6_I2C2_SIZE 0x4000 +#define FSL_IMX6_I2C1_ADDR 0x021A0000 +#define FSL_IMX6_I2C1_SIZE 0x4000 +#define FSL_IMX6_uSDHC4_ADDR 0x0219C000 +#define FSL_IMX6_uSDHC4_SIZE 0x4000 +#define FSL_IMX6_uSDHC3_ADDR 0x02198000 +#define FSL_IMX6_uSDHC3_SIZE 0x4000 +#define FSL_IMX6_uSDHC2_ADDR 0x02194000 +#define FSL_IMX6_uSDHC2_SIZE 0x4000 +#define FSL_IMX6_uSDHC1_ADDR 0x02190000 +#define FSL_IMX6_uSDHC1_SIZE 0x4000 +#define FSL_IMX6_MLB150_ADDR 0x0218C000 +#define FSL_IMX6_MLB150_SIZE 0x4000 +#define FSL_IMX6_ENET_ADDR 0x02188000 +#define FSL_IMX6_ENET_SIZE 0x4000 +#define FSL_IMX6_USBOH3_USB_ADDR 0x02184000 +#define FSL_IMX6_USBOH3_USB_SIZE 0x4000 +#define FSL_IMX6_AIPS2_CFG_ADDR 0x0217C000 +#define FSL_IMX6_AIPS2_CFG_SIZE 0x4000 +/* DAP */ +#define FSL_IMX6_PTF_CTRL_ADDR 0x02160000 +#define FSL_IMX6_PTF_CTRL_SIZE 0x1000 +#define FSL_IMX6_PTM3_ADDR 0x0215F000 +#define FSL_IMX6_PTM3_SIZE 0x1000 +#define FSL_IMX6_PTM2_ADDR 0x0215E000 +#define FSL_IMX6_PTM2_SIZE 0x1000 +#define FSL_IMX6_PTM1_ADDR 0x0215D000 +#define FSL_IMX6_PTM1_SIZE 0x1000 +#define FSL_IMX6_PTM0_ADDR 0x0215C000 +#define FSL_IMX6_PTM0_SIZE 0x1000 +#define FSL_IMX6_CTI3_ADDR 0x0215B000 +#define FSL_IMX6_CTI3_SIZE 0x1000 +#define FSL_IMX6_CTI2_ADDR 0x0215A000 +#define FSL_IMX6_CTI2_SIZE 0x1000 +#define FSL_IMX6_CTI1_ADDR 0x02159000 +#define FSL_IMX6_CTI1_SIZE 0x1000 +#define FSL_IMX6_CTI0_ADDR 0x02158000 +#define FSL_IMX6_CTI0_SIZE 0x1000 +#define FSL_IMX6_CPU3_PMU_ADDR 0x02157000 +#define FSL_IMX6_CPU3_PMU_SIZE 0x1000 +#define FSL_IMX6_CPU3_DEBUG_IF_ADDR 0x02156000 +#define FSL_IMX6_CPU3_DEBUG_IF_SIZE 0x1000 +#define FSL_IMX6_CPU2_PMU_ADDR 0x02155000 +#define FSL_IMX6_CPU2_PMU_SIZE 0x1000 +#define FSL_IMX6_CPU2_DEBUG_IF_ADDR 0x02154000 +#define FSL_IMX6_CPU2_DEBUG_IF_SIZE 0x1000 +#define FSL_IMX6_CPU1_PMU_ADDR 0x02153000 +#define FSL_IMX6_CPU1_PMU_SIZE 0x1000 +#define FSL_IMX6_CPU1_DEBUG_IF_ADDR 0x02152000 +#define FSL_IMX6_CPU1_DEBUG_IF_SIZE 0x1000 +#define FSL_IMX6_CPU0_PMU_ADDR 0x02151000 +#define FSL_IMX6_CPU0_PMU_SIZE 0x1000 +#define FSL_IMX6_CPU0_DEBUG_IF_ADDR 0x02150000 +#define FSL_IMX6_CPU0_DEBUG_IF_SIZE 0x1000 +#define FSL_IMX6_CA9_INTEG_ADDR 0x0214F000 +#define FSL_IMX6_CA9_INTEG_SIZE 0x1000 +#define FSL_IMX6_FUNNEL_ADDR 0x02144000 +#define FSL_IMX6_FUNNEL_SIZE 0x1000 +#define FSL_IMX6_TPIU_ADDR 0x02143000 +#define FSL_IMX6_TPIU_SIZE 0x1000 +#define FSL_IMX6_EXT_CTI_ADDR 0x02142000 +#define FSL_IMX6_EXT_CTI_SIZE 0x1000 +#define FSL_IMX6_ETB_ADDR 0x02141000 +#define FSL_IMX6_ETB_SIZE 0x1000 +#define FSL_IMX6_DAP_ROM_TABLE_ADDR 0x02140000 +#define FSL_IMX6_DAP_ROM_TABLE_SIZE 0x1000 +/* DAP end */ +#define FSL_IMX6_CAAM_ADDR 0x02100000 +#define FSL_IMX6_CAAM_SIZE 0x10000 +/* AIPS2 end */ +#define FSL_IMX6_AIPS_1_ADDR 0x02000000 +#define FSL_IMX6_AIPS_1_SIZE 0x100000 +/* AIPS1 */ +#define FSL_IMX6_SDMA_ADDR 0x020EC000 +#define FSL_IMX6_SDMA_SIZE 0x4000 +#define FSL_IMX6_DCIC2_ADDR 0x020E8000 +#define FSL_IMX6_DCIC2_SIZE 0x4000 +#define FSL_IMX6_DCIC1_ADDR 0x020E4000 +#define FSL_IMX6_DCIC1_SIZE 0x4000 +#define FSL_IMX6_IOMUXC_ADDR 0x020E0000 +#define FSL_IMX6_IOMUXC_SIZE 0x4000 +#define FSL_IMX6_PGCARM_ADDR 0x020DCA00 +#define FSL_IMX6_PGCARM_SIZE 0x20 +#define FSL_IMX6_PGCPU_ADDR 0x020DC260 +#define FSL_IMX6_PGCPU_SIZE 0x20 +#define FSL_IMX6_GPC_ADDR 0x020DC000 +#define FSL_IMX6_GPC_SIZE 0x4000 +#define FSL_IMX6_SRC_ADDR 0x020D8000 +#define FSL_IMX6_SRC_SIZE 0x4000 +#define FSL_IMX6_EPIT2_ADDR 0x020D4000 +#define FSL_IMX6_EPIT2_SIZE 0x4000 +#define FSL_IMX6_EPIT1_ADDR 0x020D0000 +#define FSL_IMX6_EPIT1_SIZE 0x4000 +#define FSL_IMX6_SNVSHP_ADDR 0x020CC000 +#define FSL_IMX6_SNVSHP_SIZE 0x4000 +#define FSL_IMX6_USBPHY2_ADDR 0x020CA000 +#define FSL_IMX6_USBPHY2_SIZE 0x1000 +#define FSL_IMX6_USBPHY1_ADDR 0x020C9000 +#define FSL_IMX6_USBPHY1_SIZE 0x1000 +#define FSL_IMX6_ANALOG_ADDR 0x020C8000 +#define FSL_IMX6_ANALOG_SIZE 0x1000 +#define FSL_IMX6_CCM_ADDR 0x020C4000 +#define FSL_IMX6_CCM_SIZE 0x4000 +#define FSL_IMX6_WDOG2_ADDR 0x020C0000 +#define FSL_IMX6_WDOG2_SIZE 0x4000 +#define FSL_IMX6_WDOG1_ADDR 0x020BC000 +#define FSL_IMX6_WDOG1_SIZE 0x4000 +#define FSL_IMX6_KPP_ADDR 0x020B8000 +#define FSL_IMX6_KPP_SIZE 0x4000 +#define FSL_IMX6_GPIO7_ADDR 0x020B4000 +#define FSL_IMX6_GPIO7_SIZE 0x4000 +#define FSL_IMX6_GPIO6_ADDR 0x020B0000 +#define FSL_IMX6_GPIO6_SIZE 0x4000 +#define FSL_IMX6_GPIO5_ADDR 0x020AC000 +#define FSL_IMX6_GPIO5_SIZE 0x4000 +#define FSL_IMX6_GPIO4_ADDR 0x020A8000 +#define FSL_IMX6_GPIO4_SIZE 0x4000 +#define FSL_IMX6_GPIO3_ADDR 0x020A4000 +#define FSL_IMX6_GPIO3_SIZE 0x4000 +#define FSL_IMX6_GPIO2_ADDR 0x020A0000 +#define FSL_IMX6_GPIO2_SIZE 0x4000 +#define FSL_IMX6_GPIO1_ADDR 0x0209C000 +#define FSL_IMX6_GPIO1_SIZE 0x4000 +#define FSL_IMX6_GPT_ADDR 0x02098000 +#define FSL_IMX6_GPT_SIZE 0x4000 +#define FSL_IMX6_CAN2_ADDR 0x02094000 +#define FSL_IMX6_CAN2_SIZE 0x4000 +#define FSL_IMX6_CAN1_ADDR 0x02090000 +#define FSL_IMX6_CAN1_SIZE 0x4000 +#define FSL_IMX6_PWM4_ADDR 0x0208C000 +#define FSL_IMX6_PWM4_SIZE 0x4000 +#define FSL_IMX6_PWM3_ADDR 0x02088000 +#define FSL_IMX6_PWM3_SIZE 0x4000 +#define FSL_IMX6_PWM2_ADDR 0x02084000 +#define FSL_IMX6_PWM2_SIZE 0x4000 +#define FSL_IMX6_PWM1_ADDR 0x02080000 +#define FSL_IMX6_PWM1_SIZE 0x4000 +#define FSL_IMX6_AIPS1_CFG_ADDR 0x0207C000 +#define FSL_IMX6_AIPS1_CFG_SIZE 0x4000 +#define FSL_IMX6_VPU_ADDR 0x02040000 +#define FSL_IMX6_VPU_SIZE 0x3C000 +#define FSL_IMX6_AIPS1_SPBA_ADDR 0x0203C000 +#define FSL_IMX6_AIPS1_SPBA_SIZE 0x4000 +#define FSL_IMX6_ASRC_ADDR 0x02034000 +#define FSL_IMX6_ASRC_SIZE 0x4000 +#define FSL_IMX6_SSI3_ADDR 0x02030000 +#define FSL_IMX6_SSI3_SIZE 0x4000 +#define FSL_IMX6_SSI2_ADDR 0x0202C000 +#define FSL_IMX6_SSI2_SIZE 0x4000 +#define FSL_IMX6_SSI1_ADDR 0x02028000 +#define FSL_IMX6_SSI1_SIZE 0x4000 +#define FSL_IMX6_ESAI_ADDR 0x02024000 +#define FSL_IMX6_ESAI_SIZE 0x4000 +#define FSL_IMX6_UART1_ADDR 0x02020000 +#define FSL_IMX6_UART1_SIZE 0x4000 +#define FSL_IMX6_eCSPI5_ADDR 0x02018000 +#define FSL_IMX6_eCSPI5_SIZE 0x4000 +#define FSL_IMX6_eCSPI4_ADDR 0x02014000 +#define FSL_IMX6_eCSPI4_SIZE 0x4000 +#define FSL_IMX6_eCSPI3_ADDR 0x02010000 +#define FSL_IMX6_eCSPI3_SIZE 0x4000 +#define FSL_IMX6_eCSPI2_ADDR 0x0200C000 +#define FSL_IMX6_eCSPI2_SIZE 0x4000 +#define FSL_IMX6_eCSPI1_ADDR 0x02008000 +#define FSL_IMX6_eCSPI1_SIZE 0x4000 +#define FSL_IMX6_SPDIF_ADDR 0x02004000 +#define FSL_IMX6_SPDIF_SIZE 0x4000 +/* AIPS1 end */ +#define FSL_IMX6_PCIe_REG_ADDR 0x01FFC000 +#define FSL_IMX6_PCIe_REG_SIZE 0x4000 +#define FSL_IMX6_PCIe_ADDR 0x01000000 +#define FSL_IMX6_PCIe_SIZE 0xFFC000 +#define FSL_IMX6_GPV_1_PL301_CFG_ADDR 0x00C00000 +#define FSL_IMX6_GPV_1_PL301_CFG_SIZE 0x100000 +#define FSL_IMX6_GPV_0_PL301_CFG_ADDR 0x00B00000 +#define FSL_IMX6_GPV_0_PL301_CFG_SIZE 0x100000 +#define FSL_IMX6_PL310_ADDR 0x00A02000 +#define FSL_IMX6_PL310_SIZE 0x1000 +#define FSL_IMX6_A9MPCORE_ADDR 0x00A00000 +#define FSL_IMX6_A9MPCORE_SIZE 0x2000 +#define FSL_IMX6_OCRAM_ALIAS_ADDR 0x00940000 +#define FSL_IMX6_OCRAM_ALIAS_SIZE 0xC0000 +#define FSL_IMX6_OCRAM_ADDR 0x00900000 +#define FSL_IMX6_OCRAM_SIZE 0x40000 +#define FSL_IMX6_GPV_4_PL301_CFG_ADDR 0x00800000 +#define FSL_IMX6_GPV_4_PL301_CFG_SIZE 0x100000 +#define FSL_IMX6_GPV_3_PL301_CFG_ADDR 0x00300000 +#define FSL_IMX6_GPV_3_PL301_CFG_SIZE 0x100000 +#define FSL_IMX6_GPV_2_PL301_CFG_ADDR 0x00200000 +#define FSL_IMX6_GPV_2_PL301_CFG_SIZE 0x100000 +#define FSL_IMX6_DTCP_ADDR 0x00138000 +#define FSL_IMX6_DTCP_SIZE 0x4000 +#define FSL_IMX6_GPU_2D_ADDR 0x00134000 +#define FSL_IMX6_GPU_2D_SIZE 0x4000 +#define FSL_IMX6_GPU_3D_ADDR 0x00130000 +#define FSL_IMX6_GPU_3D_SIZE 0x4000 +#define FSL_IMX6_HDMI_ADDR 0x00120000 +#define FSL_IMX6_HDMI_SIZE 0x9000 +#define FSL_IMX6_BCH_ADDR 0x00114000 +#define FSL_IMX6_BCH_SIZE 0x4000 +#define FSL_IMX6_GPMI_ADDR 0x00112000 +#define FSL_IMX6_GPMI_SIZE 0x2000 +#define FSL_IMX6_APBH_BRIDGE_DMA_ADDR 0x00110000 +#define FSL_IMX6_APBH_BRIDGE_DMA_SIZE 0x2000 +#define FSL_IMX6_CAAM_MEM_ADDR 0x00100000 +#define FSL_IMX6_CAAM_MEM_SIZE 0x4000 +#define FSL_IMX6_ROM_ADDR 0x00000000 +#define FSL_IMX6_ROM_SIZE 0x18000 + +#define FSL_IMX6_IOMUXC_IRQ 0 +#define FSL_IMX6_DAP_IRQ 1 +#define FSL_IMX6_SDMA_IRQ 2 +#define FSL_IMX6_VPU_JPEG_IRQ 3 +#define FSL_IMX6_SNVS_PMIC_IRQ 4 +#define FSL_IMX6_IPU1_ERROR_IRQ 5 +#define FSL_IMX6_IPU1_SYNC_IRQ 6 +#define FSL_IMX6_IPU2_ERROR_IRQ 7 +#define FSL_IMX6_IPU2_SYNC_IRQ 8 +#define FSL_IMX6_GPU3D_IRQ 9 +#define FSL_IMX6_R2D_IRQ 10 +#define FSL_IMX6_V2D_IRQ 11 +#define FSL_IMX6_VPU_IRQ 12 +#define FSL_IMX6_APBH_BRIDGE_DMA_IRQ 13 +#define FSL_IMX6_EIM_IRQ 14 +#define FSL_IMX6_BCH_IRQ 15 +#define FSL_IMX6_GPMI_IRQ 16 +#define FSL_IMX6_DTCP_IRQ 17 +#define FSL_IMX6_VDOA_IRQ 18 +#define FSL_IMX6_SNVS_CONS_IRQ 19 +#define FSL_IMX6_SNVS_SEC_IRQ 20 +#define FSL_IMX6_CSU_IRQ 21 +#define FSL_IMX6_uSDHC1_IRQ 22 +#define FSL_IMX6_uSDHC2_IRQ 23 +#define FSL_IMX6_uSDHC3_IRQ 24 +#define FSL_IMX6_uSDHC4_IRQ 25 +#define FSL_IMX6_UART1_IRQ 26 +#define FSL_IMX6_UART2_IRQ 27 +#define FSL_IMX6_UART3_IRQ 28 +#define FSL_IMX6_UART4_IRQ 29 +#define FSL_IMX6_UART5_IRQ 30 +#define FSL_IMX6_ECSPI1_IRQ 31 +#define FSL_IMX6_ECSPI2_IRQ 32 +#define FSL_IMX6_ECSPI3_IRQ 33 +#define FSL_IMX6_ECSPI4_IRQ 34 +#define FSL_IMX6_ECSPI5_IRQ 35 +#define FSL_IMX6_I2C1_IRQ 36 +#define FSL_IMX6_I2C2_IRQ 37 +#define FSL_IMX6_I2C3_IRQ 38 +#define FSL_IMX6_SATA_IRQ 39 +#define FSL_IMX6_USB_HOST1_IRQ 40 +#define FSL_IMX6_USB_HOST2_IRQ 41 +#define FSL_IMX6_USB_HOST3_IRQ 42 +#define FSL_IMX6_USB_OTG_IRQ 43 +#define FSL_IMX6_USB_PHY_UTMI0_IRQ 44 +#define FSL_IMX6_USB_PHY_UTMI1_IRQ 45 +#define FSL_IMX6_SSI1_IRQ 46 +#define FSL_IMX6_SSI2_IRQ 47 +#define FSL_IMX6_SSI3_IRQ 48 +#define FSL_IMX6_TEMP_IRQ 49 +#define FSL_IMX6_ASRC_IRQ 50 +#define FSL_IMX6_ESAI_IRQ 51 +#define FSL_IMX6_SPDIF_IRQ 52 +#define FSL_IMX6_MLB150_IRQ 53 +#define FSL_IMX6_PMU1_IRQ 54 +#define FSL_IMX6_GPT_IRQ 55 +#define FSL_IMX6_EPIT1_IRQ 56 +#define FSL_IMX6_EPIT2_IRQ 57 +#define FSL_IMX6_GPIO1_INT7_IRQ 58 +#define FSL_IMX6_GPIO1_INT6_IRQ 59 +#define FSL_IMX6_GPIO1_INT5_IRQ 60 +#define FSL_IMX6_GPIO1_INT4_IRQ 61 +#define FSL_IMX6_GPIO1_INT3_IRQ 62 +#define FSL_IMX6_GPIO1_INT2_IRQ 63 +#define FSL_IMX6_GPIO1_INT1_IRQ 64 +#define FSL_IMX6_GPIO1_INT0_IRQ 65 +#define FSL_IMX6_GPIO1_LOW_IRQ 66 +#define FSL_IMX6_GPIO1_HIGH_IRQ 67 +#define FSL_IMX6_GPIO2_LOW_IRQ 68 +#define FSL_IMX6_GPIO2_HIGH_IRQ 69 +#define FSL_IMX6_GPIO3_LOW_IRQ 70 +#define FSL_IMX6_GPIO3_HIGH_IRQ 71 +#define FSL_IMX6_GPIO4_LOW_IRQ 72 +#define FSL_IMX6_GPIO4_HIGH_IRQ 73 +#define FSL_IMX6_GPIO5_LOW_IRQ 74 +#define FSL_IMX6_GPIO5_HIGH_IRQ 75 +#define FSL_IMX6_GPIO6_LOW_IRQ 76 +#define FSL_IMX6_GPIO6_HIGH_IRQ 77 +#define FSL_IMX6_GPIO7_LOW_IRQ 78 +#define FSL_IMX6_GPIO7_HIGH_IRQ 79 +#define FSL_IMX6_WDOG1_IRQ 80 +#define FSL_IMX6_WDOG2_IRQ 81 +#define FSL_IMX6_KPP_IRQ 82 +#define FSL_IMX6_PWM1_IRQ 83 +#define FSL_IMX6_PWM2_IRQ 84 +#define FSL_IMX6_PWM3_IRQ 85 +#define FSL_IMX6_PWM4_IRQ 86 +#define FSL_IMX6_CCM1_IRQ 87 +#define FSL_IMX6_CCM2_IRQ 88 +#define FSL_IMX6_GPC_IRQ 89 +#define FSL_IMX6_SRC_IRQ 91 +#define FSL_IMX6_CPU_L2_IRQ 92 +#define FSL_IMX6_CPU_PARITY_IRQ 93 +#define FSL_IMX6_CPU_PERF_IRQ 94 +#define FSL_IMX6_CPU_CTI_IRQ 95 +#define FSL_IMX6_SRC_COMB_IRQ 96 +#define FSL_IMX6_MIPI_CSI1_IRQ 100 +#define FSL_IMX6_MIPI_CSI2_IRQ 101 +#define FSL_IMX6_MIPI_DSI_IRQ 102 +#define FSL_IMX6_MIPI_HSI_IRQ 103 +#define FSL_IMX6_SJC_IRQ 104 +#define FSL_IMX6_CAAM0_IRQ 105 +#define FSL_IMX6_CAAM1_IRQ 106 +#define FSL_IMX6_ASC1_IRQ 108 +#define FSL_IMX6_ASC2_IRQ 109 +#define FSL_IMX6_FLEXCAN1_IRQ 110 +#define FSL_IMX6_FLEXCAN2_IRQ 111 +#define FSL_IMX6_HDMI_MASTER_IRQ 115 +#define FSL_IMX6_HDMI_CEC_IRQ 116 +#define FSL_IMX6_MLB150_LOW_IRQ 117 +#define FSL_IMX6_ENET_MAC_IRQ 118 +#define FSL_IMX6_ENET_MAC_1588_IRQ 119 +#define FSL_IMX6_PCIE1_IRQ 120 +#define FSL_IMX6_PCIE2_IRQ 121 +#define FSL_IMX6_PCIE3_IRQ 122 +#define FSL_IMX6_PCIE4_IRQ 123 +#define FSL_IMX6_DCIC1_IRQ 124 +#define FSL_IMX6_DCIC2_IRQ 125 +#define FSL_IMX6_MLB150_HIGH_IRQ 126 +#define FSL_IMX6_PMU2_IRQ 127 +#define FSL_IMX6_MAX_IRQ 128 + +#endif /* FSL_IMX6_H */ diff --git a/include/hw/misc/imx6_src.h b/include/hw/misc/imx6_src.h new file mode 100644 index 0000000000..eb3640732e --- /dev/null +++ b/include/hw/misc/imx6_src.h @@ -0,0 +1,73 @@ +/* + * IMX6 System Reset Controller + * + * Copyright (C) 2012 NICTA + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX6_SRC_H +#define IMX6_SRC_H + +#include "hw/sysbus.h" +#include "qemu/bitops.h" + +#define SRC_SCR 0 +#define SRC_SBMR1 1 +#define SRC_SRSR 2 +#define SRC_SISR 5 +#define SRC_SIMR 6 +#define SRC_SBMR2 7 +#define SRC_GPR1 8 +#define SRC_GPR2 9 +#define SRC_GPR3 10 +#define SRC_GPR4 11 +#define SRC_GPR5 12 +#define SRC_GPR6 13 +#define SRC_GPR7 14 +#define SRC_GPR8 15 +#define SRC_GPR9 16 +#define SRC_GPR10 17 +#define SRC_MAX 18 + +/* SRC_SCR */ +#define CORE3_ENABLE_SHIFT 24 +#define CORE3_ENABLE_LENGTH 1 +#define CORE2_ENABLE_SHIFT 23 +#define CORE2_ENABLE_LENGTH 1 +#define CORE1_ENABLE_SHIFT 22 +#define CORE1_ENABLE_LENGTH 1 +#define CORE3_RST_SHIFT 16 +#define CORE3_RST_LENGTH 1 +#define CORE2_RST_SHIFT 15 +#define CORE2_RST_LENGTH 1 +#define CORE1_RST_SHIFT 14 +#define CORE1_RST_LENGTH 1 +#define CORE0_RST_SHIFT 13 +#define CORE0_RST_LENGTH 1 +#define SW_IPU1_RST_SHIFT 3 +#define SW_IPU1_RST_LENGTH 1 +#define SW_IPU2_RST_SHIFT 12 +#define SW_IPU2_RST_LENGTH 1 +#define WARM_RST_ENABLE_SHIFT 0 +#define WARM_RST_ENABLE_LENGTH 1 + +#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH) + +#define TYPE_IMX6_SRC "imx6.src" +#define IMX6_SRC(obj) OBJECT_CHECK(IMX6SRCState, (obj), TYPE_IMX6_SRC) + +typedef struct IMX6SRCState { + /* <private> */ + SysBusDevice parent_obj; + + /* <public> */ + MemoryRegion iomem; + + uint32_t regs[SRC_MAX]; + +} IMX6SRCState; + +#endif /* IMX6_SRC_H */ diff --git a/include/hw/ssi/imx_spi.h b/include/hw/ssi/imx_spi.h new file mode 100644 index 0000000000..7103953581 --- /dev/null +++ b/include/hw/ssi/imx_spi.h @@ -0,0 +1,103 @@ +/* + * IMX SPI Controller + * + * Copyright 2016 Jean-Christophe Dubois <jcd@tribudubois.net> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX_SPI_H +#define IMX_SPI_H + +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "qemu/bitops.h" +#include "qemu/fifo32.h" + +#define ECSPI_FIFO_SIZE 64 + +#define ECSPI_RXDATA 0 +#define ECSPI_TXDATA 1 +#define ECSPI_CONREG 2 +#define ECSPI_CONFIGREG 3 +#define ECSPI_INTREG 4 +#define ECSPI_DMAREG 5 +#define ECSPI_STATREG 6 +#define ECSPI_PERIODREG 7 +#define ECSPI_TESTREG 8 +#define ECSPI_MSGDATA 16 +#define ECSPI_MAX 17 + +/* ECSPI_CONREG */ +#define ECSPI_CONREG_EN (1 << 0) +#define ECSPI_CONREG_HT (1 << 1) +#define ECSPI_CONREG_XCH (1 << 2) +#define ECSPI_CONREG_SMC (1 << 3) +#define ECSPI_CONREG_CHANNEL_MODE_SHIFT 4 +#define ECSPI_CONREG_CHANNEL_MODE_LENGTH 4 +#define ECSPI_CONREG_DRCTL_SHIFT 16 +#define ECSPI_CONREG_DRCTL_LENGTH 2 +#define ECSPI_CONREG_CHANNEL_SELECT_SHIFT 18 +#define ECSPI_CONREG_CHANNEL_SELECT_LENGTH 2 +#define ECSPI_CONREG_BURST_LENGTH_SHIFT 20 +#define ECSPI_CONREG_BURST_LENGTH_LENGTH 12 + +/* ECSPI_CONFIGREG */ +#define ECSPI_CONFIGREG_SS_CTL_SHIFT 8 +#define ECSPI_CONFIGREG_SS_CTL_LENGTH 4 + +/* ECSPI_INTREG */ +#define ECSPI_INTREG_TEEN (1 << 0) +#define ECSPI_INTREG_TDREN (1 << 1) +#define ECSPI_INTREG_TFEN (1 << 2) +#define ECSPI_INTREG_RREN (1 << 3) +#define ECSPI_INTREG_RDREN (1 << 4) +#define ECSPI_INTREG_RFEN (1 << 5) +#define ECSPI_INTREG_ROEN (1 << 6) +#define ECSPI_INTREG_TCEN (1 << 7) + +/* ECSPI_DMAREG */ +#define ECSPI_DMAREG_RXTDEN (1 << 31) +#define ECSPI_DMAREG_RXDEN (1 << 23) +#define ECSPI_DMAREG_TEDEN (1 << 7) +#define ECSPI_DMAREG_RX_THRESHOLD_SHIFT 16 +#define ECSPI_DMAREG_RX_THRESHOLD_LENGTH 6 + +/* ECSPI_STATREG */ +#define ECSPI_STATREG_TE (1 << 0) +#define ECSPI_STATREG_TDR (1 << 1) +#define ECSPI_STATREG_TF (1 << 2) +#define ECSPI_STATREG_RR (1 << 3) +#define ECSPI_STATREG_RDR (1 << 4) +#define ECSPI_STATREG_RF (1 << 5) +#define ECSPI_STATREG_RO (1 << 6) +#define ECSPI_STATREG_TC (1 << 7) + +#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH) + +#define TYPE_IMX_SPI "imx.spi" +#define IMX_SPI(obj) OBJECT_CHECK(IMXSPIState, (obj), TYPE_IMX_SPI) + +typedef struct IMXSPIState { + /* <private> */ + SysBusDevice parent_obj; + + /* <public> */ + MemoryRegion iomem; + + qemu_irq irq; + + qemu_irq cs_lines[4]; + + SSIBus *bus; + + uint32_t regs[ECSPI_MAX]; + + Fifo32 rx_fifo; + Fifo32 tx_fifo; + + int16_t burst_length; +} IMXSPIState; + +#endif /* IMX_SPI_H */ diff --git a/include/qapi/dealloc-visitor.h b/include/qapi/dealloc-visitor.h index cf4c36d2d3..45b06b248c 100644 --- a/include/qapi/dealloc-visitor.h +++ b/include/qapi/dealloc-visitor.h @@ -18,6 +18,11 @@ typedef struct QapiDeallocVisitor QapiDeallocVisitor; +/* + * The dealloc visitor is primarly used only by generated + * qapi_free_FOO() functions, and is the only visitor designed to work + * correctly in the face of a partially-constructed QAPI tree. + */ QapiDeallocVisitor *qapi_dealloc_visitor_new(void); void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d); diff --git a/include/qapi/opts-visitor.h b/include/qapi/opts-visitor.h index fd48c14ec8..ae1bf7cf51 100644 --- a/include/qapi/opts-visitor.h +++ b/include/qapi/opts-visitor.h @@ -29,6 +29,11 @@ typedef struct OptsVisitor OptsVisitor; * - string representations of negative numbers yield negative values, * - values below INT64_MIN or LLONG_MIN are rejected, * - values above INT64_MAX or LLONG_MAX are rejected. + * + * The Opts input visitor does not implement support for visiting QAPI + * alternates, numbers (other than integers), null, or arbitrary + * QTypes. It also requires a non-null list argument to + * visit_start_list(). */ OptsVisitor *opts_visitor_new(const QemuOpts *opts); void opts_visitor_cleanup(OptsVisitor *nv); diff --git a/include/qapi/qmp-input-visitor.h b/include/qapi/qmp-input-visitor.h index 3ed499cc42..b0624d8683 100644 --- a/include/qapi/qmp-input-visitor.h +++ b/include/qapi/qmp-input-visitor.h @@ -19,8 +19,13 @@ typedef struct QmpInputVisitor QmpInputVisitor; -QmpInputVisitor *qmp_input_visitor_new(QObject *obj); -QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj); +/* + * Return a new input visitor that converts QMP to QAPI. + * + * Set @strict to reject a parse that doesn't consume all keys of a + * dictionary; otherwise excess input is ignored. + */ +QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict); void qmp_input_visitor_cleanup(QmpInputVisitor *v); diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 495520994c..5609946a16 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -19,11 +19,6 @@ typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); -typedef enum QmpCommandType -{ - QCT_NORMAL, -} QmpCommandType; - typedef enum QmpCommandOptions { QCO_NO_OPTIONS = 0x0, @@ -33,7 +28,6 @@ typedef enum QmpCommandOptions typedef struct QmpCommand { const char *name; - QmpCommandType type; QmpCommandFunc *fn; QmpCommandOptions options; QTAILQ_ENTRY(QmpCommand) node; diff --git a/include/qapi/string-input-visitor.h b/include/qapi/string-input-visitor.h index 089243c09e..7b76c2b9e3 100644 --- a/include/qapi/string-input-visitor.h +++ b/include/qapi/string-input-visitor.h @@ -17,6 +17,11 @@ typedef struct StringInputVisitor StringInputVisitor; +/* + * The string input visitor does not implement support for visiting + * QAPI structs, alternates, null, or arbitrary QTypes. It also + * requires a non-null list argument to visit_start_list(). + */ StringInputVisitor *string_input_visitor_new(const char *str); void string_input_visitor_cleanup(StringInputVisitor *v); diff --git a/include/qapi/string-output-visitor.h b/include/qapi/string-output-visitor.h index d99717f650..e10522a35b 100644 --- a/include/qapi/string-output-visitor.h +++ b/include/qapi/string-output-visitor.h @@ -17,6 +17,11 @@ typedef struct StringOutputVisitor StringOutputVisitor; +/* + * The string output visitor does not implement support for visiting + * QAPI structs, alternates, null, or arbitrary QTypes. It also + * requires a non-null list argument to visit_start_list(). + */ StringOutputVisitor *string_output_visitor_new(bool human); void string_output_visitor_cleanup(StringOutputVisitor *v); diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 2bd8f292b2..145afd03e7 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -14,55 +14,96 @@ #include "qapi/visitor.h" +/* + * This file describes the callback interface for implementing a QAPI + * visitor. For the client interface, see visitor.h. When + * implementing the callbacks, it is easiest to declare a struct with + * 'Visitor visitor;' as the first member. A callback's contract + * matches the corresponding public functions' contract unless stated + * otherwise. In the comments below, some callbacks are marked "must + * be set for $TYPE visits to work"; if a visitor implementation omits + * that callback, it should also document that it is only useful for a + * subset of QAPI. + */ + +/* + * There are three classes of visitors; setting the class determines + * how QAPI enums are visited, as well as what additional restrictions + * can be asserted. + */ +typedef enum VisitorType { + VISITOR_INPUT, + VISITOR_OUTPUT, + VISITOR_DEALLOC, +} VisitorType; + struct Visitor { - /* Must be set */ + /* Must be set to visit structs */ void (*start_struct)(Visitor *v, const char *name, void **obj, size_t size, Error **errp); - void (*end_struct)(Visitor *v, Error **errp); - void (*start_list)(Visitor *v, const char *name, Error **errp); + /* Optional; intended for input visitors */ + void (*check_struct)(Visitor *v, Error **errp); + + /* Must be set to visit structs */ + void (*end_struct)(Visitor *v); + + /* Must be set; implementations may require @list to be non-null, + * but must document it. */ + void (*start_list)(Visitor *v, const char *name, GenericList **list, + size_t size, Error **errp); + /* Must be set */ - GenericList *(*next_list)(Visitor *v, GenericList **list, size_t size); + GenericList *(*next_list)(Visitor *v, GenericList *tail, size_t size); + /* Must be set */ void (*end_list)(Visitor *v); - /* Optional, needed for input and dealloc visitors. */ + /* Must be set by input and dealloc visitors to visit alternates; + * optional for output visitors. */ void (*start_alternate)(Visitor *v, const char *name, GenericAlternate **obj, size_t size, bool promote_int, Error **errp); - /* Optional, needed for dealloc visitor. */ + /* Optional, needed for dealloc visitor */ void (*end_alternate)(Visitor *v); - /* Must be set. */ - void (*type_enum)(Visitor *v, const char *name, int *obj, - const char *const strings[], Error **errp); - - /* Must be set. */ + /* Must be set */ void (*type_int64)(Visitor *v, const char *name, int64_t *obj, Error **errp); - /* Must be set. */ + + /* Must be set */ void (*type_uint64)(Visitor *v, const char *name, uint64_t *obj, Error **errp); - /* Optional; fallback is type_uint64(). */ + + /* Optional; fallback is type_uint64() */ void (*type_size)(Visitor *v, const char *name, uint64_t *obj, Error **errp); - /* Must be set. */ + + /* Must be set */ void (*type_bool)(Visitor *v, const char *name, bool *obj, Error **errp); + + /* Must be set */ void (*type_str)(Visitor *v, const char *name, char **obj, Error **errp); + + /* Must be set to visit numbers */ void (*type_number)(Visitor *v, const char *name, double *obj, Error **errp); + + /* Must be set to visit arbitrary QTypes */ void (*type_any)(Visitor *v, const char *name, QObject **obj, Error **errp); - /* May be NULL; most useful for input visitors. */ + /* Must be set to visit explicit null values. */ + void (*type_null)(Visitor *v, const char *name, Error **errp); + + /* Must be set for input visitors, optional otherwise. The core + * takes care of the return type in the public interface. */ void (*optional)(Visitor *v, const char *name, bool *present); -}; -void input_type_enum(Visitor *v, const char *name, int *obj, - const char *const strings[], Error **errp); -void output_type_enum(Visitor *v, const char *name, int *obj, - const char *const strings[], Error **errp); + /* Must be set */ + VisitorType type; +}; #endif diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 9a8d0105fb..4d12167bdc 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -16,8 +16,199 @@ #include "qapi/qmp/qobject.h" +/* + * The QAPI schema defines both a set of C data types, and a QMP wire + * format. QAPI objects can contain references to other QAPI objects, + * resulting in a directed acyclic graph. QAPI also generates visitor + * functions to walk these graphs. This file represents the interface + * for doing work at each node of a QAPI graph; it can also be used + * for a virtual walk, where there is no actual QAPI C struct. + * + * There are three kinds of visitor classes: input visitors (QMP, + * string, and QemuOpts) parse an external representation and build + * the corresponding QAPI graph, output visitors (QMP and string) take + * a completed QAPI graph and generate an external representation, and + * the dealloc visitor can take a QAPI graph (possibly partially + * constructed) and recursively free its resources. While the dealloc + * and QMP input/output visitors are general, the string and QemuOpts + * visitors have some implementation limitations; see the + * documentation for each visitor for more details on what it + * supports. Also, see visitor-impl.h for the callback contracts + * implemented by each visitor, and docs/qapi-code-gen.txt for more + * about the QAPI code generator. + * + * All QAPI types have a corresponding function with a signature + * roughly compatible with this: + * + * void visit_type_FOO(Visitor *v, const char *name, T obj, Error **errp); + * + * where T is FOO for scalar types, and FOO * otherwise. The scalar + * visitors are declared here; the remaining visitors are generated in + * qapi-visit.h. + * + * The @name parameter of visit_type_FOO() describes the relation + * between this QAPI value and its parent container. When visiting + * the root of a tree, @name is ignored; when visiting a member of an + * object, @name is the key associated with the value; and when + * visiting a member of a list, @name is NULL. + * + * FIXME: Clients must pass NULL for @name when visiting a member of a + * list, but this leads to poor error messages; it might be nicer to + * require a non-NULL name such as "key.0" for '{ "key": [ "value" ] + * }' if an error is encountered on "value" (or to have the visitor + * core auto-generate the nicer name). + * + * The visit_type_FOO() functions expect a non-null @obj argument; + * they allocate *@obj during input visits, leave it unchanged on + * output visits, and recursively free any resources during a dealloc + * visit. Each function also takes the customary @errp argument (see + * qapi/error.h for details), for reporting any errors (such as if a + * member @name is not present, or is present but not the specified + * type). + * + * If an error is detected during visit_type_FOO() with an input + * visitor, then *@obj will be NULL for pointer types, and left + * unchanged for scalar types. Using an output visitor with an + * incomplete object has undefined behavior (other than a special case + * for visit_type_str() treating NULL like ""), while the dealloc + * visitor safely handles incomplete objects. Since input visitors + * never produce an incomplete object, such an object is possible only + * by manual construction. + * + * For the QAPI object types (structs, unions, and alternates), there + * is an additional generated function in qapi-visit.h compatible + * with: + * + * void visit_type_FOO_members(Visitor *v, FOO *obj, Error **errp); + * + * for visiting the members of a type without also allocating the QAPI + * struct. + * + * Additionally, in qapi-types.h, all QAPI pointer types (structs, + * unions, alternates, and lists) have a generated function compatible + * with: + * + * void qapi_free_FOO(FOO *obj); + * + * which behaves like free() in that @obj may be NULL. Because of + * these functions, the dealloc visitor is seldom used directly + * outside of generated code. QAPI types can also inherit from a base + * class; when this happens, a function is generated for easily going + * from the derived type to the base type: + * + * BASE *qapi_CHILD_base(CHILD *obj); + * + * For a real QAPI struct, typical input usage involves: + * + * <example> + * Foo *f; + * Error *err = NULL; + * Visitor *v; + * + * v = ...obtain input visitor... + * visit_type_Foo(v, NULL, &f, &err); + * if (err) { + * ...handle error... + * } else { + * ...use f... + * } + * ...clean up v... + * qapi_free_Foo(f); + * </example> + * + * For a list, it is: + * <example> + * FooList *l; + * Error *err = NULL; + * Visitor *v; + * + * v = ...obtain input visitor... + * visit_type_FooList(v, NULL, &l, &err); + * if (err) { + * ...handle error... + * } else { + * for ( ; l; l = l->next) { + * ...use l->value... + * } + * } + * ...clean up v... + * qapi_free_FooList(l); + * </example> + * + * Similarly, typical output usage is: + * + * <example> + * Foo *f = ...obtain populated object... + * Error *err = NULL; + * Visitor *v; + * + * v = ...obtain output visitor... + * visit_type_Foo(v, NULL, &f, &err); + * if (err) { + * ...handle error... + * } + * ...clean up v... + * </example> + * + * When visiting a real QAPI struct, this file provides several + * helpers that rely on in-tree information to control the walk: + * visit_optional() for the 'has_member' field associated with + * optional 'member' in the C struct; and visit_next_list() for + * advancing through a FooList linked list. Similarly, the + * visit_is_input() helper makes it possible to write code that is + * visitor-agnostic everywhere except for cleanup. Only the generated + * visit_type functions need to use these helpers. + * + * It is also possible to use the visitors to do a virtual walk, where + * no actual QAPI struct is present. In this situation, decisions + * about what needs to be walked are made by the calling code, and + * structured visits are split between pairs of start and end methods + * (where the end method must be called if the start function + * succeeded, even if an intermediate visit encounters an error). + * Thus, a virtual walk corresponding to '{ "list": [1, 2] }' looks + * like: + * + * <example> + * Visitor *v; + * Error *err = NULL; + * int value; + * + * v = ...obtain visitor... + * visit_start_struct(v, NULL, NULL, 0, &err); + * if (err) { + * goto out; + * } + * visit_start_list(v, "list", NULL, 0, &err); + * if (err) { + * goto outobj; + * } + * value = 1; + * visit_type_int(v, NULL, &value, &err); + * if (err) { + * goto outlist; + * } + * value = 2; + * visit_type_int(v, NULL, &value, &err); + * if (err) { + * goto outlist; + * } + * outlist: + * visit_end_list(v); + * if (!err) { + * visit_check_struct(v, &err); + * } + * outobj: + * visit_end_struct(v); + * out: + * error_propagate(errp, err); + * ...clean up v... + * </example> + */ + +/*** Useful types ***/ + /* This struct is layout-compatible with all other *List structs - * created by the qapi generator. It is used as a typical + * created by the QAPI generator. It is used as a typical * singly-linked list. */ typedef struct GenericList { struct GenericList *next; @@ -25,35 +216,139 @@ typedef struct GenericList { } GenericList; /* This struct is layout-compatible with all Alternate types - * created by the qapi generator. */ + * created by the QAPI generator. */ typedef struct GenericAlternate { QType type; char padding[]; } GenericAlternate; +/*** Visiting structures ***/ + +/* + * Start visiting an object @obj (struct or union). + * + * @name expresses the relationship of this object to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL for a real walk, in which case @size + * determines how much memory an input visitor will allocate into + * *@obj. @obj may also be NULL for a virtual walk, in which case + * @size is ignored. + * + * @errp obeys typical error usage, and reports failures such as a + * member @name is not present, or present but not an object. On + * error, input visitors set *@obj to NULL. + * + * After visit_start_struct() succeeds, the caller may visit its + * members one after the other, passing the member's name and address + * within the struct. Finally, visit_end_struct() needs to be called + * to clean up, even if intermediate visits fail. See the examples + * above. + * + * FIXME Should this be named visit_start_object, since it is also + * used for QAPI unions, and maps to JSON objects? + */ void visit_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp); -void visit_end_struct(Visitor *v, Error **errp); -void visit_start_list(Visitor *v, const char *name, Error **errp); -GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size); +/* + * Prepare for completing an object visit. + * + * @errp obeys typical error usage, and reports failures such as + * unparsed keys remaining in the input stream. + * + * Should be called prior to visit_end_struct() if all other + * intermediate visit steps were successful, to allow the visitor one + * last chance to report errors. May be skipped on a cleanup path, + * where there is no need to check for further errors. + */ +void visit_check_struct(Visitor *v, Error **errp); + +/* + * Complete an object visit started earlier. + * + * Must be called after any successful use of visit_start_struct(), + * even if intermediate processing was skipped due to errors, to allow + * the backend to release any resources. Destroying the visitor early + * behaves as if this was implicitly called. + */ +void visit_end_struct(Visitor *v); + + +/*** Visiting lists ***/ + +/* + * Start visiting a list. + * + * @name expresses the relationship of this list to its parent + * container; see the general description of @name above. + * + * @list must be non-NULL for a real walk, in which case @size + * determines how much memory an input visitor will allocate into + * *@list (at least sizeof(GenericList)). Some visitors also allow + * @list to be NULL for a virtual walk, in which case @size is + * ignored. + * + * @errp obeys typical error usage, and reports failures such as a + * member @name is not present, or present but not a list. On error, + * input visitors set *@list to NULL. + * + * After visit_start_list() succeeds, the caller may visit its members + * one after the other. A real visit (where @obj is non-NULL) uses + * visit_next_list() for traversing the linked list, while a virtual + * visit (where @obj is NULL) uses other means. For each list + * element, call the appropriate visit_type_FOO() with name set to + * NULL and obj set to the address of the value member of the list + * element. Finally, visit_end_list() needs to be called to clean up, + * even if intermediate visits fail. See the examples above. + */ +void visit_start_list(Visitor *v, const char *name, GenericList **list, + size_t size, Error **errp); + +/* + * Iterate over a GenericList during a non-virtual list visit. + * + * @size represents the size of a linked list node (at least + * sizeof(GenericList)). + * + * @tail must not be NULL; on the first call, @tail is the value of + * *list after visit_start_list(), and on subsequent calls @tail must + * be the previously returned value. Should be called in a loop until + * a NULL return or error occurs; for each non-NULL return, the caller + * then calls the appropriate visit_type_*() for the element type of + * the list, with that function's name parameter set to NULL and obj + * set to the address of @tail->value. + */ +GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size); + +/* + * Complete a list visit started earlier. + * + * Must be called after any successful use of visit_start_list(), even + * if intermediate processing was skipped due to errors, to allow the + * backend to release any resources. Destroying the visitor early + * behaves as if this was implicitly called. + */ void visit_end_list(Visitor *v); + +/*** Visiting alternates ***/ + /* - * Start the visit of an alternate @obj with the given @size. + * Start the visit of an alternate @obj. * - * @name specifies the relationship to the containing struct (ignored - * for a top level visit, the name of the key if this alternate is - * part of an object, or NULL if this alternate is part of a list). + * @name expresses the relationship of this alternate to its parent + * container; see the general description of @name above. * - * @obj must not be NULL. Input visitors will allocate @obj and - * determine the qtype of the next thing to be visited, stored in - * (*@obj)->type. Other visitors will leave @obj unchanged. + * @obj must not be NULL. Input visitors use @size to determine how + * much memory to allocate into *@obj, then determine the qtype of the + * next thing to be visited, stored in (*@obj)->type. Other visitors + * will leave @obj unchanged. * * If @promote_int, treat integers as QTYPE_FLOAT. * - * If successful, this must be paired with visit_end_alternate(), even - * if visiting the contents of the alternate fails. + * If successful, this must be paired with visit_end_alternate() to + * clean up, even if visiting the contents of the alternate fails. */ void visit_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, @@ -62,46 +357,202 @@ void visit_start_alternate(Visitor *v, const char *name, /* * Finish visiting an alternate type. * - * Must be called after a successful visit_start_alternate(), even if - * an error occurred in the meantime. + * Must be called after any successful use of visit_start_alternate(), + * even if intermediate processing was skipped due to errors, to allow + * the backend to release any resources. Destroying the visitor early + * behaves as if this was implicitly called. * * TODO: Should all the visit_end_* interfaces take obj parameter, so * that dealloc visitor need not track what was passed in visit_start? */ void visit_end_alternate(Visitor *v); -/** - * Check if an optional member @name of an object needs visiting. - * For input visitors, set *@present according to whether the - * corresponding visit_type_*() needs calling; for other visitors, - * leave *@present unchanged. Return *@present for convenience. + +/*** Other helpers ***/ + +/* + * Does optional struct member @name need visiting? + * + * @name must not be NULL. This function is only useful between + * visit_start_struct() and visit_end_struct(), since only objects + * have optional keys. + * + * @present points to the address of the optional member's has_ flag. + * + * Input visitors set *@present according to input; other visitors + * leave it unchanged. In either case, return *@present for + * convenience. */ bool visit_optional(Visitor *v, const char *name, bool *present); +/* + * Visit an enum value. + * + * @name expresses the relationship of this enum to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL. Input visitors parse input and set *@obj to + * the enumeration value, leaving @obj unchanged on error; other + * visitors use *@obj but leave it unchanged. + * + * Currently, all input visitors parse text input, and all output + * visitors produce text output. The mapping between enumeration + * values and strings is done by the visitor core, using @strings; it + * should be the ENUM_lookup array from visit-types.h. + * + * May call visit_type_str() under the hood, and the enum visit may + * fail even if the corresponding string visit succeeded; this implies + * that visit_type_str() must have no unwelcome side effects. + */ void visit_type_enum(Visitor *v, const char *name, int *obj, const char *const strings[], Error **errp); + +/* + * Check if visitor is an input visitor. + */ +bool visit_is_input(Visitor *v); + +/*** Visiting built-in types ***/ + +/* + * Visit an integer value. + * + * @name expresses the relationship of this integer to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL. Input visitors set *@obj to the value; + * other visitors will leave *@obj unchanged. + */ void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp); + +/* + * Visit a uint8_t value. + * Like visit_type_int(), except clamps the value to uint8_t range. + */ void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, Error **errp); + +/* + * Visit a uint16_t value. + * Like visit_type_int(), except clamps the value to uint16_t range. + */ void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, Error **errp); + +/* + * Visit a uint32_t value. + * Like visit_type_int(), except clamps the value to uint32_t range. + */ void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, Error **errp); + +/* + * Visit a uint64_t value. + * Like visit_type_int(), except clamps the value to uint64_t range, + * that is, ensures it is unsigned. + */ void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp); + +/* + * Visit an int8_t value. + * Like visit_type_int(), except clamps the value to int8_t range. + */ void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp); + +/* + * Visit an int16_t value. + * Like visit_type_int(), except clamps the value to int16_t range. + */ void visit_type_int16(Visitor *v, const char *name, int16_t *obj, Error **errp); + +/* + * Visit an int32_t value. + * Like visit_type_int(), except clamps the value to int32_t range. + */ void visit_type_int32(Visitor *v, const char *name, int32_t *obj, Error **errp); + +/* + * Visit an int64_t value. + * Identical to visit_type_int(). + */ void visit_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp); + +/* + * Visit a uint64_t value. + * Like visit_type_uint64(), except that some visitors may choose to + * recognize additional syntax, such as suffixes for easily scaling + * values. + */ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp); + +/* + * Visit a boolean value. + * + * @name expresses the relationship of this boolean to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL. Input visitors set *@obj to the value; + * other visitors will leave *@obj unchanged. + */ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); + +/* + * Visit a string value. + * + * @name expresses the relationship of this string to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL. Input visitors set *@obj to the value + * (never NULL). Other visitors leave *@obj unchanged, and commonly + * treat NULL like "". + * + * It is safe to cast away const when preparing a (const char *) value + * into @obj for use by an output visitor. + * + * FIXME: Callers that try to output NULL *obj should not be allowed. + */ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); + +/* + * Visit a number (i.e. double) value. + * + * @name expresses the relationship of this number to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL. Input visitors set *@obj to the value; + * other visitors will leave *@obj unchanged. Visitors should + * document if infinity or NaN are not permitted. + */ void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp); + +/* + * Visit an arbitrary value. + * + * @name expresses the relationship of this value to its parent + * container; see the general description of @name above. + * + * @obj must be non-NULL. Input visitors set *@obj to the value; + * other visitors will leave *@obj unchanged. *@obj must be non-NULL + * for output visitors. + */ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); +/* + * Visit a JSON null value. + * + * @name expresses the relationship of the null value to its parent + * container; see the general description of @name above. + * + * Unlike all other visit_type_* functions, no obj parameter is + * needed; rather, this is a witness that an explicit null value is + * expected rather than any other type. + */ +void visit_type_null(Visitor *v, const char *name, Error **errp); + #endif diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h new file mode 100644 index 0000000000..2e5a0ccddf --- /dev/null +++ b/include/qemu/fifo32.h @@ -0,0 +1,191 @@ +/* + * Generic FIFO32 component, based on FIFO8. + * + * Copyright (c) 2016 Jean-Christophe Dubois + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef FIFO32_H +#define FIFO32_H + +#include "qemu/osdep.h" +#include "qemu/fifo8.h" + +typedef struct { + Fifo8 fifo; +} Fifo32; + +/** + * fifo32_create: + * @fifo: struct Fifo32 to initialise with new FIFO + * @capacity: capacity of the newly created FIFO expressed in 32 bit words + * + * Create a FIFO of the specified size. Clients should call fifo32_destroy() + * when finished using the fifo. The FIFO is initially empty. + */ + +static inline void fifo32_create(Fifo32 *fifo, uint32_t capacity) +{ + fifo8_create(&fifo->fifo, capacity * sizeof(uint32_t)); +} + +/** + * fifo32_destroy: + * @fifo: FIFO to cleanup + * + * Cleanup a FIFO created with fifo32_create(). Frees memory created for FIFO + * storage. The FIFO is no longer usable after this has been called. + */ + +static inline void fifo32_destroy(Fifo32 *fifo) +{ + fifo8_destroy(&fifo->fifo); +} + +/** + * fifo32_num_free: + * @fifo: FIFO to check + * + * Return the number of free uint32_t slots in the FIFO. + * + * Returns: Number of free 32 bit words. + */ + +static inline uint32_t fifo32_num_free(Fifo32 *fifo) +{ + return DIV_ROUND_UP(fifo8_num_free(&fifo->fifo), sizeof(uint32_t)); +} + +/** + * fifo32_num_used: + * @fifo: FIFO to check + * + * Return the number of used uint32_t slots in the FIFO. + * + * Returns: Number of used 32 bit words. + */ + +static inline uint32_t fifo32_num_used(Fifo32 *fifo) +{ + return DIV_ROUND_UP(fifo8_num_used(&fifo->fifo), sizeof(uint32_t)); +} + +/** + * fifo32_push: + * @fifo: FIFO to push to + * @data: 32 bits data word to push + * + * Push a 32 bits data word to the FIFO. Behaviour is undefined if the FIFO + * is full. Clients are responsible for checking for fullness using + * fifo32_is_full(). + */ + +static inline void fifo32_push(Fifo32 *fifo, uint32_t data) +{ + int i; + + for (i = 0; i < sizeof(data); i++) { + fifo8_push(&fifo->fifo, data & 0xff); + data >>= 8; + } +} + +/** + * fifo32_push_all: + * @fifo: FIFO to push to + * @data: data to push + * @size: number of 32 bit words to push + * + * Push a 32 bit word array to the FIFO. Behaviour is undefined if the FIFO + * is full. Clients are responsible for checking the space left in the FIFO + * using fifo32_num_free(). + */ + +static inline void fifo32_push_all(Fifo32 *fifo, const uint32_t *data, + uint32_t num) +{ + int i; + + for (i = 0; i < num; i++) { + fifo32_push(fifo, data[i]); + } +} + +/** + * fifo32_pop: + * @fifo: fifo to pop from + * + * Pop a 32 bits data word from the FIFO. Behaviour is undefined if the FIFO + * is empty. Clients are responsible for checking for emptiness using + * fifo32_is_empty(). + * + * Returns: The popped 32 bits data word. + */ + +static inline uint32_t fifo32_pop(Fifo32 *fifo) +{ + uint32_t ret = 0; + int i; + + for (i = 0; i < sizeof(uint32_t); i++) { + ret |= (fifo8_pop(&fifo->fifo) << (i * 8)); + } + + return ret; +} + +/** + * There is no fifo32_pop_buf() because the data is not stored in the buffer + * as a set of native-order words. + */ + +/** + * fifo32_reset: + * @fifo: FIFO to reset + * + * Reset a FIFO. All data is discarded and the FIFO is emptied. + */ + +static inline void fifo32_reset(Fifo32 *fifo) +{ + fifo8_reset(&fifo->fifo); +} + +/** + * fifo32_is_empty: + * @fifo: FIFO to check + * + * Check if a FIFO is empty. + * + * Returns: True if the fifo is empty, false otherwise. + */ + +static inline bool fifo32_is_empty(Fifo32 *fifo) +{ + return fifo8_is_empty(&fifo->fifo); +} + +/** + * fifo32_is_full: + * @fifo: FIFO to check + * + * Check if a FIFO is full. + * + * Returns: True if the fifo is full, false otherwise. + */ + +static inline bool fifo32_is_full(Fifo32 *fifo) +{ + return fifo8_num_free(&fifo->fifo) < sizeof(uint32_t); +} + +#define VMSTATE_FIFO32(_field, _state) VMSTATE_FIFO8(_field.fifo, _state) + +#endif /* FIFO32_H */ diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 408783f532..1e3221cbec 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -158,6 +158,20 @@ extern int daemon(int, int); /* Round number up to multiple */ #define QEMU_ALIGN_UP(n, m) QEMU_ALIGN_DOWN((n) + (m) - 1, (m)) +/* Check if n is a multiple of m */ +#define QEMU_IS_ALIGNED(n, m) (((n) % (m)) == 0) + +/* n-byte align pointer down */ +#define QEMU_ALIGN_PTR_DOWN(p, n) \ + ((typeof(p))QEMU_ALIGN_DOWN((uintptr_t)(p), (n))) + +/* n-byte align pointer up */ +#define QEMU_ALIGN_PTR_UP(p, n) \ + ((typeof(p))QEMU_ALIGN_UP((uintptr_t)(p), (n))) + +/* Check if pointer p is n-bytes aligned */ +#define QEMU_PTR_IS_ALIGNED(p, n) QEMU_IS_ALIGNED((uintptr_t)(p), (n)) + #ifndef ROUND_UP #define ROUND_UP(n,d) (((n) + (d) - 1) & -(d)) #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index b7a10f791a..4349c465c5 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -238,6 +238,7 @@ struct kvm_run; * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this * CPU and return to its top level loop. + * @tb_flushed: Indicates the translation buffer has been flushed. * @singlestep_enabled: Flags for single-stepping. * @icount_extra: Instructions until next timer event. * @icount_decr: Number of cycles left, with interrupt flag in high bit. @@ -252,7 +253,6 @@ struct kvm_run; * @as: Pointer to the first AddressSpace, for the convenience of targets which * only have a single AddressSpace * @env_ptr: Pointer to subclass-specific CPUArchState field. - * @current_tb: Currently executing TB. * @gdb_regs: Additional GDB registers. * @gdb_num_regs: Number of total registers accessible to GDB. * @gdb_num_g_regs: Number of registers in GDB 'g' packets. @@ -289,6 +289,7 @@ struct CPUState { bool stopped; bool crash_occurred; bool exit_request; + bool tb_flushed; uint32_t interrupt_request; int singlestep_enabled; int64_t icount_extra; @@ -303,7 +304,6 @@ struct CPUState { MemoryRegion *memory; void *env_ptr; /* CPUArchState */ - struct TranslationBlock *current_tb; struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; struct GDBRegisterState *gdb_regs; int gdb_num_regs; diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index c62b6fe96d..26736ed84e 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -1,7 +1,7 @@ /* * QEMU Block backends * - * Copyright (C) 2014 Red Hat, Inc. + * Copyright (C) 2014-2016 Red Hat, Inc. * * Authors: * Markus Armbruster <armbru@redhat.com>, @@ -90,28 +90,25 @@ void blk_attach_dev_nofail(BlockBackend *blk, void *dev); void blk_detach_dev(BlockBackend *blk, void *dev); void *blk_get_attached_dev(BlockBackend *blk); void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque); -int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf, - int nb_sectors); -int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf, - int nb_sectors); -int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf, - int nb_sectors); -int blk_write_zeroes(BlockBackend *blk, int64_t sector_num, - int nb_sectors, BdrvRequestFlags flags); -BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num, - int nb_sectors, BdrvRequestFlags flags, +int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf, + int count); +int blk_write_zeroes(BlockBackend *blk, int64_t offset, + int count, BdrvRequestFlags flags); +BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t offset, + int count, BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count); -int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count); +int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count, + BdrvRequestFlags flags); int64_t blk_getlength(BlockBackend *blk); void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); int64_t blk_nb_sectors(BlockBackend *blk); -BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num, - QEMUIOVector *iov, int nb_sectors, - BlockCompletionFunc *cb, void *opaque); -BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num, - QEMUIOVector *iov, int nb_sectors, +BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset, + QEMUIOVector *qiov, BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); +BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, + QEMUIOVector *qiov, BdrvRequestFlags flags, + BlockCompletionFunc *cb, void *opaque); BlockAIOCB *blk_aio_flush(BlockBackend *blk, BlockCompletionFunc *cb, void *opaque); BlockAIOCB *blk_aio_discard(BlockBackend *blk, @@ -178,8 +175,8 @@ int blk_get_open_flags_from_root_state(BlockBackend *blk); void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, BlockCompletionFunc *cb, void *opaque); -int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num, - int nb_sectors, BdrvRequestFlags flags); +int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset, + int count, BdrvRequestFlags flags); int blk_write_compressed(BlockBackend *blk, int64_t sector_num, const uint8_t *buf, int nb_sectors); int blk_truncate(BlockBackend *blk, int64_t offset); diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h index b0fbb9bb35..0f7cd4d3ce 100644 --- a/include/sysemu/dma.h +++ b/include/sysemu/dma.h @@ -197,8 +197,8 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len); void qemu_sglist_destroy(QEMUSGList *qsg); #endif -typedef BlockAIOCB *DMAIOFunc(BlockBackend *blk, int64_t sector_num, - QEMUIOVector *iov, int nb_sectors, +typedef BlockAIOCB *DMAIOFunc(BlockBackend *blk, int64_t offset, + QEMUIOVector *iov, BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); BlockAIOCB *dma_blk_io(BlockBackend *blk, |