| /* |
| * QTest testcase for PowerNV 10 interrupt controller (xive2) |
| * - Test cache flush/queue sync injection |
| * |
| * Copyright (c) 2024, IBM Corporation. |
| * |
| * SPDX-License-Identifier: GPL-2.0-or-later |
| */ |
| #include "qemu/osdep.h" |
| #include "libqtest.h" |
| |
| #include "pnv-xive2-common.h" |
| #include "hw/intc/pnv_xive2_regs.h" |
| #include "hw/ppc/xive_regs.h" |
| #include "hw/ppc/xive2_regs.h" |
| |
| #define PNV_XIVE2_QUEUE_IPI 0x00 |
| #define PNV_XIVE2_QUEUE_HW 0x01 |
| #define PNV_XIVE2_QUEUE_NXC 0x02 |
| #define PNV_XIVE2_QUEUE_INT 0x03 |
| #define PNV_XIVE2_QUEUE_OS 0x04 |
| #define PNV_XIVE2_QUEUE_POOL 0x05 |
| #define PNV_XIVE2_QUEUE_HARD 0x06 |
| #define PNV_XIVE2_CACHE_ENDC 0x08 |
| #define PNV_XIVE2_CACHE_ESBC 0x09 |
| #define PNV_XIVE2_CACHE_EASC 0x0a |
| #define PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO 0x10 |
| #define PNV_XIVE2_QUEUE_NXC_LD_LCL_CO 0x11 |
| #define PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI 0x12 |
| #define PNV_XIVE2_QUEUE_NXC_ST_LCL_CI 0x13 |
| #define PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI 0x14 |
| #define PNV_XIVE2_QUEUE_NXC_ST_RMT_CI 0x15 |
| #define PNV_XIVE2_CACHE_NXC 0x18 |
| |
| #define PNV_XIVE2_SYNC_IPI 0x000 |
| #define PNV_XIVE2_SYNC_HW 0x080 |
| #define PNV_XIVE2_SYNC_NxC 0x100 |
| #define PNV_XIVE2_SYNC_INT 0x180 |
| #define PNV_XIVE2_SYNC_OS_ESC 0x200 |
| #define PNV_XIVE2_SYNC_POOL_ESC 0x280 |
| #define PNV_XIVE2_SYNC_HARD_ESC 0x300 |
| #define PNV_XIVE2_SYNC_NXC_LD_LCL_NCO 0x800 |
| #define PNV_XIVE2_SYNC_NXC_LD_LCL_CO 0x880 |
| #define PNV_XIVE2_SYNC_NXC_ST_LCL_NCI 0x900 |
| #define PNV_XIVE2_SYNC_NXC_ST_LCL_CI 0x980 |
| #define PNV_XIVE2_SYNC_NXC_ST_RMT_NCI 0xA00 |
| #define PNV_XIVE2_SYNC_NXC_ST_RMT_CI 0xA80 |
| |
| |
| static uint64_t get_sync_addr(uint32_t src_pir, int ic_topo_id, int type) |
| { |
| int thread_nr = src_pir & 0x7f; |
| uint64_t addr = XIVE_SYNC_MEM + thread_nr * 512 + ic_topo_id * 32 + type; |
| return addr; |
| } |
| |
| static uint8_t get_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id, |
| int type) |
| { |
| uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type); |
| return qtest_readb(qts, addr); |
| } |
| |
| static void clr_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id, |
| int type) |
| { |
| uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type); |
| qtest_writeb(qts, addr, 0x0); |
| } |
| |
| static void inject_cache_flush(QTestState *qts, int ic_topo_id, |
| uint64_t scom_addr) |
| { |
| (void)ic_topo_id; |
| pnv_xive_xscom_write(qts, scom_addr, 0); |
| } |
| |
| static void inject_queue_sync(QTestState *qts, int ic_topo_id, uint64_t offset) |
| { |
| (void)ic_topo_id; |
| uint64_t addr = XIVE_IC_ADDR + (VST_SYNC << XIVE_PAGE_SHIFT) + offset; |
| qtest_writeq(qts, addr, 0); |
| } |
| |
| static void inject_op(QTestState *qts, int ic_topo_id, int type) |
| { |
| switch (type) { |
| case PNV_XIVE2_QUEUE_IPI: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_IPI); |
| break; |
| case PNV_XIVE2_QUEUE_HW: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HW); |
| break; |
| case PNV_XIVE2_QUEUE_NXC: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NxC); |
| break; |
| case PNV_XIVE2_QUEUE_INT: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_INT); |
| break; |
| case PNV_XIVE2_QUEUE_OS: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_OS_ESC); |
| break; |
| case PNV_XIVE2_QUEUE_POOL: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_POOL_ESC); |
| break; |
| case PNV_XIVE2_QUEUE_HARD: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HARD_ESC); |
| break; |
| case PNV_XIVE2_CACHE_ENDC: |
| inject_cache_flush(qts, ic_topo_id, X_VC_ENDC_FLUSH_INJECT); |
| break; |
| case PNV_XIVE2_CACHE_ESBC: |
| inject_cache_flush(qts, ic_topo_id, X_VC_ESBC_FLUSH_INJECT); |
| break; |
| case PNV_XIVE2_CACHE_EASC: |
| inject_cache_flush(qts, ic_topo_id, X_VC_EASC_FLUSH_INJECT); |
| break; |
| case PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_NCO); |
| break; |
| case PNV_XIVE2_QUEUE_NXC_LD_LCL_CO: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_CO); |
| break; |
| case PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_NCI); |
| break; |
| case PNV_XIVE2_QUEUE_NXC_ST_LCL_CI: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_CI); |
| break; |
| case PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_NCI); |
| break; |
| case PNV_XIVE2_QUEUE_NXC_ST_RMT_CI: |
| inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_CI); |
| break; |
| case PNV_XIVE2_CACHE_NXC: |
| inject_cache_flush(qts, ic_topo_id, X_PC_NXC_FLUSH_INJECT); |
| break; |
| default: |
| g_assert_not_reached(); |
| break; |
| } |
| } |
| |
| const uint8_t xive_inject_tests[] = { |
| PNV_XIVE2_QUEUE_IPI, |
| PNV_XIVE2_QUEUE_HW, |
| PNV_XIVE2_QUEUE_NXC, |
| PNV_XIVE2_QUEUE_INT, |
| PNV_XIVE2_QUEUE_OS, |
| PNV_XIVE2_QUEUE_POOL, |
| PNV_XIVE2_QUEUE_HARD, |
| PNV_XIVE2_CACHE_ENDC, |
| PNV_XIVE2_CACHE_ESBC, |
| PNV_XIVE2_CACHE_EASC, |
| PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO, |
| PNV_XIVE2_QUEUE_NXC_LD_LCL_CO, |
| PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI, |
| PNV_XIVE2_QUEUE_NXC_ST_LCL_CI, |
| PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI, |
| PNV_XIVE2_QUEUE_NXC_ST_RMT_CI, |
| PNV_XIVE2_CACHE_NXC, |
| }; |
| |
| void test_flush_sync_inject(QTestState *qts) |
| { |
| int ic_topo_id = 0; |
| |
| /* |
| * Writes performed by qtest are not done in the context of a thread. |
| * This means that QEMU XIVE code doesn't have a way to determine what |
| * thread is originating the write. In order to allow for some testing, |
| * QEMU XIVE code will assume a PIR of 0 when unable to determine the |
| * source thread for cache flush and queue sync inject operations. |
| * See hw/intc/pnv_xive2.c: pnv_xive2_inject_notify() for details. |
| */ |
| int src_pir = 0; |
| int test_nr; |
| uint8_t byte; |
| |
| printf("# ============================================================\n"); |
| printf("# Starting cache flush/queue sync injection tests...\n"); |
| |
| for (test_nr = 0; test_nr < sizeof(xive_inject_tests); |
| test_nr++) { |
| int op_type = xive_inject_tests[test_nr]; |
| |
| printf("# Running test %d\n", test_nr); |
| |
| /* start with status byte set to 0 */ |
| clr_sync(qts, src_pir, ic_topo_id, op_type); |
| byte = get_sync(qts, src_pir, ic_topo_id, op_type); |
| g_assert_cmphex(byte, ==, 0); |
| |
| /* request cache flush or queue sync operation */ |
| inject_op(qts, ic_topo_id, op_type); |
| |
| /* verify that status byte was written to 0xff */ |
| byte = get_sync(qts, src_pir, ic_topo_id, op_type); |
| g_assert_cmphex(byte, ==, 0xff); |
| |
| clr_sync(qts, src_pir, ic_topo_id, op_type); |
| } |
| } |
| |