All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/32] target-arm queue
@ 2016-10-24 17:24 Peter Maydell
  2016-10-24 17:24 ` [Qemu-devel] [PULL 01/32] migration: Remove static allocation of xzblre cache buffer Peter Maydell
                   ` (33 more replies)
  0 siblings, 34 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:24 UTC (permalink / raw)
  To: qemu-devel

My review queue is currently empty. I may do another
small pullreq towards the end of the week if a few things
that didn't pass code review get respun.

thanks
-- PMM

The following changes since commit a3ae21ec3fe036f536dc94cad735931777143103:

  Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging (2016-10-24 15:03:09 +0100)

are available in the git repository at:

  git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20161024

for you to fetch changes up to cc083d8a25e0a886c3cd4bea0bf57ac4e896fa3f:

  i2c: Add asserts for second smbus i2c_start_transfer() (2016-10-24 16:48:02 +0100)

----------------------------------------------------------------
target-arm queue:
 * support variable (runtime-determined) page sizes, for a
   nearly-20% speedup of TCG for ARMv7 and v8 CPUs with 4K pages
 * ptimer: add tests, support more flexible behaviour around
   what happens on the "zero" tick, use ptimer for a9gtimer
 * virt: ACPI: Add IORT Structure definition
 * i2c: Fix SMBus read transactions to avoid double events
 * timer: stm32f2xx_timer: add check for prescaler value
 * QOMify musicpal, pxa2xx_gpio, strongarm, pl110
 * target-arm: Implement new HLT trap for semihosting
 * i2c: Add asserts for second smbus i2c_start_transfer()

----------------------------------------------------------------
Corey Minyard (2):
      i2c: Fix SMBus read transactions to avoid double events
      i2c: Add asserts for second smbus i2c_start_transfer()

Dmitry Osipenko (14):
      hw/ptimer: Add "wraparound after one period" policy
      tests: ptimer: Add tests for "wraparound after one period" policy
      hw/ptimer: Add "continuous trigger" policy
      tests: ptimer: Add tests for "continuous trigger" policy
      hw/ptimer: Add "no immediate trigger" policy
      tests: ptimer: Add tests for "no immediate trigger" policy
      hw/ptimer: Add "no immediate reload" policy
      tests: ptimer: Add tests for "no immediate reload" policy
      hw/ptimer: Add "no counter round down" policy
      tests: ptimer: Add tests for "no counter round down" policy
      tests: ptimer: Change the copyright comment
      tests: ptimer: Replace 10000 with 1
      arm_mptimer: Convert to use ptimer
      tests: Add tests for the ARM MPTimer

Peter Maydell (5):
      cpu: Support a target CPU having a variable page size
      migration/savevm.c: migrate non-default page size
      target-arm: Make page size a runtime setting
      hw/arm/virt: Set minimum_page_bits to 12
      target-arm: Implement new HLT trap for semihosting

Prasad J Pandit (2):
      timer: a9gtimer: remove loop to auto-increment comparator
      timer: stm32f2xx_timer: add check for prescaler value

Prem Mallappa (2):
      ACPI: Add IORT Structure definition
      ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes

Vijaya Kumar K (3):
      migration: Remove static allocation of xzblre cache buffer
      exec.c: Remove static allocation of sub_section of sub_page
      translate-all.c: Compute L1 page table properties at runtime

xiaoqiang zhao (4):
      hw/arm: QOM'ify musicpal.c
      hw/arm: QOM'ify pxa2xx_gpio.c
      hw/arm: QOM'ify strongarm.c
      hw/display: QOM'ify pl110.c

 exec.c                         |   47 +-
 hw/arm/musicpal.c              |   88 ++--
 hw/arm/pxa2xx_gpio.c           |   25 +-
 hw/arm/strongarm.c             |   15 +-
 hw/arm/virt-acpi-build.c       |   71 ++-
 hw/arm/virt.c                  |    4 +
 hw/core/ptimer.c               |  130 ++++-
 hw/display/pl110.c             |    8 +-
 hw/i2c/core.c                  |   39 +-
 hw/i2c/smbus.c                 |   12 +-
 hw/timer/a9gtimer.c            |   14 +-
 hw/timer/arm_mptimer.c         |  149 +++---
 hw/timer/stm32f2xx_timer.c     |    2 +-
 include/exec/cpu-all.h         |    9 +
 include/hw/acpi/acpi-defs.h    |   68 +++
 include/hw/boards.h            |    7 +
 include/hw/ptimer.h            |   20 +
 include/hw/timer/arm_mptimer.h |    5 +-
 include/qemu-common.h          |   12 +
 linux-user/main.c              |    3 +
 migration/ram.c                |    4 +-
 migration/savevm.c             |   49 ++
 target-arm/cpu.c               |   24 +
 target-arm/cpu.h               |   11 +-
 target-arm/helper.c            |   11 +-
 target-arm/translate.c         |   54 +-
 tests/Makefile.include         |    3 +
 tests/ptimer-test-stubs.c      |    2 +-
 tests/ptimer-test.c            |  362 ++++++++++---
 tests/ptimer-test.h            |    2 +-
 tests/test-arm-mptimer.c       | 1105 ++++++++++++++++++++++++++++++++++++++++
 translate-all.c                |   71 ++-
 vl.c                           |   10 +
 33 files changed, 2135 insertions(+), 301 deletions(-)
 create mode 100644 tests/test-arm-mptimer.c

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 01/32] migration: Remove static allocation of xzblre cache buffer
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
@ 2016-10-24 17:24 ` Peter Maydell
  2016-10-24 17:24 ` [Qemu-devel] [PULL 02/32] exec.c: Remove static allocation of sub_section of sub_page Peter Maydell
                   ` (32 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:24 UTC (permalink / raw)
  To: qemu-devel

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Allocate xzblre zero page cache buffer dynamically.
Remove dependency on TARGET_PAGE_SIZE to make run-time
page size detection for arm platforms.

Signed-off-by: Vijaya Kumar K <vijayak@cavium.com>
Message-id: 1465808915-4887-2-git-send-email-vijayak@caviumnetworks.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 migration/ram.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/migration/ram.c b/migration/ram.c
index bc6154f..d032d38 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -69,7 +69,7 @@ static uint64_t bitmap_sync_count;
 /* 0x80 is reserved in migration.h start with 0x100 next */
 #define RAM_SAVE_FLAG_COMPRESS_PAGE    0x100
 
-static const uint8_t ZERO_TARGET_PAGE[TARGET_PAGE_SIZE];
+static uint8_t *ZERO_TARGET_PAGE;
 
 static inline bool is_zero_range(uint8_t *p, uint64_t size)
 {
@@ -1431,6 +1431,7 @@ static void ram_migration_cleanup(void *opaque)
         cache_fini(XBZRLE.cache);
         g_free(XBZRLE.encoded_buf);
         g_free(XBZRLE.current_buf);
+        g_free(ZERO_TARGET_PAGE);
         XBZRLE.cache = NULL;
         XBZRLE.encoded_buf = NULL;
         XBZRLE.current_buf = NULL;
@@ -1889,6 +1890,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
 
     if (migrate_use_xbzrle()) {
         XBZRLE_cache_lock();
+        ZERO_TARGET_PAGE = g_malloc0(TARGET_PAGE_SIZE);
         XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
                                   TARGET_PAGE_SIZE,
                                   TARGET_PAGE_SIZE);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 02/32] exec.c: Remove static allocation of sub_section of sub_page
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
  2016-10-24 17:24 ` [Qemu-devel] [PULL 01/32] migration: Remove static allocation of xzblre cache buffer Peter Maydell
