| 1 | /* |
| 2 | * QTest testcase for PowerNV 10 interrupt controller (xive2) |
| 3 | * - Test cache flush/queue sync injection |
| 4 | * |
| 5 | * Copyright (c) 2024, IBM Corporation. |
| 6 | * |
| 7 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 8 | */ |
| 9 | #include "qemu/osdep.h" |
| 10 | #include "libqtest.h" |
| 11 | |
| 12 | #include "pnv-xive2-common.h" |
| 13 | #include "hw/intc/pnv_xive2_regs.h" |
| 14 | #include "hw/ppc/xive_regs.h" |
| 15 | #include "hw/ppc/xive2_regs.h" |
| 16 | |
| 17 | #define PNV_XIVE2_QUEUE_IPI 0x00 |
| 18 | #define PNV_XIVE2_QUEUE_HW 0x01 |
| 19 | #define PNV_XIVE2_QUEUE_NXC 0x02 |
| 20 | #define PNV_XIVE2_QUEUE_INT 0x03 |
| 21 | #define PNV_XIVE2_QUEUE_OS 0x04 |
| 22 | #define PNV_XIVE2_QUEUE_POOL 0x05 |
| 23 | #define PNV_XIVE2_QUEUE_HARD 0x06 |
| 24 | #define PNV_XIVE2_CACHE_ENDC 0x08 |
| 25 | #define PNV_XIVE2_CACHE_ESBC 0x09 |
| 26 | #define PNV_XIVE2_CACHE_EASC 0x0a |
| 27 | #define PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO 0x10 |
| 28 | #define PNV_XIVE2_QUEUE_NXC_LD_LCL_CO 0x11 |
| 29 | #define PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI 0x12 |
| 30 | #define PNV_XIVE2_QUEUE_NXC_ST_LCL_CI 0x13 |
| 31 | #define PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI 0x14 |
| 32 | #define PNV_XIVE2_QUEUE_NXC_ST_RMT_CI 0x15 |
| 33 | #define PNV_XIVE2_CACHE_NXC 0x18 |
| 34 | |
| 35 | #define PNV_XIVE2_SYNC_IPI 0x000 |
| 36 | #define PNV_XIVE2_SYNC_HW 0x080 |
| 37 | #define PNV_XIVE2_SYNC_NxC 0x100 |
| 38 | #define PNV_XIVE2_SYNC_INT 0x180 |
| 39 | #define PNV_XIVE2_SYNC_OS_ESC 0x200 |
| 40 | #define PNV_XIVE2_SYNC_POOL_ESC 0x280 |
| 41 | #define PNV_XIVE2_SYNC_HARD_ESC 0x300 |
| 42 | #define PNV_XIVE2_SYNC_NXC_LD_LCL_NCO 0x800 |
| 43 | #define PNV_XIVE2_SYNC_NXC_LD_LCL_CO 0x880 |
| 44 | #define PNV_XIVE2_SYNC_NXC_ST_LCL_NCI 0x900 |
| 45 | #define PNV_XIVE2_SYNC_NXC_ST_LCL_CI 0x980 |
| 46 | #define PNV_XIVE2_SYNC_NXC_ST_RMT_NCI 0xA00 |
| 47 | #define PNV_XIVE2_SYNC_NXC_ST_RMT_CI 0xA80 |
| 48 | |
| 49 | |
| 50 | static uint64_t get_sync_addr(uint32_t src_pir, int ic_topo_id, int type) |
| 51 | { |
| 52 | int thread_nr = src_pir & 0x7f; |
| 53 | uint64_t addr = XIVE_SYNC_MEM + thread_nr * 512 + ic_topo_id * 32 + type; |
| 54 | return addr; |
| 55 | } |
| 56 | |
| 57 | static uint8_t get_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id, |
| 58 | int type) |
| 59 | { |
| 60 | uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type); |
| 61 | return qtest_readb(qts, addr); |
| 62 | } |
| 63 | |
| 64 | static void clr_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id, |
| 65 | int type) |
| 66 | { |
| 67 | uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type); |
| 68 | qtest_writeb(qts, addr, 0x0); |
| 69 | } |
| 70 | |
| 71 | static void inject_cache_flush(QTestState *qts, int ic_topo_id, |
| 72 | uint64_t scom_addr) |
| 73 | { |
| 74 | (void)ic_topo_id; |
| 75 | pnv_xive_xscom_write(qts, scom_addr, 0); |
| 76 | } |
| 77 | |
| 78 | static void inject_queue_sync(QTestState *qts, int ic_topo_id, uint64_t offset) |
| 79 | { |
| 80 | (void)ic_topo_id; |
| 81 | uint64_t addr = XIVE_IC_ADDR + (VST_SYNC << XIVE_PAGE_SHIFT) + offset; |
| 82 | qtest_writeq(qts, addr, 0); |
| 83 | } |
| 84 | |
| 85 | static void inject_op(QTestState *qts, int ic_topo_id, int type) |
| 86 | { |
| 87 | switch (type) { |
| 88 | case PNV_XIVE2_QUEUE_IPI: |
| 89 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_IPI); |
| 90 | break; |
| 91 | case PNV_XIVE2_QUEUE_HW: |
| 92 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HW); |
| 93 | break; |
| 94 | case PNV_XIVE2_QUEUE_NXC: |
| 95 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NxC); |
| 96 | break; |
| 97 | case PNV_XIVE2_QUEUE_INT: |
| 98 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_INT); |
| 99 | break; |
| 100 | case PNV_XIVE2_QUEUE_OS: |
| 101 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_OS_ESC); |
| 102 | break; |
| 103 | case PNV_XIVE2_QUEUE_POOL: |
| 104 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_POOL_ESC); |
| 105 | break; |
| 106 | case PNV_XIVE2_QUEUE_HARD: |
| 107 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HARD_ESC); |
| 108 | break; |
| 109 | case PNV_XIVE2_CACHE_ENDC: |
| 110 | inject_cache_flush(qts, ic_topo_id, X_VC_ENDC_FLUSH_INJECT); |
| 111 | break; |
| 112 | case PNV_XIVE2_CACHE_ESBC: |
| 113 | inject_cache_flush(qts, ic_topo_id, X_VC_ESBC_FLUSH_INJECT); |
| 114 | break; |
| 115 | case PNV_XIVE2_CACHE_EASC: |
| 116 | inject_cache_flush(qts, ic_topo_id, X_VC_EASC_FLUSH_INJECT); |
| 117 | break; |
| 118 | case PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO: |
| 119 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_NCO); |
| 120 | break; |
| 121 | case PNV_XIVE2_QUEUE_NXC_LD_LCL_CO: |
| 122 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_CO); |
| 123 | break; |
| 124 | case PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI: |
| 125 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_NCI); |
| 126 | break; |
| 127 | case PNV_XIVE2_QUEUE_NXC_ST_LCL_CI: |
| 128 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_CI); |
| 129 | break; |
| 130 | case PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI: |
| 131 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_NCI); |
| 132 | break; |
| 133 | case PNV_XIVE2_QUEUE_NXC_ST_RMT_CI: |
| 134 | inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_CI); |
| 135 | break; |
| 136 | case PNV_XIVE2_CACHE_NXC: |
| 137 | inject_cache_flush(qts, ic_topo_id, X_PC_NXC_FLUSH_INJECT); |
| 138 | break; |
| 139 | default: |
| 140 | g_assert_not_reached(); |
| 141 | break; |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | const uint8_t xive_inject_tests[] = { |
| 146 | PNV_XIVE2_QUEUE_IPI, |
| 147 | PNV_XIVE2_QUEUE_HW, |
| 148 | PNV_XIVE2_QUEUE_NXC, |
| 149 | PNV_XIVE2_QUEUE_INT, |
| 150 | PNV_XIVE2_QUEUE_OS, |
| 151 | PNV_XIVE2_QUEUE_POOL, |
| 152 | PNV_XIVE2_QUEUE_HARD, |
| 153 | PNV_XIVE2_CACHE_ENDC, |
| 154 | PNV_XIVE2_CACHE_ESBC, |
| 155 | PNV_XIVE2_CACHE_EASC, |
| 156 | PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO, |
| 157 | PNV_XIVE2_QUEUE_NXC_LD_LCL_CO, |
| 158 | PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI, |
| 159 | PNV_XIVE2_QUEUE_NXC_ST_LCL_CI, |
| 160 | PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI, |
| 161 | PNV_XIVE2_QUEUE_NXC_ST_RMT_CI, |
| 162 | PNV_XIVE2_CACHE_NXC, |
| 163 | }; |
| 164 | |
| 165 | void test_flush_sync_inject(QTestState *qts) |
| 166 | { |
| 167 | int ic_topo_id = 0; |
| 168 | |
| 169 | /* |
| 170 | * Writes performed by qtest are not done in the context of a thread. |
| 171 | * This means that QEMU XIVE code doesn't have a way to determine what |
| 172 | * thread is originating the write. In order to allow for some testing, |
| 173 | * QEMU XIVE code will assume a PIR of 0 when unable to determine the |
| 174 | * source thread for cache flush and queue sync inject operations. |
| 175 | * See hw/intc/pnv_xive2.c: pnv_xive2_inject_notify() for details. |
| 176 | */ |
| 177 | int src_pir = 0; |
| 178 | int test_nr; |
| 179 | uint8_t byte; |
| 180 | |
| 181 | g_test_message("========================================================="); |
| 182 | g_test_message("Starting cache flush/queue sync injection tests..."); |
| 183 | |
| 184 | for (test_nr = 0; test_nr < sizeof(xive_inject_tests); |
| 185 | test_nr++) { |
| 186 | int op_type = xive_inject_tests[test_nr]; |
| 187 | |
| 188 | g_test_message("Running test %d", test_nr); |
| 189 | |
| 190 | /* start with status byte set to 0 */ |
| 191 | clr_sync(qts, src_pir, ic_topo_id, op_type); |
| 192 | byte = get_sync(qts, src_pir, ic_topo_id, op_type); |
| 193 | g_assert_cmphex(byte, ==, 0); |
| 194 | |
| 195 | /* request cache flush or queue sync operation */ |
| 196 | inject_op(qts, ic_topo_id, op_type); |
| 197 | |
| 198 | /* verify that status byte was written to 0xff */ |
| 199 | byte = get_sync(qts, src_pir, ic_topo_id, op_type); |
| 200 | g_assert_cmphex(byte, ==, 0xff); |
| 201 | |
| 202 | clr_sync(qts, src_pir, ic_topo_id, op_type); |
| 203 | } |
| 204 | } |
| 205 |