On Tue, Aug 20, 2024 at 2:13 AM Ian Brockbank <ian.brockb...@cirrus.com> wrote:
>
> This adds riscv32-clic-test.c, containing qtest test cases for configuring
> CLIC (via virt machine) and for triggering interrupts.
>
> In order to detect the interrupts, qtest.c has been updated to send interrupt
> information back to the test about the IRQ being delivered. Since we need to
> both trigger and detect the interrupt, qtest has also been updated to allow
> both an input and an output GPIO to be intercepted.
>
> Signed-off-by: Troy Song <wb-szh830...@alibaba-inc.com>
> Signed-off-by: Ian Brockbank <ian.brockb...@cirrus.com>
> ---
>  hw/intc/riscv_clic.c            |    4 +
>  include/sysemu/qtest.h          |    2 +
>  system/qtest.c                  |   72 +-
>  tests/qtest/libqtest.c          |    9 +
>  tests/qtest/libqtest.h          |    9 +
>  tests/qtest/meson.build         |    3 +-
>  tests/qtest/riscv32-clic-test.c | 1928 +++++++++++++++++++++++++++++++

Wow! Lots of tests.

The general qtest changes should be split into their own patches so
the qtest maintainers can easily review/ack them without worrying
about the CLIC

Alistair

>  7 files changed, 2010 insertions(+), 17 deletions(-)
>  create mode 100644 tests/qtest/riscv32-clic-test.c
>
> diff --git a/hw/intc/riscv_clic.c b/hw/intc/riscv_clic.c
> index 1800e84dfd..155ba65492 100644
> --- a/hw/intc/riscv_clic.c
> +++ b/hw/intc/riscv_clic.c
> @@ -174,6 +174,10 @@ static void riscv_clic_next_interrupt(void *opaque)
>                  clic->clicintip[active->irq] = 0;
>              }
>              /* Post pending interrupt for this hart */
> +            if (qtest_enabled()) {
> +                qemu_set_irq(clic->cpu_irq, qtest_encode_irq(active->irq, 
> 1));
> +                return;
> +            }
>              clic->exccode = active->irq |
>                              mode << RISCV_EXCP_CLIC_MODE_SHIFT |
>                              level << RISCV_EXCP_CLIC_LEVEL_SHIFT;
> diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
> index c161d75165..1a34d27c6d 100644
> --- a/include/sysemu/qtest.h
> +++ b/include/sysemu/qtest.h
> @@ -34,6 +34,8 @@ void qtest_server_init(const char *qtest_chrdev, const char 
> *qtest_log, Error **
>  void qtest_server_set_send_handler(void (*send)(void *, const char *),
>                                   void *opaque);
>  void qtest_server_inproc_recv(void *opaque, const char *buf);
> +
> +int qtest_encode_irq(int irqn, int level);
>  #endif
>
>  #endif
> diff --git a/system/qtest.c b/system/qtest.c
> index 12703a2045..0ba6e0fcbe 100644
> --- a/system/qtest.c
> +++ b/system/qtest.c
> @@ -49,7 +49,8 @@ struct QTest {
>
>  bool qtest_allowed;
>
> -static DeviceState *irq_intercept_dev;
> +static DeviceState *irq_intercept_dev_in;
> +static DeviceState *irq_intercept_dev_out;
>  static FILE *qtest_log_fp;
>  static QTest *qtest;
>  static GString *inbuf;
> @@ -61,6 +62,14 @@ static void *qtest_server_send_opaque;
>
>  #define FMT_timeval "%.06f"
>
> +/*
> + * Encoding for passing the specific IRQ information from an interrupt 
> handler
> + * to QTest. This needs to support CLIC, which has a 12-bit interrupt number.
> + */
> +#define QTEST_IRQN              0x0fff
> +#define QTEST_IRQN_SHIFT        0
> +#define QTEST_IRQ_LEVEL_SHIFT   12
> +
>  /**
>   * DOC: QTest Protocol
>   *
> @@ -311,6 +320,18 @@ void qtest_sendf(CharBackend *chr, const char *fmt, ...)
>      va_end(ap);
>  }
>
> +/* Encode the IRQ number and level for QTest */
> +int qtest_encode_irq(int irqn, int level)
> +{
> +    return (irqn & QTEST_IRQN) | (level << QTEST_IRQ_LEVEL_SHIFT);
> +}
> +
> +static void qtest_decode_irq(int value, int *irqn, int *level)
> +{
> +    *irqn = value & QTEST_IRQN;
> +    *level = value >> QTEST_IRQ_LEVEL_SHIFT;
> +}
> +
>  static void qtest_irq_handler(void *opaque, int n, int level)
>  {
>      qemu_irq old_irq = *(qemu_irq *)opaque;
> @@ -320,6 +341,16 @@ static void qtest_irq_handler(void *opaque, int n, int 
> level)
>          CharBackend *chr = &qtest->qtest_chr;
>          irq_levels[n] = level;
>          qtest_send_prefix(chr);
> +        if (level > 1) {
> +            int delivered_irq_num, pin_level;
> +            qtest_decode_irq(level, &delivered_irq_num, &pin_level);
> +            qtest_sendf(chr, "IRQ %s %d\n",
> +                        "delivered", delivered_irq_num);
> +            qtest_send_prefix(chr);
> +            qtest_sendf(chr, "IRQ %s %d\n",
> +                        pin_level ? "raise" : "lower", n);
> +            return;
> +        }
>          qtest_sendf(chr, "IRQ %s %d\n",
>                      level ? "raise" : "lower", n);
>      }
> @@ -369,6 +400,7 @@ static void qtest_process_command(CharBackend *chr, gchar 
> **words)
>          bool is_named;
>          bool is_outbound;
>          bool interception_succeeded = false;
> +        bool interception_duplicated = false;
>
>          g_assert(words[1]);
>          is_named = words[2] != NULL;
> @@ -386,38 +418,46 @@ static void qtest_process_command(CharBackend *chr, 
> gchar **words)
>              return;
>          }
>
> -        if (irq_intercept_dev) {
> -            qtest_send_prefix(chr);
> -            if (irq_intercept_dev != dev) {
> -                qtest_send(chr, "FAIL IRQ intercept already enabled\n");
> -            } else {
> -                qtest_send(chr, "OK\n");
> -            }
> -            return;
> -        }
> -
>          QLIST_FOREACH(ngl, &dev->gpios, node) {
>              /* We don't support inbound interception of named GPIOs yet */
>              if (is_outbound) {
> +                if (irq_intercept_dev_out) {
> +                    if (irq_intercept_dev_out == dev) {
> +                        interception_succeeded = true;
> +                    } else {
> +                        interception_duplicated = true;
> +                    }
> +                }
>                  /* NULL is valid and matchable, for "unnamed GPIO" */
> -                if (g_strcmp0(ngl->name, words[2]) == 0) {
> +                else if (g_strcmp0(ngl->name, words[2]) == 0) {
>                      int i;
>                      for (i = 0; i < ngl->num_out; ++i) {
>                          qtest_install_gpio_out_intercept(dev, ngl->name, i);
>                      }
> +                    irq_intercept_dev_out = dev;
>                      interception_succeeded = true;
>                  }
>              } else {
> -                qemu_irq_intercept_in(ngl->in, qtest_irq_handler,
> -                                      ngl->num_in);
> -                interception_succeeded = true;
> +                if (irq_intercept_dev_in) {
> +                    if (irq_intercept_dev_in == dev) {
> +                        interception_succeeded = true;
> +                    } else {
> +                        interception_duplicated = true;
> +                    }
> +                } else {
> +                    qemu_irq_intercept_in(ngl->in, qtest_irq_handler,
> +                                          ngl->num_in);
> +                    irq_intercept_dev_in = dev;
> +                    interception_succeeded = true;
> +                }
>              }
>          }
>
>          qtest_send_prefix(chr);
>          if (interception_succeeded) {
> -            irq_intercept_dev = dev;
>              qtest_send(chr, "OK\n");
> +        } else if (interception_duplicated) {
> +            qtest_send(chr, "FAIL IRQ intercept already enabled\n");
>          } else {
>              qtest_send(chr, "FAIL No intercepts installed\n");
>          }
> diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
> index 1326e34291..754c78dad7 100644
> --- a/tests/qtest/libqtest.c
> +++ b/tests/qtest/libqtest.c
> @@ -83,6 +83,7 @@ struct QTestState
>      int expected_status;
>      bool big_endian;
>      bool irq_level[MAX_IRQ];
> +    bool is_delivered[MAX_IRQ];
>      GString *rx;
>      QTestTransportOps ops;
>      GList *pending_events;
> @@ -499,6 +500,7 @@ static QTestState *qtest_init_internal(const char 
> *qemu_bin,
>      s->rx = g_string_new("");
>      for (i = 0; i < MAX_IRQ; i++) {
>          s->irq_level[i] = false;
> +        s->is_delivered[i] = false;
>      }
>
>      /*
> @@ -696,6 +698,8 @@ redo:
>
>          if (strcmp(words[1], "raise") == 0) {
>              s->irq_level[irq] = true;
> +        } else if (strcmp(words[1], "delivered") == 0) {
> +            s->is_delivered[irq] = true;
>          } else {
>              s->irq_level[irq] = false;
>          }
> @@ -988,6 +992,11 @@ bool qtest_get_irq(QTestState *s, int num)
>      return s->irq_level[num];
>  }
>
> +bool qtest_irq_delivered(QTestState *s, int num)
> +{
> +    return s->is_delivered[num];
> +}
> +
>  void qtest_module_load(QTestState *s, const char *prefix, const char 
> *libname)
>  {
>      qtest_sendf(s, "module_load %s %s\n", prefix, libname);
> diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
> index c261b7e0b3..6bd0ada1b2 100644
> --- a/tests/qtest/libqtest.h
> +++ b/tests/qtest/libqtest.h
> @@ -366,6 +366,15 @@ void qtest_module_load(QTestState *s, const char 
> *prefix, const char *libname);
>   */
>  bool qtest_get_irq(QTestState *s, int num);
>
> +/**
> + * qtest_irq_delivered:
> + * @s: #QTestState instance to operate on.
> + * @num: Interrupt to observe.
> + *
> + * Returns: Is @num interrupt delivered or not.
> + */
> +bool qtest_irq_delivered(QTestState *s, int num);
> +
>  /**
>   * qtest_irq_intercept_in:
>   * @s: #QTestState instance to operate on.
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 2f0d3ef080..3170c1b386 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -258,7 +258,8 @@ qtests_s390x = \
>     'migration-test']
>
>  qtests_riscv32 = \
> -  (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? 
> ['sifive-e-aon-watchdog-test'] : [])
> +  (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? 
> ['sifive-e-aon-watchdog-test'] : []) + \
> +  (config_all_devices.has_key('CONFIG_RISCV_CLIC') ? ['riscv32-clic-test'] : 
> [])
>
>  qtests_riscv64 = \
>    (unpack_edk2_blobs ? ['bios-tables-test'] : [])
> diff --git a/tests/qtest/riscv32-clic-test.c b/tests/qtest/riscv32-clic-test.c
> new file mode 100644
> index 0000000000..7b0102142f
> --- /dev/null
> +++ b/tests/qtest/riscv32-clic-test.c
> @@ -0,0 +1,1928 @@
> +/*
> + * QTest testcase for the RISC-V CLIC (Core Local Interrupt Controller)
> + *
> + * Copyright (c) 2021 T-Head Semiconductor Co., Ltd. All rights reserved.
> + * Copyright (c) 2024 Cirrus Logic, Inc
> + *      and Cirrus Logic International Semiconductor Ltd.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this program; if not, see 
> <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/cutils.h"
> +#include "libqtest-single.h"
> +
> +/*
> + * Standard arguments to qtest_start.
> + * This finishes with the machine so that machine parameters can be passed
> + * by appending the string with them. E.g. QEMU_BASE_ARGS ",clic-mode=m".
> + * QEMU_ARGS makes use of this to give more normal-looking code.
> + */
> +#define QEMU_BASE_ARGS  "-bios none -cpu rv32 -d guest_errors " \
> +                        "-machine virt,clic=on"
> +#define QEMU_ARGS(_machine_params) QEMU_BASE_ARGS _machine_params
> +
> +/*
> + * CLIC register addresses.
> + * The spec doesn't define a memory layout, other than to say that each
> + * CLIC should be on a 4KiB boundary if memory-mapped.
> + * This implementation makes all the CLICs contiguous, in the order M, S, U,
> + * and assumes the worst-case size. If there is only PRV_M and PRV_U, the 
> PRV_U
> + * registers will appear instead of the PRV_S.
> + */
> +#define VIRT_CLIC_MAX_IRQS      0x1000
> +#define VIRT_CLIC_CONTEXT_BASE  0x1000
> +#define VIRT_CLIC_INT_SIZE(_irq_count) ((_irq_count) * 4)
> +#define VIRT_CLIC_BLOCK_SIZE \
> +    (VIRT_CLIC_CONTEXT_BASE + VIRT_CLIC_INT_SIZE(VIRT_CLIC_MAX_IRQS))
> +
> +#define VIRT_CLIC_MMODE_BASE 0x2000000
> +#define VIRT_CLIC_SMODE_BASE (VIRT_CLIC_MMODE_BASE + VIRT_CLIC_BLOCK_SIZE)
> +#define VIRT_CLIC_UMODE_BASE (VIRT_CLIC_SMODE_BASE + VIRT_CLIC_BLOCK_SIZE)
> +
> +#define MCLICCFG_ADDR (VIRT_CLIC_MMODE_BASE + 0)
> +#define MCLICINFO_ADDR (VIRT_CLIC_MMODE_BASE + 4)
> +#define SCLICCFG_ADDR (VIRT_CLIC_SMODE_BASE + 0)
> +#define SCLICINFO_ADDR (VIRT_CLIC_SMODE_BASE + 4)
> +#define UCLICCFG_ADDR (VIRT_CLIC_UMODE_BASE + 0)
> +#define UCLICINFO_ADDR (VIRT_CLIC_UMODE_BASE + 4)
> +
> +/*
> + * Generate control register addresses for an irq
> + *
> + * @param   irq_num     IRQ to generate the addresses for
> + *
> + * Defines symbolic names for the clicintip, clicintie, clicintattr and
> + * clicintctl registers for interrupt irq_num.
> + */
> +#define GEN_CLIC_IRQ_REG(irq_num) \
> +    uint64_t clicint##irq_num##_addr =                                      \
> +    VIRT_CLIC_MMODE_BASE + 0x1000 + 4 * irq_num;                           \
> +    uint64_t clicintip##irq_num##_addr =                                    \
> +    VIRT_CLIC_MMODE_BASE + 0x1000 + 4 * irq_num;                           \
> +    uint64_t clicintie##irq_num##_addr =                                    \
> +    VIRT_CLIC_MMODE_BASE + 0x1001 + 4 * irq_num;                           \
> +    uint64_t clicintattr##irq_num##_addr =                                  \
> +    VIRT_CLIC_MMODE_BASE + 0x1002 + 4 * irq_num;                           \
> +    uint64_t clicintctl##irq_num##_addr =                                   \
> +    VIRT_CLIC_MMODE_BASE + 0x1003 + 4 * irq_num;                           \
> +    uint64_t clicint##irq_num##_addr_s =                                    \
> +    VIRT_CLIC_SMODE_BASE + 0x1000 + 4 * irq_num;                           \
> +    uint64_t clicintip##irq_num##_addr_s =                                  \
> +    VIRT_CLIC_SMODE_BASE + 0x1000 + 4 * irq_num;                           \
> +    uint64_t clicintie##irq_num##_addr_s =                                  \
> +    VIRT_CLIC_SMODE_BASE + 0x1001 + 4 * irq_num;                           \
> +    uint64_t clicintattr##irq_num##_addr_s =                                \
> +    VIRT_CLIC_SMODE_BASE + 0x1002 + 4 * irq_num;                           \
> +    uint64_t clicintctl##irq_num##_addr_s =                                 \
> +    VIRT_CLIC_SMODE_BASE + 0x1003 + 4 * irq_num;                           \
> +    uint64_t clicint##irq_num##_addr_u =                                    \
> +    VIRT_CLIC_UMODE_BASE + 0x1000 + 4 * irq_num;                           \
> +    uint64_t clicintip##irq_num##_addr_u =                                  \
> +    VIRT_CLIC_UMODE_BASE + 0x1000 + 4 * irq_num;                           \
> +    uint64_t clicintie##irq_num##_addr_u =                                  \
> +    VIRT_CLIC_UMODE_BASE + 0x1001 + 4 * irq_num;                           \
> +    uint64_t clicintattr##irq_num##_addr_u =                                \
> +    VIRT_CLIC_UMODE_BASE + 0x1002 + 4 * irq_num;                           \
> +    uint64_t clicintctl##irq_num##_addr_u =                                 \
> +    VIRT_CLIC_UMODE_BASE + 0x1003 + 4 * irq_num;
> +
> +/* test variable for configure case and we use 12 irq to test */
> +GEN_CLIC_IRQ_REG(12)
> +
> +/* test variable for interrupt case we use irq 25 and irq 26 to test */
> +GEN_CLIC_IRQ_REG(25)
> +GEN_CLIC_IRQ_REG(26)
> +
> +/*
> + * Register decodes
> + */
> +#define INTIP_SHIFT     0
> +#define INTIE_SHIFT     8
> +#define INTATTR_SHIFT   16
> +#define INTCTL_SHIFT    24
> +
> +/* CLICCFG field definitions */
> +#define MNL_MASK        0x0000000f
> +#define MNL_SHIFT       0
> +#define NMBITS_MASK_1   0x00000000      /* Only PRV_M mode */
> +#define NMBITS_MASK_2   0x00000010      /* PRV_M plus either PRV_S or PRV_U 
> */
> +#define NMBITS_MASK_3   0x00000030      /* PRV_M, PRV_S and PRV_U */
> +#define NMBITS_SHIFT    4
> +#define SNL_MASK        0x000f0000
> +#define SNL_SHIFT       16
> +#define UNL_MASK        0x0f000000
> +#define UNL_SHIFT       24
> +
> +/* The bits available in the different privilege modes */
> +#define MCFG_MASK_1     (MNL_MASK | NMBITS_MASK_1)
> +#define MCFG_MASK_2     (MNL_MASK | NMBITS_MASK_2)
> +#define MCFG_MASK_3     (MNL_MASK | NMBITS_MASK_3)
> +#define MCFG_MASK       MCFG_MASK_1
> +#define SCFG_MASK       SNL_MASK
> +#define UCFG_MASK       UNL_MASK
> +#define SUCFG_MASK      (SCFG_MASK | UCFG_MASK)
> +#define MUCFG_MASK      (MCFG_MASK_2 | UCFG_MASK)
> +#define MSCFG_MASK      (MCFG_MASK_2 | SCFG_MASK)
> +#define MSUCFG_MASK     (MCFG_MASK_3 | SCFG_MASK | UCFG_MASK)
> +
> +/* CLICINTATTR field definitions */
> +#define INTATTR_SHV            0x1
> +enum INTATTR_TRIG {
> +    TRIG_LEVEL = 0b00,
> +    TRIG_EDGE = 0b01,
> +    TRIG_POS = 0b00,
> +    TRIG_NEG = 0b10,
> +
> +    TRIG_HIGH = TRIG_LEVEL | TRIG_POS,
> +    TRIG_LOW = TRIG_LEVEL | TRIG_NEG,
> +    TRIG_RISING = TRIG_EDGE | TRIG_POS,
> +    TRIG_FALLING = TRIG_EDGE | TRIG_NEG,
> +};
> +enum INTATTR_MODE {
> +    PRV_U = 0,
> +    PRV_S = 1,
> +    PRV_M = 3
> +};
> +#define INTATTR_TRIG_MASK      0x06
> +#define INTATTR_TRIG_SHIFT     1
> +#define INTATTR_MODE_MASK      0xC0
> +#define INTATTR_MODE_SHIFT     6
> +
> +/* Convert the byte register definitions to the 32-bit register */
> +#define REG_INTIP       0x00000001
> +#define REG_INTIE       0x00000100
> +#define REG_SHV         (INTATTR_SHV << INTATTR_SHIFT)
> +#define REG_TRIG_MASK   (INTATTR_TRIG_MASK << INTATTR_SHIFT)
> +#define REG_TRIG_SHIFT  (INTATTR_TRIG_SHIFT + INTATTR_SHIFT)
> +#define REG_MODE_MASK   (INTATTR_MODE_MASK << INTATTR_SHIFT)
> +#define REG_MODE_SHIFT  (INTATTR_MODE_SHIFT + INTATTR_SHIFT)
> +#define REG_INTCTL_MASK (0xff << INTCTL_SHIFT)
> +
> +/*
> + * Some test values, based on nmbits (_nmb)
> + */
> +#define TEST_CFG(_nmb)      ((7 << UNL_SHIFT) | (7 << SNL_SHIFT) |           
>  \
> +                             (7 << MNL_SHIFT) | ((_nmb) << NMBITS_SHIFT))
> +#define TEST_CFG_M(_nmb)    (TEST_CFG(_nmb) & MCFG_MASK)    /* PRV_M only */
> +#define TEST_CFG_S(_nmb)    (TEST_CFG(_nmb) & SCFG_MASK)    /* PRV_S in MS */
> +#define TEST_CFG_U(_nmb)    (TEST_CFG(_nmb) & UCFG_MASK)    /* PRV_U */
> +#define TEST_CFG_SU(_nmb)   (TEST_CFG(_nmb) & SUCFG_MASK)   /* PRV_S in MSU 
> */
> +#define TEST_CFG_MU(_nmb)   (TEST_CFG(_nmb) & MUCFG_MASK)   /* PRV_M in MU */
> +#define TEST_CFG_MS(_nmb)   (TEST_CFG(_nmb) & MSCFG_MASK)   /* PRV_M in MS */
> +#define TEST_CFG_MSU(_nmb)  (TEST_CFG(_nmb) & MSUCFG_MASK)  /* PRV_M in MSU 
> */
> +
> +/*
> + * Generate a test function
> + *
> + * This writes to the given register, reads it back, and checks it has the
> + * expected value (which may be different from the write).
> + *
> + * @param   CASE_NAME   test case name
> + * @param   WIDTH       register access width - one of b, w, l or q
> + * @param   WIDTH_BITS  value width in bits
> + * @param   reg_addr    register to write and read
> + * @param   set_value   value to write to the register
> + * @param   expected    expected value to read back from the register
> + */
> +#define GEN_CHECK_REG_MMIO(CASE_NAME, WIDTH, WIDTH_BITS, reg_addr,          \
> +                           set_value, expected)                             \
> +static void test_configure_##CASE_NAME(void)                                \
> +{                                                                           \
> +    uint##WIDTH_BITS##_t _set_value = set_value;                            \
> +    uint##WIDTH_BITS##_t _expected = expected;                              \
> +    write##WIDTH(reg_addr, _set_value);                                     \
> +    uint##WIDTH_BITS##_t result = read##WIDTH(reg_addr);                    \
> +    g_assert_cmpuint(result, ==, _expected);                                \
> +}
> +
> +/* test function for an 8-bit value */
> +#define GEN_CHECK_REG_MMIO_B(CASE_NAME, reg_addr, set_value, expected) \
> +    GEN_CHECK_REG_MMIO(CASE_NAME, b, 8, reg_addr, set_value, expected)
> +/* test function for a 16-bit value */
> +#define GEN_CHECK_REG_MMIO_W(CASE_NAME, reg_addr, set_value, expected) \
> +    GEN_CHECK_REG_MMIO(CASE_NAME, w, 16, reg_addr, set_value, expected)
> +/* test function for a 32-bit value */
> +#define GEN_CHECK_REG_MMIO_L(CASE_NAME, reg_addr, set_value, expected) \
> +    GEN_CHECK_REG_MMIO(CASE_NAME, l, 32, reg_addr, set_value, expected)
> +/* test function for a 64-bit value */
> +#define GEN_CHECK_REG_MMIO_Q(CASE_NAME, reg_addr, set_value, expected) \
> +    GEN_CHECK_REG_MMIO(CASE_NAME, q, 64, reg_addr, set_value, expected)
> +
> +
> + /* test case definitions */
> +
> +/*
> + * cliccfg tests
> + *
> + * Layout:
> + * 31:28    reserved (WPRI 0)
> + * 27:24    unlbits
> + * 23:20    reserved (WPRI 0)
> + * 19:16    snlbits
> + * 15:6     reserved (WPRI 0)
> + *  5:4     nmbits
> + *  3:0     mnlbits
> + */
> +
> +/*
> + * Set the minimum mnlbits
> + * set nmbits = 0, mnlbits = 0, snlbits = 0, unlbits = 0
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_min_mnlbits, MCLICCFG_ADDR, 0x0, 0x0)
> +
> +/*
> + * Set the max supported mnlbits
> + * set nmbits = 0, mnlbits = 8, snlbits = 0, unlbits = 0
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_supported_max_mnlbits, MCLICCFG_ADDR, 0x8, 0x8)
> +
> +/*
> + * Set mnlbits to an unsupported value
> + * set nmbits = 0, mnlbits = 10, snlbits = 0, unlbits = 0
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_unsupported_mnlbits, MCLICCFG_ADDR, 0xA, 0x8)
> +
> +/*
> + * Set the minimum snlbits
> + * set nmbits = 0, mnlbits = 4, snlbits = 0, unlbits = 0
> + * Requires PRV_S mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_min_snlbits_s, MCLICCFG_ADDR, 0x00004, 0x00004)
> +
> +/*
> + * Set the max supported snlbits
> + * set nmbits = 0, mnlbits = 4, snlbits = 8, unlbits = 0
> + * Requires PRV_S mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_supported_max_snlbits_s, MCLICCFG_ADDR,
> +                     0x80004, 0x80004)
> +
> +/*
> + * Set snlbits to an unsupported value
> + * set nmbits = 0, mnlbits = 4, snlbits = 10, unlbits = 0
> + * Requires PRV_S mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_unsupported_snlbits_s, MCLICCFG_ADDR,
> +                     0xA0004, 0x80004)
> +
> +/*
> + * Set snlbits with no PRV_S support
> + * set nmbits = 0, mnlbits = 4, snlbits = 8, unlbits = 0
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_snlbits_no_s, MCLICCFG_ADDR, 0x80004, 0x00004)
> +
> +/*
> + * Set the minimum unlbits
> + * set nmbits = 0, mnlbits = 4, snlbits = 0, unlbits = 0
> + * Requires PRV_S mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_min_unlbits_u, MCLICCFG_ADDR, 0x0000004, 
> 0x0000004)
> +
> +/*
> + * Set the max supported unlbits
> + * set nmbits = 0, mnlbits = 4, snlbits = 0, unlbits = 8
> + * Requires PRV_U mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_supported_max_unlbits_u, MCLICCFG_ADDR,
> +                     0x8000004, 0x8000004)
> +
> +/*
> + * Set unlbits to an unsupported value
> + * set nmbits = 0, mnlbits = 4, snlbits = 0, unlbits = 10
> + * Requires PRV_U mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_unsupported_unlbits_u, MCLICCFG_ADDR,
> +                     0xA000004, 0x8000004)
> +
> +/*
> + * Set unlbits with no PRV_U support
> + * set nmbits = 0, mnlbits = 4, snlbits = 0, unlbits = 8
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_unlbits_no_u, MCLICCFG_ADDR, 0x8000004, 
> 0x0000004)
> +
> +/*
> + * Set all modes
> + * set nmbits = 0, mnlbits = 4, snlbits = 2, unlbits = 2
> + * Requires PRV_S + PRV_U mode
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_xnlbits, MCLICCFG_ADDR, 0x2020004, 0x2020004)
> +
> +/*
> + * nmbits = 0
> + * set nmbits = 0, mnlbits = 8
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_nmbits_0, MCLICCFG_ADDR, 0x08, 0x08)
> +
> +/*
> + * nmbits = 1 needs PRV_S or PRV_U
> + * set nmbits = 1, mnlbits = 8
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_nmbits_1, MCLICCFG_ADDR, 0x18, 0x18)
> +GEN_CHECK_REG_MMIO_L(cliccfg_unsupported_nmbits_1, MCLICCFG_ADDR, 0x18, 0x08)
> +
> +/*
> + * nmbits = 2 needs PRV_S and PRV_U
> + * set nmbits = 2, mnlbits = 8
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_nmbits_2, MCLICCFG_ADDR, 0x28, 0x28)
> +GEN_CHECK_REG_MMIO_L(cliccfg_unsupported_nmbits_2, MCLICCFG_ADDR, 0x28, 0x08)
> +
> +/*
> + * nmbits = 3 is not supported
> + * set nmbits = 3, mnlbits = 8
> + */
> +GEN_CHECK_REG_MMIO_L(cliccfg_unsupported_nmbits_3, MCLICCFG_ADDR, 0x38, 0x08)
> +
> +/*
> + * clicintie tests
> + *
> + * Layout:
> + *  [0]     enable: 1 = enabled, 0 = disabled
> + */
> +
> +/* set clicintie[i] = 0x1 and compare */
> +GEN_CHECK_REG_MMIO_B(clicintie_enable, clicintie12_addr, 0x1, 0x1)
> +
> +/* set clicintie[i] = 0x0 and compare */
> +GEN_CHECK_REG_MMIO_B(clicintie_disable, clicintie12_addr, 0, 0)
> +
> +/*
> + * clicintattr tests
> + *
> + * Layout:
> + *  [7:6]   mode        b00 = U, b01 = S, b10 = reserved, b11 = M
> + *  [5:3]   reserved
> + *  [2:1]   trig        trig[0]: 0 = level, 1 = edge; trig[1]: 0 = pos, 1 = 
> neg
> + *  [0]     shv         0 = non-vectored, 1 = vectored
> + */
> +
> +/* Mode tests - note these deliberately use different trig and int settings 
> */
> +/*
> + * Set mode 3 - PRV_M
> + * mode = b11, trig = b11, shv = b1
> + * clicintattr[i] = 0xc7
> + * expected
> + * mode = b11, tri = b11, shv = b1
> + * clicintattr[i] = 0xc7
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_m, clicintattr12_addr,
> +                     0xc7, 0xc7)
> +
> +/*
> + * Set mode 1 - PRV_S
> + * mode = b01, trig = b10, shv = b0
> + * clicintattr[i] = 0x44
> + * expected
> + * mode = b01, tri = b10, shv = b0
> + * clicintattr[i] = 0x44
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_s_supported, clicintattr12_addr,
> +                     0x44, 0x44)
> +
> +/*
> + * Set mode 0 - PRV_U
> + * mode = b00, trig = b01, shv = b1
> + * clicintattr[i] = 0x03
> + * expected
> + * mode = b00, tri = b01, shv = b1
> + * clicintattr[i] = 0x03
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_u_supported, clicintattr12_addr,
> +                     0x03, 0x03)
> +
> +/*
> + * WARL: clicintattr should return PRV_M for PRV_S if PRV_U and PRV_S are
> + * both unsupported or nmbits = 0.
> + *
> + * mode = b01, tri = b10, shv = b0
> + * clicintattr[i] = 0x44
> + * expected
> + * mode = b11, tri = b10, shv = b0
> + * clicintattr[i] = 0xc4
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_s_to_m_warl, clicintattr12_addr,
> +                     0x44, 0xc4)
> +
> +/*
> + * WARL: clicintattr should return PRV_U for PRV_S if PRV_S is unsupported 
> and
> + * nmbits = 1.
> + *
> + * mode = b01, tri = b10, shv = b0
> + * clicintattr[i] = 0x44
> + * expected
> + * mode = b11, tri = b10, shv = b0
> + * clicintattr[i] = 0x04
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_s_to_u_warl, clicintattr12_addr,
> +                     0x44, 0x04)
> +
> +/*
> + * WARL: clicintattr should return PRV_M for PRV_U if PRV_U and PRV_S are
> + * both unsupported or nmbits = 0.
> + *
> + * mode = b00, tri = b01, shv = b1
> + * clicintattr[i] = 0x03
> + * expected
> + * mode = b11, tri = b01, shv = b1
> + * clicintattr[i] = 0xc3
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_u_to_m_warl, clicintattr12_addr,
> +                     0x03, 0xc3)
> +
> +/*
> + * WARL: clicintattr should return PRV_S for PRV_U if PRV_U is unsupported 
> and
> + * nmbits = 1.
> + *
> + * mode = b00, tri = b01, shv = b1
> + * clicintattr[i] = 0x03
> + * expected
> + * mode = b01, tri = b01, shv = b1
> + * clicintattr[i] = 0x43
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_prv_u_to_s_warl, clicintattr12_addr,
> +                     0x03, 0x43)
> +
> +/*
> + * Mode 2 is invalid
> + * mode = b10, trig = b00, shv = b0
> + * clicintattr[i] = 0x80
> + * expected
> + * mode = b11, tri = b00, shv = b1
> + * clicintattr[i] = 0xc1
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_unsupported_mode_10, clicintattr12_addr,
> +                     0x81, 0xc1)
> +
> +/*
> + * set positive edge-triggered, vectored
> + * mode = b11, tri = b01, shv = b1
> + * clicintattr[i] = 0xc1
> + * expected
> + * mode = b11, tri = b01, shv = b1
> + * clicintattr[i] = 0xc1
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_positive_edge_triggered, clicintattr12_addr,
> +                     0xc3, 0xc3)
> +
> +/*
> + * set negative edge-triggered, vectored
> + * mode = b11, tri = b11, shv = b1
> + * clicintattr[i] = 0xc7
> + * expected
> + * mode = b11, tri = b11, shv = b1
> + * clicintattr[i] = 0xc7
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_negative_edge_triggered, clicintattr12_addr,
> +                     0xc7, 0xc7)
> +
> +/*
> + * set positive level-triggered, vectored
> + * mode = b11, tri = b00, shv = b1
> + * clicintattr[i] = 0xc1
> + * expected
> + * mode = b11, tri = b00, shv = b1
> + * clicintattr[i] = 0xc1
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_positive_level_triggered, 
> clicintattr12_addr,
> +                     0xc1, 0xc1)
> +
> +/*
> + * set negative level-triggered, vectored
> + * mode = b11, tri = b10, shv = b1
> + * clicintattr[i] = 0xc5
> + * expected
> + * mode = b11, tri = b00, shv = b1
> + * clicintattr[i] = 0xc5
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_negative_level_triggered, 
> clicintattr12_addr,
> +                     0xc5, 0xc5)
> +
> +/*
> + * set non-vectored
> + * mode = b11, tri = b11, shv = b0
> + * clicintattr[i] = 0xc6
> + * expected
> + * mode = b11, tri = b11, shv = b0
> + * clicintattr[i] = 0xc6
> + */
> +GEN_CHECK_REG_MMIO_B(clicintattr_non_vectored, clicintattr12_addr,
> +                     0xc6, 0xc6)
> +
> +/*
> + * clicintctl tests
> + *
> + * Layout depends on mnlbits/snlbits/unlbits in mcliccfg.
> + *
> + */
> +
> +/*
> + * Test with 0 intctlbits - mask 0xff
> + * Everything rounds up
> + * clicintctl[i] = 0xFF
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_0_bits, clicintctl12_addr,
> +                     0x00, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_0_bits, clicintctl12_addr,
> +                     0x21, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_0_bits, clicintctl12_addr,
> +                     0x58, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_0_bits, clicintctl12_addr,
> +                     0x80, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_0_bits, clicintctl12_addr,
> +                     0xcc, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_0_bits, clicintctl12_addr,
> +                     0xf0, 0xff)
> +
> +/*
> + * Test with 1 intctlbit - mask 0x7f
> + * The top bit is used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_1_bits, clicintctl12_addr,
> +                     0x00, 0x7f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_1_bits, clicintctl12_addr,
> +                     0x21, 0x7f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_1_bits, clicintctl12_addr,
> +                     0x58, 0x7f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_1_bits, clicintctl12_addr,
> +                     0x80, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_1_bits, clicintctl12_addr,
> +                     0xcc, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_1_bits, clicintctl12_addr,
> +                     0xf0, 0xff)
> +
> +/*
> + * Test with 2 intctlbits - mask 0x3f
> + * The top 2 bits are used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_2_bits, clicintctl12_addr,
> +                     0x00, 0x3f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_2_bits, clicintctl12_addr,
> +                     0x21, 0x3f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_2_bits, clicintctl12_addr,
> +                     0x58, 0x7f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_2_bits, clicintctl12_addr,
> +                     0x80, 0xbf)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_2_bits, clicintctl12_addr,
> +                     0xcc, 0xff)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_2_bits, clicintctl12_addr,
> +                     0xf0, 0xff)
> +
> +/*
> + * Test with 3 intctlbits - mask 0x1f
> + * The top 3 bits are used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_3_bits, clicintctl12_addr,
> +                     0x00, 0x1f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_3_bits, clicintctl12_addr,
> +                     0x21, 0x3f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_3_bits, clicintctl12_addr,
> +                     0x58, 0x5f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_3_bits, clicintctl12_addr,
> +                     0x80, 0x9f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_3_bits, clicintctl12_addr,
> +                     0xcc, 0xdf)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_3_bits, clicintctl12_addr,
> +                     0xf0, 0xff)
> +
> +/*
> + * Test with 4 intctlbits - mask 0x0f
> + * The top 4 bits are used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_4_bits, clicintctl12_addr,
> +                     0x00, 0x0f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_4_bits, clicintctl12_addr,
> +                     0x21, 0x2f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_4_bits, clicintctl12_addr,
> +                     0x58, 0x5f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_4_bits, clicintctl12_addr,
> +                     0x80, 0x8f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_4_bits, clicintctl12_addr,
> +                     0xcc, 0xcf)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_4_bits, clicintctl12_addr,
> +                     0xf0, 0xff)
> +
> +/*
> + * Test with 5 intctlbits - mask 0x07
> + * The top 5 bits are used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_5_bits, clicintctl12_addr,
> +                     0x00, 0x07)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_5_bits, clicintctl12_addr,
> +                     0x21, 0x27)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_5_bits, clicintctl12_addr,
> +                     0x58, 0x5f)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_5_bits, clicintctl12_addr,
> +                     0x80, 0x87)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_5_bits, clicintctl12_addr,
> +                     0xcc, 0xcf)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_5_bits, clicintctl12_addr,
> +                     0xf0, 0xf7)
> +
> +/*
> + * Test with 6 intctlbits - mask 0x03
> + * The top 6 bits are used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_6_bits, clicintctl12_addr,
> +                     0x00, 0x03)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_6_bits, clicintctl12_addr,
> +                     0x21, 0x23)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_6_bits, clicintctl12_addr,
> +                     0x58, 0x5b)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_6_bits, clicintctl12_addr,
> +                     0x80, 0x83)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_6_bits, clicintctl12_addr,
> +                     0xcc, 0xcf)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_6_bits, clicintctl12_addr,
> +                     0xf0, 0xf3)
> +
> +/*
> + * Test with 7 intctlbits - mask 0x01
> + * The top 7 bits are used, everything else rounds up
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_7_bits, clicintctl12_addr,
> +                     0x00, 0x01)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_7_bits, clicintctl12_addr,
> +                     0x21, 0x21)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_7_bits, clicintctl12_addr,
> +                     0x58, 0x59)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_7_bits, clicintctl12_addr,
> +                     0x80, 0x81)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_7_bits, clicintctl12_addr,
> +                     0xcc, 0xcd)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_7_bits, clicintctl12_addr,
> +                     0xf0, 0xf1)
> +
> +/*
> + * Test with 8 intctlbits - mask 0x00
> + * All bits are used
> + */
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_0_8_bits, clicintctl12_addr,
> +                     0x00, 0x00)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_33_8_bits, clicintctl12_addr,
> +                     0x21, 0x21)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_88_8_bits, clicintctl12_addr,
> +                     0x58, 0x58)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_128_8_bits, clicintctl12_addr,
> +                     0x80, 0x80)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_204_8_bits, clicintctl12_addr,
> +                     0xcc, 0xcc)
> +GEN_CHECK_REG_MMIO_B(clicintctl_set_240_8_bits, clicintctl12_addr,
> +                     0xf0, 0xf0)
> +
> +/*
> + * read clicintip[i] to result
> + * set cliccfg = 0x11, clicintattr[i] = 0x31, clicintip[i] = 0x1
> + * check the value of clicintip[i] that is changed or not
> + */
> +static void test_configure_clicintip_level_triggered_read_only(void)
> +{
> +    /* configure level-triggered mode */
> +    writeb(clicintattr12_addr, 0xc1);
> +    g_assert_cmpuint(readb(clicintattr12_addr), ==, 0xc1);
> +
> +    uint8_t orig_value = readb(clicintip12_addr);
> +    writeb(clicintip12_addr, 0x1);
> +    uint32_t result = readb(clicintip12_addr);
> +
> +    g_assert_cmpuint(orig_value, ==, result);
> +}
> +
> +static void boot_qemu_m(void)
> +{
> +    global_qtest = qtest_start(QEMU_ARGS(",clic-mode=m"));
> +}
> +
> +static void boot_qemu_ms(void)
> +{
> +    global_qtest = qtest_start(QEMU_ARGS(",clic-mode=ms"));
> +}
> +
> +static void boot_qemu_mu(void)
> +{
> +    global_qtest = qtest_start(QEMU_ARGS(",clic-mode=mu"));
> +}
> +
> +static void boot_qemu_msu(void)
> +{
> +    global_qtest = qtest_start(QEMU_ARGS(",clic-mode=msu"));
> +}
> +
> +#define GEN_BOOT_QEMU_INTCTL(_nbits)                                        \
> +static void boot_qemu_##_nbits##_bits(void)                                 \
> +{                                                                           \
> +    global_qtest = qtest_initf(QEMU_BASE_ARGS                               \
> +                               ",clic-mode=msu,clic-intctlbits=%d",         \
> +                               _nbits);                                     \
> +}
> +
> +static void shut_down_qemu(void)
> +{
> +    qtest_quit(global_qtest);
> +}
> +
> +/*
> + * test vectored positive level triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in two situation:
> + *    same level, different level.
> + * 2. within level triggered mode, we can only use device to clear pending.
> + * 3. within positive level triggered mode, set gpio-in rise
> + *    to trigger interrupt.
> + */
> +static void test_vectored_positive_level_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc1);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    /*
> +     * level trigger wouldn't auto clear clear pending,
> +     * so we need to manually do it.
> +     */
> +    qtest_writeb(qts, clicintie25_addr, 0);
> +    qtest_writeb(qts, clicintie26_addr, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 0, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set interrupt 25 level 255, interrupt 26 level 127 */
> +    /* arbitration will be made and 25 will rise */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintctl25_addr, 0xbf);
> +    qtest_writeb(qts, clicintctl26_addr, 0x3f);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_true(qtest_irq_delivered(qts, 25));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test vectored negative level triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in two situation:
> + *    same level, different level.
> + * 2. within level triggered mode, we can only use device to clear pending.
> + * 3. within negative level triggered mode,
> + *    set gpio-in lower to trigger interrupt.
> + */
> +static void test_vectored_negative_level_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc5);
> +    qtest_readb(qts, clicintattr25_addr);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc5);
> +    qtest_readb(qts, clicintattr26_addr);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    /*
> +     * level trigger wouldn't auto clear clear pending,
> +     * so we need to manually do it.
> +     */
> +    qtest_writeb(qts, clicintie25_addr, 0);
> +    qtest_writeb(qts, clicintie26_addr, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 0, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set interrupt 25 level 255, interrupt 26 level 127 */
> +    /* arbitration will be made and 25 will rise */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintctl25_addr, 0xbf);
> +    qtest_writeb(qts, clicintctl26_addr, 0x3f);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 25));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test vectored positive edge triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in two situation:
> + *    same level, different level.
> + * 2. within vectored edge triggered mode, pending bit will be
> + *    automatically cleared.
> + * 3. within positive edge triggered mode, set gpio-in from
> + *    lower to rise to trigger interrupt.
> + */
> +static void test_vectored_positive_edge_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc3);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc3);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_writeb(qts, clicintip25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_writeb(qts, clicintip26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    /* vectored edge trigger will auto clear clear pending */
> +    qtest_writeb(qts, clicintie25_addr, 0);
> +    qtest_writeb(qts, clicintie26_addr, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 0, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set interrupt 25 level 255, interrupt 26 level 127 */
> +    /* arbitration will be made and 25 will rise */
> +    qtest_writeb(qts, clicintip25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_writeb(qts, clicintip26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintctl25_addr, 0xbf);
> +    qtest_writeb(qts, clicintctl26_addr, 0x3f);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_true(qtest_irq_delivered(qts, 25));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test vectored negative edge triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in two situation:
> + *    same level, different level.
> + * 2. within vectored edge triggered mode, pending bit will be
> + *    automatically cleared.
> + * 3. within negative edge triggered mode, set gpio-in from
> + *    rise to lower to trigger interrupt.
> + */
> +static void test_vectored_negative_edge_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc7);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc7);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_writeb(qts, clicintip25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_writeb(qts, clicintip26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    /* vectored edge trigger will auto clear clear pending */
> +    qtest_writeb(qts, clicintie25_addr, 0);
> +    qtest_writeb(qts, clicintie26_addr, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 0, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set interrupt 25 level 255, interrupt 26 level 127 */
> +    /* arbitration will be made and 25 will rise */
> +    qtest_writeb(qts, clicintip25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_writeb(qts, clicintip26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintctl25_addr, 0xbf);
> +    qtest_writeb(qts, clicintctl26_addr, 0x3f);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 25));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test unvectored positive level triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in two situation:
> + *    same level, different level.
> + * 2. within level triggered mode, we can only use device to clear pending.
> + * 3. within positive level triggered mode, set gpio-in rise to
> + *    trigger interrupt.
> + */
> +static void test_unvectored_positive_level_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc0);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    /*
> +     * level trigger wouldn't auto clear clear pending,
> +     * so we need to manually do it.
> +     */
> +    qtest_writeb(qts, clicintie25_addr, 0);
> +    qtest_writeb(qts, clicintie26_addr, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 0, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set interrupt 25 level 255, interrupt 26 level 127 */
> +    /* arbitration will be made and 25 will rise */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintctl25_addr, 0xbf);
> +    qtest_writeb(qts, clicintctl26_addr, 0x3f);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    g_assert_true(qtest_irq_delivered(qts, 25));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test unvectored negative level triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in two situation:
> + *    same level, different level.
> + * 2. within level triggered mode, we can only use device to clear pending.
> + * 3. within negative level triggered mode, set gpio-in lower
> + *    to trigger interrupt.
> + */
> +static void test_unvectored_negative_level_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc4);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc4);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    /*
> +     * level trigger wouldn't auto clear clear pending,
> +     * so we need to manually do it.
> +     */
> +    qtest_writeb(qts, clicintie25_addr, 0);
> +    qtest_writeb(qts, clicintie26_addr, 0);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 0, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set interrupt 25 level 255, interrupt 26 level 127 */
> +    /* arbitration will be made and 25 will rise */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintctl25_addr, 0xbf);
> +    qtest_writeb(qts, clicintctl26_addr, 0x3f);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 25));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test unvectored positive edge triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in same level
> + * 2. within unvectored edge triggered mode, pending bit can be
> + *    cleared by using nxti instruction which can't be tested in qtest.
> + * 3. within positive edge triggered mode, set gpio-in
> + *    from lower to rise to trigger interrupt.
> + */
> +static void test_unvectored_positive_edge_triggered_interrupt(void)
> +{
> +   QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc2);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc2);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_writeb(qts, clicintip25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_writeb(qts, clicintip26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * test unvectored negative edge triggered interrupt
> + * test points:
> + * 1. we use interrupt 25 and 26 to test arbitration in same level
> + * 2. within unvectored edge triggered mode, pending bit can be cleared
> + *    by using nxti instruction which can't be tested in qtest.
> + * 3. within positive edge triggered mode, set gpio-in from
> + *    rise to lower to trigger interrupt.
> + */
> +static void test_unvectored_negative_edge_triggered_interrupt(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_BASE_ARGS);
> +    /* intercept in and out irq */
> +    qtest_irq_intercept_out(qts, "/machine/unattached/device[1]");
> +    qtest_irq_intercept_in(qts, "/machine/unattached/device[1]");
> +
> +    /* configure */
> +    qtest_writeb(qts, MCLICCFG_ADDR, 0x1);
> +    qtest_writeb(qts, clicintattr25_addr, 0xc6);
> +    qtest_writeb(qts, clicintattr26_addr, 0xc6);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 1);
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 26, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 0);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 0);
> +
> +    /* set pending */
> +    /* arbitration will be made and 26 will be delivered */
> +    qtest_writeb(qts, clicintip25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip25_addr), ==, 1);
> +    qtest_writeb(qts, clicintip26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintip26_addr), ==, 1);
> +    qtest_writeb(qts, clicintie25_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie25_addr), ==, 1);
> +    qtest_writeb(qts, clicintie26_addr, 1);
> +    g_assert_cmpuint(qtest_readb(qts, clicintie26_addr), ==, 1);
> +    /* trigger arbitration */
> +    qtest_set_irq_in(qts, "/machine/unattached/device[1]", NULL, 25, 0);
> +    g_assert_true(qtest_irq_delivered(qts, 26));
> +    g_assert_true(qtest_get_irq(qts, 0));
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * Test that PRV_S is a filtered view of PRV_M.
> + *
> + * IRQs configured as PRV_M in the mode field of intattr are not visible via
> + * the PRV_S registers, and all registers appear as hard-wired zeros.
> + */
> +static void test_prv_s_access(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_ARGS(",clic-mode=ms"));
> +    int default_intattr = INTATTR_SHV | (TRIG_LEVEL << INTATTR_TRIG_SHIFT);
> +    int default_reg_value = (default_intattr << INTATTR_SHIFT) |
> +                            (PRV_M << REG_MODE_SHIFT) | (0x7 << 
> INTCTL_SHIFT);
> +    int reg_value_2 = (TRIG_FALLING << REG_TRIG_SHIFT) |
> +                      (PRV_S << REG_MODE_SHIFT) | (0x5 << INTCTL_SHIFT);
> +    int value;
> +
> +    /*
> +     * Make sure of our base state using the PRV_M registers
> +     */
> +    qtest_writel(qts, MCLICCFG_ADDR, TEST_CFG(1));
> +    /* No PRV_U, so no UNLBITS */
> +    g_assert_cmpuint(qtest_readl(qts, MCLICCFG_ADDR), == , TEST_CFG_MS(1));
> +
> +    qtest_writel(qts, clicint12_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint25_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * Now check the PRV_S view
> +     */
> +
> +    /* We should only see the PRV_S part of CLICCFG */
> +    g_assert_cmpuint(qtest_readl(qts, SCLICCFG_ADDR), == , TEST_CFG_S(1));
> +
> +    /* These are all PRV_M mode so reading via PRV_S should see them all as 
> 0 */
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_s), == , 0);
> +
> +    /* Writing should leave them unchanged */
> +    qtest_writel(qts, clicint12_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint25_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * If we change IRQ 12 to PRV_S mode, we should now be able to see it
> +     */
> +    value = (default_reg_value & ~REG_MODE_MASK) | (PRV_S << REG_MODE_SHIFT);
> +    qtest_writel(qts, clicint12_addr, value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , value);
> +
> +    /* ...but not the others */
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_s), == , 0);
> +
> +    /* We should also be able to write to it */
> +    qtest_writel(qts, clicint12_addr_s, reg_value_2);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , reg_value_2);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , reg_value_2);
> +
> +    /* ...but not the others */
> +    qtest_writel(qts, clicint25_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * Test that PRV_U is a filtered view of PRV_M.
> + *
> + * IRQs configured as PRV_M in the mode field of intattr are not visible via
> + * the PRV_U registers, and all registers appear as hard-wired zeros.
> + */
> +static void test_prv_u_access(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_ARGS(",clic-mode=mu"));
> +    int default_intattr = INTATTR_SHV | (TRIG_LEVEL << INTATTR_TRIG_SHIFT);
> +    int default_reg_value = (default_intattr << INTATTR_SHIFT) |
> +                            (PRV_M << REG_MODE_SHIFT) | (0x7 << 
> INTCTL_SHIFT);
> +    int reg_value_2 = (TRIG_FALLING << REG_TRIG_SHIFT) |
> +                      (PRV_U << REG_MODE_SHIFT) | (0x5 << INTCTL_SHIFT);
> +    int value;
> +
> +    /*
> +     * Make sure of our base state using the PRV_M registers
> +     */
> +    qtest_writel(qts, MCLICCFG_ADDR, TEST_CFG(1));
> +    /* No PRV_S, so no SNLBITS */
> +    g_assert_cmpuint(qtest_readl(qts, MCLICCFG_ADDR), == , TEST_CFG_MU(1));
> +
> +    qtest_writel(qts, clicint12_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint25_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * Now check the PRV_U view. Note we only have one additional mode, so we
> +     * use the xxx_addr_s register bank.
> +     */
> +
> +     /* We should only see the PRV_U part of CLICCFG */
> +    g_assert_cmpuint(qtest_readl(qts, SCLICCFG_ADDR), == , TEST_CFG_U(1));
> +
> +    /* These are all PRV_M mode so reading via PRV_S should see them all as 
> 0 */
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_s), == , 0);
> +
> +    /* Writing should leave them unchanged */
> +    qtest_writel(qts, clicint12_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint25_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * If we change IRQ 12 to PRV_U mode, we should now be able to see it
> +     */
> +    value = (default_reg_value & ~REG_MODE_MASK) | (PRV_U << REG_MODE_SHIFT);
> +    qtest_writel(qts, clicint12_addr, value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , value);
> +
> +    /* ...but not the others */
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_s), == , 0);
> +
> +    /* We should also be able to write to it */
> +    qtest_writel(qts, clicint12_addr_s, reg_value_2);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , reg_value_2);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , reg_value_2);
> +
> +    /* ...but not the others */
> +    qtest_writel(qts, clicint25_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    qtest_quit(qts);
> +}
> +
> +/*
> + * Test that PRV_S and PRV_U are filtered views of PRV_M.
> + *
> + * IRQs configured as PRV_M in the mode field of intattr are not visible via
> + * the PRV_S or PRV_U registers, and all registers appear as hard-wired 
> zeros.
> + */
> +static void test_prv_su_access(void)
> +{
> +    QTestState *qts = qtest_start(QEMU_ARGS(",clic-mode=msu"));
> +    int default_intattr = INTATTR_SHV | (TRIG_LEVEL << INTATTR_TRIG_SHIFT);
> +    int default_reg_value = (default_intattr << INTATTR_SHIFT) |
> +                            (PRV_M << REG_MODE_SHIFT) | (0x7 << 
> INTCTL_SHIFT);
> +    int reg_value_2 = (TRIG_FALLING << REG_TRIG_SHIFT) |
> +                      (PRV_S << REG_MODE_SHIFT) | (0x5 << INTCTL_SHIFT);
> +    int reg_value_3 = (TRIG_RISING << REG_TRIG_SHIFT) |
> +                      (PRV_U << REG_MODE_SHIFT) | (0x2 << INTCTL_SHIFT);
> +    int reg_value_4 = INTATTR_SHV | (TRIG_HIGH << REG_TRIG_SHIFT) |
> +                      (PRV_U << REG_MODE_SHIFT) | (0x3 << INTCTL_SHIFT);
> +    int value;
> +
> +    /*
> +     * Make sure of our base state using the PRV_M registers
> +     */
> +    qtest_writel(qts, MCLICCFG_ADDR, TEST_CFG(2));
> +    g_assert_cmpuint(qtest_readl(qts, MCLICCFG_ADDR), == , TEST_CFG_MSU(2));
> +
> +    qtest_writel(qts, clicint12_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint25_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr, default_reg_value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * Now check the PRV_S view
> +     */
> +
> +     /* We should only see the PRV_S and PRV_U parts of CLICCFG */
> +    g_assert_cmpuint(qtest_readl(qts, SCLICCFG_ADDR), == , TEST_CFG_SU(2));
> +
> +    /* These are all PRV_M mode so reading via PRV_S should see them all as 
> 0 */
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_s), == , 0);
> +
> +    /* Writing should leave them unchanged */
> +    qtest_writel(qts, clicint12_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint25_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * If we change IRQ 12 to PRV_S mode, we should now be able to see it
> +     */
> +    value = (default_reg_value & ~REG_MODE_MASK) | (PRV_S << REG_MODE_SHIFT);
> +    qtest_writel(qts, clicint12_addr, value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , value);
> +
> +    /* ...but not the others */
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_s), == , 0);
> +
> +    /* We should also be able to write to it */
> +    qtest_writel(qts, clicint12_addr_s, reg_value_2);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , reg_value_2);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_s), == , reg_value_2);
> +
> +    /* ...but not the others */
> +    qtest_writel(qts, clicint25_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_s, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * Now check the PRV_U view
> +     */
> +
> +     /* We should only see the PRV_U part of CLICCFG */
> +    g_assert_cmpuint(qtest_readl(qts, UCLICCFG_ADDR), == , TEST_CFG_U(2));
> +
> +    /* These are all PRV_M or PRV_S so reading via PRV_U should see them as 
> 0 */
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_u), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_u), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_u), == , 0);
> +
> +    /* Writing should leave them unchanged */
> +    qtest_writel(qts, clicint12_addr_u, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , reg_value_2);
> +    qtest_writel(qts, clicint25_addr_u, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , 
> default_reg_value);
> +    qtest_writel(qts, clicint26_addr_u, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    /*
> +     * If we change IRQ 25 to PRV_U mode, we should now be able to see it
> +     * in both PRV_S and PRV_U modes
> +     */
> +    value = (default_reg_value & ~REG_MODE_MASK) | (PRV_U << REG_MODE_SHIFT);
> +    qtest_writel(qts, clicint25_addr, value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , value);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_u), == , value);
> +
> +    /* ...we can't see the others in PRV_U */
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr_u), == , 0);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr_u), == , 0);
> +
> +    /* We should also be able to write to it from both PRV_S and PRV_U */
> +    qtest_writel(qts, clicint25_addr_s, reg_value_3);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , reg_value_3);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , reg_value_3);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_u), == , reg_value_3);
> +    qtest_writel(qts, clicint25_addr_u, reg_value_4);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr), == , reg_value_4);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_s), == , reg_value_4);
> +    g_assert_cmpuint(qtest_readl(qts, clicint25_addr_u), == , reg_value_4);
> +
> +    /* ...but we still can't write to the others in PRV_U */
> +    qtest_writel(qts, clicint12_addr_u, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint12_addr), == , reg_value_2);
> +    qtest_writel(qts, clicint26_addr_u, 0x55555555);
> +    g_assert_cmpuint(qtest_readl(qts, clicint26_addr), == , 
> default_reg_value);
> +
> +    qtest_quit(qts);
> +}
> +
> +/* Test configuration in PRV_M-only mode */
> +static void clic_configure_reg_mmio_test_case_m(void)
> +{
> +    /* Start QEMU */
> +    qtest_add_func("virt/clic/prv_m/boot_qemu_m",
> +                   boot_qemu_m);
> +
> +    /* cliccfg configure case */
> +    qtest_add_func("virt/clic/prv_m/cliccfg_min_mnlbits",
> +                   test_configure_cliccfg_min_mnlbits);
> +    qtest_add_func("virt/clic/prv_m/cliccfg_supported_max_mnlbits",
> +                   test_configure_cliccfg_supported_max_mnlbits);
> +    qtest_add_func("virt/clic/prv_m/cliccfg_unsupported_mnlbits",
> +                   test_configure_cliccfg_unsupported_mnlbits);
> +    /* snlbits and unlbits should not work */
> +    qtest_add_func("virt/clic/prv_m/cliccfg_snlbits_no_s",
> +                   test_configure_cliccfg_snlbits_no_s);
> +    qtest_add_func("virt/clic/prv_m/cliccfg_snlbits_no_u",
> +                   test_configure_cliccfg_unlbits_no_u);
> +    /* clicintip configure case */
> +    qtest_add_func("virt/clic/prv_m/clicintip_level_triggered_readonly",
> +                   test_configure_clicintip_level_triggered_read_only);
> +
> +    /* clicintie configure case */
> +    qtest_add_func("virt/clic/prv_m/clicintie_enable",
> +                   test_configure_clicintie_enable);
> +    qtest_add_func("virt/clic/prv_m/clicintie_disable",
> +                   test_configure_clicintie_disable);
> +
> +    /* clicintattr mode configure cases are all PRV_M WARL - nmbits == 0*/
> +    qtest_add_func("virt/clic/prv_m/cliccfg_nmbits_0_m",
> +                   test_configure_cliccfg_nmbits_0);
> +    qtest_add_func("virt/clic/prv_m/intattr_prv_m",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_m/intattr_prv_s_to_m_warl",
> +                   test_configure_clicintattr_prv_s_to_m_warl);
> +    qtest_add_func("virt/clic/prv_m/intattr_prv_u_to_m_warl",
> +                   test_configure_clicintattr_prv_u_to_m_warl);
> +    qtest_add_func("virt/clic/prv_m/intattr_unsupported_mode_10",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +
> +    /* unsupported nmbits */
> +    qtest_add_func("virt/clic/prv_m/cliccfg_unsupported_nmbits_1_m",
> +                   test_configure_cliccfg_unsupported_nmbits_1);
> +    qtest_add_func("virt/clic/prv_m/cliccfg_unsupported_nmbits_2_m",
> +                   test_configure_cliccfg_unsupported_nmbits_2);
> +    qtest_add_func("virt/clic/prv_m/cliccfg_unsupported_nmbits_3_m",
> +                   test_configure_cliccfg_unsupported_nmbits_3);
> +
> +    /* clicintattr TRIG and SHV */
> +    qtest_add_func("virt/clic/prv_m/intattr_positive_edge_triggered",
> +                   test_configure_clicintattr_positive_edge_triggered);
> +    qtest_add_func("virt/clic/prv_m/clicintattr_negative_edge_triggered",
> +                   test_configure_clicintattr_negative_edge_triggered);
> +    qtest_add_func("virt/clic/prv_m/clicintattr_positive_level_triggered",
> +                   test_configure_clicintattr_positive_level_triggered);
> +    qtest_add_func("virt/clic/prv_m/clicintattr_negative_level_triggered",
> +                   test_configure_clicintattr_negative_level_triggered);
> +    qtest_add_func("virt/clic/prv_m/clicintattr_non_vectored",
> +                   test_configure_clicintattr_non_vectored);
> +
> +    /* Shut down QEMU */
> +    qtest_add_func("virt/clic/prv_m/shut_down_qemu_m",
> +                   shut_down_qemu);
> +}
> +
> +/* Test configuration in PRV_M + PRV_S mode */
> +static void clic_configure_reg_mmio_test_case_ms(void)
> +{
> +    /* Start QEMU */
> +    qtest_add_func("virt/clic/prv_ms/boot_qemu_ms",
> +                   boot_qemu_ms);
> +
> +    /* cliccfg configure cases */
> +
> +    /* mnlbits should be unaffected */
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_min_mnlbits_ms",
> +                   test_configure_cliccfg_min_mnlbits);
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_supported_max_mnlbits_ms",
> +                   test_configure_cliccfg_supported_max_mnlbits);
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_unsupported_mnlbits_ms",
> +                   test_configure_cliccfg_unsupported_mnlbits);
> +    /* snlbits should work*/
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_min_snlbits_s_ms",
> +                   test_configure_cliccfg_min_snlbits_s);
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_supported_max_snlbits_s_ms",
> +                   test_configure_cliccfg_supported_max_snlbits_s);
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_unsupported_snlbits_s_ms",
> +                   test_configure_cliccfg_unsupported_snlbits_s);
> +    /* unlbits should not work */
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_unlbits_no_u_ms",
> +                   test_configure_cliccfg_unlbits_no_u);
> +
> +    /* clicintattr mode configure cases with nmbits = 1 */
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_nmbits_1_ms",
> +                   test_configure_cliccfg_nmbits_1);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_m_nmbits_1",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_ms/intattr_unsupported_mode_10_nmbits_1",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_u_to_s_warl_nmbits_1_prv_m",
> +                   test_configure_clicintattr_prv_u_to_s_warl);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_s_supported_nmbits_1",
> +                   test_configure_clicintattr_prv_s_supported);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_u_to_s_warl_nmbits_1_prv_s",
> +                   test_configure_clicintattr_prv_u_to_s_warl);
> +
> +    /* clicintattr mode configure cases with nmbits = 0 - PRV_M only */
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_nmbits_0_ms",
> +                   test_configure_cliccfg_nmbits_0);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_m_nmbits_0",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_ms/intattr_unsupported_mode_10_nmbits_0",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_u_to_m_warl_nmbits_0",
> +                   test_configure_clicintattr_prv_u_to_m_warl);
> +    qtest_add_func("virt/clic/prv_ms/intattr_prv_s_to_m_warl_nmbits_0",
> +                   test_configure_clicintattr_prv_s_to_m_warl);
> +
> +    /* unsupported nmbits */
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_unsupported_nmbits_2_ms",
> +                   test_configure_cliccfg_unsupported_nmbits_2);
> +    qtest_add_func("virt/clic/prv_ms/cliccfg_unsupported_nmbits_3_ms",
> +                   test_configure_cliccfg_unsupported_nmbits_3);
> +
> +    /* clicintattr TRIG and SHV */
> +    qtest_add_func("virt/clic/prv_ms/intattr_positive_edge_triggered",
> +                   test_configure_clicintattr_positive_edge_triggered);
> +    qtest_add_func("virt/clic/prv_ms/clicintattr_negative_edge_triggered",
> +                   test_configure_clicintattr_negative_edge_triggered);
> +    qtest_add_func("virt/clic/prv_ms/clicintattr_positive_level_triggered",
> +                   test_configure_clicintattr_positive_level_triggered);
> +    qtest_add_func("virt/clic/prv_ms/clicintattr_negative_level_triggered",
> +                   test_configure_clicintattr_negative_level_triggered);
> +    qtest_add_func("virt/clic/prv_ms/clicintattr_non_vectored",
> +                   test_configure_clicintattr_non_vectored);
> +
> +    /* Shut down QEMU */
> +    qtest_add_func("virt/clic/prv_ms/shut_down_qemu_ms",
> +                   shut_down_qemu);
> +}
> +
> +/* Test configuration in PRV_M + PRV_U mode */
> +static void clic_configure_reg_mmio_test_case_mu(void)
> +{
> +    /* Start QEMU */
> +    qtest_add_func("virt/clic/prv_mu/boot_qemu_mu",
> +                   boot_qemu_mu);
> +
> +    /* cliccfg configure cases */
> +
> +    /* mnlbits should be unaffected */
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_min_mnlbits_mu",
> +                   test_configure_cliccfg_min_mnlbits);
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_supported_max_mnlbits_mu",
> +                   test_configure_cliccfg_supported_max_mnlbits);
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_unsupported_mnlbits_mu",
> +                   test_configure_cliccfg_unsupported_mnlbits);
> +    /* snlbits should not work */
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_snlbits_no_s_mu",
> +                   test_configure_cliccfg_snlbits_no_s);
> +    /* unlbits should work*/
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_min_unlbits_u_mu",
> +                   test_configure_cliccfg_min_unlbits_u);
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_uupported_max_unlbits_u_mu",
> +                   test_configure_cliccfg_supported_max_unlbits_u);
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_unsupported_unlbits_u_mu",
> +                   test_configure_cliccfg_unsupported_unlbits_u);
> +
> +    /* clicintattr mode configure cases with nmbits = 1 */
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_nmbits_1_ms",
> +                   test_configure_cliccfg_nmbits_1);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_m_nmbits_1",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_mu/intattr_unsupported_mode_10_nmbits_1",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_s_to_u_warl_nmbits_1_prv_m",
> +                   test_configure_clicintattr_prv_s_to_u_warl);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_u_supported_nmbits_1",
> +                   test_configure_clicintattr_prv_u_supported);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_s_to_u_warl_nmbits_1_prv_u",
> +                   test_configure_clicintattr_prv_s_to_u_warl);
> +
> +    /* clicintattr mode configure cases with nmbits = 0 - PRV_M only */
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_nmbits_0_ms",
> +                   test_configure_cliccfg_nmbits_0);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_m_nmbits_0",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_mu/intattr_unsupported_mode_10_nmbits_0",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_u_to_m_warl_nmbits_0",
> +                   test_configure_clicintattr_prv_u_to_m_warl);
> +    qtest_add_func("virt/clic/prv_mu/intattr_prv_s_to_m_warl_nmbits_0",
> +                   test_configure_clicintattr_prv_s_to_m_warl);
> +
> +    /* unsupported nmbits */
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_unsupported_nmbits_2_ms",
> +                   test_configure_cliccfg_unsupported_nmbits_2);
> +    qtest_add_func("virt/clic/prv_mu/cliccfg_unsupported_nmbits_3_ms",
> +                   test_configure_cliccfg_unsupported_nmbits_3);
> +
> +    /* clicintattr TRIG and SHV */
> +    qtest_add_func("virt/clic/prv_mu/intattr_positive_edge_triggered",
> +                   test_configure_clicintattr_positive_edge_triggered);
> +    qtest_add_func("virt/clic/prv_mu/clicintattr_negative_edge_triggered",
> +                   test_configure_clicintattr_negative_edge_triggered);
> +    qtest_add_func("virt/clic/prv_mu/clicintattr_positive_level_triggered",
> +                   test_configure_clicintattr_positive_level_triggered);
> +    qtest_add_func("virt/clic/prv_mu/clicintattr_negative_level_triggered",
> +                   test_configure_clicintattr_negative_level_triggered);
> +    qtest_add_func("virt/clic/prv_mu/clicintattr_non_vectored",
> +                   test_configure_clicintattr_non_vectored);
> +
> +    /* Shut down QEMU */
> +    qtest_add_func("virt/clic/prv_mu/shut_down_qemu_mu",
> +                   shut_down_qemu);
> +}
> +
> +/* Test configuration in PRV_M + PRV_S + PRV_U mode */
> +static void clic_configure_reg_mmio_test_case_msu(void)
> +{
> +    /* Start QEMU */
> +    qtest_add_func("virt/clic/prv_msu/boot_qemu_msu",
> +                   boot_qemu_msu);
> +
> +    /* cliccfg configure cases */
> +
> +    /* mnlbits should be unaffected */
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_min_mnlbits_msu",
> +                   test_configure_cliccfg_min_mnlbits);
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_supported_max_mnlbits_msu",
> +                   test_configure_cliccfg_supported_max_mnlbits);
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_unsupported_mnlbits_msu",
> +                   test_configure_cliccfg_unsupported_mnlbits);
> +    /* snlbits should work*/
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_min_snlbits_s_msu",
> +                   test_configure_cliccfg_min_snlbits_s);
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_supported_max_snlbits_s_msu",
> +                   test_configure_cliccfg_supported_max_snlbits_s);
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_unsupported_snlbits_s_msu",
> +                   test_configure_cliccfg_unsupported_snlbits_s);
> +    /* unlbits should work*/
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_min_unlbits_u_msu",
> +                   test_configure_cliccfg_min_unlbits_u);
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_uupported_max_unlbits_u_msu",
> +                   test_configure_cliccfg_supported_max_unlbits_u);
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_unsupported_unlbits_u_msu",
> +                   test_configure_cliccfg_unsupported_unlbits_u);
> +    /* all bits should work */
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_xnlbits_msu",
> +                   test_configure_cliccfg_xnlbits);
> +
> +    /* clicintattr mode configure cases with nmbits = 2 => all modes */
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_nmbits_2_ms",
> +                   test_configure_cliccfg_nmbits_2);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_m_nmbits_2",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_msu/intattr_unsupported_mode_10_nmbits_2",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_s_supported_nmbits_2",
> +                   test_configure_clicintattr_prv_s_supported);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_u_supported_nmbits_2",
> +                   test_configure_clicintattr_prv_u_supported);
> +
> +    /* clicintattr mode configure cases with nmbits = 1 => PRV_M and PRV_S */
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_nmbits_1_ms",
> +                   test_configure_cliccfg_nmbits_1);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_m_nmbits_1",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_msu/intattr_unsupported_mode_10_nmbits_1",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    
> qtest_add_func("virt/clic/prv_msu/intattr_prv_u_to_s_warl_nmbits_1_prv_m",
> +                   test_configure_clicintattr_prv_u_to_s_warl);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_s_supported_nmbits_1",
> +                   test_configure_clicintattr_prv_s_supported);
> +    
> qtest_add_func("virt/clic/prv_msu/intattr_prv_u_to_s_warl_nmbits_1_prv_s",
> +                   test_configure_clicintattr_prv_u_to_s_warl);
> +
> +    /* clicintattr mode configure cases with nmbits = 0 - PRV_M only */
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_nmbits_0_ms",
> +                   test_configure_cliccfg_nmbits_0);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_m_nmbits_0",
> +                   test_configure_clicintattr_prv_m);
> +    qtest_add_func("virt/clic/prv_msu/intattr_unsupported_mode_10_nmbits_0",
> +                   test_configure_clicintattr_unsupported_mode_10);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_u_to_m_warl_nmbits_0",
> +                   test_configure_clicintattr_prv_u_to_m_warl);
> +    qtest_add_func("virt/clic/prv_msu/intattr_prv_s_to_m_warl_nmbits_0",
> +                   test_configure_clicintattr_prv_s_to_m_warl);
> +
> +    /* unsupported nmbits */
> +    qtest_add_func("virt/clic/prv_msu/cliccfg_unsupported_nmbits_3_ms",
> +                   test_configure_cliccfg_unsupported_nmbits_3);
> +
> +    /* clicintattr TRIG and SHV */
> +    qtest_add_func("virt/clic/prv_msu/intattr_positive_edge_triggered",
> +                   test_configure_clicintattr_positive_edge_triggered);
> +    qtest_add_func("virt/clic/prv_msu/clicintattr_negative_edge_triggered",
> +                   test_configure_clicintattr_negative_edge_triggered);
> +    qtest_add_func("virt/clic/prv_msu/clicintattr_positive_level_triggered",
> +                   test_configure_clicintattr_positive_level_triggered);
> +    qtest_add_func("virt/clic/prv_msu/clicintattr_negative_level_triggered",
> +                   test_configure_clicintattr_negative_level_triggered);
> +    qtest_add_func("virt/clic/prv_msu/clicintattr_non_vectored",
> +                   test_configure_clicintattr_non_vectored);
> +
> +    /* Shut down QEMU */
> +    qtest_add_func("virt/clic/prv_msu/shut_down_qemu_msu",
> +                   shut_down_qemu);
> +}
> +
> +#define GEN_INTCTL_TEST(_nbits)                                             \
> +GEN_BOOT_QEMU_INTCTL(_nbits)                                                \
> +static void clic_configure_clicintctl_test_case_##_nbits##_bits(void)       \
> +{                                                                           \
> +    g_autofree char *prefix = g_strdup_printf("virt/clic/clicintl_%d_bits", \
> +                                              _nbits);                      \
> +    g_autofree char *path;                                                  \
> +                                                                            \
> +    path = g_strdup_printf("%s/boot_qemu", prefix);                         \
> +    qtest_add_func(path, boot_qemu_##_nbits##_bits);                        \
> +                                                                            \
> +    path = g_strdup_printf("%s/intctl_0_%d_bits", prefix, _nbits);          \
> +    qtest_add_func(path,                                                    \
> +                   test_configure_clicintctl_set_0_##_nbits##_bits);        \
> +    path = g_strdup_printf("%s/intctl_33_%d_bits", prefix, _nbits);         \
> +    qtest_add_func(path,                                                    \
> +                   test_configure_clicintctl_set_33_##_nbits##_bits);       \
> +    path = g_strdup_printf("%s/intctl_88_%d_bits", prefix, _nbits);         \
> +    qtest_add_func(path,                                                    \
> +                   test_configure_clicintctl_set_88_##_nbits##_bits);       \
> +    path = g_strdup_printf("%s/intctl_128_%d_bits", prefix, _nbits);        \
> +    qtest_add_func(path,                                                    \
> +                   test_configure_clicintctl_set_128_##_nbits##_bits);      \
> +    path = g_strdup_printf("%s/intctl_204_%d_bits", prefix, _nbits);        \
> +    qtest_add_func(path,                                                    \
> +                   test_configure_clicintctl_set_204_##_nbits##_bits);      \
> +    path = g_strdup_printf("%s/intctl_240_%d_bits", prefix, _nbits);        \
> +    qtest_add_func(path,                                                    \
> +                   test_configure_clicintctl_set_240_##_nbits##_bits);      \
> +                                                                            \
> +    path = g_strdup_printf("%s/shut_down_qemu", prefix);                    \
> +    qtest_add_func(path, shut_down_qemu);                                   \
> +}
> +
> +GEN_INTCTL_TEST(0)
> +GEN_INTCTL_TEST(1)
> +GEN_INTCTL_TEST(2)
> +GEN_INTCTL_TEST(3)
> +GEN_INTCTL_TEST(4)
> +GEN_INTCTL_TEST(5)
> +GEN_INTCTL_TEST(6)
> +GEN_INTCTL_TEST(7)
> +GEN_INTCTL_TEST(8)
> +
> +static void clic_irq_test_case(void)
> +{
> +    /* interrupt test case */
> +    qtest_add_func("virt/clic/vectored_positive_level_triggered_interrupt",
> +                   test_vectored_positive_level_triggered_interrupt);
> +    qtest_add_func("virt/clic/vectored_negative_level_triggered_interrupt",
> +                   test_vectored_negative_level_triggered_interrupt);
> +    qtest_add_func("virt/clic/vectored_positive_edge_triggered_interrupt",
> +                   test_vectored_positive_edge_triggered_interrupt);
> +    qtest_add_func("virt/clic/vectored_negative_edge_triggered_interrupt",
> +                   test_vectored_negative_edge_triggered_interrupt);
> +    qtest_add_func("virt/clic/unvectored_positive_level_triggered_interrupt",
> +                   test_unvectored_positive_level_triggered_interrupt);
> +    qtest_add_func("virt/clic/unvectored_negative_level_triggered_interrupt",
> +                   test_unvectored_negative_level_triggered_interrupt);
> +    qtest_add_func("virt/clic/unvectored_positive_edge_triggered_interrupt",
> +                   test_unvectored_positive_edge_triggered_interrupt);
> +    qtest_add_func("virt/clic/unvectored_negative_edge_triggered_interrupt",
> +                   test_unvectored_negative_edge_triggered_interrupt);
> +}
> +
> +static void clic_mode_access_test_case(void)
> +{
> +    qtest_add_func("virt/clic/test_prv_s_access", test_prv_s_access);
> +    qtest_add_func("virt/clic/test_prv_u_access", test_prv_u_access);
> +    qtest_add_func("virt/clic/test_prv_su_access", test_prv_su_access);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    g_test_init(&argc, &argv, NULL);
> +    g_test_set_nonfatal_assertions();
> +
> +    /* test cases */
> +    clic_configure_reg_mmio_test_case_m();
> +    clic_configure_reg_mmio_test_case_ms();
> +    clic_configure_reg_mmio_test_case_mu();
> +    clic_configure_reg_mmio_test_case_msu();
> +    clic_configure_clicintctl_test_case_0_bits();
> +    clic_configure_clicintctl_test_case_1_bits();
> +    clic_configure_clicintctl_test_case_2_bits();
> +    clic_configure_clicintctl_test_case_3_bits();
> +    clic_configure_clicintctl_test_case_4_bits();
> +    clic_configure_clicintctl_test_case_5_bits();
> +    clic_configure_clicintctl_test_case_6_bits();
> +    clic_configure_clicintctl_test_case_7_bits();
> +    clic_configure_clicintctl_test_case_8_bits();
> +    clic_irq_test_case();
> +    clic_mode_access_test_case();
> +
> +    /* Run the tests */
> +    int ret = g_test_run();
> +
> +    return ret;
> +}
> --
> 2.46.0.windows.1
> This message and any attachments may contain privileged and confidential 
> information that is intended solely for the person(s) to whom it is 
> addressed. If you are not an intended recipient you must not: read; copy; 
> distribute; discuss; take any action in or make any reliance upon the 
> contents of this message; nor open or read any attachment. If you have 
> received this message in error, please notify us as soon as possible on the 
> following telephone number and destroy this message including any 
> attachments. Thank you. Cirrus Logic International (UK) Ltd and Cirrus Logic 
> International Semiconductor Ltd are companies registered in Scotland, with 
> registered numbers SC089839 and SC495735 respectively. Our registered office 
> is at 7B Nightingale Way, Quartermile, Edinburgh, EH3 9EG, UK. Tel: +44 
> (0)131 272 7000. www.cirrus.com
>

Reply via email to