@ 2016-10-24 17:24 ` Peter Maydell
  2016-10-24 17:24 ` [Qemu-devel] [PULL 03/32] translate-all.c: Compute L1 page table properties at runtime Peter Maydell
                   ` (31 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:24 UTC (permalink / raw)
  To: qemu-devel

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Allocate sub_section dynamically. Remove dependency
on TARGET_PAGE_SIZE to make run-time page size detection
for arm platforms.

Signed-off-by: Vijaya Kumar K <vijayak@cavium.com>
Message-id: 1465808915-4887-3-git-send-email-vijayak@caviumnetworks.com
[PMM: use flexible array member rather than separate malloc
 so we don't need an extra pointer deref when using it]
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 exec.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/exec.c b/exec.c
index 6d7f600..93128fd 100644
--- a/exec.c
+++ b/exec.c
@@ -153,7 +153,7 @@ typedef struct subpage_t {
     MemoryRegion iomem;
     AddressSpace *as;
     hwaddr base;
-    uint16_t sub_section[TARGET_PAGE_SIZE];
+    uint16_t sub_section[];
 } subpage_t;
 
 #define PHYS_SECTION_UNASSIGNED 0
@@ -2215,8 +2215,7 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
 {
     subpage_t *mmio;
 
-    mmio = g_malloc0(sizeof(subpage_t));
-
+    mmio = g_malloc0(sizeof(subpage_t) + TARGET_PAGE_SIZE * sizeof(uint16_t));
     mmio->as = as;
     mmio->base = base;
     memory_region_init_io(&mmio->iomem, NULL, &subpage_ops, mmio,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 03/32] translate-all.c: Compute L1 page table properties at runtime
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
  2016-10-24 17:24 ` [Qemu-devel] [PULL 01/32] migration: Remove static allocation of xzblre cache buffer Peter Maydell
  2016-10-24 17:24 ` [Qemu-devel] [PULL 02/32] exec.c: Remove static allocation of sub_section of sub_page Peter Maydell
@ 2016-10-24 17:24 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 04/32] cpu: Support a target CPU having a variable page size Peter Maydell
                   ` (30 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:24 UTC (permalink / raw)
  To: qemu-devel

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Remove L1 page mapping table properties computing
statically using macros which is dependent on
TARGET_PAGE_BITS. Drop macros V_L1_SIZE, V_L1_SHIFT,
V_L1_BITS macros and replace with variables which are
computed at early stage of VM boot.

Removing dependency can help to make TARGET_PAGE_BITS
dynamic.

Signed-off-by: Vijaya Kumar K <vijayak@cavium.com>
Message-id: 1465808915-4887-4-git-send-email-vijayak@caviumnetworks.com
[PMM:
 assert(v_l1_shift % V_L2_BITS == 0)
 cache v_l2_levels
 initialize from page_init() rather than vl.c
 minor code style fixes
 put v_l1_size into a local where used as a loop limit]
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 translate-all.c | 71 +++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 46 insertions(+), 25 deletions(-)

diff --git a/translate-all.c b/translate-all.c
index 8ca393c9d..86b45a1 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -97,25 +97,24 @@ typedef struct PageDesc {
 #define V_L2_BITS 10
 #define V_L2_SIZE (1 << V_L2_BITS)
 
-/* The bits remaining after N lower levels of page tables.  */
-#define V_L1_BITS_REM \
-    ((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % V_L2_BITS)
-
-#if V_L1_BITS_REM < 4
-#define V_L1_BITS  (V_L1_BITS_REM + V_L2_BITS)
-#else
-#define V_L1_BITS  V_L1_BITS_REM
-#endif
-
-#define V_L1_SIZE  ((target_ulong)1 << V_L1_BITS)
-
-#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
-
 uintptr_t qemu_host_page_size;
 intptr_t qemu_host_page_mask;
 
-/* The bottom level has pointers to PageDesc */
-static void *l1_map[V_L1_SIZE];
+/*
+ * L1 Mapping properties
+ */
+static int v_l1_size;
+static int v_l1_shift;
+static int v_l2_levels;
+
+/* The bottom level has pointers to PageDesc, and is indexed by
+ * anything from 4 to (V_L2_BITS + 3) bits, depending on target page size.
+ */
+#define V_L1_MIN_BITS 4
+#define V_L1_MAX_BITS (V_L2_BITS + 3)
+#define V_L1_MAX_SIZE (1 << V_L1_MAX_BITS)
+
+static void *l1_map[V_L1_MAX_SIZE];
 
 /* code generation context */
 TCGContext tcg_ctx;
@@ -125,6 +124,26 @@ TCGContext tcg_ctx;
 __thread int have_tb_lock;
 #endif
 
+static void page_table_config_init(void)
+{
+    uint32_t v_l1_bits;
+
+    assert(TARGET_PAGE_BITS);
+    /* The bits remaining after N lower levels of page tables.  */
+    v_l1_bits = (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % V_L2_BITS;
+    if (v_l1_bits < V_L1_MIN_BITS) {
+        v_l1_bits += V_L2_BITS;
+    }
+
+    v_l1_size = 1 << v_l1_bits;
+    v_l1_shift = L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - v_l1_bits;
+    v_l2_levels = v_l1_shift / V_L2_BITS - 1;
+
+    assert(v_l1_bits <= V_L1_MAX_BITS);
+    assert(v_l1_shift % V_L2_BITS == 0);
+    assert(v_l2_levels >= 0);
+}
+
 void tb_lock(void)
 {
 #ifdef CONFIG_USER_ONLY
@@ -332,6 +351,8 @@ void page_size_init(void)
 static void page_init(void)
 {
     page_size_init();
+    page_table_config_init();
+
 #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
     {
 #ifdef HAVE_KINFO_GETVMMAP
@@ -408,10 +429,10 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
     int i;
 
     /* Level 1.  Always allocated.  */
-    lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1));
+    lp = l1_map + ((index >> v_l1_shift) & (v_l1_size - 1));
 
     /* Level 2..N-1.  */
-    for (i = V_L1_SHIFT / V_L2_BITS - 1; i > 0; i--) {
+    for (i = v_l2_levels; i > 0; i--) {
         void **p = atomic_rcu_read(lp);
 
         if (p == NULL) {
@@ -826,10 +847,10 @@ static void page_flush_tb_1(int level, void **lp)
 
 static void page_flush_tb(void)
 {
-    int i;
+    int i, l1_sz = v_l1_size;
 
-    for (i = 0; i < V_L1_SIZE; i++) {
-        page_flush_tb_1(V_L1_SHIFT / V_L2_BITS - 1, l1_map + i);
+    for (i = 0; i < l1_sz; i++) {
+        page_flush_tb_1(v_l2_levels, l1_map + i);
     }
 }
 
@@ -1883,16 +1904,16 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data,
 int walk_memory_regions(void *priv, walk_memory_regions_fn fn)
 {
     struct walk_memory_regions_data data;
-    uintptr_t i;
+    uintptr_t i, l1_sz = v_l1_size;
 
     data.fn = fn;
     data.priv = priv;
     data.start = -1u;
     data.prot = 0;
 
-    for (i = 0; i < V_L1_SIZE; i++) {
-        int rc = walk_memory_regions_1(&data, (target_ulong)i << (V_L1_SHIFT + TARGET_PAGE_BITS),
-                                       V_L1_SHIFT / V_L2_BITS - 1, l1_map + i);
+    for (i = 0; i < l1_sz; i++) {
+        target_ulong base = i << (v_l1_shift + TARGET_PAGE_BITS);
+        int rc = walk_memory_regions_1(&data, base, v_l2_levels, l1_map + i);
         if (rc != 0) {
             return rc;
         }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 04/32] cpu: Support a target CPU having a variable page size
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (2 preceding siblings ...)
  2016-10-24 17:24 ` [Qemu-devel] [PULL 03/32] translate-all.c: Compute L1 page table properties at runtime Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 05/32] migration/savevm.c: migrate non-default " Peter Maydell
                   ` (29 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

Support target CPUs having a page size which isn't knownn
at compile time. To use this, the CPU implementation should:
 * define TARGET_PAGE_BITS_VARY
 * not define TARGET_PAGE_BITS
 * define TARGET_PAGE_BITS_MIN to the smallest value it
   might possibly want for TARGET_PAGE_BITS
 * call set_preferred_target_page_bits() in its realize
   function to indicate the actual preferred target page
   size for the CPU (and report any error from it)

In CONFIG_USER_ONLY, the CPU implementation should continue
to define TARGET_PAGE_BITS appropriately for the guest
OS page size.

Machines which want to take advantage of having the page
size something larger than TARGET_PAGE_BITS_MIN must
set the MachineClass minimum_page_bits field to a value
which they guarantee will be no greater than the preferred
page size for any CPU they create.

Note that changing the target page size by setting
minimum_page_bits is a migration compatibility break
for that machine.

For debugging purposes, attempts to use TARGET_PAGE_SIZE
before it has been finally confirmed will assert.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 exec.c                 | 42 ++++++++++++++++++++++++++++++++++++++++++
 include/exec/cpu-all.h |  9 +++++++++
 include/hw/boards.h    |  7 +++++++
 include/qemu-common.h  | 12 ++++++++++++
 vl.c                   | 10 ++++++++++
 5 files changed, 80 insertions(+)

diff --git a/exec.c b/exec.c
index 93128fd..963b91a 100644
--- a/exec.c
+++ b/exec.c
@@ -93,6 +93,11 @@ static MemoryRegion io_mem_unassigned;
 
 #endif
 
+#ifdef TARGET_PAGE_BITS_VARY
+int target_page_bits;
+bool target_page_bits_decided;
+#endif
+
 struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
 /* current CPU in the current thread. It is only valid inside
    cpu_exec() */
@@ -102,8 +107,37 @@ __thread CPUState *current_cpu;
    2 = Adaptive rate instruction counting.  */
 int use_icount;
 
+bool set_preferred_target_page_bits(int bits)
+{
+    /* The target page size is the lowest common denominator for all
+     * the CPUs in the system, so we can only make it smaller, never
+     * larger. And we can't make it smaller once we've committed to
+     * a particular size.
+     */
+#ifdef TARGET_PAGE_BITS_VARY
+    assert(bits >= TARGET_PAGE_BITS_MIN);
+    if (target_page_bits == 0 || target_page_bits > bits) {
+        if (target_page_bits_decided) {
+            return false;
+        }
+        target_page_bits = bits;
+    }
+#endif
+    return true;
+}
+
 #if !defined(CONFIG_USER_ONLY)
 
+static void finalize_target_page_bits(void)
+{
+#ifdef TARGET_PAGE_BITS_VARY
+    if (target_page_bits == 0) {
+        target_page_bits = TARGET_PAGE_BITS_MIN;
+    }
+    target_page_bits_decided = true;
+#endif
+}
+
 typedef struct PhysPageEntry PhysPageEntry;
 
 struct PhysPageEntry {
@@ -2807,6 +2841,14 @@ void cpu_register_map_client(QEMUBH *bh)
 void cpu_exec_init_all(void)
 {
     qemu_mutex_init(&ram_list.mutex);
+    /* The data structures we set up here depend on knowing the page size,
+     * so no more changes can be made after this point.
+     * In an ideal world, nothing we did before we had finished the
+     * machine setup would care about the target page size, and we could
+     * do this much later, rather than requiring board models to state
+     * up front what their requirements are.
+     */
+    finalize_target_page_bits();
     io_mem_init();
     memory_map_init();
     qemu_mutex_init(&map_client_list_lock);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index b6a7059..861260d 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -189,6 +189,15 @@ void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val,
 
 /* page related stuff */
 
+#ifdef TARGET_PAGE_BITS_VARY
+extern bool target_page_bits_decided;
+extern int target_page_bits;
+#define TARGET_PAGE_BITS ({ assert(target_page_bits_decided); \
+                            target_page_bits; })
+#else
+#define TARGET_PAGE_BITS_MIN TARGET_PAGE_BITS
+#endif
+
 #define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
 #define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
 #define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
diff --git a/include/hw/boards.h b/include/hw/boards.h
index e46a744..a51da9c 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -86,6 +86,12 @@ typedef struct {
  *    Returns a @HotpluggableCPUList, which describes CPUs objects which
  *    could be added with -device/device_add.
  *    Caller is responsible for freeing returned list.
+ * @minimum_page_bits:
+ *    If non-zero, the board promises never to create a CPU with a page size
+ *    smaller than this, so QEMU can use a more efficient larger page
+ *    size than the target architecture's minimum. (Attempting to create
+ *    such a CPU will fail.) Note that changing this is a migration
+ *    compatibility break for the machine.
  */
 struct MachineClass {
     /*< private >*/
@@ -124,6 +130,7 @@ struct MachineClass {
     ram_addr_t default_ram_size;
     bool option_rom_has_mr;
     bool rom_file_has_mr;
+    int minimum_page_bits;
 
     HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
                                            DeviceState *dev);
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 9e8b0bd..7e6e4fe 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -82,6 +82,18 @@ bool tcg_enabled(void);
 void cpu_exec_init_all(void);
 
 /**
+ * set_preferred_target_page_bits:
+ * @bits: number of bits needed to represent an address within the page
+ *
+ * Set the preferred target page size (the actual target page
+ * size may be smaller than any given CPU's preference).
+ * Returns true on success, false on failure (which can only happen
+ * if this is called after the system has already finalized its
+ * choice of page size and the requested page size is smaller than that).
+ */
+bool set_preferred_target_page_bits(int bits);
+
+/**
  * Sends a (part of) iovec down a socket, yielding when the socket is full, or
  * Receives data into a (part of) iovec from a socket,
  * yielding when there is no data in the socket.
diff --git a/vl.c b/vl.c
index 44e08b4..4ec8120 100644
--- a/vl.c
+++ b/vl.c
@@ -4088,6 +4088,16 @@ int main(int argc, char **argv, char **envp)
     }
     object_property_add_child(object_get_root(), "machine",
                               OBJECT(current_machine), &error_abort);
+
+    if (machine_class->minimum_page_bits) {
+        if (!set_preferred_target_page_bits(machine_class->minimum_page_bits)) {
+            /* This would be a board error: specifying a minimum smaller than
+             * a target's compile-time fixed setting.
+             */
+            g_assert_not_reached();
+        }
+    }
+
     cpu_exec_init_all();
 
     if (machine_class->hw_version) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 05/32] migration/savevm.c: migrate non-default page size
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (3 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 04/32] cpu: Support a target CPU having a variable page size Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 06/32] target-arm: Make page size a runtime setting Peter Maydell
                   ` (28 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

Add a subsection to vmstate_configuration which is present
only if the guest is using a target page size which is
different from the default. This allows us to helpfully
diagnose attempts to migrate between machines which
are using different target page sizes.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 migration/savevm.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/migration/savevm.c b/migration/savevm.c
index a831ec2..cfcbbd0 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -265,6 +265,7 @@ typedef struct SaveState {
     bool skip_configuration;
     uint32_t len;
     const char *name;
+    uint32_t target_page_bits;
 } SaveState;
 
 static SaveState savevm_state = {
@@ -286,6 +287,19 @@ static void configuration_pre_save(void *opaque)
 
     state->len = strlen(current_name);
     state->name = current_name;
+    state->target_page_bits = TARGET_PAGE_BITS;
+}
+
+static int configuration_pre_load(void *opaque)
+{
+    SaveState *state = opaque;
+
+    /* If there is no target-page-bits subsection it means the source
+     * predates the variable-target-page-bits support and is using the
+     * minimum possible value for this CPU.
+     */
+    state->target_page_bits = TARGET_PAGE_BITS_MIN;
+    return 0;
 }
 
 static int configuration_post_load(void *opaque, int version_id)
@@ -298,12 +312,43 @@ static int configuration_post_load(void *opaque, int version_id)
                      (int) state->len, state->name, current_name);
         return -EINVAL;
     }
+
+    if (state->target_page_bits != TARGET_PAGE_BITS) {
+        error_report("Received TARGET_PAGE_BITS is %d but local is %d",
+                     state->target_page_bits, TARGET_PAGE_BITS);
+        return -EINVAL;
+    }
+
     return 0;
 }
 
+/* The target-page-bits subsection is present only if the
+ * target page size is not the same as the default (ie the
+ * minimum page size for a variable-page-size guest CPU).
+ * If it is present then it contains the actual target page
+ * bits for the machine, and migration will fail if the
+ * two ends don't agree about it.
+ */
+static bool vmstate_target_page_bits_needed(void *opaque)
+{
+    return TARGET_PAGE_BITS > TARGET_PAGE_BITS_MIN;
+}
+
+static const VMStateDescription vmstate_target_page_bits = {
+    .name = "configuration/target-page-bits",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = vmstate_target_page_bits_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(target_page_bits, SaveState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_configuration = {
     .name = "configuration",
     .version_id = 1,
+    .pre_load = configuration_pre_load,
     .post_load = configuration_post_load,
     .pre_save = configuration_pre_save,
     .fields = (VMStateField[]) {
@@ -311,6 +356,10 @@ static const VMStateDescription vmstate_configuration = {
         VMSTATE_VBUFFER_ALLOC_UINT32(name, SaveState, 0, NULL, 0, len),
         VMSTATE_END_OF_LIST()
     },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_target_page_bits,
+        NULL
+    }
 };
 
 static void dump_vmstate_vmsd(FILE *out_file,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 06/32] target-arm: Make page size a runtime setting
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (4 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 05/32] migration/savevm.c: migrate non-default " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 07/32] hw/arm/virt: Set minimum_page_bits to 12 Peter Maydell
                   ` (27 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

Rather than defining TARGET_PAGE_BITS to always be 10,
switch to using a value picked at runtime. This allows us
to use 4K pages for modern ARM CPUs (and in particular all
64-bit CPUs) without having to drop support for the old
ARMv5 CPUs which had 1K pages.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/cpu.c | 24 ++++++++++++++++++++++++
 target-arm/cpu.h |  9 +++++----
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 1b9540e..c94a324 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -576,6 +576,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
     ARMCPU *cpu = ARM_CPU(dev);
     ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev);
     CPUARMState *env = &cpu->env;
+    int pagebits;
 
     /* Some features automatically imply others: */
     if (arm_feature(env, ARM_FEATURE_V8)) {
@@ -631,6 +632,29 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         set_feature(env, ARM_FEATURE_THUMB_DSP);
     }
 
+    if (arm_feature(env, ARM_FEATURE_V7) &&
+        !arm_feature(env, ARM_FEATURE_M) &&
+        !arm_feature(env, ARM_FEATURE_MPU)) {
+        /* v7VMSA drops support for the old ARMv5 tiny pages, so we
+         * can use 4K pages.
+         */
+        pagebits = 12;
+    } else {
+        /* For CPUs which might have tiny 1K pages, or which have an
+         * MPU and might have small region sizes, stick with 1K pages.
+         */
+        pagebits = 10;
+    }
+    if (!set_preferred_target_page_bits(pagebits)) {
+        /* This can only ever happen for hotplugging a CPU, or if
+         * the board code incorrectly creates a CPU which it has
+         * promised via minimum_page_size that it will not.
+         */
+        error_setg(errp, "This CPU requires a smaller page size than the "
+                   "system is using");
+        return;
+    }
+
     if (cpu->reset_hivecs) {
             cpu->reset_sctlr |= (1 << 13);
     }
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 2218c00..6695390 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1766,10 +1766,11 @@ bool write_cpustate_to_list(ARMCPU *cpu);
 #if defined(CONFIG_USER_ONLY)
 #define TARGET_PAGE_BITS 12
 #else
-/* The ARM MMU allows 1k pages.  */
-/* ??? Linux doesn't actually use these, and they're deprecated in recent
-   architecture revisions.  Maybe a configure option to disable them.  */
-#define TARGET_PAGE_BITS 10
+/* ARMv7 and later CPUs have 4K pages minimum, but ARMv5 and v6
+ * have to support 1K tiny pages.
+ */
+#define TARGET_PAGE_BITS_VARY
+#define TARGET_PAGE_BITS_MIN 10
 #endif
 
 #if defined(TARGET_AARCH64)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 07/32] hw/arm/virt: Set minimum_page_bits to 12
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (5 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 06/32] target-arm: Make page size a runtime setting Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 08/32] hw/ptimer: Add "wraparound after one period" policy Peter Maydell
                   ` (26 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

Since the virt board model will never create a CPU which is
pre-ARMv7, we know that our minimum page size is 4K and can
set minimum_page_bits accordingly, for improved performance.

Note that this is a migration compatibility break, so
we introduce it only for the virt-2.8 machine and onward;
virt-2.7 continues using the old 1K pages.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 hw/arm/virt.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 895446f..47ec7ff 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1499,6 +1499,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
     mc->block_default_type = IF_VIRTIO;
     mc->no_cdrom = 1;
     mc->pci_allow_0_address = true;
+    /* We know we will never create a pre-ARMv7 CPU which needs 1K pages */
+    mc->minimum_page_bits = 12;
 }
 
 static const TypeInfo virt_machine_info = {
@@ -1570,6 +1572,8 @@ static void virt_machine_2_7_options(MachineClass *mc)
     SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7);
     /* ITS was introduced with 2.8 */
     vmc->no_its = true;
+    /* Stick with 1K pages for migration compatibility */
+    mc->minimum_page_bits = 0;
 }
 DEFINE_VIRT_MACHINE(2, 7)
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 08/32] hw/ptimer: Add "wraparound after one period" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (6 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 07/32] hw/arm/virt: Set minimum_page_bits to 12 Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 09/32] tests: ptimer: Add tests for " Peter Maydell
                   ` (25 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

Currently, periodic counter wraps around immediately once counter reaches
"0", this is wrong behaviour for some of the timers, resulting in one period
being lost. Add new ptimer policy that provides correct behaviour for such
timers, so that counter stays with "0" for a one period before wrapping
around.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: f22a670cf1f4be298b31640cb5f4be1df0f20ab6.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/core/ptimer.c    | 58 +++++++++++++++++++++++++++++++++++++++--------------
 include/hw/ptimer.h |  4 ++++
 2 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index c45c835..1f4122d 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -13,6 +13,8 @@
 #include "sysemu/replay.h"
 #include "sysemu/qtest.h"
 
+#define DELTA_ADJUST    1
+
 struct ptimer_state
 {
     uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
@@ -35,16 +37,17 @@ static void ptimer_trigger(ptimer_state *s)
     }
 }
 
-static void ptimer_reload(ptimer_state *s)
+static void ptimer_reload(ptimer_state *s, int delta_adjust)
 {
     uint32_t period_frac = s->period_frac;
     uint64_t period = s->period;
+    uint64_t delta = s->delta;
 
-    if (s->delta == 0) {
+    if (delta == 0) {
         ptimer_trigger(s);
-        s->delta = s->limit;
+        delta = s->delta = s->limit;
     }
-    if (s->delta == 0 || s->period == 0) {
+    if (delta == 0 || s->period == 0) {
         if (!qtest_enabled()) {
             fprintf(stderr, "Timer with period zero, disabling\n");
         }
@@ -53,6 +56,10 @@ static void ptimer_reload(ptimer_state *s)
         return;
     }
 
+    if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
+        delta += delta_adjust;
+    }
+
     /*
      * Artificially limit timeout rate to something
      * achievable under QEMU.  Otherwise, QEMU spends all
@@ -62,15 +69,15 @@ static void ptimer_reload(ptimer_state *s)
      * on the current generation of host machines.
      */
 
-    if (s->enabled == 1 && (s->delta * period < 10000) && !use_icount) {
-        period = 10000 / s->delta;
+    if (s->enabled == 1 && (delta * period < 10000) && !use_icount) {
+        period = 10000 / delta;
         period_frac = 0;
     }
 
     s->last_event = s->next_event;
-    s->next_event = s->last_event + s->delta * period;
+    s->next_event = s->last_event + delta * period;
     if (period_frac) {
-        s->next_event += ((int64_t)period_frac * s->delta) >> 32;
+        s->next_event += ((int64_t)period_frac * delta) >> 32;
     }
     timer_mod(s->timer, s->next_event);
 }
@@ -83,7 +90,7 @@ static void ptimer_tick(void *opaque)
     if (s->enabled == 2) {
         s->enabled = 0;
     } else {
-        ptimer_reload(s);
+        ptimer_reload(s, DELTA_ADJUST);
     }
 }
 
@@ -94,6 +101,7 @@ uint64_t ptimer_get_count(ptimer_state *s)
     if (s->enabled) {
         int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
         int64_t next = s->next_event;
+        int64_t last = s->last_event;
         bool expired = (now - next >= 0);
         bool oneshot = (s->enabled == 2);
 
@@ -118,7 +126,7 @@ uint64_t ptimer_get_count(ptimer_state *s)
             /* We need to divide time by period, where time is stored in
                rem (64-bit integer) and period is stored in period/period_frac
                (64.32 fixed point).
-              
+
                Doing full precision division is hard, so scale values and
                do a 64-bit division.  The result should be rounded down,
                so that the rounding error never causes the timer to go
@@ -145,6 +153,26 @@ uint64_t ptimer_get_count(ptimer_state *s)
                     div += 1;
             }
             counter = rem / div;
+
+            if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
+                /* Before wrapping around, timer should stay with counter = 0
+                   for a one period.  */
+                if (!oneshot && s->delta == s->limit) {
+                    if (now == last) {
+                        /* Counter == delta here, check whether it was
+                           adjusted and if it was, then right now it is
+                           that "one period".  */
+                        if (counter == s->limit + DELTA_ADJUST) {
+                            return 0;
+                        }
+                    } else if (counter == s->limit) {
+                        /* Since the counter is rounded down and now != last,
+                           the counter == limit means that delta was adjusted
+                           by +1 and right now it is that adjusted period.  */
+                        return 0;
+                    }
+                }
+            }
         }
     } else {
         counter = s->delta;
@@ -157,7 +185,7 @@ void ptimer_set_count(ptimer_state *s, uint64_t count)
     s->delta = count;
     if (s->enabled) {
         s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        ptimer_reload(s);
+        ptimer_reload(s, 0);
     }
 }
 
@@ -174,7 +202,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
     s->enabled = oneshot ? 2 : 1;
     if (was_disabled) {
         s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        ptimer_reload(s);
+        ptimer_reload(s, 0);
     }
 }
 
@@ -198,7 +226,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period)
     s->period_frac = 0;
     if (s->enabled) {
         s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        ptimer_reload(s);
+        ptimer_reload(s, 0);
     }
 }
 
@@ -210,7 +238,7 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
     s->period_frac = (1000000000ll << 32) / freq;
     if (s->enabled) {
         s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        ptimer_reload(s);
+        ptimer_reload(s, 0);
     }
 }
 
@@ -223,7 +251,7 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
         s->delta = limit;
     if (s->enabled && reload) {
         s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        ptimer_reload(s);
+        ptimer_reload(s, 0);
     }
 }
 
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 26c7fdc..03441cb 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -35,6 +35,10 @@
  */
 #define PTIMER_POLICY_DEFAULT               0
 
+/* Periodic timer counter stays with "0" for a one period before wrapping
+ * around.  */
+#define PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD (1 << 0)
+
 /* ptimer.c */
 typedef struct ptimer_state ptimer_state;
 typedef void (*ptimer_cb)(void *opaque);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 09/32] tests: ptimer: Add tests for "wraparound after one period" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (7 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 08/32] hw/ptimer: Add "wraparound after one period" policy Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 10/32] hw/ptimer: Add "continuous trigger" policy Peter Maydell
                   ` (24 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD changes ptimer behaviour in a such way,
that it would wrap around after one period instead of doing it immediately.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: ce27bb84ed9f2b64300dd4e90f3eff235a7dcedf.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test.c | 127 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 104 insertions(+), 23 deletions(-)

diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index 7b0ddf6..b95958f 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -188,6 +188,7 @@ static void check_periodic(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
 
     triggered = false;
 
@@ -195,20 +196,41 @@ static void check_periodic(gconstpointer arg)
     ptimer_set_limit(ptimer, 10, 1);
     ptimer_run(ptimer, 0);
 
-    qemu_clock_step(2000000 * 10 + 100000);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
+    g_assert_false(triggered);
+
+    qemu_clock_step(100000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
+    g_assert_false(triggered);
+
+    qemu_clock_step(2000000 * 10 - 100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 10);
+    g_assert_true(triggered);
+
+    qemu_clock_step(100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 9);
     g_assert_true(triggered);
 
     triggered = false;
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 20);
 
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 20);
+    g_assert_false(triggered);
+
+    qemu_clock_step(100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 19);
+    g_assert_false(triggered);
+
     qemu_clock_step(2000000 * 11 + 100000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
@@ -216,7 +238,24 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 10);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
+    g_assert_true(triggered);
+
+    triggered = false;
+
+    ptimer_set_count(ptimer, 3);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
+    g_assert_false(triggered);
+
+    qemu_clock_step(100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 2);
+    g_assert_false(triggered);
+
+    qemu_clock_step(2000000 * 4);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -224,7 +263,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 3);
@@ -232,14 +271,14 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 3 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 9);
     g_assert_true(triggered);
 
     triggered = false;
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 0);
@@ -248,18 +287,23 @@ static void check_periodic(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(2000000 * 12 + 100000);
+    qemu_clock_step(100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
+    g_assert_false(triggered);
+
+    qemu_clock_step(2000000 * 12);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 8 : 7);
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
 
     triggered = false;
 
-    qemu_clock_step(2000000 * 12 + 100000);
+    qemu_clock_step(2000000 * 10);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 8 : 7);
     g_assert_false(triggered);
 
     ptimer_run(ptimer, 0);
@@ -267,7 +311,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 8 : 7);
     g_assert_false(triggered);
 }
 
@@ -276,6 +320,7 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
 
     triggered = false;
 
@@ -285,6 +330,9 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
 
     qemu_clock_step(2000000 * 9 + 100000);
 
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_false(triggered);
+
     ptimer_run(ptimer, 0);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
@@ -292,7 +340,7 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 9);
     g_assert_true(triggered);
 
     triggered = false;
@@ -301,7 +349,7 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
 
     ptimer_run(ptimer, 1);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 1 : 0);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 3);
@@ -394,6 +442,7 @@ static void check_run_with_delta_0(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
 
     triggered = false;
 
@@ -429,14 +478,21 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98);
+    g_assert_false(triggered);
+
+    triggered = false;
+
+    qemu_clock_step(2000000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 98);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 98);
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -463,6 +519,23 @@ static void check_periodic_with_load_0(gconstpointer arg)
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
     g_assert_false(triggered);
 
+    triggered = false;
+
+    ptimer_set_count(ptimer, 10);
+    ptimer_run(ptimer, 0);
+
+    qemu_clock_step(2000000 * 10 + 100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_true(triggered);
+
+    triggered = false;
+
+    qemu_clock_step(2000000 + 100000);
+
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_false(triggered);
+
     ptimer_stop(ptimer);
 }
 
@@ -486,18 +559,12 @@ static void check_oneshot_with_load_0(gconstpointer arg)
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
     g_assert_false(triggered);
-
-    triggered = false;
-
-    qemu_clock_step(2000000 + 100000);
-
-    g_assert_false(triggered);
 }
 
 static void add_ptimer_tests(uint8_t policy)
 {
     uint8_t *ppolicy = g_malloc(1);
-    char *policy_name = g_malloc(64);
+    char *policy_name = g_malloc0(256);
 
     *ppolicy = policy;
 
@@ -505,6 +572,10 @@ static void add_ptimer_tests(uint8_t policy)
         g_sprintf(policy_name, "default");
     }
 
+    if (policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
+        g_strlcat(policy_name, "wrap_after_one_period,", 256);
+    }
+
     g_test_add_data_func(
         g_strdup_printf("/ptimer/set_count policy=%s", policy_name),
         ppolicy, check_set_count);
@@ -550,6 +621,16 @@ static void add_ptimer_tests(uint8_t policy)
         ppolicy, check_oneshot_with_load_0);
 }
 
+static void add_all_ptimer_policies_comb_tests(void)
+{
+    int last_policy = PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD;
+    int policy = PTIMER_POLICY_DEFAULT;
+
+    for (; policy < (last_policy << 1); policy++) {
+        add_ptimer_tests(policy);
+    }
+}
+
 int main(int argc, char **argv)
 {
     int i;
@@ -560,7 +641,7 @@ int main(int argc, char **argv)
         main_loop_tlg.tl[i] = g_new0(QEMUTimerList, 1);
     }
 
-    add_ptimer_tests(PTIMER_POLICY_DEFAULT);
+    add_all_ptimer_policies_comb_tests();
 
     qtest_allowed = true;
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 10/32] hw/ptimer: Add "continuous trigger" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (8 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 09/32] tests: ptimer: Add tests for " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 11/32] tests: ptimer: Add tests for " Peter Maydell
                   ` (23 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

Currently, periodic timer that has load = delta = 0 performs trigger
on timer reload and stops, printing a "period zero" error message.
Introduce new policy that makes periodic timer to continuously trigger
with a period interval in case of load = 0.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 632b23dd11055d9bd5e338d66b38fac0bd51462e.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/core/ptimer.c    | 30 +++++++++++++++++++++++++++---
 include/hw/ptimer.h |  4 ++++
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 1f4122d..1aa0194 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -47,7 +47,8 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
         ptimer_trigger(s);
         delta = s->delta = s->limit;
     }
-    if (delta == 0 || s->period == 0) {
+
+    if (s->period == 0) {
         if (!qtest_enabled()) {
             fprintf(stderr, "Timer with period zero, disabling\n");
         }
@@ -60,6 +61,21 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
         delta += delta_adjust;
     }
 
+    if (delta == 0 && (s->policy_mask & PTIMER_POLICY_CONTINUOUS_TRIGGER)) {
+        if (s->enabled == 1 && s->limit == 0) {
+            delta = 1;
+        }
+    }
+
+    if (delta == 0) {
+        if (!qtest_enabled()) {
+            fprintf(stderr, "Timer with delta zero, disabling\n");
+        }
+        timer_del(s->timer);
+        s->enabled = 0;
+        return;
+    }
+
     /*
      * Artificially limit timeout rate to something
      * achievable under QEMU.  Otherwise, QEMU spends all
@@ -90,7 +106,15 @@ static void ptimer_tick(void *opaque)
     if (s->enabled == 2) {
         s->enabled = 0;
     } else {
-        ptimer_reload(s, DELTA_ADJUST);
+        int delta_adjust = DELTA_ADJUST;
+
+        if (s->limit == 0) {
+            /* If a "continuous trigger" policy is not used and limit == 0,
+               we should error out.  */
+            delta_adjust = 0;
+        }
+
+        ptimer_reload(s, delta_adjust);
     }
 }
 
