1 /* 2 * QTest testcase for PowerNV 10 interrupt controller (xive2) 3 * - Test irq to hardware thread 4 * - Test 'Pull Thread Context to Odd Thread Reporting Line' 5 * 6 * Copyright (c) 2024, IBM Corporation. 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 #include "qemu/osdep.h" 11 #include "libqtest.h" 12 13 #include "pnv-xive2-common.h" 14 #include "hw/intc/pnv_xive2_regs.h" 15 #include "hw/ppc/xive_regs.h" 16 #include "hw/ppc/xive2_regs.h" 17 18 #define SMT 4 /* some tests will break if less than 4 */ 19 20 21 static void set_table(QTestState *qts, uint64_t type, uint64_t addr) 22 { 23 uint64_t vsd, size, log_size; 24 25 /* 26 * First, let's make sure that all the resources used fit in the 27 * given table. 28 */ 29 switch (type) { 30 case VST_ESB: 31 size = MAX_IRQS / 4; 32 break; 33 case VST_EAS: 34 size = MAX_IRQS * 8; 35 break; 36 case VST_END: 37 size = MAX_ENDS * 32; 38 break; 39 case VST_NVP: 40 case VST_NVG: 41 case VST_NVC: 42 size = MAX_VPS * 32; 43 break; 44 case VST_SYNC: 45 size = 64 * 1024; 46 break; 47 default: 48 g_assert_not_reached(); 49 } 50 51 g_assert_cmpuint(size, <=, XIVE_VST_SIZE); 52 log_size = ctzl(XIVE_VST_SIZE) - 12; 53 54 vsd = ((uint64_t) VSD_MODE_EXCLUSIVE) << 62 | addr | log_size; 55 pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_ADDR, type << 48); 56 pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_DATA, vsd); 57 58 if (type != VST_EAS && type != VST_IC && type != VST_ERQ) { 59 pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_ADDR, type << 48); 60 pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_DATA, vsd); 61 } 62 } 63 64 static void set_tima8(QTestState *qts, uint32_t pir, uint32_t offset, 65 uint8_t b) 66 { 67 uint64_t ic_addr; 68 69 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 70 qtest_writeb(qts, ic_addr + offset, b); 71 } 72 73 static void set_tima32(QTestState *qts, uint32_t pir, uint32_t offset, 74 uint32_t l) 75 { 76 uint64_t ic_addr; 77 78 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 79 qtest_writel(qts, ic_addr + offset, l); 80 } 81 82 static uint8_t get_tima8(QTestState *qts, uint32_t pir, uint32_t offset) 83 { 84 uint64_t ic_addr; 85 86 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 87 return qtest_readb(qts, ic_addr + offset); 88 } 89 90 static uint16_t get_tima16(QTestState *qts, uint32_t pir, uint32_t offset) 91 { 92 uint64_t ic_addr; 93 94 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 95 return qtest_readw(qts, ic_addr + offset); 96 } 97 98 static uint32_t get_tima32(QTestState *qts, uint32_t pir, uint32_t offset) 99 { 100 uint64_t ic_addr; 101 102 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 103 return qtest_readl(qts, ic_addr + offset); 104 } 105 106 static void reset_pool_threads(QTestState *qts) 107 { 108 uint8_t first_group = 0; 109 int i; 110 111 for (i = 0; i < SMT; i++) { 112 uint32_t nvp_idx = 0x100 + i; 113 set_nvp(qts, nvp_idx, first_group); 114 set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD0, 0x000000ff); 115 set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD1, 0); 116 set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD2, TM_QW2W2_VP | nvp_idx); 117 } 118 } 119 120 static void reset_hw_threads(QTestState *qts) 121 { 122 uint8_t first_group = 0; 123 uint32_t w1 = 0x000000ff; 124 int i; 125 126 if (SMT >= 4) { 127 /* define 2 groups of 2, part of a bigger group of size 4 */ 128 set_nvg(qts, 0x80, 0x02); 129 set_nvg(qts, 0x82, 0x02); 130 set_nvg(qts, 0x81, 0); 131 first_group = 0x01; 132 w1 = 0x000300ff; 133 } 134 135 for (i = 0; i < SMT; i++) { 136 set_nvp(qts, 0x80 + i, first_group); 137 set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0, 0x00ff00ff); 138 set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD1, w1); 139 set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD2, 0x80000000); 140 } 141 } 142 143 static void reset_state(QTestState *qts) 144 { 145 size_t mem_used = XIVE_MEM_END - XIVE_MEM_START; 146 147 qtest_memset(qts, XIVE_MEM_START, 0, mem_used); 148 reset_hw_threads(qts); 149 reset_pool_threads(qts); 150 } 151 152 static void init_xive(QTestState *qts) 153 { 154 uint64_t val1, val2, range; 155 156 /* 157 * We can take a few shortcuts here, as we know the default values 158 * used for xive initialization 159 */ 160 161 /* 162 * Set the BARs. 163 * We reuse the same values used by firmware to ease debug. 164 */ 165 pnv_xive_xscom_write(qts, X_CQ_IC_BAR, XIVE_IC_BAR); 166 pnv_xive_xscom_write(qts, X_CQ_TM_BAR, XIVE_TM_BAR); 167 168 /* ESB and NVPG use 2 pages per resource. The others only one page */ 169 range = (MAX_IRQS << 17) >> 25; 170 val1 = XIVE_ESB_BAR | range; 171 pnv_xive_xscom_write(qts, X_CQ_ESB_BAR, val1); 172 173 range = (MAX_ENDS << 16) >> 25; 174 val1 = XIVE_END_BAR | range; 175 pnv_xive_xscom_write(qts, X_CQ_END_BAR, val1); 176 177 range = (MAX_VPS << 17) >> 25; 178 val1 = XIVE_NVPG_BAR | range; 179 pnv_xive_xscom_write(qts, X_CQ_NVPG_BAR, val1); 180 181 range = (MAX_VPS << 16) >> 25; 182 val1 = XIVE_NVC_BAR | range; 183 pnv_xive_xscom_write(qts, X_CQ_NVC_BAR, val1); 184 185 /* 186 * Enable hw threads. 187 * We check the value written. Useless with current 188 * implementation, but it validates the xscom read path and it's 189 * what the hardware procedure says 190 */ 191 val1 = 0xF000000000000000ull; /* core 0, 4 threads */ 192 pnv_xive_xscom_write(qts, X_TCTXT_EN0, val1); 193 val2 = pnv_xive_xscom_read(qts, X_TCTXT_EN0); 194 g_assert_cmphex(val1, ==, val2); 195 196 /* Memory tables */ 197 set_table(qts, VST_ESB, XIVE_ESB_MEM); 198 set_table(qts, VST_EAS, XIVE_EAS_MEM); 199 set_table(qts, VST_END, XIVE_END_MEM); 200 set_table(qts, VST_NVP, XIVE_NVP_MEM); 201 set_table(qts, VST_NVG, XIVE_NVG_MEM); 202 set_table(qts, VST_NVC, XIVE_NVC_MEM); 203 set_table(qts, VST_SYNC, XIVE_SYNC_MEM); 204 205 reset_hw_threads(qts); 206 reset_pool_threads(qts); 207 } 208 209 static void test_hw_irq(QTestState *qts) 210 { 211 uint32_t irq = 2; 212 uint32_t irq_data = 0x600df00d; 213 uint32_t end_index = 5; 214 uint32_t target_pir = 1; 215 uint32_t target_nvp = 0x80 + target_pir; 216 uint8_t priority = 5; 217 uint32_t reg32; 218 uint16_t reg16; 219 uint8_t pq, nsr, cppr; 220 221 printf("# ============================================================\n"); 222 printf("# Testing irq %d to hardware thread %d\n", irq, target_pir); 223 224 /* irq config */ 225 set_eas(qts, irq, end_index, irq_data); 226 set_end(qts, end_index, target_nvp, priority, false /* group */); 227 228 /* enable and trigger irq */ 229 get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00); 230 set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0); 231 232 /* check irq is raised on cpu */ 233 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 234 g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING); 235 236 reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0); 237 nsr = reg32 >> 24; 238 cppr = (reg32 >> 16) & 0xFF; 239 g_assert_cmphex(nsr, ==, 0x80); 240 g_assert_cmphex(cppr, ==, 0xFF); 241 242 /* ack the irq */ 243 reg16 = get_tima16(qts, target_pir, TM_SPC_ACK_HV_REG); 244 nsr = reg16 >> 8; 245 cppr = reg16 & 0xFF; 246 g_assert_cmphex(nsr, ==, 0x80); 247 g_assert_cmphex(cppr, ==, priority); 248 249 /* check irq data is what was configured */ 250 reg32 = qtest_readl(qts, xive_get_queue_addr(end_index)); 251 g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff)); 252 253 /* End Of Interrupt */ 254 set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0); 255 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 256 g_assert_cmpuint(pq, ==, XIVE_ESB_RESET); 257 258 /* reset CPPR */ 259 set_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_CPPR, 0xFF); 260 reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0); 261 nsr = reg32 >> 24; 262 cppr = (reg32 >> 16) & 0xFF; 263 g_assert_cmphex(nsr, ==, 0x00); 264 g_assert_cmphex(cppr, ==, 0xFF); 265 } 266 267 #define XIVE_ODD_CL 0x80 268 static void test_pull_thread_ctx_to_odd_thread_cl(QTestState *qts) 269 { 270 uint32_t target_pir = 1; 271 uint32_t target_nvp = 0x80 + target_pir; 272 Xive2Nvp nvp; 273 uint8_t cl_pair[XIVE_REPORT_SIZE]; 274 uint32_t qw1w0, qw3w0, qw1w2, qw2w2; 275 uint8_t qw3b8; 276 uint32_t cl_word; 277 uint32_t word2; 278 279 printf("# ============================================================\n"); 280 printf("# Testing 'Pull Thread Context to Odd Thread Reporting Line'\n"); 281 282 /* clear odd cache line prior to pull operation */ 283 memset(cl_pair, 0, sizeof(cl_pair)); 284 get_nvp(qts, target_nvp, &nvp); 285 set_cl_pair(qts, &nvp, cl_pair); 286 287 /* Read some values from TIMA that we expect to see in cacheline */ 288 qw1w0 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD0); 289 qw3w0 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0); 290 qw1w2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2); 291 qw2w2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2); 292 qw3b8 = get_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2); 293 294 /* Execute the pull operation */ 295 set_tima8(qts, target_pir, TM_SPC_PULL_PHYS_CTX_OL, 0); 296 297 /* Verify odd cache line values match TIMA after pull operation */ 298 get_cl_pair(qts, &nvp, cl_pair); 299 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD0], 4); 300 g_assert_cmphex(qw1w0, ==, be32_to_cpu(cl_word)); 301 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD0], 4); 302 g_assert_cmphex(qw3w0, ==, be32_to_cpu(cl_word)); 303 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD2], 4); 304 g_assert_cmphex(qw1w2, ==, be32_to_cpu(cl_word)); 305 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW2_HV_POOL + TM_WORD2], 4); 306 g_assert_cmphex(qw2w2, ==, be32_to_cpu(cl_word)); 307 g_assert_cmphex(qw3b8, ==, 308 cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD2]); 309 310 /* Verify that all TIMA valid bits for target thread are cleared */ 311 word2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2); 312 g_assert_cmphex(xive_get_field32(TM_QW1W2_VO, word2), ==, 0); 313 word2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2); 314 g_assert_cmphex(xive_get_field32(TM_QW2W2_VP, word2), ==, 0); 315 word2 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2); 316 g_assert_cmphex(xive_get_field32(TM_QW3W2_VT, word2), ==, 0); 317 } 318 static void test_xive(void) 319 { 320 QTestState *qts; 321 322 qts = qtest_initf("-M powernv10 -smp %d,cores=1,threads=%d -nographic " 323 "-nodefaults -serial mon:stdio -S " 324 "-d guest_errors -trace '*xive*'", 325 SMT, SMT); 326 init_xive(qts); 327 328 test_hw_irq(qts); 329 330 /* omit reset_state here and use settings from test_hw_irq */ 331 test_pull_thread_ctx_to_odd_thread_cl(qts); 332 333 reset_state(qts); 334 test_flush_sync_inject(qts); 335 336 qtest_quit(qts); 337 } 338 339 int main(int argc, char **argv) 340 { 341 g_test_init(&argc, &argv, NULL); 342 qtest_add_func("xive2", test_xive); 343 return g_test_run(); 344 } 345