@@ -98,7 +122,7 @@ uint64_t ptimer_get_count(ptimer_state *s)
 {
     uint64_t counter;
 
-    if (s->enabled) {
+    if (s->enabled && s->delta != 0) {
         int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
         int64_t next = s->next_event;
         int64_t last = s->last_event;
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 03441cb..b2fb4f9 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -39,6 +39,10 @@
  * around.  */
 #define PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD (1 << 0)
 
+/* Running periodic timer that has counter = limit = 0 would continuously
+ * re-trigger every period.  */
+#define PTIMER_POLICY_CONTINUOUS_TRIGGER    (1 << 1)
+
 /* ptimer.c */
 typedef struct ptimer_state ptimer_state;
 typedef void (*ptimer_cb)(void *opaque);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 11/32] tests: ptimer: Add tests for "continuous trigger" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (9 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 10/32] hw/ptimer: Add "continuous trigger" policy Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 12/32] hw/ptimer: Add "no immediate " Peter Maydell
                   ` (22 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

PTIMER_POLICY_CONTINUOUS_TRIGGER makes periodic ptimer to re-trigger every
period in case of load = delta = 0.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 7a908ab38b902d521eb959941f9efe2df8ce4297.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index b95958f..dd4b1a1 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -503,6 +503,7 @@ static void check_periodic_with_load_0(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool continuous_trigger = (*policy & PTIMER_POLICY_CONTINUOUS_TRIGGER);
 
     triggered = false;
 
@@ -517,7 +518,12 @@ static void check_periodic_with_load_0(gconstpointer arg)
     qemu_clock_step(2000000 + 100000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_false(triggered);
+
+    if (continuous_trigger) {
+        g_assert_true(triggered);
+    } else {
+        g_assert_false(triggered);
+    }
 
     triggered = false;
 
@@ -534,7 +540,12 @@ static void check_periodic_with_load_0(gconstpointer arg)
     qemu_clock_step(2000000 + 100000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_false(triggered);
+
+    if (continuous_trigger) {
+        g_assert_true(triggered);
+    } else {
+        g_assert_false(triggered);
+    }
 
     ptimer_stop(ptimer);
 }
@@ -576,6 +587,10 @@ static void add_ptimer_tests(uint8_t policy)
         g_strlcat(policy_name, "wrap_after_one_period,", 256);
     }
 
+    if (policy & PTIMER_POLICY_CONTINUOUS_TRIGGER) {
+        g_strlcat(policy_name, "continuous_trigger,", 256);
+    }
+
     g_test_add_data_func(
         g_strdup_printf("/ptimer/set_count policy=%s", policy_name),
         ppolicy, check_set_count);
@@ -623,7 +638,7 @@ static void add_ptimer_tests(uint8_t policy)
 
 static void add_all_ptimer_policies_comb_tests(void)
 {
-    int last_policy = PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD;
+    int last_policy = PTIMER_POLICY_CONTINUOUS_TRIGGER;
     int policy = PTIMER_POLICY_DEFAULT;
 
     for (; policy < (last_policy << 1); policy++) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 12/32] hw/ptimer: Add "no immediate trigger" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (10 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 11/32] tests: ptimer: Add tests for " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 13/32] tests: ptimer: Add tests for " Peter Maydell
                   ` (21 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

Performing trigger on setting (or starting to run with) counter = 0 could
be a wrong behaviour for some of the timers, provide "no immediate trigger"
policy to maintain correct behaviour for such timers.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 72c0319cf2ec599f22397b7da280c06c34dc40dd.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/core/ptimer.c    | 20 ++++++++++++++++----
 include/hw/ptimer.h |  4 ++++
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 1aa0194..ed3fb6c 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -13,7 +13,8 @@
 #include "sysemu/replay.h"
 #include "sysemu/qtest.h"
 
-#define DELTA_ADJUST    1
+#define DELTA_ADJUST     1
+#define DELTA_NO_ADJUST -1
 
 struct ptimer_state
 {
@@ -43,8 +44,11 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
     uint64_t period = s->period;
     uint64_t delta = s->delta;
 
-    if (delta == 0) {
+    if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) {
         ptimer_trigger(s);
+    }
+
+    if (delta == 0) {
         delta = s->delta = s->limit;
     }
 
@@ -58,7 +62,9 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
     }
 
     if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
-        delta += delta_adjust;
+        if (delta_adjust != DELTA_NO_ADJUST) {
+            delta += delta_adjust;
+        }
     }
 
     if (delta == 0 && (s->policy_mask & PTIMER_POLICY_CONTINUOUS_TRIGGER)) {
@@ -67,6 +73,12 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
         }
     }
 
+    if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) {
+        if (delta_adjust != DELTA_NO_ADJUST) {
+            delta = 1;
+        }
+    }
+
     if (delta == 0) {
         if (!qtest_enabled()) {
             fprintf(stderr, "Timer with delta zero, disabling\n");
@@ -111,7 +123,7 @@ static void ptimer_tick(void *opaque)
         if (s->limit == 0) {
             /* If a "continuous trigger" policy is not used and limit == 0,
                we should error out.  */
-            delta_adjust = 0;
+            delta_adjust = DELTA_NO_ADJUST;
         }
 
         ptimer_reload(s, delta_adjust);
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index b2fb4f9..911cc11 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -43,6 +43,10 @@
  * re-trigger every period.  */
 #define PTIMER_POLICY_CONTINUOUS_TRIGGER    (1 << 1)
 
+/* Starting to run with/setting counter to "0" won't trigger immediately,
+ * but after a one period for both oneshot and periodic modes.  */
+#define PTIMER_POLICY_NO_IMMEDIATE_TRIGGER  (1 << 2)
+
 /* ptimer.c */
 typedef struct ptimer_state ptimer_state;
 typedef void (*ptimer_cb)(void *opaque);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 13/32] tests: ptimer: Add tests for "no immediate trigger" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (11 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 12/32] hw/ptimer: Add "no immediate " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 14/32] hw/ptimer: Add "no immediate reload" policy Peter Maydell
                   ` (20 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

PTIMER_POLICY_NO_IMMEDIATE_TRIGGER makes ptimer to not to trigger on starting
to run with / setting counter to "0".

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 12b1e745f90fe2ca3d59197166bc3d379260f912.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 56 insertions(+), 8 deletions(-)

diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index dd4b1a1..d55cc79 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -189,6 +189,7 @@ static void check_periodic(gconstpointer arg)
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
+    bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
 
     triggered = false;
 
@@ -283,7 +284,12 @@ static void check_periodic(gconstpointer arg)
 
     ptimer_set_count(ptimer, 0);
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
-    g_assert_true(triggered);
+
+    if (no_immediate_trigger) {
+        g_assert_false(triggered);
+    } else {
+        g_assert_true(triggered);
+    }
 
     triggered = false;
 
@@ -443,6 +449,7 @@ static void check_run_with_delta_0(gconstpointer arg)
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
+    bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
 
     triggered = false;
 
@@ -450,10 +457,25 @@ static void check_run_with_delta_0(gconstpointer arg)
     ptimer_set_limit(ptimer, 99, 0);
     ptimer_run(ptimer, 1);
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
-    g_assert_true(triggered);
+
+    if (no_immediate_trigger) {
+        g_assert_false(triggered);
+    } else {
+        g_assert_true(triggered);
+    }
 
     triggered = false;
 
+    if (no_immediate_trigger) {
+        qemu_clock_step(2000000 + 100000);
+
+        g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
+        g_assert_false(triggered);
+
+        ptimer_set_count(ptimer, 99);
+        ptimer_run(ptimer, 1);
+    }
+
     qemu_clock_step(2000000 + 100000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
@@ -474,7 +496,12 @@ static void check_run_with_delta_0(gconstpointer arg)
     ptimer_set_count(ptimer, 0);
     ptimer_run(ptimer, 0);
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
-    g_assert_true(triggered);
+
+    if (no_immediate_trigger) {
+        g_assert_false(triggered);
+    } else {
+        g_assert_true(triggered);
+    }
 
     triggered = false;
 
@@ -504,6 +531,7 @@ static void check_periodic_with_load_0(gconstpointer arg)
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
     bool continuous_trigger = (*policy & PTIMER_POLICY_CONTINUOUS_TRIGGER);
+    bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
 
     triggered = false;
 
@@ -511,7 +539,12 @@ static void check_periodic_with_load_0(gconstpointer arg)
     ptimer_run(ptimer, 0);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_true(triggered);
+
+    if (no_immediate_trigger) {
+        g_assert_false(triggered);
+    } else {
+        g_assert_true(triggered);
+    }
 
     triggered = false;
 
@@ -519,7 +552,7 @@ static void check_periodic_with_load_0(gconstpointer arg)
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
 
-    if (continuous_trigger) {
+    if (continuous_trigger || no_immediate_trigger) {
         g_assert_true(triggered);
     } else {
         g_assert_false(triggered);
@@ -555,6 +588,7 @@ static void check_oneshot_with_load_0(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
 
     triggered = false;
 
@@ -562,14 +596,24 @@ static void check_oneshot_with_load_0(gconstpointer arg)
     ptimer_run(ptimer, 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_true(triggered);
+
+    if (no_immediate_trigger) {
+        g_assert_false(triggered);
+    } else {
+        g_assert_true(triggered);
+    }
 
     triggered = false;
 
     qemu_clock_step(2000000 + 100000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_false(triggered);
+
+    if (no_immediate_trigger) {
+        g_assert_true(triggered);
+    } else {
+        g_assert_false(triggered);
+    }
 }
 
 static void add_ptimer_tests(uint8_t policy)
@@ -591,6 +635,10 @@ static void add_ptimer_tests(uint8_t policy)
         g_strlcat(policy_name, "continuous_trigger,", 256);
     }
 
+    if (policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER) {
+        g_strlcat(policy_name, "no_immediate_trigger,", 256);
+    }
+
     g_test_add_data_func(
         g_strdup_printf("/ptimer/set_count policy=%s", policy_name),
         ppolicy, check_set_count);
@@ -638,7 +686,7 @@ static void add_ptimer_tests(uint8_t policy)
 
 static void add_all_ptimer_policies_comb_tests(void)
 {
-    int last_policy = PTIMER_POLICY_CONTINUOUS_TRIGGER;
+    int last_policy = PTIMER_POLICY_NO_IMMEDIATE_TRIGGER;
     int policy = PTIMER_POLICY_DEFAULT;
 
     for (; policy < (last_policy << 1); policy++) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 14/32] hw/ptimer: Add "no immediate reload" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (12 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 13/32] tests: ptimer: Add tests for " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 15/32] tests: ptimer: Add tests for " Peter Maydell
                   ` (19 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

Immediate counter re-load on setting (or on starting to run with)
counter = 0 is a wrong behaviour for some of the timers. Add "no
immediate reload" policy that provides correct behaviour for such timers.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: bf9385cd2550ca451d564fa46007688cee3f3d9d.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/core/ptimer.c    | 31 ++++++++++++++++++++++++++-----
 include/hw/ptimer.h |  4 ++++
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index ed3fb6c..2a69daf 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -48,7 +48,7 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
         ptimer_trigger(s);
     }
 
-    if (delta == 0) {
+    if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) {
         delta = s->delta = s->limit;
     }
 
@@ -79,6 +79,12 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
         }
     }
 
+    if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) {
+        if (s->enabled == 1 && s->limit != 0) {
+            delta = 1;
+        }
+    }
+
     if (delta == 0) {
         if (!qtest_enabled()) {
             fprintf(stderr, "Timer with delta zero, disabling\n");
@@ -113,21 +119,36 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
 static void ptimer_tick(void *opaque)
 {
     ptimer_state *s = (ptimer_state *)opaque;
-    ptimer_trigger(s);
-    s->delta = 0;
+    bool trigger = true;
+
     if (s->enabled == 2) {
+        s->delta = 0;
         s->enabled = 0;
     } else {
         int delta_adjust = DELTA_ADJUST;
 
-        if (s->limit == 0) {
+        if (s->delta == 0 || s->limit == 0) {
             /* If a "continuous trigger" policy is not used and limit == 0,
-               we should error out.  */
+               we should error out. delta == 0 means that this tick is
+               caused by a "no immediate reload" policy, so it shouldn't
+               be adjusted.  */
             delta_adjust = DELTA_NO_ADJUST;
         }
 
+        if (!(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) {
+            /* Avoid re-trigger on deferred reload if "no immediate trigger"
+               policy isn't used.  */
+            trigger = (delta_adjust == DELTA_ADJUST);
+        }
+
+        s->delta = s->limit;
+
         ptimer_reload(s, delta_adjust);
     }
+
+    if (trigger) {
+        ptimer_trigger(s);
+    }
 }
 
 uint64_t ptimer_get_count(ptimer_state *s)
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 911cc11..5455340 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -47,6 +47,10 @@
  * but after a one period for both oneshot and periodic modes.  */
 #define PTIMER_POLICY_NO_IMMEDIATE_TRIGGER  (1 << 2)
 
+/* Starting to run with/setting counter to "0" won't re-load counter
+ * immediately, but after a one period.  */
+#define PTIMER_POLICY_NO_IMMEDIATE_RELOAD   (1 << 3)
+
 /* ptimer.c */
 typedef struct ptimer_state ptimer_state;
 typedef void (*ptimer_cb)(void *opaque);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 15/32] tests: ptimer: Add tests for "no immediate reload" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (13 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 14/32] hw/ptimer: Add "no immediate reload" policy Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 16/32] hw/ptimer: Add "no counter round down" policy Peter Maydell
                   ` (18 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

PTIMER_POLICY_NO_IMMEDIATE_RELOAD makes ptimer to not to re-load
counter on setting counter value to "0" or starting to run with "0".

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: a7acf805e447cc7f637ecacbd45cca34ea3bf425.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test.c | 73 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 57 insertions(+), 16 deletions(-)

diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index d55cc79..0badfe7 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -190,6 +190,7 @@ static void check_periodic(gconstpointer arg)
     ptimer_state *ptimer = ptimer_init(bh, *policy);
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
     bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
+    bool no_immediate_reload = (*policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
 
     triggered = false;
 
@@ -219,7 +220,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 20);
@@ -239,7 +240,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 10);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
     g_assert_true(triggered);
 
     triggered = false;
@@ -256,7 +257,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 4);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -264,7 +265,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 3);
@@ -279,11 +280,12 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 9 : 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 0);
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                     no_immediate_reload ? 0 : 10);
 
     if (no_immediate_trigger) {
         g_assert_false(triggered);
@@ -295,12 +297,27 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(100000);
 
+    if (no_immediate_reload) {
+        g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+        g_assert_false(triggered);
+
+        qemu_clock_step(2000000);
+
+        if (no_immediate_trigger) {
+            g_assert_true(triggered);
+        } else {
+            g_assert_false(triggered);
+        }
+
+        triggered = false;
+    }
+
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 12);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 8 : 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7 + (wrap_policy ? 1 : 0));
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -309,7 +326,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 10);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 8 : 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7 + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_run(ptimer, 0);
@@ -317,7 +334,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 8 : 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7 + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 }
 
@@ -450,13 +467,15 @@ static void check_run_with_delta_0(gconstpointer arg)
     ptimer_state *ptimer = ptimer_init(bh, *policy);
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
     bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
+    bool no_immediate_reload = (*policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
 
     triggered = false;
 
     ptimer_set_period(ptimer, 2000000);
     ptimer_set_limit(ptimer, 99, 0);
     ptimer_run(ptimer, 1);
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                     no_immediate_reload ? 0 : 99);
 
     if (no_immediate_trigger) {
         g_assert_false(triggered);
@@ -466,11 +485,19 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     triggered = false;
 
-    if (no_immediate_trigger) {
+    if (no_immediate_trigger || no_immediate_reload) {
         qemu_clock_step(2000000 + 100000);
 
-        g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
-        g_assert_false(triggered);
+        g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                         no_immediate_reload ? 0 : 97);
+
+        if (no_immediate_trigger && no_immediate_reload) {
+            g_assert_true(triggered);
+
+            triggered = false;
+        } else {
+            g_assert_false(triggered);
+        }
 
         ptimer_set_count(ptimer, 99);
         ptimer_run(ptimer, 1);
@@ -495,7 +522,8 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     ptimer_set_count(ptimer, 0);
     ptimer_run(ptimer, 0);
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                     no_immediate_reload ? 0 : 99);
 
     if (no_immediate_trigger) {
         g_assert_false(triggered);
@@ -507,8 +535,17 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     qemu_clock_step(100000);
 
+    if (no_immediate_reload) {
+        qemu_clock_step(2000000);
+    }
+
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98);
-    g_assert_false(triggered);
+
+    if (no_immediate_reload && no_immediate_trigger) {
+        g_assert_true(triggered);
+    } else {
+        g_assert_false(triggered);
+    }
 
     triggered = false;
 
@@ -639,6 +676,10 @@ static void add_ptimer_tests(uint8_t policy)
         g_strlcat(policy_name, "no_immediate_trigger,", 256);
     }
 
+    if (policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD) {
+        g_strlcat(policy_name, "no_immediate_reload,", 256);
+    }
+
     g_test_add_data_func(
         g_strdup_printf("/ptimer/set_count policy=%s", policy_name),
         ppolicy, check_set_count);
@@ -686,7 +727,7 @@ static void add_ptimer_tests(uint8_t policy)
 
 static void add_all_ptimer_policies_comb_tests(void)
 {
-    int last_policy = PTIMER_POLICY_NO_IMMEDIATE_TRIGGER;
+    int last_policy = PTIMER_POLICY_NO_IMMEDIATE_RELOAD;
     int policy = PTIMER_POLICY_DEFAULT;
 
     for (; policy < (last_policy << 1); policy++) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 16/32] hw/ptimer: Add "no counter round down" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (14 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 15/32] tests: ptimer: Add tests for " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 17/32] tests: ptimer: Add tests for " Peter Maydell
                   ` (17 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

For most of the timers counter starts to decrement after first period
expires. Due to rounding down performed by the ptimer_get_count, it returns
counter - 1 for the running timer, so that for the ptimer user it looks
like counter gets decremented immediately after running the timer. Add "no
counter round down" policy that provides correct behaviour for those timers.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: ef39622d0ebfdc32a0877e59ffdf6910dc3db688.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/core/ptimer.c    | 9 +++++++++
 include/hw/ptimer.h | 4 ++++
 2 files changed, 13 insertions(+)

diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 2a69daf..3af82af 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -231,6 +231,15 @@ uint64_t ptimer_get_count(ptimer_state *s)
                 }
             }
         }
+
+        if (s->policy_mask & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN) {
+            /* If now == last then delta == limit, i.e. the counter already
+               represents the correct value. It would be rounded down a 1ns
+               later.  */
+            if (now != last) {
+                counter += 1;
+            }
+        }
     } else {
         counter = s->delta;
     }
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 5455340..48cccbd 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -51,6 +51,10 @@
  * immediately, but after a one period.  */
 #define PTIMER_POLICY_NO_IMMEDIATE_RELOAD   (1 << 3)
 
+/* Make counter value of the running timer represent the actual value and
+ * not the one less.  */
+#define PTIMER_POLICY_NO_COUNTER_ROUND_DOWN (1 << 4)
+
 /* ptimer.c */
 typedef struct ptimer_state ptimer_state;
 typedef void (*ptimer_cb)(void *opaque);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 17/32] tests: ptimer: Add tests for "no counter round down" policy
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (15 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 16/32] hw/ptimer: Add "no counter round down" policy Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 18/32] tests: ptimer: Change the copyright comment Peter Maydell
                   ` (16 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

PTIMER_POLICY_NO_COUNTER_ROUND_DOWN makes ptimer_get_count() return the
actual counter value and not the one less.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 0082889309b3dc66c03c8de00b8c1ef40c1e3955.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test.c | 117 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 76 insertions(+), 41 deletions(-)

diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index 0badfe7..1bd5924 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -99,6 +99,7 @@ static void check_oneshot(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 
     triggered = false;
 
@@ -108,32 +109,44 @@ static void check_oneshot(gconstpointer arg)
 
     qemu_clock_step(2000000 * 2 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
     g_assert_false(triggered);
 
     ptimer_stop(ptimer);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 11);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
     g_assert_false(triggered);
 
     ptimer_run(ptimer, 1);
 
     qemu_clock_step(2000000 * 7 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_true(triggered);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
 
-    triggered = false;
+    if (no_round_down) {
+        g_assert_false(triggered);
+    } else {
+        g_assert_true(triggered);
+
+        triggered = false;
+    }
 
     qemu_clock_step(2000000);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
-    g_assert_false(triggered);
+
+    if (no_round_down) {
+        g_assert_true(triggered);
+
+        triggered = false;
+    } else {
+        g_assert_false(triggered);
+    }
 
     qemu_clock_step(4000000);
 
@@ -158,14 +171,14 @@ static void check_oneshot(gconstpointer arg)
 
     qemu_clock_step(2000000 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 20);
 
     qemu_clock_step(2000000 * 19 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000);
@@ -191,6 +204,7 @@ static void check_periodic(gconstpointer arg)
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
     bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
     bool no_immediate_reload = (*policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
+    bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 
     triggered = false;
 
@@ -203,7 +217,7 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 10 : 9);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 10 - 100000);
@@ -213,14 +227,16 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                     wrap_policy ? 0 : (no_round_down ? 10 : 9));
     g_assert_true(triggered);
 
     triggered = false;
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 20);
@@ -230,17 +246,18 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 19);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 20 : 19);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 11 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 9 : 8);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 10);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
     g_assert_true(triggered);
 
     triggered = false;
@@ -252,12 +269,13 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 2);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 3 : 2);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 4);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -265,7 +283,8 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 3);
@@ -273,14 +292,16 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 3 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                     wrap_policy ? 0 : (no_round_down ? 10 : 9));
     g_assert_true(triggered);
 
     triggered = false;
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 9 : 8) + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 0);
@@ -312,12 +333,13 @@ static void check_periodic(gconstpointer arg)
         triggered = false;
     }
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 10 : 9);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 12);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 8 : 7) + (wrap_policy ? 1 : 0));
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -326,7 +348,8 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 * 10);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 8 : 7) + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     ptimer_run(ptimer, 0);
@@ -334,7 +357,8 @@ static void check_periodic(gconstpointer arg)
 
     qemu_clock_step(2000000 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7 + (wrap_policy ? 1 : 0));
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    (no_round_down ? 8 : 7) + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 }
 
@@ -344,6 +368,7 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
+    bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 
     triggered = false;
 
@@ -353,17 +378,18 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
 
     qemu_clock_step(2000000 * 9 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
     g_assert_false(triggered);
 
     ptimer_run(ptimer, 0);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 9);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    wrap_policy ? 0 : (no_round_down ? 10 : 9));
     g_assert_true(triggered);
 
     triggered = false;
@@ -372,7 +398,8 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
 
     ptimer_run(ptimer, 1);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 1 : 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                     (no_round_down ? 1 : 0) + (wrap_policy ? 1 : 0));
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 3);
@@ -386,6 +413,7 @@ static void check_on_the_fly_period_change(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 
     triggered = false;
 
@@ -395,15 +423,15 @@ static void check_on_the_fly_period_change(gconstpointer arg)
 
     qemu_clock_step(2000000 * 4 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
     g_assert_false(triggered);
 
     ptimer_set_period(ptimer, 4000000);
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
 
     qemu_clock_step(4000000 * 2 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 2 : 0);
     g_assert_false(triggered);
 
     qemu_clock_step(4000000 * 2);
@@ -417,6 +445,7 @@ static void check_on_the_fly_freq_change(gconstpointer arg)
     const uint8_t *policy = arg;
     QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
     ptimer_state *ptimer = ptimer_init(bh, *policy);
+    bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 
     triggered = false;
 
@@ -426,15 +455,15 @@ static void check_on_the_fly_freq_change(gconstpointer arg)
 
     qemu_clock_step(2000000 * 4 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
     g_assert_false(triggered);
 
     ptimer_set_freq(ptimer, 250);
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
 
     qemu_clock_step(2000000 * 4 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 2 : 0);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 4);
@@ -468,6 +497,7 @@ static void check_run_with_delta_0(gconstpointer arg)
     bool wrap_policy = (*policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD);
     bool no_immediate_trigger = (*policy & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER);
     bool no_immediate_reload = (*policy & PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
+    bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
 
     triggered = false;
 
@@ -489,7 +519,7 @@ static void check_run_with_delta_0(gconstpointer arg)
         qemu_clock_step(2000000 + 100000);
 
         g_assert_cmpuint(ptimer_get_count(ptimer), ==,
-                         no_immediate_reload ? 0 : 97);
+                         no_immediate_reload ? 0 : (no_round_down ? 98 : 97));
 
         if (no_immediate_trigger && no_immediate_reload) {
             g_assert_true(triggered);
@@ -505,12 +535,12 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     qemu_clock_step(2000000 + 100000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 98 : 97);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 97);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 2);
@@ -539,7 +569,7 @@ static void check_run_with_delta_0(gconstpointer arg)
         qemu_clock_step(2000000);
     }
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 99 : 98);
 
     if (no_immediate_reload && no_immediate_trigger) {
         g_assert_true(triggered);
@@ -551,12 +581,13 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     qemu_clock_step(2000000);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 98 : 97);
     g_assert_false(triggered);
 
     qemu_clock_step(2000000 * 98);
 
-    g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 98);
+    g_assert_cmpuint(ptimer_get_count(ptimer), ==,
+                    wrap_policy ? 0 : (no_round_down ? 99 : 98));
     g_assert_true(triggered);
 
     ptimer_stop(ptimer);
@@ -680,6 +711,10 @@ static void add_ptimer_tests(uint8_t policy)
         g_strlcat(policy_name, "no_immediate_reload,", 256);
     }
 
+    if (policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN) {
+        g_strlcat(policy_name, "no_counter_rounddown,", 256);
+    }
+
     g_test_add_data_func(
         g_strdup_printf("/ptimer/set_count policy=%s", policy_name),
         ppolicy, check_set_count);
@@ -727,7 +762,7 @@ static void add_ptimer_tests(uint8_t policy)
 
 static void add_all_ptimer_policies_comb_tests(void)
 {
-    int last_policy = PTIMER_POLICY_NO_IMMEDIATE_RELOAD;
+    int last_policy = PTIMER_POLICY_NO_COUNTER_ROUND_DOWN;
     int policy = PTIMER_POLICY_DEFAULT;
 
     for (; policy < (last_policy << 1); policy++) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 18/32] tests: ptimer: Change the copyright comment
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (16 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 17/32] tests: ptimer: Add tests for " Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 19/32] tests: ptimer: Replace 10000 with 1 Peter Maydell
                   ` (15 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

Eric Blake suggested that use of "Author:" in the copyright text of the
files created by individuals is incorrect, replace it with "Copyright".

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 9d8b626f462d4a5094b1945fbd763b8a2e28dd86.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test-stubs.c | 2 +-
 tests/ptimer-test.c       | 2 +-
 tests/ptimer-test.h       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c
index e028a81..21d4ebb 100644
--- a/tests/ptimer-test-stubs.c
+++ b/tests/ptimer-test-stubs.c
@@ -1,7 +1,7 @@
 /*
  * Stubs for the ptimer-test
  *
- * Author: Dmitry Osipenko <digetx@gmail.com>
+ * Copyright (c) 2016 Dmitry Osipenko <digetx@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.
diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index 1bd5924..47fccd3 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -1,7 +1,7 @@
 /*
  * QTest testcase for the ptimer
  *
- * Author: Dmitry Osipenko <digetx@gmail.com>
+ * Copyright (c) 2016 Dmitry Osipenko <digetx@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.
diff --git a/tests/ptimer-test.h b/tests/ptimer-test.h
index 98d9b8f..09ac56d 100644
--- a/tests/ptimer-test.h
+++ b/tests/ptimer-test.h
@@ -1,7 +1,7 @@
 /*
  * QTest testcase for the ptimer
  *
- * Author: Dmitry Osipenko <digetx@gmail.com>
+ * Copyright (c) 2016 Dmitry Osipenko <digetx@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.
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 19/32] tests: ptimer: Replace 10000 with 1
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (17 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 18/32] tests: ptimer: Change the copyright comment Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 20/32] arm_mptimer: Convert to use ptimer Peter Maydell
                   ` (14 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

The 10000 is an arbitrarily chosen value used for advancing the QEMU
time, so that ptimer's now != last. Change it to 1 to make code a bit
more readable.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 63256eaac54c84dac7c797f41296cc49e751d09d.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/ptimer-test.c | 56 ++++++++++++++++++++++++++---------------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index 47fccd3..b36a476 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -107,7 +107,7 @@ static void check_oneshot(gconstpointer arg)
     ptimer_set_count(ptimer, 10);
     ptimer_run(ptimer, 1);
 
-    qemu_clock_step(2000000 * 2 + 100000);
+    qemu_clock_step(2000000 * 2 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
     g_assert_false(triggered);
@@ -124,7 +124,7 @@ static void check_oneshot(gconstpointer arg)
 
     ptimer_run(ptimer, 1);
 
-    qemu_clock_step(2000000 * 7 + 100000);
+    qemu_clock_step(2000000 * 7 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
 
@@ -155,28 +155,28 @@ static void check_oneshot(gconstpointer arg)
 
     ptimer_set_count(ptimer, 10);
 
-    qemu_clock_step(20000000 + 100000);
+    qemu_clock_step(20000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
     g_assert_false(triggered);
 
     ptimer_set_limit(ptimer, 9, 1);
 
-    qemu_clock_step(20000000 + 100000);
+    qemu_clock_step(20000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
     g_assert_false(triggered);
 
     ptimer_run(ptimer, 1);
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(2000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 8 : 7);
     g_assert_false(triggered);
 
     ptimer_set_count(ptimer, 20);
 
-    qemu_clock_step(2000000 * 19 + 100000);
+    qemu_clock_step(2000000 * 19 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
     g_assert_false(triggered);
@@ -190,7 +190,7 @@ static void check_oneshot(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(2000000 * 12 + 100000);
+    qemu_clock_step(2000000 * 12 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
     g_assert_false(triggered);
@@ -215,17 +215,17 @@ static void check_periodic(gconstpointer arg)
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
     g_assert_false(triggered);
 
-    qemu_clock_step(100000);
+    qemu_clock_step(1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 10 : 9);
     g_assert_false(triggered);
 
-    qemu_clock_step(2000000 * 10 - 100000);
+    qemu_clock_step(2000000 * 10 - 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, wrap_policy ? 0 : 10);
     g_assert_true(triggered);
 
-    qemu_clock_step(100000);
+    qemu_clock_step(1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==,
                      wrap_policy ? 0 : (no_round_down ? 10 : 9));
@@ -244,12 +244,12 @@ static void check_periodic(gconstpointer arg)
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 20);
     g_assert_false(triggered);
 
-    qemu_clock_step(100000);
+    qemu_clock_step(1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 20 : 19);
     g_assert_false(triggered);
 
-    qemu_clock_step(2000000 * 11 + 100000);
+    qemu_clock_step(2000000 * 11 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 9 : 8);
     g_assert_false(triggered);
@@ -267,7 +267,7 @@ static void check_periodic(gconstpointer arg)
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
     g_assert_false(triggered);
 
-    qemu_clock_step(100000);
+    qemu_clock_step(1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 3 : 2);
     g_assert_false(triggered);
@@ -290,7 +290,7 @@ static void check_periodic(gconstpointer arg)
     ptimer_set_count(ptimer, 3);
     ptimer_run(ptimer, 0);
 
-    qemu_clock_step(2000000 * 3 + 100000);
+    qemu_clock_step(2000000 * 3 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==,
                      wrap_policy ? 0 : (no_round_down ? 10 : 9));
@@ -316,7 +316,7 @@ static void check_periodic(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(100000);
+    qemu_clock_step(1);
 
     if (no_immediate_reload) {
         g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
@@ -355,7 +355,7 @@ static void check_periodic(gconstpointer arg)
     ptimer_run(ptimer, 0);
     ptimer_set_period(ptimer, 0);
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(2000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==,
                     (no_round_down ? 8 : 7) + (wrap_policy ? 1 : 0));
@@ -376,7 +376,7 @@ static void check_on_the_fly_mode_change(gconstpointer arg)
     ptimer_set_limit(ptimer, 10, 1);
     ptimer_run(ptimer, 1);
 
-    qemu_clock_step(2000000 * 9 + 100000);
+    qemu_clock_step(2000000 * 9 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 1 : 0);
     g_assert_false(triggered);
@@ -421,7 +421,7 @@ static void check_on_the_fly_period_change(gconstpointer arg)
     ptimer_set_limit(ptimer, 8, 1);
     ptimer_run(ptimer, 1);
 
-    qemu_clock_step(2000000 * 4 + 100000);
+    qemu_clock_step(2000000 * 4 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
     g_assert_false(triggered);
@@ -429,7 +429,7 @@ static void check_on_the_fly_period_change(gconstpointer arg)
     ptimer_set_period(ptimer, 4000000);
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
 
-    qemu_clock_step(4000000 * 2 + 100000);
+    qemu_clock_step(4000000 * 2 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 2 : 0);
     g_assert_false(triggered);
@@ -453,7 +453,7 @@ static void check_on_the_fly_freq_change(gconstpointer arg)
     ptimer_set_limit(ptimer, 8, 1);
     ptimer_run(ptimer, 1);
 
-    qemu_clock_step(2000000 * 4 + 100000);
+    qemu_clock_step(2000000 * 4 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
     g_assert_false(triggered);
@@ -461,7 +461,7 @@ static void check_on_the_fly_freq_change(gconstpointer arg)
     ptimer_set_freq(ptimer, 250);
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 4 : 3);
 
-    qemu_clock_step(2000000 * 4 + 100000);
+    qemu_clock_step(2000000 * 4 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 2 : 0);
     g_assert_false(triggered);
@@ -516,7 +516,7 @@ static void check_run_with_delta_0(gconstpointer arg)
     triggered = false;
 
     if (no_immediate_trigger || no_immediate_reload) {
-        qemu_clock_step(2000000 + 100000);
+        qemu_clock_step(2000000 + 1);
 
         g_assert_cmpuint(ptimer_get_count(ptimer), ==,
                          no_immediate_reload ? 0 : (no_round_down ? 98 : 97));
@@ -533,7 +533,7 @@ static void check_run_with_delta_0(gconstpointer arg)
         ptimer_run(ptimer, 1);
     }
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(2000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 98 : 97);
     g_assert_false(triggered);
@@ -563,7 +563,7 @@ static void check_run_with_delta_0(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(100000);
+    qemu_clock_step(1);
 
     if (no_immediate_reload) {
         qemu_clock_step(2000000);
@@ -616,7 +616,7 @@ static void check_periodic_with_load_0(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(2000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
 
@@ -631,14 +631,14 @@ static void check_periodic_with_load_0(gconstpointer arg)
     ptimer_set_count(ptimer, 10);
     ptimer_run(ptimer, 0);
 
-    qemu_clock_step(2000000 * 10 + 100000);
+    qemu_clock_step(2000000 * 10 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
     g_assert_true(triggered);
 
     triggered = false;
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(2000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
 
@@ -673,7 +673,7 @@ static void check_oneshot_with_load_0(gconstpointer arg)
 
     triggered = false;
 
-    qemu_clock_step(2000000 + 100000);
+    qemu_clock_step(2000000 + 1);
 
     g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 20/32] arm_mptimer: Convert to use ptimer
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (18 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 19/32] tests: ptimer: Replace 10000 with 1 Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 21/32] tests: Add tests for the ARM MPTimer Peter Maydell
                   ` (13 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

Current ARM MPTimer implementation uses QEMUTimer for the actual timer,
this implementation isn't complete and mostly tries to duplicate of what
generic ptimer is already doing fine.

Conversion to ptimer brings the following benefits and fixes:
	- Simple timer pausing implementation
	- Fixes counter value preservation after stopping the timer
	- Properly handles prescaler != 0 / counter = 0 / load = 0 cases
	- Code simplification and reduction

Bump VMSD to version 3, since VMState is changed and is not compatible
with the previous implementation.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Message-id: 37f378c33bb5a28d5cd71167a6bd5bff5e59cbc3.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/arm_mptimer.c         | 149 +++++++++++++++++++++++------------------
 include/hw/timer/arm_mptimer.h |   5 +-
 2 files changed, 83 insertions(+), 71 deletions(-)

diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index d66bbf0..daf6c48 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -20,22 +20,33 @@
  */
 
 #include "qemu/osdep.h"
+#include "hw/ptimer.h"
 #include "hw/timer/arm_mptimer.h"
 #include "qapi/error.h"
-#include "qemu/timer.h"
+#include "qemu/main-loop.h"
 #include "qom/cpu.h"
 
+#define PTIMER_POLICY                       \
+    (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |  \
+     PTIMER_POLICY_CONTINUOUS_TRIGGER    |  \
+     PTIMER_POLICY_NO_IMMEDIATE_TRIGGER  |  \
+     PTIMER_POLICY_NO_IMMEDIATE_RELOAD   |  \
+     PTIMER_POLICY_NO_COUNTER_ROUND_DOWN)
+
 /* This device implements the per-cpu private timer and watchdog block
  * which is used in both the ARM11MPCore and Cortex-A9MP.
  */
 
 static inline int get_current_cpu(ARMMPTimerState *s)
 {
-    if (current_cpu->cpu_index >= s->num_cpu) {
+    int cpu_id = current_cpu ? current_cpu->cpu_index : 0;
+
+    if (cpu_id >= s->num_cpu) {
         hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
-                 s->num_cpu, current_cpu->cpu_index);
+                 s->num_cpu, cpu_id);
     }
-    return current_cpu->cpu_index;
+
+    return cpu_id;
 }
 
 static inline void timerblock_update_irq(TimerBlock *tb)
@@ -44,33 +55,42 @@ static inline void timerblock_update_irq(TimerBlock *tb)
 }
 
 /* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
-static inline uint32_t timerblock_scale(TimerBlock *tb)
+static inline uint32_t timerblock_scale(uint32_t control)
 {
-    return (((tb->control >> 8) & 0xff) + 1) * 10;
+    return (((control >> 8) & 0xff) + 1) * 10;
 }
 
-static void timerblock_reload(TimerBlock *tb, int restart)
+static inline void timerblock_set_count(struct ptimer_state *timer,
+                                        uint32_t control, uint64_t *count)
 {
-    if (tb->count == 0) {
-        return;
+    /* PTimer would trigger interrupt for periodic timer when counter set
+     * to 0, MPtimer under certain condition only.
+     */
+    if ((control & 3) == 3 && (control & 0xff00) == 0 && *count == 0) {
+        *count = ptimer_get_limit(timer);
     }
-    if (restart) {
-        tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    ptimer_set_count(timer, *count);
+}
+
+static inline void timerblock_run(struct ptimer_state *timer,
+                                  uint32_t control, uint32_t load)
+{
+    if ((control & 1) && ((control & 0xff00) || load != 0)) {
+        ptimer_run(timer, !(control & 2));
     }
-    tb->tick += (int64_t)tb->count * timerblock_scale(tb);
-    timer_mod(tb->timer, tb->tick);
 }
 
 static void timerblock_tick(void *opaque)
 {
     TimerBlock *tb = (TimerBlock *)opaque;
-    tb->status = 1;
-    if (tb->control & 2) {
-        tb->count = tb->load;
-        timerblock_reload(tb, 0);
-    } else {
-        tb->count = 0;
+    /* Periodic timer with load = 0 and prescaler != 0 would re-trigger
+     * IRQ after one period, otherwise it either stops or wraps around.
+     */
+    if ((tb->control & 2) && (tb->control & 0xff00) == 0 &&
+            ptimer_get_limit(tb->timer) == 0) {
+        ptimer_stop(tb->timer);
     }
+    tb->status = 1;
     timerblock_update_irq(tb);
 }
 
@@ -78,21 +98,11 @@ static uint64_t timerblock_read(void *opaque, hwaddr addr,
                                 unsigned size)
 {
     TimerBlock *tb = (TimerBlock *)opaque;
-    int64_t val;
     switch (addr) {
     case 0: /* Load */
-        return tb->load;
+        return ptimer_get_limit(tb->timer);
     case 4: /* Counter.  */
-        if (((tb->control & 1) == 0) || (tb->count == 0)) {
-            return 0;
-        }
-        /* Slow and ugly, but hopefully won't happen too often.  */
-        val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        val /= timerblock_scale(tb);
-        if (val < 0) {
-            val = 0;
-        }
-        return val;
+        return ptimer_get_count(tb->timer);
     case 8: /* Control.  */
         return tb->control;
     case 12: /* Interrupt status.  */
@@ -106,37 +116,45 @@ static void timerblock_write(void *opaque, hwaddr addr,
                              uint64_t value, unsigned size)
 {
     TimerBlock *tb = (TimerBlock *)opaque;
-    int64_t old;
+    uint32_t control = tb->control;
     switch (addr) {
     case 0: /* Load */
-        tb->load = value;
-        /* Fall through.  */
-    case 4: /* Counter.  */
-        if ((tb->control & 1) && tb->count) {
-            /* Cancel the previous timer.  */
-            timer_del(tb->timer);
+        /* Setting load to 0 stops the timer without doing the tick if
+         * prescaler = 0.
+         */
+        if ((control & 1) && (control & 0xff00) == 0 && value == 0) {
+            ptimer_stop(tb->timer);
         }
-        tb->count = value;
-        if (tb->control & 1) {
-            timerblock_reload(tb, 1);
+        ptimer_set_limit(tb->timer, value, 1);
+        timerblock_run(tb->timer, control, value);
+        break;
+    case 4: /* Counter.  */
+        /* Setting counter to 0 stops the one-shot timer, or periodic with
+         * load = 0, without doing the tick if prescaler = 0.
+         */
+        if ((control & 1) && (control & 0xff00) == 0 && value == 0 &&
+                (!(control & 2) || ptimer_get_limit(tb->timer) == 0)) {
+            ptimer_stop(tb->timer);
         }
+        timerblock_set_count(tb->timer, control, &value);
+        timerblock_run(tb->timer, control, value);
         break;
     case 8: /* Control.  */
-        old = tb->control;
-        tb->control = value;
+        if ((control & 3) != (value & 3)) {
+            ptimer_stop(tb->timer);
+        }
+        if ((control & 0xff00) != (value & 0xff00)) {
+            ptimer_set_period(tb->timer, timerblock_scale(value));
+        }
         if (value & 1) {
-            if ((old & 1) && (tb->count != 0)) {
-                /* Do nothing if timer is ticking right now.  */
-                break;
+            uint64_t count = ptimer_get_count(tb->timer);
+            /* Re-load periodic timer counter if needed.  */
+            if ((value & 2) && count == 0) {
+                timerblock_set_count(tb->timer, value, &count);
             }
-            if (tb->control & 2) {
-                tb->count = tb->load;
-            }
-            timerblock_reload(tb, 1);
-        } else if (old & 1) {
-            /* Shutdown the timer.  */
-            timer_del(tb->timer);
+            timerblock_run(tb->timer, value, count);
         }
+        tb->control = value;
         break;
     case 12: /* Interrupt status.  */
         tb->status &= ~value;
@@ -186,13 +204,12 @@ static const MemoryRegionOps timerblock_ops = {
 
 static void timerblock_reset(TimerBlock *tb)
 {
-    tb->count = 0;
-    tb->load = 0;
     tb->control = 0;
     tb->status = 0;
-    tb->tick = 0;
     if (tb->timer) {
-        timer_del(tb->timer);
+        ptimer_stop(tb->timer);
+        ptimer_set_limit(tb->timer, 0, 1);
+        ptimer_set_period(tb->timer, timerblock_scale(0));
     }
 }
 
@@ -238,7 +255,8 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp)
      */
     for (i = 0; i < s->num_cpu; i++) {
         TimerBlock *tb = &s->timerblock[i];
-        tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb);
+        QEMUBH *bh = qemu_bh_new(timerblock_tick, tb);
+        tb->timer = ptimer_init(bh, PTIMER_POLICY);
         sysbus_init_irq(sbd, &tb->irq);
         memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
                               "arm_mptimer_timerblock", 0x20);
@@ -248,26 +266,23 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp)
 
 static const VMStateDescription vmstate_timerblock = {
     .name = "arm_mptimer_timerblock",
-    .version_id = 2,
-    .minimum_version_id = 2,
+    .version_id = 3,
+    .minimum_version_id = 3,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT32(count, TimerBlock),
-        VMSTATE_UINT32(load, TimerBlock),
         VMSTATE_UINT32(control, TimerBlock),
         VMSTATE_UINT32(status, TimerBlock),
-        VMSTATE_INT64(tick, TimerBlock),
-        VMSTATE_TIMER_PTR(timer, TimerBlock),
+        VMSTATE_PTIMER(timer, TimerBlock),
         VMSTATE_END_OF_LIST()
     }
 };
 
 static const VMStateDescription vmstate_arm_mptimer = {
     .name = "arm_mptimer",
-    .version_id = 2,
-    .minimum_version_id = 2,
+    .version_id = 3,
+    .minimum_version_id = 3,
     .fields = (VMStateField[]) {
         VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
-                                     2, vmstate_timerblock, TimerBlock),
+                                     3, vmstate_timerblock, TimerBlock),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/include/hw/timer/arm_mptimer.h b/include/hw/timer/arm_mptimer.h
index b34cba0..c46d8d2 100644
--- a/include/hw/timer/arm_mptimer.h
+++ b/include/hw/timer/arm_mptimer.h
@@ -27,12 +27,9 @@
 
 /* State of a single timer or watchdog block */
 typedef struct {
-    uint32_t count;
-    uint32_t load;
     uint32_t control;
     uint32_t status;
-    int64_t tick;
-    QEMUTimer *timer;
+    struct ptimer_state *timer;
     qemu_irq irq;
     MemoryRegion iomem;
 } TimerBlock;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 21/32] tests: Add tests for the ARM MPTimer
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (19 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 20/32] arm_mptimer: Convert to use ptimer Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 22/32] ACPI: Add IORT Structure definition Peter Maydell
                   ` (12 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Dmitry Osipenko <digetx@gmail.com>

ARM MPTimer is a per-CPU core timer, essential part of the ARM Cortex-A9
MPCore. Add QTests for it.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Message-id: 1c9a2f1c80f87e935b4a28919457c81b6b2256e9.1475421224.git.digetx@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/Makefile.include   |    3 +
 tests/test-arm-mptimer.c | 1105 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1108 insertions(+)
 create mode 100644 tests/test-arm-mptimer.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index e65e9f7..91cc308 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -303,6 +303,8 @@ check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
+check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
+gcov-files-arm-y += hw/timer/arm_mptimer.c
 
 check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
 
@@ -684,6 +686,7 @@ tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-
 tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y)
 tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o
 tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y)
+tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
 
 tests/migration/stress$(EXESUF): tests/migration/stress.o
 	$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
diff --git a/tests/test-arm-mptimer.c b/tests/test-arm-mptimer.c
new file mode 100644
index 0000000..cb8f2df
--- /dev/null
+++ b/tests/test-arm-mptimer.c
@@ -0,0 +1,1105 @@
+/*
+ * QTest testcase for the ARM MPTimer
+ *
+ * Copyright (c) 2016 Dmitry Osipenko <digetx@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/timer.h"
+#include "libqtest.h"
+
+#define TIMER_BLOCK_SCALE(s)    ((((s) & 0xff) + 1) * 10)
+
+#define TIMER_BLOCK_STEP(scaler, steps_nb) \
+    clock_step(TIMER_BLOCK_SCALE(scaler) * (int64_t)(steps_nb) + 1)
+
+#define TIMER_BASE_PHYS 0x1e000600
+
+#define TIMER_LOAD      0x00
+#define TIMER_COUNTER   0x04
+#define TIMER_CONTROL   0x08
+#define TIMER_INTSTAT   0x0C
+
+#define TIMER_CONTROL_ENABLE        (1 << 0)
+#define TIMER_CONTROL_PERIODIC      (1 << 1)
+#define TIMER_CONTROL_IT_ENABLE     (1 << 2)
+#define TIMER_CONTROL_PRESCALER(p)  (((p) & 0xff) << 8)
+
+#define PERIODIC     1
+#define ONESHOT      0
+#define NOSCALE      0
+
+static int nonscaled = NOSCALE;
+static int scaled = 122;
+
+static void timer_load(uint32_t load)
+{
+    writel(TIMER_BASE_PHYS + TIMER_LOAD, load);
+}
+
+static void timer_start(int periodic, uint32_t scale)
+{
+    uint32_t ctl = TIMER_CONTROL_ENABLE | TIMER_CONTROL_PRESCALER(scale);
+
+    if (periodic) {
+        ctl |= TIMER_CONTROL_PERIODIC;
+    }
+
+    writel(TIMER_BASE_PHYS + TIMER_CONTROL, ctl);
+}
+
+static void timer_stop(void)
+{
+    writel(TIMER_BASE_PHYS + TIMER_CONTROL, 0);
+}
+
+static void timer_int_clr(void)
+{
+    writel(TIMER_BASE_PHYS + TIMER_INTSTAT, 1);
+}
+
+static void timer_reset(void)
+{
+    timer_stop();
+    timer_load(0);
+    timer_int_clr();
+}
+
+static uint32_t timer_get_and_clr_int_sts(void)
+{
+    uint32_t int_sts = readl(TIMER_BASE_PHYS + TIMER_INTSTAT);
+
+    if (int_sts) {
+        timer_int_clr();
+    }
+
+    return int_sts;
+}
+
+static uint32_t timer_counter(void)
+{
+    return readl(TIMER_BASE_PHYS + TIMER_COUNTER);
+}
+
+static void timer_set_counter(uint32_t value)
+{
+    writel(TIMER_BASE_PHYS + TIMER_COUNTER, value);
+}
+
+static void test_timer_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 9999);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    g_assert_cmpuint(timer_counter(), ==, 9990000);
+
+    TIMER_BLOCK_STEP(scaler, 9990000);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    TIMER_BLOCK_STEP(scaler, 9990000);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_pause(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(999999999);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 999999000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 9000);
+
+    g_assert_cmpuint(timer_counter(), ==, 999990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_stop();
+
+    g_assert_cmpuint(timer_counter(), ==, 999990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 90000);
+
+    g_assert_cmpuint(timer_counter(), ==, 999990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 999990000);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 999990000);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+}
+
+static void test_timer_reload(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 90000);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 90000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(UINT32_MAX);
+
+    TIMER_BLOCK_STEP(scaler, 90000);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 90000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+    int repeat = 10;
+
+    timer_reset();
+    timer_load(100);
+    timer_start(PERIODIC, scaler);
+
+    while (repeat--) {
+        clock_step(TIMER_BLOCK_SCALE(scaler) * (101 + repeat) + 1);
+
+        g_assert_cmpuint(timer_counter(), ==, 100 - repeat);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+        clock_step(TIMER_BLOCK_SCALE(scaler) * (101 - repeat) - 1);
+    }
+}
+
+static void test_timer_oneshot_to_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(10000);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1000);
+
+    g_assert_cmpuint(timer_counter(), ==, 9000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 14001);
+
+    g_assert_cmpuint(timer_counter(), ==, 5000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_periodic_to_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(99999999);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 99999000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 99999009);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_prescaler(void)
+{
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 9999998);
+
+    g_assert_cmpuint(timer_counter(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, 0xAB);
+
+    TIMER_BLOCK_STEP(0xAB, 9999998);
+
+    g_assert_cmpuint(timer_counter(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(0xAB, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_prescaler_on_the_fly(void)
+{
+    timer_reset();
+    timer_load(9999999);
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 9999000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, 0xAB);
+
+    TIMER_BLOCK_STEP(0xAB, 9000);
+
+    g_assert_cmpuint(timer_counter(), ==, 9990000);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_oneshot_counter_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    TIMER_BLOCK_STEP(scaler, 10);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_set_periodic_counter_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - (scaler ? 0 : 1));
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_reset();
+    timer_set_counter(UINT32_MAX);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_noload_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_noload_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_zero_load_oneshot(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_periodic(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_zero_load_oneshot_to_nonzero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(999);
+
+    TIMER_BLOCK_STEP(scaler, 1001);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+}
+
+static void test_timer_zero_load_periodic_to_nonzero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+    int i;
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_load(1999999);
+
+    for (i = 1; i < 10; i++) {
+        TIMER_BLOCK_STEP(scaler, 2000001);
+
+        g_assert_cmpuint(timer_counter(), ==, 1999999 - i);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    }
+}
+
+static void test_timer_nonzero_load_oneshot_to_zero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_load(UINT32_MAX);
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_nonzero_load_periodic_to_zero(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_load(UINT32_MAX);
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_set_periodic_counter_on_the_fly(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX / 2);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX / 2 - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(UINT32_MAX);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_enable_and_set_counter(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_set_counter(UINT32_MAX);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_counter_and_enable(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_set_counter(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_counter_disabled(void)
+{
+    timer_reset();
+    timer_set_counter(999999999);
+
+    TIMER_BLOCK_STEP(NOSCALE, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 999999999);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_load_disabled(void)
+{
+    timer_reset();
+    timer_load(999999999);
+
+    TIMER_BLOCK_STEP(NOSCALE, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 999999999);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_oneshot_with_counter_0_on_start(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(999);
+    timer_set_counter(0);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_periodic_with_counter_0_on_start(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+    int i;
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_set_counter(0);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX + (scaler ? 1 : 0) - 100);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX + (scaler ? 1 : 0) - 200);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_reset();
+    timer_load(1999999);
+    timer_set_counter(0);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    for (i = 2 - (!!scaler ? 1 : 0); i < 10; i++) {
+        TIMER_BLOCK_STEP(scaler, 2000001);
+
+        g_assert_cmpuint(timer_counter(), ==, 1999999 - i);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+        g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+    }
+}
+
+static void test_periodic_counter(gconstpointer arg)
+{
+    const int test_load = 10;
+    int scaler = *((int *) arg);
+    int test_val;
+
+    timer_reset();
+    timer_load(test_load);
+    timer_start(PERIODIC, scaler);
+
+    clock_step(1);
+
+    for (test_val = 0; test_val <= test_load; test_val++) {
+        clock_step(TIMER_BLOCK_SCALE(scaler) * test_load);
+        g_assert_cmpint(timer_counter(), ==, test_val);
+    }
+}
+
+static void test_timer_set_counter_periodic_with_zero_load(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_start(PERIODIC, scaler);
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    timer_set_counter(999);
+
+    TIMER_BLOCK_STEP(scaler, 999);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_set_oneshot_load_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_set_periodic_load_to_0(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, UINT32_MAX - 100);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(0);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+    g_assert_cmpuint(timer_counter(), ==, 0);
+}
+
+static void test_deferred_trigger(void)
+{
+    int mode = ONESHOT;
+
+again:
+    timer_reset();
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(2);
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_set_counter(0);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    timer_reset();
+    timer_load(UINT32_MAX);
+    timer_start(mode, 255);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_load(0);
+
+    clock_step(100);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+
+    if (mode == ONESHOT) {
+        mode = PERIODIC;
+        goto again;
+    }
+}
+
+static void test_timer_zero_load_mode_switch(gconstpointer arg)
+{
+    int scaler = *((int *) arg);
+
+    timer_reset();
+    timer_load(0);
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    timer_start(ONESHOT, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    timer_start(PERIODIC, scaler);
+
+    TIMER_BLOCK_STEP(scaler, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, !!scaler);
+}
+
+static void test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(PERIODIC, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(ONESHOT, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(ONESHOT, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(PERIODIC, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+static void test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot(void)
+{
+    timer_reset();
+    timer_load(0);
+    timer_start(PERIODIC, NOSCALE);
+
+    TIMER_BLOCK_STEP(NOSCALE, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    timer_start(ONESHOT, 255);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 1);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+
+    TIMER_BLOCK_STEP(255, 1);
+
+    g_assert_cmpuint(timer_counter(), ==, 0);
+    g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
+}
+
+int main(int argc, char **argv)
+{
+    int *scaler = &nonscaled;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("mptimer/deferred_trigger", test_deferred_trigger);
+    qtest_add_func("mptimer/load_disabled", test_timer_load_disabled);
+    qtest_add_func("mptimer/set_counter_disabled", test_timer_set_counter_disabled);
+    qtest_add_func("mptimer/zero_load_prescaled_periodic_to_nonscaled_oneshot",
+                   test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot);
+    qtest_add_func("mptimer/zero_load_prescaled_oneshot_to_nonscaled_periodic",
+                   test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic);
+    qtest_add_func("mptimer/zero_load_nonscaled_oneshot_to_prescaled_periodic",
+                   test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic);
+    qtest_add_func("mptimer/zero_load_nonscaled_periodic_to_prescaled_oneshot",
+                   test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot);
+    qtest_add_func("mptimer/prescaler", test_timer_prescaler);
+    qtest_add_func("mptimer/prescaler_on_the_fly", test_timer_prescaler_on_the_fly);
+
+tests_with_prescaler_arg:
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/oneshot scaler=%d", *scaler),
+                        scaler, test_timer_oneshot);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/pause scaler=%d", *scaler),
+                        scaler, test_timer_pause);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/reload scaler=%d", *scaler),
+                        scaler, test_timer_reload);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/periodic scaler=%d", *scaler),
+                        scaler, test_timer_periodic);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/oneshot_to_periodic scaler=%d", *scaler),
+                        scaler, test_timer_oneshot_to_periodic);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/periodic_to_oneshot scaler=%d", *scaler),
+                        scaler, test_timer_periodic_to_oneshot);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_oneshot_counter_to_0 scaler=%d", *scaler),
+                        scaler, test_timer_set_oneshot_counter_to_0);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_periodic_counter_to_0 scaler=%d", *scaler),
+                        scaler, test_timer_set_periodic_counter_to_0);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/noload_oneshot scaler=%d", *scaler),
+                        scaler, test_timer_noload_oneshot);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/noload_periodic scaler=%d", *scaler),
+                        scaler, test_timer_noload_periodic);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/zero_load_oneshot scaler=%d", *scaler),
+                        scaler, test_timer_zero_load_oneshot);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/zero_load_periodic scaler=%d", *scaler),
+                        scaler, test_timer_zero_load_periodic);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/zero_load_oneshot_to_nonzero scaler=%d", *scaler),
+                        scaler, test_timer_zero_load_oneshot_to_nonzero);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/zero_load_periodic_to_nonzero scaler=%d", *scaler),
+                        scaler, test_timer_zero_load_periodic_to_nonzero);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/nonzero_load_oneshot_to_zero scaler=%d", *scaler),
+                        scaler, test_timer_nonzero_load_oneshot_to_zero);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/nonzero_load_periodic_to_zero scaler=%d", *scaler),
+                        scaler, test_timer_nonzero_load_periodic_to_zero);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_periodic_counter_on_the_fly scaler=%d", *scaler),
+                        scaler, test_timer_set_periodic_counter_on_the_fly);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/enable_and_set_counter scaler=%d", *scaler),
+                        scaler, test_timer_enable_and_set_counter);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_counter_and_enable scaler=%d", *scaler),
+                        scaler, test_timer_set_counter_and_enable);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/oneshot_with_counter_0_on_start scaler=%d", *scaler),
+                        scaler, test_timer_oneshot_with_counter_0_on_start);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/periodic_with_counter_0_on_start scaler=%d", *scaler),
+                        scaler, test_timer_periodic_with_counter_0_on_start);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/periodic_counter scaler=%d", *scaler),
+                        scaler, test_periodic_counter);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_counter_periodic_with_zero_load scaler=%d", *scaler),
+                        scaler, test_timer_set_counter_periodic_with_zero_load);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_oneshot_load_to_0 scaler=%d", *scaler),
+                        scaler, test_timer_set_oneshot_load_to_0);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/set_periodic_load_to_0 scaler=%d", *scaler),
+                        scaler, test_timer_set_periodic_load_to_0);
+    qtest_add_data_func(
+        g_strdup_printf("mptimer/zero_load_mode_switch scaler=%d", *scaler),
+                        scaler, test_timer_zero_load_mode_switch);
+
+    if (scaler == &nonscaled) {
+        scaler = &scaled;
+        goto tests_with_prescaler_arg;
+    }
+
+    qtest_start("-machine vexpress-a9");
+    ret = g_test_run();
+    qtest_end();
+
+    return ret;
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 22/32] ACPI: Add IORT Structure definition
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (20 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 21/32] tests: Add tests for the ARM MPTimer Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 23/32] ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes Peter Maydell
                   ` (11 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Prem Mallappa <prem.mallappa@broadcom.com>

ACPI Spec 6.0 introduces IO Remapping Table Structure. This patch
introduces the definitions required to describe the IO relationship
between the PCIe root complex and the ITS.

This conforms to:
"IO Remapping Table System Software on ARM Platforms",
Document number: ARM DEN 0049B, October 2015.

Signed-off-by: Prem Mallappa <prem.mallappa@broadcom.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Message-id: 1476707466-14300-2-git-send-email-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/acpi/acpi-defs.h | 68 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 9c1b7cb..90a5353 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -609,4 +609,72 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit;
 /* Masks for Flags field above */
 #define ACPI_DMAR_INCLUDE_PCI_ALL   1
 
+/*
+ * Input Output Remapping Table (IORT)
+ * Conforms to "IO Remapping Table System Software on ARM Platforms",
+ * Document number: ARM DEN 0049B, October 2015
+ */
+
+struct AcpiIortTable {
+    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
+    uint32_t node_count;
+    uint32_t node_offset;
+    uint32_t reserved;
+} QEMU_PACKED;
+typedef struct AcpiIortTable AcpiIortTable;
+
+/*
+ * IORT node types
+ */
+
+#define ACPI_IORT_NODE_HEADER_DEF   /* Node format common fields */ \
+    uint8_t  type;          \
+    uint16_t length;        \
+    uint8_t  revision;      \
+    uint32_t reserved;      \
+    uint32_t mapping_count; \
+    uint32_t mapping_offset;
+
+/* Values for node Type above */
+enum {
+        ACPI_IORT_NODE_ITS_GROUP = 0x00,
+        ACPI_IORT_NODE_NAMED_COMPONENT = 0x01,
+        ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02,
+        ACPI_IORT_NODE_SMMU = 0x03,
+        ACPI_IORT_NODE_SMMU_V3 = 0x04
+};
+
+struct AcpiIortIdMapping {
+    uint32_t input_base;
+    uint32_t id_count;
+    uint32_t output_base;
+    uint32_t output_reference;
+    uint32_t flags;
+} QEMU_PACKED;
+typedef struct AcpiIortIdMapping AcpiIortIdMapping;
+
+struct AcpiIortMemoryAccess {
+    uint32_t cache_coherency;
+    uint8_t  hints;
+    uint16_t reserved;
+    uint8_t  memory_flags;
+} QEMU_PACKED;
+typedef struct AcpiIortMemoryAccess AcpiIortMemoryAccess;
+
+struct AcpiIortItsGroup {
+    ACPI_IORT_NODE_HEADER_DEF
+    uint32_t its_count;
+    uint32_t identifiers[0];
+} QEMU_PACKED;
+typedef struct AcpiIortItsGroup AcpiIortItsGroup;
+
+struct AcpiIortRC {
+    ACPI_IORT_NODE_HEADER_DEF
+    AcpiIortMemoryAccess memory_properties;
+    uint32_t ats_attribute;
+    uint32_t pci_segment_number;
+    AcpiIortIdMapping id_mapping_array[0];
+} QEMU_PACKED;
+typedef struct AcpiIortRC AcpiIortRC;
+
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 23/32] ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (21 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 22/32] ACPI: Add IORT Structure definition Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 24/32] timer: a9gtimer: remove loop to auto-increment comparator Peter Maydell
                   ` (10 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Prem Mallappa <prem.mallappa@broadcom.com>

This patch builds an IORT table that features a root complex node and
an ITS node. This complements the ITS description in the ACPI MADT
table and allows vhost-net on ACPI guest.

Signed-off-by: Prem Mallappa <prem.mallappa@broadcom.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Message-id: 1476707466-14300-3-git-send-email-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/virt-acpi-build.c | 71 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 60 insertions(+), 11 deletions(-)

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index fa0655a..5fc10df 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -384,6 +384,61 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
 }
 
 static void
+build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
+{
+    int iort_start = table_data->len;
+    AcpiIortIdMapping *idmap;
+    AcpiIortItsGroup *its;
+    AcpiIortTable *iort;
+    size_t node_size, iort_length;
+    AcpiIortRC *rc;
+
+    iort = acpi_data_push(table_data, sizeof(*iort));
+
+    iort_length = sizeof(*iort);
+    iort->node_count = cpu_to_le32(2); /* RC and ITS nodes */
+    iort->node_offset = cpu_to_le32(sizeof(*iort));
+
+    /* ITS group node */
+    node_size =  sizeof(*its) + sizeof(uint32_t);
+    iort_length += node_size;
+    its = acpi_data_push(table_data, node_size);
+
+    its->type = ACPI_IORT_NODE_ITS_GROUP;
+    its->length = cpu_to_le16(node_size);
+    its->its_count = cpu_to_le32(1);
+    its->identifiers[0] = 0; /* MADT translation_id */
+
+    /* Root Complex Node */
+    node_size = sizeof(*rc) + sizeof(*idmap);
+    iort_length += node_size;
+    rc = acpi_data_push(table_data, node_size);
+
+    rc->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
+    rc->length = cpu_to_le16(node_size);
+    rc->mapping_count = cpu_to_le32(1);
+    rc->mapping_offset = cpu_to_le32(sizeof(*rc));
+
+    /* fully coherent device */
+    rc->memory_properties.cache_coherency = cpu_to_le32(1);
+    rc->memory_properties.memory_flags = 0x3; /* CCA = CPM = DCAS = 1 */
+    rc->pci_segment_number = 0; /* MCFG pci_segment */
+
+    /* Identity RID mapping covering the whole input RID range */
+    idmap = &rc->id_mapping_array[0];
+    idmap->input_base = 0;
+    idmap->id_count = cpu_to_le32(0xFFFF);
+    idmap->output_base = 0;
+    /* output IORT node is the ITS group node (the first node) */
+    idmap->output_reference = cpu_to_le32(iort->node_offset);
+
+    iort->length = cpu_to_le32(iort_length);
+
+    build_header(linker, table_data, (void *)(table_data->data + iort_start),
+                 "IORT", table_data->len - iort_start, 0, NULL, NULL);
+}
+
+static void
 build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
 {
     AcpiSerialPortConsoleRedirection *spcr;
@@ -667,17 +722,6 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
                              ACPI_BUILD_TABLE_FILE, tables_blob,
                              64, false /* high memory */);
 
-    /*
-     * The ACPI v5.1 tables for Hardware-reduced ACPI platform are:
-     * RSDP
-     * RSDT
-     * FADT
-     * GTDT
-     * MADT
-     * MCFG
-     * DSDT
-     */
-
     /* DSDT is pointed to by FADT */
     dsdt = tables_blob->len;
     build_dsdt(tables_blob, tables->linker, guest_info);
@@ -703,6 +747,11 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
         build_srat(tables_blob, tables->linker, guest_info);
     }
 
+    if (its_class_name() && !guest_info->no_its) {
+        acpi_add_table(table_offsets, tables_blob);
+        build_iort(tables_blob, tables->linker, guest_info);
+    }
+
     /* RSDT is pointed to by RSDP */
     rsdt = tables_blob->len;
     build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 24/32] timer: a9gtimer: remove loop to auto-increment comparator
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (22 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 23/32] ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 25/32] i2c: Fix SMBus read transactions to avoid double events Peter Maydell
                   ` (9 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Prasad J Pandit <pjp@fedoraproject.org>

ARM A9MP processor has a peripheral timer with an auto-increment
register, which holds an increment step value. A user could set
this value to zero. When auto-increment control bit is enabled,
it leads to an infinite loop in 'a9_gtimer_update' while
updating comparator value. Remove this loop incrementing the
comparator value.

Reported-by: Li Qiang <liqiang6-s@360.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 1476733226-11635-1-git-send-email-ppandit@redhat.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/a9gtimer.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c
index 772f85f..ce1dc63 100644
--- a/hw/timer/a9gtimer.c
+++ b/hw/timer/a9gtimer.c
@@ -82,15 +82,15 @@ static void a9_gtimer_update(A9GTimerState *s, bool sync)
         if ((s->control & R_CONTROL_TIMER_ENABLE) &&
                 (gtb->control & R_CONTROL_COMP_ENABLE)) {
             /* R2p0+, where the compare function is >= */
-            while (gtb->compare < update.new) {
+            if (gtb->compare < update.new) {
                 DB_PRINT("Compare event happened for CPU %d\n", i);
                 gtb->status = 1;
-                if (gtb->control & R_CONTROL_AUTO_INCREMENT) {
-                    DB_PRINT("Auto incrementing timer compare by %" PRId32 "\n",
-                             gtb->inc);
-                    gtb->compare += gtb->inc;
-                } else {
-                    break;
+                if (gtb->control & R_CONTROL_AUTO_INCREMENT && gtb->inc) {
+                    uint64_t inc =
+                        QEMU_ALIGN_UP(update.new - gtb->compare, gtb->inc);
+                    DB_PRINT("Auto incrementing timer compare by %"
+                                                        PRId64 "\n", inc);
+                    gtb->compare += inc;
                 }
             }
             cdiff = (int64_t)gtb->compare - (int64_t)update.new + 1;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 25/32] i2c: Fix SMBus read transactions to avoid double events
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (23 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 24/32] timer: a9gtimer: remove loop to auto-increment comparator Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 26/32] timer: stm32f2xx_timer: add check for prescaler value Peter Maydell
                   ` (8 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Corey Minyard <cminyard@mvista.com>

Change 2293c27faddf (i2c: implement broadcast write) added broadcast
capability to the I2C bus, but it broke SMBus read transactions.
An SMBus read transaction does two i2c_start_transaction() calls
without an intervening i2c_end_transfer() call.  This will
result in i2c_start_transfer() adding the same device to the
current_devs list twice, and then the ->event() for the same
device gets called twice in the second call to i2c_start_transfer(),
resulting in the smbus code getting confused.

Note that this happens even with pure I2C devices when simulating
SMBus over I2C.

This fix only scans the bus if the current set of devices is empty.
This means that the current set of devices stays fixed until
i2c_end_transfer() is called, which is really what you want.

This also deletes the empty check from the top of i2c_end_transfer().
It's unnecessary, and it prevents the broadcast variable from being
set to false at the end of the transaction if no devices were on
the bus.

Cc: KONRAD Frederic <fred.konrad@greensocs.com>
Cc: Alistair Francis <alistair.francis@xilinx.com>
Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Cc: Kwon <hyun.kwon@xilinx.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: KONRAD Frederic <fred.konrad@greensocs.com>
Tested-by: KONRAD Frederic <fred.konrad@greensocs.com>
Message-id: 1470153614-6657-1-git-send-email-minyard@acm.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/i2c/core.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 4afbe0b..bd8f167 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -104,15 +104,25 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
         bus->broadcast = true;
     }
 
-    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        I2CSlave *candidate = I2C_SLAVE(qdev);
-        if ((candidate->address == address) || (bus->broadcast)) {
-            node = g_malloc(sizeof(struct I2CNode));
-            node->elt = candidate;
-            QLIST_INSERT_HEAD(&bus->current_devs, node, next);
-            if (!bus->broadcast) {
-                break;
+    /*
+     * If there are already devices in the list, that means we are in
+     * the middle of a transaction and we shouldn't rescan the bus.
+     *
+     * This happens with any SMBus transaction, even on a pure I2C
+     * device.  The interface does a transaction start without
+     * terminating the previous transaction.
+     */
+    if (QLIST_EMPTY(&bus->current_devs)) {
+        QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+            DeviceState *qdev = kid->child;
+            I2CSlave *candidate = I2C_SLAVE(qdev);
+            if ((candidate->address == address) || (bus->broadcast)) {
+                node = g_malloc(sizeof(struct I2CNode));
+                node->elt = candidate;
+                QLIST_INSERT_HEAD(&bus->current_devs, node, next);
+                if (!bus->broadcast) {
+                    break;
+                }
             }
         }
     }
@@ -137,10 +147,6 @@ void i2c_end_transfer(I2CBus *bus)
     I2CSlaveClass *sc;
     I2CNode *node, *next;
 
-    if (QLIST_EMPTY(&bus->current_devs)) {
-        return;
-    }
-
     QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
         sc = I2C_SLAVE_GET_CLASS(node->elt);
         if (sc->event) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 26/32] timer: stm32f2xx_timer: add check for prescaler value
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (24 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 25/32] i2c: Fix SMBus read transactions to avoid double events Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 27/32] hw/arm: QOM'ify musicpal.c Peter Maydell
                   ` (7 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Prasad J Pandit <pjp@fedoraproject.org>

The STM32F2XX Timer emulator uses a 16 bit prescaler value to
limit the timer clock rate. It does that by dividing the timer
frequency. If the prescaler 's->tim_psc' was set to be UINT_MAX,
it'd lead to divide by zero error. Limit prescaler value to 16
bits to avoid it.

Reported-by: Huawei PSIRT <psirt@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 1476800269-31902-1-git-send-email-ppandit@redhat.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/stm32f2xx_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
index 8c4c1f9..e5f5e14 100644
--- a/hw/timer/stm32f2xx_timer.c
+++ b/hw/timer/stm32f2xx_timer.c
@@ -217,7 +217,7 @@ static void stm32f2xx_timer_write(void *opaque, hwaddr offset,
         return;
     case TIM_PSC:
         timer_val = stm32f2xx_ns_to_ticks(s, now) - s->tick_offset;
-        s->tim_psc = value;
+        s->tim_psc = value & 0xFFFF;
         value = timer_val;
         break;
     case TIM_CNT:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 27/32] hw/arm: QOM'ify musicpal.c
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (25 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 26/32] timer: stm32f2xx_timer: add check for prescaler value Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 28/32] hw/arm: QOM'ify pxa2xx_gpio.c Peter Maydell
                   ` (6 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: xiaoqiang zhao <zxq_yx_007@163.com>

Drop the old Sysbus init and use instance_init and
DeviceClass::realize instead

Signed-off-by: xiaoqiang zhao <zxq_yx_007@163.com>
Message-id: 20161023091816.3839-2-zxq_yx_007@163.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/musicpal.c | 88 ++++++++++++++++++++++++++++---------------------------
 1 file changed, 45 insertions(+), 43 deletions(-)

diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 7527037..cbbca4e 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -384,18 +384,24 @@ static NetClientInfo net_mv88w8618_info = {
     .cleanup = eth_cleanup,
 };
 
-static int mv88w8618_eth_init(SysBusDevice *sbd)
+static void mv88w8618_eth_init(Object *obj)
 {
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     DeviceState *dev = DEVICE(sbd);
     mv88w8618_eth_state *s = MV88W8618_ETH(dev);
 
     sysbus_init_irq(sbd, &s->irq);
-    s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->id, s);
-    memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_eth_ops, s,
+    memory_region_init_io(&s->iomem, obj, &mv88w8618_eth_ops, s,
                           "mv88w8618-eth", MP_ETH_SIZE);
     sysbus_init_mmio(sbd, &s->iomem);
-    return 0;
+}
+
+static void mv88w8618_eth_realize(DeviceState *dev, Error **errp)
+{
+    mv88w8618_eth_state *s = MV88W8618_ETH(dev);
+
+    s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->id, s);
 }
 
 static const VMStateDescription mv88w8618_eth_vmsd = {
@@ -423,17 +429,17 @@ static Property mv88w8618_eth_properties[] = {
 static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = mv88w8618_eth_init;
     dc->vmsd = &mv88w8618_eth_vmsd;
     dc->props = mv88w8618_eth_properties;
+    dc->realize = mv88w8618_eth_realize;
 }
 
 static const TypeInfo mv88w8618_eth_info = {
     .name          = TYPE_MV88W8618_ETH,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(mv88w8618_eth_state),
+    .instance_init = mv88w8618_eth_init,
     .class_init    = mv88w8618_eth_class_init,
 };
 
@@ -615,23 +621,26 @@ static const GraphicHwOps musicpal_gfx_ops = {
     .gfx_update  = lcd_refresh,
 };
 
-static int musicpal_lcd_init(SysBusDevice *sbd)
+static void musicpal_lcd_realize(DeviceState *dev, Error **errp)
+{
+    musicpal_lcd_state *s = MUSICPAL_LCD(dev);
+    s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
+    qemu_console_resize(s->con, 128 * 3, 64 * 3);
+}
+
+static void musicpal_lcd_init(Object *obj)
 {
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     DeviceState *dev = DEVICE(sbd);
     musicpal_lcd_state *s = MUSICPAL_LCD(dev);
 
     s->brightness = 7;
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_lcd_ops, s,
+    memory_region_init_io(&s->iomem, obj, &musicpal_lcd_ops, s,
                           "musicpal-lcd", MP_LCD_SIZE);
     sysbus_init_mmio(sbd, &s->iomem);
 
-    s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
-    qemu_console_resize(s->con, 128*3, 64*3);
-
     qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
-
-    return 0;
 }
 
 static const VMStateDescription musicpal_lcd_vmsd = {
@@ -652,16 +661,16 @@ static const VMStateDescription musicpal_lcd_vmsd = {
 static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = musicpal_lcd_init;
     dc->vmsd = &musicpal_lcd_vmsd;
+    dc->realize = musicpal_lcd_realize;
 }
 
 static const TypeInfo musicpal_lcd_info = {
     .name          = TYPE_MUSICPAL_LCD,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(musicpal_lcd_state),
+    .instance_init = musicpal_lcd_init,
     .class_init    = musicpal_lcd_class_init,
 };
 
@@ -748,16 +757,16 @@ static const MemoryRegionOps mv88w8618_pic_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int mv88w8618_pic_init(SysBusDevice *dev)
+static void mv88w8618_pic_init(Object *obj)
 {
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
     mv88w8618_pic_state *s = MV88W8618_PIC(dev);
 
     qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32);
     sysbus_init_irq(dev, &s->parent_irq);
-    memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pic_ops, s,
+    memory_region_init_io(&s->iomem, obj, &mv88w8618_pic_ops, s,
                           "musicpal-pic", MP_PIC_SIZE);
     sysbus_init_mmio(dev, &s->iomem);
-    return 0;
 }
 
 static const VMStateDescription mv88w8618_pic_vmsd = {
@@ -774,9 +783,7 @@ static const VMStateDescription mv88w8618_pic_vmsd = {
 static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = mv88w8618_pic_init;
     dc->reset = mv88w8618_pic_reset;
     dc->vmsd = &mv88w8618_pic_vmsd;
 }
@@ -785,6 +792,7 @@ static const TypeInfo mv88w8618_pic_info = {
     .name          = TYPE_MV88W8618_PIC,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(mv88w8618_pic_state),
+    .instance_init = mv88w8618_pic_init,
     .class_init    = mv88w8618_pic_class_init,
 };
 
@@ -913,8 +921,9 @@ static const MemoryRegionOps mv88w8618_pit_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int mv88w8618_pit_init(SysBusDevice *dev)
+static void mv88w8618_pit_init(Object *obj)
 {
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
     mv88w8618_pit_state *s = MV88W8618_PIT(dev);
     int i;
 
@@ -924,10 +933,9 @@ static int mv88w8618_pit_init(SysBusDevice *dev)
         mv88w8618_timer_init(dev, &s->timer[i], 1000000);
     }
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pit_ops, s,
+    memory_region_init_io(&s->iomem, obj, &mv88w8618_pit_ops, s,
                           "musicpal-pit", MP_PIT_SIZE);
     sysbus_init_mmio(dev, &s->iomem);
-    return 0;
 }
 
 static const VMStateDescription mv88w8618_timer_vmsd = {
@@ -955,9 +963,7 @@ static const VMStateDescription mv88w8618_pit_vmsd = {
 static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = mv88w8618_pit_init;
     dc->reset = mv88w8618_pit_reset;
     dc->vmsd = &mv88w8618_pit_vmsd;
 }
@@ -966,6 +972,7 @@ static const TypeInfo mv88w8618_pit_info = {
     .name          = TYPE_MV88W8618_PIT,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(mv88w8618_pit_state),
+    .instance_init = mv88w8618_pit_init,
     .class_init    = mv88w8618_pit_class_init,
 };
 
@@ -1018,15 +1025,15 @@ static const MemoryRegionOps mv88w8618_flashcfg_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int mv88w8618_flashcfg_init(SysBusDevice *dev)
+static void mv88w8618_flashcfg_init(Object *obj)
 {
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
     mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev);
 
     s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
-    memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_flashcfg_ops, s,
+    memory_region_init_io(&s->iomem, obj, &mv88w8618_flashcfg_ops, s,
                           "musicpal-flashcfg", MP_FLASHCFG_SIZE);
     sysbus_init_mmio(dev, &s->iomem);
-    return 0;
 }
 
 static const VMStateDescription mv88w8618_flashcfg_vmsd = {
@@ -1042,9 +1049,7 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = {
 static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = mv88w8618_flashcfg_init;
     dc->vmsd = &mv88w8618_flashcfg_vmsd;
 }
 
@@ -1052,6 +1057,7 @@ static const TypeInfo mv88w8618_flashcfg_info = {
     .name          = TYPE_MV88W8618_FLASHCFG,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(mv88w8618_flashcfg_state),
+    .instance_init = mv88w8618_flashcfg_init,
     .class_init    = mv88w8618_flashcfg_class_init,
 };
 
@@ -1350,22 +1356,21 @@ static void musicpal_gpio_reset(DeviceState *d)
     s->isr = 0;
 }
 
-static int musicpal_gpio_init(SysBusDevice *sbd)
+static void musicpal_gpio_init(Object *obj)
 {
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     DeviceState *dev = DEVICE(sbd);
     musicpal_gpio_state *s = MUSICPAL_GPIO(dev);
 
     sysbus_init_irq(sbd, &s->irq);
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_gpio_ops, s,
+    memory_region_init_io(&s->iomem, obj, &musicpal_gpio_ops, s,
                           "musicpal-gpio", MP_GPIO_SIZE);
     sysbus_init_mmio(sbd, &s->iomem);
 
     qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
 
     qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32);
-
-    return 0;
 }
 
 static const VMStateDescription musicpal_gpio_vmsd = {
@@ -1386,9 +1391,7 @@ static const VMStateDescription musicpal_gpio_vmsd = {
 static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = musicpal_gpio_init;
     dc->reset = musicpal_gpio_reset;
     dc->vmsd = &musicpal_gpio_vmsd;
 }
@@ -1397,6 +1400,7 @@ static const TypeInfo musicpal_gpio_info = {
     .name          = TYPE_MUSICPAL_GPIO,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(musicpal_gpio_state),
+    .instance_init = musicpal_gpio_init,
     .class_init    = musicpal_gpio_class_init,
 };
 
@@ -1516,12 +1520,13 @@ static void musicpal_key_event(void *opaque, int keycode)
     s->kbd_extended = 0;
 }
 
-static int musicpal_key_init(SysBusDevice *sbd)
+static void musicpal_key_init(Object *obj)
 {
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     DeviceState *dev = DEVICE(sbd);
     musicpal_key_state *s = MUSICPAL_KEY(dev);
 
-    memory_region_init(&s->iomem, OBJECT(s), "dummy", 0);
+    memory_region_init(&s->iomem, obj, "dummy", 0);
     sysbus_init_mmio(sbd, &s->iomem);
 
     s->kbd_extended = 0;
@@ -1530,8 +1535,6 @@ static int musicpal_key_init(SysBusDevice *sbd)
     qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
 
     qemu_add_kbd_event_handler(musicpal_key_event, s);
-
-    return 0;
 }
 
 static const VMStateDescription musicpal_key_vmsd = {
@@ -1548,9 +1551,7 @@ static const VMStateDescription musicpal_key_vmsd = {
 static void musicpal_key_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = musicpal_key_init;
     dc->vmsd = &musicpal_key_vmsd;
 }
 
@@ -1558,6 +1559,7 @@ static const TypeInfo musicpal_key_info = {
     .name          = TYPE_MUSICPAL_KEY,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(musicpal_key_state),
+    .instance_init = musicpal_key_init,
     .class_init    = musicpal_key_class_init,
 };
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 28/32] hw/arm: QOM'ify pxa2xx_gpio.c
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (26 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 27/32] hw/arm: QOM'ify musicpal.c Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 29/32] hw/arm: QOM'ify strongarm.c Peter Maydell
                   ` (5 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: xiaoqiang zhao <zxq_yx_007@163.com>

Drop the old Sysbus init and use instance_init and
DeviceClass::realize instead

Signed-off-by: xiaoqiang zhao <zxq_yx_007@163.com>
Message-id: 20161023091816.3839-3-zxq_yx_007@163.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/pxa2xx_gpio.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
index 576a8eb..521dbad 100644
--- a/hw/arm/pxa2xx_gpio.c
+++ b/hw/arm/pxa2xx_gpio.c
@@ -280,23 +280,28 @@ DeviceState *pxa2xx_gpio_init(hwaddr base,
     return dev;
 }
 
-static int pxa2xx_gpio_initfn(SysBusDevice *sbd)
+static void pxa2xx_gpio_initfn(Object *obj)
 {
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     DeviceState *dev = DEVICE(sbd);
     PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
 
-    s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu));
-
-    qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
-    qdev_init_gpio_out(dev, s->handler, s->lines);
-
-    memory_region_init_io(&s->iomem, OBJECT(s), &pxa_gpio_ops, s, "pxa2xx-gpio", 0x1000);
+    memory_region_init_io(&s->iomem, obj, &pxa_gpio_ops,
+                          s, "pxa2xx-gpio", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq0);
     sysbus_init_irq(sbd, &s->irq1);
     sysbus_init_irq(sbd, &s->irqX);
+}
 
-    return 0;
+static void pxa2xx_gpio_realize(DeviceState *dev, Error **errp)
+{
+    PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
+
+    s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu));
+
+    qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
+    qdev_init_gpio_out(dev, s->handler, s->lines);
 }
 
 /*
@@ -336,18 +341,18 @@ static Property pxa2xx_gpio_properties[] = {
 static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = pxa2xx_gpio_initfn;
     dc->desc = "PXA2xx GPIO controller";
     dc->props = pxa2xx_gpio_properties;
     dc->vmsd = &vmstate_pxa2xx_gpio_regs;
+    dc->realize = pxa2xx_gpio_realize;
 }
 
 static const TypeInfo pxa2xx_gpio_info = {
     .name          = TYPE_PXA2XX_GPIO,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(PXA2xxGPIOInfo),
+    .instance_init = pxa2xx_gpio_initfn,
     .class_init    = pxa2xx_gpio_class_init,
 };
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 29/32] hw/arm: QOM'ify strongarm.c
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (27 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 28/32] hw/arm: QOM'ify pxa2xx_gpio.c Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 30/32] hw/display: QOM'ify pl110.c Peter Maydell
                   ` (4 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: xiaoqiang zhao <zxq_yx_007@163.com>

Drop the old Sysbus init and use instance_init and
DeviceClass::realize instead

Signed-off-by: xiaoqiang zhao <zxq_yx_007@163.com>
Message-id: 20161023091816.3839-4-zxq_yx_007@163.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/strongarm.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 85db1e2..3311cc3 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1236,6 +1236,11 @@ static void strongarm_uart_init(Object *obj)
 
     s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s);
     s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
+}
+
+static void strongarm_uart_realize(DeviceState *dev, Error **errp)
+{
+    StrongARMUARTState *s = STRONGARM_UART(dev);
 
     qemu_chr_fe_set_handlers(&s->chr,
                              strongarm_uart_can_receive,
@@ -1316,6 +1321,7 @@ static void strongarm_uart_class_init(ObjectClass *klass, void *data)
     dc->reset = strongarm_uart_reset;
     dc->vmsd = &vmstate_strongarm_uart_regs;
     dc->props = strongarm_uart_properties;
+    dc->realize = strongarm_uart_realize;
 }
 
 static const TypeInfo strongarm_uart_info = {
@@ -1516,19 +1522,19 @@ static int strongarm_ssp_post_load(void *opaque, int version_id)
     return 0;
 }
 
-static int strongarm_ssp_init(SysBusDevice *sbd)
+static void strongarm_ssp_init(Object *obj)
 {
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     DeviceState *dev = DEVICE(sbd);
     StrongARMSSPState *s = STRONGARM_SSP(dev);
 
     sysbus_init_irq(sbd, &s->irq);
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ssp_ops, s,
+    memory_region_init_io(&s->iomem, obj, &strongarm_ssp_ops, s,
                           "ssp", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
 
     s->bus = ssi_create_bus(dev, "ssi");
-    return 0;
 }
 
 static void strongarm_ssp_reset(DeviceState *dev)
@@ -1558,9 +1564,7 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = {
 static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = strongarm_ssp_init;
     dc->desc = "StrongARM SSP controller";
     dc->reset = strongarm_ssp_reset;
     dc->vmsd = &vmstate_strongarm_ssp_regs;
@@ -1570,6 +1574,7 @@ static const TypeInfo strongarm_ssp_info = {
     .name          = TYPE_STRONGARM_SSP,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(StrongARMSSPState),
+    .instance_init = strongarm_ssp_init,
     .class_init    = strongarm_ssp_class_init,
 };
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 30/32] hw/display: QOM'ify pl110.c
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (28 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 29/32] hw/arm: QOM'ify strongarm.c Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 31/32] target-arm: Implement new HLT trap for semihosting Peter Maydell
                   ` (3 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: xiaoqiang zhao <zxq_yx_007@163.com>

Drop the old Sysbus init and use instance_init and
DeviceClass::realize instead

Signed-off-by: xiaoqiang zhao <zxq_yx_007@163.com>
Message-id: 20161023091816.3839-5-zxq_yx_007@163.com
[PMM: added accidentally dropped blank line]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/display/pl110.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index c069c0b..8c7dcc6 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -466,17 +466,16 @@ static const GraphicHwOps pl110_gfx_ops = {
     .gfx_update  = pl110_update_display,
 };
 
-static int pl110_initfn(SysBusDevice *sbd)
+static void pl110_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *dev = DEVICE(sbd);
     PL110State *s = PL110(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 
     memory_region_init_io(&s->iomem, OBJECT(s), &pl110_ops, s, "pl110", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq);
     qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
     s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
-    return 0;
 }
 
 static void pl110_init(Object *obj)
@@ -503,11 +502,10 @@ static void pl111_init(Object *obj)
 static void pl110_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = pl110_initfn;
     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
     dc->vmsd = &vmstate_pl110;
+    dc->realize = pl110_realize;
 }
 
 static const TypeInfo pl110_info = {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 31/32] target-arm: Implement new HLT trap for semihosting
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (29 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 30/32] hw/display: QOM'ify pl110.c Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 17:25 ` [Qemu-devel] [PULL 32/32] i2c: Add asserts for second smbus i2c_start_transfer() Peter Maydell
                   ` (2 subsequent siblings)
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

Version 2.0 of the semihosting specification introduces new trap
instructions for AArch32: HLT 0xF000 for A32 and HLT 0x3C for T32.
Implement these (in the same way we implement the existing HLT
semihosting trap for A64).

The old traps via SVC and BKPT are unaffected.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1476792973-18508-1-git-send-email-peter.maydell@linaro.org
---
 linux-user/main.c      |  3 +++
 target-arm/cpu.h       |  2 +-
 target-arm/helper.c    | 11 ++++++++--
 target-arm/translate.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index c6f2e20..54970bc 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -806,6 +806,9 @@ void cpu_loop(CPUARMState *env)
                 }
             }
             break;
+        case EXCP_SEMIHOST:
+            env->regs[0] = do_arm_semihosting(env);
+            break;
         case EXCP_INTERRUPT:
             /* just indicate that signals should be handled asap */
             break;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 6695390..9d75227 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -52,7 +52,7 @@
 #define EXCP_SMC            13   /* Secure Monitor Call */
 #define EXCP_VIRQ           14
 #define EXCP_VFIQ           15
-#define EXCP_SEMIHOST       16   /* semihosting call (A64 only) */
+#define EXCP_SEMIHOST       16   /* semihosting call */
 
 #define ARMV7M_EXCP_RESET   1
 #define ARMV7M_EXCP_NMI     2
diff --git a/target-arm/helper.c b/target-arm/helper.c
index cb83ee2..25b15dc 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6573,12 +6573,19 @@ static inline bool check_for_semihosting(CPUState *cs)
         /* Only intercept calls from privileged modes, to provide some
          * semblance of security.
          */
-        if (!semihosting_enabled() ||
-            ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)) {
+        if (cs->exception_index != EXCP_SEMIHOST &&
+            (!semihosting_enabled() ||
+             ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) {
             return false;
         }
 
         switch (cs->exception_index) {
+        case EXCP_SEMIHOST:
+            /* This is always a semihosting call; the "is this usermode"
+             * and "is semihosting enabled" checks have been done at
+             * translate time.
+             */
+            break;
         case EXCP_SWI:
             /* Check for semihosting interrupt.  */
             if (env->thumb) {
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 164b52a..ef62f8b 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -28,6 +28,7 @@
 #include "qemu/log.h"
 #include "qemu/bitops.h"
 #include "arm_ldst.h"
+#include "exec/semihost.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -1144,6 +1145,33 @@ static inline void gen_lookup_tb(DisasContext *s)
     s->is_jmp = DISAS_JUMP;
 }
 
+static inline void gen_hlt(DisasContext *s, int imm)
+{
+    /* HLT. This has two purposes.
+     * Architecturally, it is an external halting debug instruction.
+     * Since QEMU doesn't implement external debug, we treat this as
+     * it is required for halting debug disabled: it will UNDEF.
+     * Secondly, "HLT 0x3C" is a T32 semihosting trap instruction,
+     * and "HLT 0xF000" is an A32 semihosting syscall. These traps
+     * must trigger semihosting even for ARMv7 and earlier, where
+     * HLT was an undefined encoding.
+     * In system mode, we don't allow userspace access to
+     * semihosting, to provide some semblance of security
+     * (and for consistency with our 32-bit semihosting).
+     */
+    if (semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+        s->current_el != 0 &&
+#endif
+        (imm == (s->thumb ? 0x3c : 0xf000))) {
+        gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
+        return;
+    }
+
+    gen_exception_insn(s, s->thumb ? 2 : 4, EXCP_UDEF, syn_uncategorized(),
+                       default_exception_el(s));
+}
+
 static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
                                        TCGv_i32 var)
 {
@@ -8395,6 +8423,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
         {
             int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
             switch (op1) {
+            case 0:
+                /* HLT */
+                gen_hlt(s, imm16);
+                break;
             case 1:
                 /* bkpt */
                 ARCH(5);
@@ -8419,7 +8451,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                 gen_smc(s);
                 break;
             default:
-                goto illegal_op;
+                g_assert_not_reached();
             }
             break;
         }
@@ -11451,19 +11483,33 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
             break;
         }
 
-        case 0xa: /* rev */
+        case 0xa: /* rev, and hlt */
+        {
+            int op1 = extract32(insn, 6, 2);
+
+            if (op1 == 2) {
+                /* HLT */
+                int imm6 = extract32(insn, 0, 6);
+
+                gen_hlt(s, imm6);
+                break;
+            }
+
+            /* Otherwise this is rev */
             ARCH(6);
             rn = (insn >> 3) & 0x7;
             rd = insn & 0x7;
             tmp = load_reg(s, rn);
-            switch ((insn >> 6) & 3) {
+            switch (op1) {
             case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
             case 1: gen_rev16(tmp); break;
             case 3: gen_revsh(tmp); break;
-            default: goto illegal_op;
+            default:
+                g_assert_not_reached();
             }
             store_reg(s, rd, tmp);
             break;
+        }
 
         case 6:
             switch ((insn >> 5) & 7) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 32/32] i2c: Add asserts for second smbus i2c_start_transfer()
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (30 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 31/32] target-arm: Implement new HLT trap for semihosting Peter Maydell
@ 2016-10-24 17:25 ` Peter Maydell
  2016-10-24 19:11 ` [Qemu-devel] [PULL 00/32] target-arm queue no-reply
  2016-10-25  9:17 ` Peter Maydell
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-24 17:25 UTC (permalink / raw)
  To: qemu-devel

From: Corey Minyard <cminyard@mvista.com>

Some SMBus operations restart the transfer to convert from
write to read mode without an intervening i2c_end_transfer().
The second call cannot fail, so the return code is unchecked,
but this causes Coverity to complain.  So add some asserts
and documentation about this.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/i2c/core.c  |  7 ++++++-
 hw/i2c/smbus.c | 12 +++++++++---
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index bd8f167..abd4c4c 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -88,7 +88,12 @@ int i2c_bus_busy(I2CBus *bus)
     return !QLIST_EMPTY(&bus->current_devs);
 }
 
-/* Returns non-zero if the address is not valid.  */
+/*
+ * Returns non-zero if the address is not valid.  If this is called
+ * again without an intervening i2c_end_transfer(), like in the SMBus
+ * case where the operation is switched from write to read, this
+ * function will not rescan the bus and thus cannot fail.
+ */
 /* TODO: Make this handle multiple masters.  */
 int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
 {
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 3979b3d..5b4dd3e 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -248,7 +248,9 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
         return -1;
     }
     i2c_send(bus, command);
-    i2c_start_transfer(bus, addr, 1);
+    if (i2c_start_transfer(bus, addr, 1)) {
+        assert(0);
+    }
     data = i2c_recv(bus);
     i2c_nack(bus);
     i2c_end_transfer(bus);
@@ -273,7 +275,9 @@ int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
         return -1;
     }
     i2c_send(bus, command);
-    i2c_start_transfer(bus, addr, 1);
+    if (i2c_start_transfer(bus, addr, 1)) {
+        assert(0);
+    }
     data = i2c_recv(bus);
     data |= i2c_recv(bus) << 8;
     i2c_nack(bus);
@@ -302,7 +306,9 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
         return -1;
     }
     i2c_send(bus, command);
-    i2c_start_transfer(bus, addr, 1);
+    if (i2c_start_transfer(bus, addr, 1)) {
+        assert(0);
+    }
     len = i2c_recv(bus);
     if (len > 32) {
         len = 0;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [Qemu-devel] [PULL 00/32] target-arm queue
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (31 preceding siblings ...)
  2016-10-24 17:25 ` [Qemu-devel] [PULL 32/32] i2c: Add asserts for second smbus i2c_start_transfer() Peter Maydell
@ 2016-10-24 19:11 ` no-reply
  2016-10-25  9:17 ` Peter Maydell
  33 siblings, 0 replies; 41+ messages in thread
From: no-reply @ 2016-10-24 19:11 UTC (permalink / raw)
  To: peter.maydell; +Cc: famz, qemu-devel

Hi,

Your series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 1477329928-26414-1-git-send-email-peter.maydell@linaro.org
Subject: [Qemu-devel] [PULL 00/32] target-arm queue

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

# Useful git options
git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git show --no-patch --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
a4bdaba i2c: Add asserts for second smbus i2c_start_transfer()
28b6053 target-arm: Implement new HLT trap for semihosting
09d4ec5 hw/display: QOM'ify pl110.c
b3e97d0 hw/arm: QOM'ify strongarm.c
4b8eae3 hw/arm: QOM'ify pxa2xx_gpio.c
4e06f2b hw/arm: QOM'ify musicpal.c
92e91ad timer: stm32f2xx_timer: add check for prescaler value
967e6fa i2c: Fix SMBus read transactions to avoid double events
43ae1e2 timer: a9gtimer: remove loop to auto-increment comparator
b95b19e ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes
34a7836 ACPI: Add IORT Structure definition
cf7ab3a tests: Add tests for the ARM MPTimer
8de02d8 arm_mptimer: Convert to use ptimer
fd8b3a0 tests: ptimer: Replace 10000 with 1
d032b39 tests: ptimer: Change the copyright comment
2baf14c tests: ptimer: Add tests for "no counter round down" policy
6f60e0f hw/ptimer: Add "no counter round down" policy
4bf3a94 tests: ptimer: Add tests for "no immediate reload" policy
289b047 hw/ptimer: Add "no immediate reload" policy
ce78ba6 tests: ptimer: Add tests for "no immediate trigger" policy
e3f51a9 hw/ptimer: Add "no immediate trigger" policy
53ee1b7 tests: ptimer: Add tests for "continuous trigger" policy
6212b41 hw/ptimer: Add "continuous trigger" policy
b9f1014 tests: ptimer: Add tests for "wraparound after one period" policy
5552280 hw/ptimer: Add "wraparound after one period" policy
499ec72 hw/arm/virt: Set minimum_page_bits to 12
9dea37c target-arm: Make page size a runtime setting
1f435b7 migration/savevm.c: migrate non-default page size
5eae29a cpu: Support a target CPU having a variable page size
d48bab7 translate-all.c: Compute L1 page table properties at runtime
49f5d09 exec.c: Remove static allocation of sub_section of sub_page
fc33d3c migration: Remove static allocation of xzblre cache buffer

=== OUTPUT BEGIN ===
Checking PATCH 1/32: migration: Remove static allocation of xzblre cache buffer...
Checking PATCH 2/32: exec.c: Remove static allocation of sub_section of sub_page...
Checking PATCH 3/32: translate-all.c: Compute L1 page table properties at runtime...
Checking PATCH 4/32: cpu: Support a target CPU having a variable page size...
Checking PATCH 5/32: migration/savevm.c: migrate non-default page size...
ERROR: spaces required around that '*' (ctx:VxV)
#96: FILE: migration/savevm.c:359:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 1 errors, 0 warnings, 79 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 6/32: target-arm: Make page size a runtime setting...
Checking PATCH 7/32: hw/arm/virt: Set minimum_page_bits to 12...
Checking PATCH 8/32: hw/ptimer: Add "wraparound after one period" policy...
Checking PATCH 9/32: tests: ptimer: Add tests for "wraparound after one period" policy...
Checking PATCH 10/32: hw/ptimer: Add "continuous trigger" policy...
Checking PATCH 11/32: tests: ptimer: Add tests for "continuous trigger" policy...
Checking PATCH 12/32: hw/ptimer: Add "no immediate trigger" policy...
Checking PATCH 13/32: tests: ptimer: Add tests for "no immediate trigger" policy...
Checking PATCH 14/32: hw/ptimer: Add "no immediate reload" policy...
Checking PATCH 15/32: tests: ptimer: Add tests for "no immediate reload" policy...
Checking PATCH 16/32: hw/ptimer: Add "no counter round down" policy...
Checking PATCH 17/32: tests: ptimer: Add tests for "no counter round down" policy...
Checking PATCH 18/32: tests: ptimer: Change the copyright comment...
Checking PATCH 19/32: tests: ptimer: Replace 10000 with 1...
Checking PATCH 20/32: arm_mptimer: Convert to use ptimer...
Checking PATCH 21/32: tests: Add tests for the ARM MPTimer...
WARNING: line over 80 characters
#1044: FILE: tests/test-arm-mptimer.c:1003:
+    qtest_add_func("mptimer/set_counter_disabled", test_timer_set_counter_disabled);

WARNING: line over 80 characters
#1046: FILE: tests/test-arm-mptimer.c:1005:
+                   test_timer_zero_load_prescaled_periodic_to_nonscaled_oneshot);

WARNING: line over 80 characters
#1048: FILE: tests/test-arm-mptimer.c:1007:
+                   test_timer_zero_load_prescaled_oneshot_to_nonscaled_periodic);

WARNING: line over 80 characters
#1050: FILE: tests/test-arm-mptimer.c:1009:
+                   test_timer_zero_load_nonscaled_oneshot_to_prescaled_periodic);

WARNING: line over 80 characters
#1052: FILE: tests/test-arm-mptimer.c:1011:
+                   test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot);

WARNING: line over 80 characters
#1054: FILE: tests/test-arm-mptimer.c:1013:
+    qtest_add_func("mptimer/prescaler_on_the_fly", test_timer_prescaler_on_the_fly);

WARNING: line over 80 characters
#1094: FILE: tests/test-arm-mptimer.c:1053:
+        g_strdup_printf("mptimer/zero_load_oneshot_to_nonzero scaler=%d", *scaler),

WARNING: line over 80 characters
#1097: FILE: tests/test-arm-mptimer.c:1056:
+        g_strdup_printf("mptimer/zero_load_periodic_to_nonzero scaler=%d", *scaler),

WARNING: line over 80 characters
#1100: FILE: tests/test-arm-mptimer.c:1059:
+        g_strdup_printf("mptimer/nonzero_load_oneshot_to_zero scaler=%d", *scaler),

WARNING: line over 80 characters
#1103: FILE: tests/test-arm-mptimer.c:1062:
+        g_strdup_printf("mptimer/nonzero_load_periodic_to_zero scaler=%d", *scaler),

WARNING: line over 80 characters
#1106: FILE: tests/test-arm-mptimer.c:1065:
+        g_strdup_printf("mptimer/set_periodic_counter_on_the_fly scaler=%d", *scaler),

WARNING: line over 80 characters
#1115: FILE: tests/test-arm-mptimer.c:1074:
+        g_strdup_printf("mptimer/oneshot_with_counter_0_on_start scaler=%d", *scaler),

WARNING: line over 80 characters
#1118: FILE: tests/test-arm-mptimer.c:1077:
+        g_strdup_printf("mptimer/periodic_with_counter_0_on_start scaler=%d", *scaler),

WARNING: line over 80 characters
#1124: FILE: tests/test-arm-mptimer.c:1083:
+        g_strdup_printf("mptimer/set_counter_periodic_with_zero_load scaler=%d", *scaler),

total: 0 errors, 14 warnings, 1120 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 22/32: ACPI: Add IORT Structure definition...
Checking PATCH 23/32: ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes...
Checking PATCH 24/32: timer: a9gtimer: remove loop to auto-increment comparator...
Checking PATCH 25/32: i2c: Fix SMBus read transactions to avoid double events...
Checking PATCH 26/32: timer: stm32f2xx_timer: add check for prescaler value...
Checking PATCH 27/32: hw/arm: QOM'ify musicpal.c...
Checking PATCH 28/32: hw/arm: QOM'ify pxa2xx_gpio.c...
Checking PATCH 29/32: hw/arm: QOM'ify strongarm.c...
Checking PATCH 30/32: hw/display: QOM'ify pl110.c...
Checking PATCH 31/32: target-arm: Implement new HLT trap for semihosting...
Checking PATCH 32/32: i2c: Add asserts for second smbus i2c_start_transfer()...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [Qemu-devel] [PULL 00/32] target-arm queue
  2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
                   ` (32 preceding siblings ...)
  2016-10-24 19:11 ` [Qemu-devel] [PULL 00/32] target-arm queue no-reply
@ 2016-10-25  9:17 ` Peter Maydell
  33 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2016-10-25  9:17 UTC (permalink / raw)
  To: QEMU Developers

On 24 October 2016 at 18:24, Peter Maydell <peter.maydell@linaro.org> wrote:
> My review queue is currently empty. I may do another
> small pullreq towards the end of the week if a few things
> that didn't pass code review get respun.
>
> thanks
> -- PMM
>
> The following changes since commit a3ae21ec3fe036f536dc94cad735931777143103:
>
>   Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging (2016-10-24 15:03:09 +0100)
>
> are available in the git repository at:
>
>   git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20161024
>
> for you to fetch changes up to cc083d8a25e0a886c3cd4bea0bf57ac4e896fa3f:
>
>   i2c: Add asserts for second smbus i2c_start_transfer() (2016-10-24 16:48:02 +0100)
>
> ----------------------------------------------------------------
> target-arm queue:
>  * support variable (runtime-determined) page sizes, for a
>    nearly-20% speedup of TCG for ARMv7 and v8 CPUs with 4K pages
>  * ptimer: add tests, support more flexible behaviour around
>    what happens on the "zero" tick, use ptimer for a9gtimer
>  * virt: ACPI: Add IORT Structure definition
>  * i2c: Fix SMBus read transactions to avoid double events
>  * timer: stm32f2xx_timer: add check for prescaler value
>  * QOMify musicpal, pxa2xx_gpio, strongarm, pl110
>  * target-arm: Implement new HLT trap for semihosting
>  * i2c: Add asserts for second smbus i2c_start_transfer()
>

Applied, thanks.

-- PMM

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [Qemu-devel] [PULL 00/32] target-arm queue
  2018-06-26 16:56 Peter Maydell
@ 2018-06-26 18:19 ` Peter Maydell
  0 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2018-06-26 18:19 UTC (permalink / raw)
  To: QEMU Developers

On 26 June 2018 at 17:56, Peter Maydell <peter.maydell@linaro.org> wrote:
> target-arm queue: mostly smallish stuff. I expect to send
> out another pullreq at the end of this week, but since this
> is up to 32 patches already I'd rather send it out now
> than accumulate a monster sized patchset.
>
> thanks
> -- PMM
>
>
> The following changes since commit 0ab4c574a55448a37b9f616259b82950742c9427:
>
>   Merge remote-tracking branch 'remotes/kraxel/tags/ui-20180626-pull-request' into staging (2018-06-26 16:44:57 +0100)
>
> are available in the Git repository at:
>
>   git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180626
>
> for you to fetch changes up to 9b945a9ee36a34eaeca412ef9ef35fbfe33c2c85:
>
>   aspeed/timer: use the APB frequency from the SCU (2018-06-26 17:50:42 +0100)
>
> ----------------------------------------------------------------
> target-arm queue:
>  * aspeed: set APB clocks correctly (fixes slowdown on palmetto)
>  * smmuv3: cache config data and TLB entries
>  * v7m/v8m: support read/write from MPU regions smaller than 1K
>  * various: clean up logging/debug messages
>  * xilinx_spips: Make dma transactions as per dma_burst_size
>
> ----------------------------------------------------------------

Applied, thanks.

-- PMM

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 00/32] target-arm queue
@ 2018-06-26 16:56 Peter Maydell
  2018-06-26 18:19 ` Peter Maydell
  0 siblings, 1 reply; 41+ messages in thread
From: Peter Maydell @ 2018-06-26 16:56 UTC (permalink / raw)
  To: qemu-devel

target-arm queue: mostly smallish stuff. I expect to send
out another pullreq at the end of this week, but since this
is up to 32 patches already I'd rather send it out now
than accumulate a monster sized patchset.

thanks
-- PMM


The following changes since commit 0ab4c574a55448a37b9f616259b82950742c9427:

  Merge remote-tracking branch 'remotes/kraxel/tags/ui-20180626-pull-request' into staging (2018-06-26 16:44:57 +0100)

are available in the Git repository at:

  git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180626

for you to fetch changes up to 9b945a9ee36a34eaeca412ef9ef35fbfe33c2c85:

  aspeed/timer: use the APB frequency from the SCU (2018-06-26 17:50:42 +0100)

----------------------------------------------------------------
target-arm queue:
 * aspeed: set APB clocks correctly (fixes slowdown on palmetto)
 * smmuv3: cache config data and TLB entries
 * v7m/v8m: support read/write from MPU regions smaller than 1K
 * various: clean up logging/debug messages
 * xilinx_spips: Make dma transactions as per dma_burst_size

----------------------------------------------------------------
Cédric Le Goater (6):
      aspeed/smc: fix dummy cycles count when in dual IO mode
      aspeed/smc: fix HW strapping
      aspeed/smc: rename aspeed_smc_flash_send_addr() to aspeed_smc_flash_setup()
      aspeed/scu: introduce clock frequencies
      aspeed: initialize the SCU controller first
      aspeed/timer: use the APB frequency from the SCU

Eric Auger (3):
      hw/arm/smmuv3: Cache/invalidate config data
      hw/arm/smmuv3: IOTLB emulation
      hw/arm/smmuv3: Add notifications on invalidation

Jia He (1):
      hw/arm/smmuv3: Fix translate error handling

Joel Stanley (1):
      MAINTAINERS: Add ASPEED BMCs

Peter Maydell (3):
      tcg: Support MMU protection regions smaller than TARGET_PAGE_SIZE
      target/arm: Set page (region) size in get_phys_addr_pmsav7()
      target/arm: Handle small regions in get_phys_addr_pmsav8()

Philippe Mathieu-Daudé (17):
      MAINTAINERS: Adopt the Gumstix computers-on-module machines
      hw/input/pckbd: Use qemu_log_mask(GUEST_ERROR) instead of fprintf
      hw/input/tsc2005: Use qemu_log_mask(GUEST_ERROR) instead of fprintf
      hw/dma/omap_dma: Use qemu_log_mask(UNIMP) instead of printf
      hw/dma/omap_dma: Use qemu_log_mask(GUEST_ERROR) instead of fprintf
      hw/ssi/omap_spi: Use qemu_log_mask(GUEST_ERROR) instead of fprintf
      hw/sd/omap_mmc: Use qemu_log_mask(UNIMP) instead of printf
      hw/i2c/omap_i2c: Use qemu_log_mask(UNIMP) instead of fprintf
      hw/arm/omap1: Use qemu_log_mask(GUEST_ERROR) instead of fprintf
      hw/arm/omap: Use qemu_log_mask(GUEST_ERROR) instead of fprintf
      hw/arm/stellaris: Use qemu_log_mask(UNIMP) instead of fprintf
      hw/net/stellaris_enet: Fix a typo
      hw/net/stellaris_enet: Use qemu_log_mask(GUEST_ERROR) instead of hw_error
      hw/net/smc91c111: Use qemu_log_mask(GUEST_ERROR) instead of hw_error
      hw/net/smc91c111: Use qemu_log_mask(UNIMP) instead of fprintf
      hw/arm/stellaris: Fix gptm_write() error message
      hw/arm/stellaris: Use HWADDR_PRIx to display register address

Sai Pavan Boddu (1):
      xilinx_spips: Make dma transactions as per dma_burst_size

 accel/tcg/softmmu_template.h    |  24 ++-
 hw/arm/smmuv3-internal.h        |  12 +-
 include/exec/cpu-all.h          |   5 +-
 include/hw/arm/omap.h           |  30 +--
 include/hw/arm/smmu-common.h    |  24 +++
 include/hw/arm/smmuv3.h         |   1 +
 include/hw/misc/aspeed_scu.h    |  70 ++++++-
 include/hw/ssi/xilinx_spips.h   |   5 +-
 include/hw/timer/aspeed_timer.h |   4 +
 accel/tcg/cputlb.c              | 131 +++++++++++--
 hw/arm/aspeed_soc.c             |  42 ++--
 hw/arm/omap1.c                  |  18 +-
 hw/arm/smmu-common.c            | 118 ++++++++++-
 hw/arm/smmuv3.c                 | 420 ++++++++++++++++++++++++++++++++++++----
 hw/arm/stellaris.c              |   8 +-
 hw/dma/omap_dma.c               |  70 ++++---
 hw/i2c/omap_i2c.c               |  20 +-
 hw/input/pckbd.c                |   4 +-
 hw/input/tsc2005.c              |  13 +-
 hw/misc/aspeed_scu.c            | 106 ++++++++++
 hw/net/smc91c111.c              |  21 +-
 hw/net/stellaris_enet.c         |  11 +-
 hw/sd/omap_mmc.c                |  13 +-
 hw/ssi/aspeed_smc.c             |  48 ++---
 hw/ssi/omap_spi.c               |  15 +-
 hw/ssi/xilinx_spips.c           |  23 ++-
 hw/timer/aspeed_timer.c         |  19 +-
 target/arm/helper.c             | 115 +++++++----
 MAINTAINERS                     |  14 +-
 hw/arm/trace-events             |  27 ++-
 30 files changed, 1176 insertions(+), 255 deletions(-)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [Qemu-devel] [PULL 00/32] target-arm queue
  2018-05-18 17:19 Peter Maydell
@ 2018-05-18 18:48 ` Peter Maydell
  0 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2018-05-18 18:48 UTC (permalink / raw)
  To: QEMU Developers

On 18 May 2018 at 18:19, Peter Maydell <peter.maydell@linaro.org> wrote:
> Another target-arm queue, since we're over 30 patches
> already. Most of this is RTH's SVE-patches-part-1.
>
> thanks
> -- PMM
>
>
> The following changes since commit d32e41a1188e929cc0fb16829ce3736046951e39:
>
>   Merge remote-tracking branch 'remotes/famz/tags/docker-and-block-pull-request' into staging (2018-05-18 14:11:52 +0100)
>
> are available in the Git repository at:
>
>   git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180518
>
> for you to fetch changes up to b94f8f60bd841c5b737185cd38263e26822f77ab:
>
>   target/arm: Implement SVE Permute - Extract Group (2018-05-18 17:48:09 +0100)
>
> ----------------------------------------------------------------
> target-arm queue:
>  * Initial part of SVE implementation (currently disabled)
>  * smmuv3: fix some minor Coverity issues
>  * add model of Xilinx ZynqMP generic DMA controller
>  * expose (most) Arm coprocessor/system registers to
>    gdb via QEMU's gdbstub, for reads only
>

Applied, thanks.

-- PMM

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 00/32] target-arm queue
@ 2018-05-18 17:19 Peter Maydell
  2018-05-18 18:48 ` Peter Maydell
  0 siblings, 1 reply; 41+ messages in thread
From: Peter Maydell @ 2018-05-18 17:19 UTC (permalink / raw)
  To: qemu-devel

Another target-arm queue, since we're over 30 patches
already. Most of this is RTH's SVE-patches-part-1.

thanks
-- PMM


The following changes since commit d32e41a1188e929cc0fb16829ce3736046951e39:

  Merge remote-tracking branch 'remotes/famz/tags/docker-and-block-pull-request' into staging (2018-05-18 14:11:52 +0100)

are available in the Git repository at:

  git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180518

for you to fetch changes up to b94f8f60bd841c5b737185cd38263e26822f77ab:

  target/arm: Implement SVE Permute - Extract Group (2018-05-18 17:48:09 +0100)

----------------------------------------------------------------
target-arm queue:
 * Initial part of SVE implementation (currently disabled)
 * smmuv3: fix some minor Coverity issues
 * add model of Xilinx ZynqMP generic DMA controller
 * expose (most) Arm coprocessor/system registers to
   gdb via QEMU's gdbstub, for reads only

----------------------------------------------------------------
Abdallah Bouassida (3):
      target/arm: Add "ARM_CP_NO_GDB" as a new bit field for ARMCPRegInfo type
      target/arm: Add "_S" suffix to the secure version of a sysreg
      target/arm: Add the XML dynamic generation

Eric Auger (2):
      hw/arm/smmuv3: Fix Coverity issue in smmuv3_record_event
      hw/arm/smmu-common: Fix coverity issue in get_block_pte_address

Francisco Iglesias (2):
      xlnx-zdma: Add a model of the Xilinx ZynqMP generic DMA
      xlnx-zynqmp: Connect the ZynqMP GDMA and ADMA

Richard Henderson (25):
      target/arm: Introduce translate-a64.h
      target/arm: Add SVE decode skeleton
      target/arm: Implement SVE Bitwise Logical - Unpredicated Group
      target/arm: Implement SVE load vector/predicate
      target/arm: Implement SVE predicate test
      target/arm: Implement SVE Predicate Logical Operations Group
      target/arm: Implement SVE Predicate Misc Group
      target/arm: Implement SVE Integer Binary Arithmetic - Predicated Group
      target/arm: Implement SVE Integer Reduction Group
      target/arm: Implement SVE bitwise shift by immediate (predicated)
      target/arm: Implement SVE bitwise shift by vector (predicated)
      target/arm: Implement SVE bitwise shift by wide elements (predicated)
      target/arm: Implement SVE Integer Arithmetic - Unary Predicated Group
      target/arm: Implement SVE Integer Multiply-Add Group
      target/arm: Implement SVE Integer Arithmetic - Unpredicated Group
      target/arm: Implement SVE Index Generation Group
      target/arm: Implement SVE Stack Allocation Group
      target/arm: Implement SVE Bitwise Shift - Unpredicated Group
      target/arm: Implement SVE Compute Vector Address Group
      target/arm: Implement SVE floating-point exponential accelerator
      target/arm: Implement SVE floating-point trig select coefficient
      target/arm: Implement SVE Element Count Group
      target/arm: Implement SVE Bitwise Immediate Group
      target/arm: Implement SVE Integer Wide Immediate - Predicated Group
      target/arm: Implement SVE Permute - Extract Group

 hw/dma/Makefile.objs         |    1 +
 target/arm/Makefile.objs     |   10 +
 include/hw/arm/xlnx-zynqmp.h |    5 +
 include/hw/dma/xlnx-zdma.h   |   84 ++
 include/qom/cpu.h            |    5 +-
 target/arm/cpu.h             |   37 +-
 target/arm/helper-sve.h      |  427 +++++++++
 target/arm/helper.h          |    1 +
 target/arm/translate-a64.h   |  118 +++
 gdbstub.c                    |   10 +
 hw/arm/smmu-common.c         |    4 +-
 hw/arm/smmuv3.c              |    2 +-
 hw/arm/xlnx-zynqmp.c         |   53 ++
 hw/dma/xlnx-zdma.c           |  832 +++++++++++++++++
 target/arm/cpu.c             |    1 +
 target/arm/gdbstub.c         |   76 ++
 target/arm/helper.c          |   57 +-
 target/arm/sve_helper.c      | 1562 +++++++++++++++++++++++++++++++
 target/arm/translate-a64.c   |  119 +--
 target/arm/translate-sve.c   | 2070 ++++++++++++++++++++++++++++++++++++++++++
 .gitignore                   |    1 +
 target/arm/sve.decode        |  419 +++++++++
 22 files changed, 5778 insertions(+), 116 deletions(-)
 create mode 100644 include/hw/dma/xlnx-zdma.h
 create mode 100644 target/arm/helper-sve.h
 create mode 100644 target/arm/translate-a64.h
 create mode 100644 hw/dma/xlnx-zdma.c
 create mode 100644 target/arm/sve_helper.c
 create mode 100644 target/arm/translate-sve.c
 create mode 100644 target/arm/sve.decode

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [Qemu-devel] [PULL 00/32] target-arm queue
  2018-02-22 15:22 Peter Maydell
@ 2018-02-23 10:04 ` Peter Maydell
  0 siblings, 0 replies; 41+ messages in thread
From: Peter Maydell @ 2018-02-23 10:04 UTC (permalink / raw)
  To: QEMU Developers

On 22 February 2018 at 15:22, Peter Maydell <peter.maydell@linaro.org> wrote:
> Latest run of arm patches -- most of these are Philippe's SD card
> cleanups. I have more in my queue to review, but 32 is enough
> patches to warrant sending out.
>
> thanks
> -- PMM
>
> The following changes since commit ff8689611a1d954897d857b28f7ef404e11cfa2c:
>
>   Merge remote-tracking branch 'remotes/mcayland/tags/qemu-openbios-signed' into staging (2018-02-22 11:37:05 +0000)
>
> are available in the Git repository at:
>
>   git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180222
>
> for you to fetch changes up to 4e5cc6756586e967993187657dfcdde4e00288d9:
>
>   sdcard: simplify SD_SEND_OP_COND (ACMD41) (2018-02-22 15:12:54 +0000)
>
> ----------------------------------------------------------------
>  * New "raspi3" machine emulating RaspberryPi 3
>  * Fix bad register definitions for VMIDR and VMPIDR (which caused
>    assertions for 64-bit guest CPUs with EL2 on big-endian hosts)
>  * hw/char/stm32f2xx_usart: fix TXE/TC bit handling
>  * Fix ast2500 protection register emulation
>  * Lots of SD card emulation cleanups and bugfixes
>

Applied, thanks.

-- PMM

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PULL 00/32] target-arm queue
@ 2018-02-22 15:22 Peter Maydell
  2018-02-23 10:04 ` Peter Maydell
  0 siblings, 1 reply; 41+ messages in thread
From: Peter Maydell @ 2018-02-22 15:22 UTC (permalink / raw)
  To: qemu-devel

Latest run of arm patches -- most of these are Philippe's SD card
cleanups. I have more in my queue to review, but 32 is enough
patches to warrant sending out.

thanks
-- PMM

The following changes since commit ff8689611a1d954897d857b28f7ef404e11cfa2c:

  Merge remote-tracking branch 'remotes/mcayland/tags/qemu-openbios-signed' into staging (2018-02-22 11:37:05 +0000)

are available in the Git repository at:

  git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180222

for you to fetch changes up to 4e5cc6756586e967993187657dfcdde4e00288d9:

  sdcard: simplify SD_SEND_OP_COND (ACMD41) (2018-02-22 15:12:54 +0000)

----------------------------------------------------------------
 * New "raspi3" machine emulating RaspberryPi 3
 * Fix bad register definitions for VMIDR and VMPIDR (which caused
   assertions for 64-bit guest CPUs with EL2 on big-endian hosts)
 * hw/char/stm32f2xx_usart: fix TXE/TC bit handling
 * Fix ast2500 protection register emulation
 * Lots of SD card emulation cleanups and bugfixes

----------------------------------------------------------------
Hugo Landau (1):
      Fix ast2500 protection register emulation

Pekka Enberg (1):
      raspi: Add "raspi3" machine type

Peter Maydell (1):
      target/arm: Fix register definitions for VMIDR and VMPIDR

Philippe Mathieu-Daudé (28):
      hw/sd/milkymist-memcard: use qemu_log_mask()
      hw/sd/milkymist-memcard: split realize() out of SysBusDevice init()
      hw/sd/milkymist-memcard: expose a SDBus and connect the SDCard to it
      hw/sd/ssi-sd: use the SDBus API, connect the SDCard to the bus
      sdcard: reorder SDState struct members
      sdcard: replace DPRINTF() by trace events
      sdcard: add a trace event for command responses
      sdcard: replace fprintf() by qemu_hexdump()
      sdcard: add more trace events
      sdcard: define SDMMC_CMD_MAX instead of using the magic '64'
      sdcard: use G_BYTE from cutils
      sdcard: use the registerfields API to access the OCR register
      sdcard: Don't always set the high capacity bit
      sdcard: update the CSD CRC register regardless the CSD structure version
      sdcard: fix the 'maximum data transfer rate' to 25MHz
      sdcard: clean the SCR register and add few comments
      sdcard: remove commands from unsupported old MMC specification
      sdcard: simplify using the ldst API
      sdcard: use the correct masked OCR in the R3 reply
      sdcard: use the registerfields API for the CARD_STATUS register masks
      sdcard: handle CMD54 (SDIO)
      sdcard: handle the Security Specification commands
      sdcard: use a more descriptive label 'unimplemented_spi_cmd'
      sdcard: handles more commands in SPI mode
      sdcard: check the card is in correct state for APP CMD (CMD55)
      sdcard: warn if host uses an incorrect address for APP CMD (CMD55)
      sdcard: simplify SEND_IF_COND (CMD8)
      sdcard: simplify SD_SEND_OP_COND (ACMD41)

Richard Braun (1):
      hw/char/stm32f2xx_usart: fix TXE/TC bit handling

 hw/sd/sdmmc-internal.h            |  15 ++
 include/hw/char/stm32f2xx_usart.h |   7 +-
 include/hw/sd/sd.h                |   1 -
 hw/arm/raspi.c                    |  23 ++
 hw/char/stm32f2xx_usart.c         |  12 +-
 hw/misc/aspeed_scu.c              |   6 +-
 hw/misc/aspeed_sdmc.c             |   8 +-
 hw/sd/milkymist-memcard.c         |  87 +++----
 hw/sd/sd.c                        | 467 +++++++++++++++++++++++---------------
 hw/sd/ssi-sd.c                    |  32 +--
 target/arm/helper.c               |   8 +-
 hw/sd/trace-events                |  20 ++
 12 files changed, 446 insertions(+), 240 deletions(-)
 create mode 100644 hw/sd/sdmmc-internal.h

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2018-06-26 18:19 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-24 17:24 [Qemu-devel] [PULL 00/32] target-arm queue Peter Maydell
2016-10-24 17:24 ` [Qemu-devel] [PULL 01/32] migration: Remove static allocation of xzblre cache buffer Peter Maydell
2016-10-24 17:24 ` [Qemu-devel] [PULL 02/32] exec.c: Remove static allocation of sub_section of sub_page Peter Maydell
2016-10-24 17:24 ` [Qemu-devel] [PULL 03/32] translate-all.c: Compute L1 page table properties at runtime Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 04/32] cpu: Support a target CPU having a variable page size Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 05/32] migration/savevm.c: migrate non-default " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 06/32] target-arm: Make page size a runtime setting Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 07/32] hw/arm/virt: Set minimum_page_bits to 12 Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 08/32] hw/ptimer: Add "wraparound after one period" policy Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 09/32] tests: ptimer: Add tests for " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 10/32] hw/ptimer: Add "continuous trigger" policy Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 11/32] tests: ptimer: Add tests for " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 12/32] hw/ptimer: Add "no immediate " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 13/32] tests: ptimer: Add tests for " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 14/32] hw/ptimer: Add "no immediate reload" policy Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 15/32] tests: ptimer: Add tests for " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 16/32] hw/ptimer: Add "no counter round down" policy Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 17/32] tests: ptimer: Add tests for " Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 18/32] tests: ptimer: Change the copyright comment Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 19/32] tests: ptimer: Replace 10000 with 1 Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 20/32] arm_mptimer: Convert to use ptimer Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 21/32] tests: Add tests for the ARM MPTimer Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 22/32] ACPI: Add IORT Structure definition Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 23/32] ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 24/32] timer: a9gtimer: remove loop to auto-increment comparator Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 25/32] i2c: Fix SMBus read transactions to avoid double events Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 26/32] timer: stm32f2xx_timer: add check for prescaler value Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 27/32] hw/arm: QOM'ify musicpal.c Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 28/32] hw/arm: QOM'ify pxa2xx_gpio.c Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 29/32] hw/arm: QOM'ify strongarm.c Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 30/32] hw/display: QOM'ify pl110.c Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 31/32] target-arm: Implement new HLT trap for semihosting Peter Maydell
2016-10-24 17:25 ` [Qemu-devel] [PULL 32/32] i2c: Add asserts for second smbus i2c_start_transfer() Peter Maydell
2016-10-24 19:11 ` [Qemu-devel] [PULL 00/32] target-arm queue no-reply
2016-10-25  9:17 ` Peter Maydell
2018-02-22 15:22 Peter Maydell
2018-02-23 10:04 ` Peter Maydell
2018-05-18 17:19 Peter Maydell
2018-05-18 18:48 ` Peter Maydell
2018-06-26 16:56 Peter Maydell
2018-06-26 18:19 ` Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.