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 * - Test irq to hardware group 6 * - Test irq to hardware group going through backlog 7 * 8 * Copyright (c) 2024, IBM Corporation. 9 * 10 * SPDX-License-Identifier: GPL-2.0-or-later 11 */ 12 #include "qemu/osdep.h" 13 #include "libqtest.h" 14 15 #include "pnv-xive2-common.h" 16 #include "hw/intc/pnv_xive2_regs.h" 17 #include "hw/ppc/xive_regs.h" 18 #include "hw/ppc/xive2_regs.h" 19 20 #define SMT 4 /* some tests will break if less than 4 */ 21 22 23 static void set_table(QTestState *qts, uint64_t type, uint64_t addr) 24 { 25 uint64_t vsd, size, log_size; 26 27 /* 28 * First, let's make sure that all the resources used fit in the 29 * given table. 30 */ 31 switch (type) { 32 case VST_ESB: 33 size = MAX_IRQS / 4; 34 break; 35 case VST_EAS: 36 size = MAX_IRQS * 8; 37 break; 38 case VST_END: 39 size = MAX_ENDS * 32; 40 break; 41 case VST_NVP: 42 case VST_NVG: 43 case VST_NVC: 44 size = MAX_VPS * 32; 45 break; 46 case VST_SYNC: 47 size = 64 * 1024; 48 break; 49 default: 50 g_assert_not_reached(); 51 } 52 53 g_assert_cmpuint(size, <=, XIVE_VST_SIZE); 54 log_size = ctzl(XIVE_VST_SIZE) - 12; 55 56 vsd = ((uint64_t) VSD_MODE_EXCLUSIVE) << 62 | addr | log_size; 57 pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_ADDR, type << 48); 58 pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_DATA, vsd); 59 60 if (type != VST_EAS && type != VST_IC && type != VST_ERQ) { 61 pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_ADDR, type << 48); 62 pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_DATA, vsd); 63 } 64 } 65 66 static void set_tima8(QTestState *qts, uint32_t pir, uint32_t offset, 67 uint8_t b) 68 { 69 uint64_t ic_addr; 70 71 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 72 qtest_writeb(qts, ic_addr + offset, b); 73 } 74 75 static void set_tima32(QTestState *qts, uint32_t pir, uint32_t offset, 76 uint32_t l) 77 { 78 uint64_t ic_addr; 79 80 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 81 qtest_writel(qts, ic_addr + offset, l); 82 } 83 84 static uint8_t get_tima8(QTestState *qts, uint32_t pir, uint32_t offset) 85 { 86 uint64_t ic_addr; 87 88 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 89 return qtest_readb(qts, ic_addr + offset); 90 } 91 92 static uint16_t get_tima16(QTestState *qts, uint32_t pir, uint32_t offset) 93 { 94 uint64_t ic_addr; 95 96 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 97 return qtest_readw(qts, ic_addr + offset); 98 } 99 100 static uint32_t get_tima32(QTestState *qts, uint32_t pir, uint32_t offset) 101 { 102 uint64_t ic_addr; 103 104 ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT); 105 return qtest_readl(qts, ic_addr + offset); 106 } 107 108 static void reset_pool_threads(QTestState *qts) 109 { 110 uint8_t first_group = 0; 111 int i; 112 113 for (i = 0; i < SMT; i++) { 114 uint32_t nvp_idx = 0x100 + i; 115 set_nvp(qts, nvp_idx, first_group); 116 set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD0, 0x000000ff); 117 set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD1, 0); 118 set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD2, TM_QW2W2_VP | nvp_idx); 119 } 120 } 121 122 static void reset_hw_threads(QTestState *qts) 123 { 124 uint8_t first_group = 0; 125 uint32_t w1 = 0x000000ff; 126 int i; 127 128 if (SMT >= 4) { 129 /* define 2 groups of 2, part of a bigger group of size 4 */ 130 set_nvg(qts, 0x80, 0x02); 131 set_nvg(qts, 0x82, 0x02); 132 set_nvg(qts, 0x81, 0); 133 first_group = 0x01; 134 w1 = 0x000300ff; 135 } 136 137 for (i = 0; i < SMT; i++) { 138 set_nvp(qts, 0x80 + i, first_group); 139 set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0, 0x00ff00ff); 140 set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD1, w1); 141 set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD2, 0x80000000); 142 } 143 } 144 145 static void reset_state(QTestState *qts) 146 { 147 size_t mem_used = XIVE_MEM_END - XIVE_MEM_START; 148 149 qtest_memset(qts, XIVE_MEM_START, 0, mem_used); 150 reset_hw_threads(qts); 151 reset_pool_threads(qts); 152 } 153 154 static void init_xive(QTestState *qts) 155 { 156 uint64_t val1, val2, range; 157 158 /* 159 * We can take a few shortcuts here, as we know the default values 160 * used for xive initialization 161 */ 162 163 /* 164 * Set the BARs. 165 * We reuse the same values used by firmware to ease debug. 166 */ 167 pnv_xive_xscom_write(qts, X_CQ_IC_BAR, XIVE_IC_BAR); 168 pnv_xive_xscom_write(qts, X_CQ_TM_BAR, XIVE_TM_BAR); 169 170 /* ESB and NVPG use 2 pages per resource. The others only one page */ 171 range = (MAX_IRQS << 17) >> 25; 172 val1 = XIVE_ESB_BAR | range; 173 pnv_xive_xscom_write(qts, X_CQ_ESB_BAR, val1); 174 175 range = (MAX_ENDS << 16) >> 25; 176 val1 = XIVE_END_BAR | range; 177 pnv_xive_xscom_write(qts, X_CQ_END_BAR, val1); 178 179 range = (MAX_VPS << 17) >> 25; 180 val1 = XIVE_NVPG_BAR | range; 181 pnv_xive_xscom_write(qts, X_CQ_NVPG_BAR, val1); 182 183 range = (MAX_VPS << 16) >> 25; 184 val1 = XIVE_NVC_BAR | range; 185 pnv_xive_xscom_write(qts, X_CQ_NVC_BAR, val1); 186 187 /* 188 * Enable hw threads. 189 * We check the value written. Useless with current 190 * implementation, but it validates the xscom read path and it's 191 * what the hardware procedure says 192 */ 193 val1 = 0xF000000000000000ull; /* core 0, 4 threads */ 194 pnv_xive_xscom_write(qts, X_TCTXT_EN0, val1); 195 val2 = pnv_xive_xscom_read(qts, X_TCTXT_EN0); 196 g_assert_cmphex(val1, ==, val2); 197 198 /* Memory tables */ 199 set_table(qts, VST_ESB, XIVE_ESB_MEM); 200 set_table(qts, VST_EAS, XIVE_EAS_MEM); 201 set_table(qts, VST_END, XIVE_END_MEM); 202 set_table(qts, VST_NVP, XIVE_NVP_MEM); 203 set_table(qts, VST_NVG, XIVE_NVG_MEM); 204 set_table(qts, VST_NVC, XIVE_NVC_MEM); 205 set_table(qts, VST_SYNC, XIVE_SYNC_MEM); 206 207 reset_hw_threads(qts); 208 reset_pool_threads(qts); 209 } 210 211 static void test_hw_irq(QTestState *qts) 212 { 213 uint32_t irq = 2; 214 uint32_t irq_data = 0x600df00d; 215 uint32_t end_index = 5; 216 uint32_t target_pir = 1; 217 uint32_t target_nvp = 0x80 + target_pir; 218 uint8_t priority = 5; 219 uint32_t reg32; 220 uint16_t reg16; 221 uint8_t pq, nsr, cppr; 222 223 printf("# ============================================================\n"); 224 printf("# Testing irq %d to hardware thread %d\n", irq, target_pir); 225 226 /* irq config */ 227 set_eas(qts, irq, end_index, irq_data); 228 set_end(qts, end_index, target_nvp, priority, false /* group */); 229 230 /* enable and trigger irq */ 231 get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00); 232 set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0); 233 234 /* check irq is raised on cpu */ 235 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 236 g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING); 237 238 reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0); 239 nsr = reg32 >> 24; 240 cppr = (reg32 >> 16) & 0xFF; 241 g_assert_cmphex(nsr, ==, 0x80); 242 g_assert_cmphex(cppr, ==, 0xFF); 243 244 /* ack the irq */ 245 reg16 = get_tima16(qts, target_pir, TM_SPC_ACK_HV_REG); 246 nsr = reg16 >> 8; 247 cppr = reg16 & 0xFF; 248 g_assert_cmphex(nsr, ==, 0x80); 249 g_assert_cmphex(cppr, ==, priority); 250 251 /* check irq data is what was configured */ 252 reg32 = qtest_readl(qts, xive_get_queue_addr(end_index)); 253 g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff)); 254 255 /* End Of Interrupt */ 256 set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0); 257 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 258 g_assert_cmpuint(pq, ==, XIVE_ESB_RESET); 259 260 /* reset CPPR */ 261 set_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_CPPR, 0xFF); 262 reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0); 263 nsr = reg32 >> 24; 264 cppr = (reg32 >> 16) & 0xFF; 265 g_assert_cmphex(nsr, ==, 0x00); 266 g_assert_cmphex(cppr, ==, 0xFF); 267 } 268 269 #define XIVE_ODD_CL 0x80 270 static void test_pull_thread_ctx_to_odd_thread_cl(QTestState *qts) 271 { 272 uint32_t target_pir = 1; 273 uint32_t target_nvp = 0x80 + target_pir; 274 Xive2Nvp nvp; 275 uint8_t cl_pair[XIVE_REPORT_SIZE]; 276 uint32_t qw1w0, qw3w0, qw1w2, qw2w2; 277 uint8_t qw3b8; 278 uint32_t cl_word; 279 uint32_t word2; 280 281 printf("# ============================================================\n"); 282 printf("# Testing 'Pull Thread Context to Odd Thread Reporting Line'\n"); 283 284 /* clear odd cache line prior to pull operation */ 285 memset(cl_pair, 0, sizeof(cl_pair)); 286 get_nvp(qts, target_nvp, &nvp); 287 set_cl_pair(qts, &nvp, cl_pair); 288 289 /* Read some values from TIMA that we expect to see in cacheline */ 290 qw1w0 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD0); 291 qw3w0 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0); 292 qw1w2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2); 293 qw2w2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2); 294 qw3b8 = get_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2); 295 296 /* Execute the pull operation */ 297 set_tima8(qts, target_pir, TM_SPC_PULL_PHYS_CTX_OL, 0); 298 299 /* Verify odd cache line values match TIMA after pull operation */ 300 get_cl_pair(qts, &nvp, cl_pair); 301 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD0], 4); 302 g_assert_cmphex(qw1w0, ==, be32_to_cpu(cl_word)); 303 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD0], 4); 304 g_assert_cmphex(qw3w0, ==, be32_to_cpu(cl_word)); 305 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD2], 4); 306 g_assert_cmphex(qw1w2, ==, be32_to_cpu(cl_word)); 307 memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW2_HV_POOL + TM_WORD2], 4); 308 g_assert_cmphex(qw2w2, ==, be32_to_cpu(cl_word)); 309 g_assert_cmphex(qw3b8, ==, 310 cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD2]); 311 312 /* Verify that all TIMA valid bits for target thread are cleared */ 313 word2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2); 314 g_assert_cmphex(xive_get_field32(TM_QW1W2_VO, word2), ==, 0); 315 word2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2); 316 g_assert_cmphex(xive_get_field32(TM_QW2W2_VP, word2), ==, 0); 317 word2 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2); 318 g_assert_cmphex(xive_get_field32(TM_QW3W2_VT, word2), ==, 0); 319 } 320 321 static void test_hw_group_irq(QTestState *qts) 322 { 323 uint32_t irq = 100; 324 uint32_t irq_data = 0xdeadbeef; 325 uint32_t end_index = 23; 326 uint32_t chosen_one; 327 uint32_t target_nvp = 0x81; /* group size = 4 */ 328 uint8_t priority = 6; 329 uint32_t reg32; 330 uint16_t reg16; 331 uint8_t pq, nsr, cppr; 332 333 printf("# ============================================================\n"); 334 printf("# Testing irq %d to hardware group of size 4\n", irq); 335 336 /* irq config */ 337 set_eas(qts, irq, end_index, irq_data); 338 set_end(qts, end_index, target_nvp, priority, true /* group */); 339 340 /* enable and trigger irq */ 341 get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00); 342 set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0); 343 344 /* check irq is raised on cpu */ 345 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 346 g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING); 347 348 /* find the targeted vCPU */ 349 for (chosen_one = 0; chosen_one < SMT; chosen_one++) { 350 reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0); 351 nsr = reg32 >> 24; 352 if (nsr == 0x82) { 353 break; 354 } 355 } 356 g_assert_cmphex(chosen_one, <, SMT); 357 cppr = (reg32 >> 16) & 0xFF; 358 g_assert_cmphex(nsr, ==, 0x82); 359 g_assert_cmphex(cppr, ==, 0xFF); 360 361 /* ack the irq */ 362 reg16 = get_tima16(qts, chosen_one, TM_SPC_ACK_HV_REG); 363 nsr = reg16 >> 8; 364 cppr = reg16 & 0xFF; 365 g_assert_cmphex(nsr, ==, 0x82); 366 g_assert_cmphex(cppr, ==, priority); 367 368 /* check irq data is what was configured */ 369 reg32 = qtest_readl(qts, xive_get_queue_addr(end_index)); 370 g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff)); 371 372 /* End Of Interrupt */ 373 set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0); 374 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 375 g_assert_cmpuint(pq, ==, XIVE_ESB_RESET); 376 377 /* reset CPPR */ 378 set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, 0xFF); 379 reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0); 380 nsr = reg32 >> 24; 381 cppr = (reg32 >> 16) & 0xFF; 382 g_assert_cmphex(nsr, ==, 0x00); 383 g_assert_cmphex(cppr, ==, 0xFF); 384 } 385 386 static void test_hw_group_irq_backlog(QTestState *qts) 387 { 388 uint32_t irq = 31; 389 uint32_t irq_data = 0x01234567; 390 uint32_t end_index = 129; 391 uint32_t target_nvp = 0x81; /* group size = 4 */ 392 uint32_t chosen_one = 3; 393 uint8_t blocking_priority, priority = 3; 394 uint32_t reg32; 395 uint16_t reg16; 396 uint8_t pq, nsr, cppr, lsmfb, i; 397 398 printf("# ============================================================\n"); 399 printf("# Testing irq %d to hardware group of size 4 going through " \ 400 "backlog\n", 401 irq); 402 403 /* 404 * set current priority of all threads in the group to something 405 * higher than what we're about to trigger 406 */ 407 blocking_priority = priority - 1; 408 for (i = 0; i < SMT; i++) { 409 set_tima8(qts, i, TM_QW3_HV_PHYS + TM_CPPR, blocking_priority); 410 } 411 412 /* irq config */ 413 set_eas(qts, irq, end_index, irq_data); 414 set_end(qts, end_index, target_nvp, priority, true /* group */); 415 416 /* enable and trigger irq */ 417 get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00); 418 set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0); 419 420 /* check irq is raised on cpu */ 421 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 422 g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING); 423 424 /* check no interrupt is pending on the 2 possible targets */ 425 for (i = 0; i < SMT; i++) { 426 reg32 = get_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0); 427 nsr = reg32 >> 24; 428 cppr = (reg32 >> 16) & 0xFF; 429 lsmfb = reg32 & 0xFF; 430 g_assert_cmphex(nsr, ==, 0x0); 431 g_assert_cmphex(cppr, ==, blocking_priority); 432 g_assert_cmphex(lsmfb, ==, priority); 433 } 434 435 /* lower priority of one thread */ 436 set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, priority + 1); 437 438 /* check backlogged interrupt is presented */ 439 reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0); 440 nsr = reg32 >> 24; 441 cppr = (reg32 >> 16) & 0xFF; 442 g_assert_cmphex(nsr, ==, 0x82); 443 g_assert_cmphex(cppr, ==, priority + 1); 444 445 /* ack the irq */ 446 reg16 = get_tima16(qts, chosen_one, TM_SPC_ACK_HV_REG); 447 nsr = reg16 >> 8; 448 cppr = reg16 & 0xFF; 449 g_assert_cmphex(nsr, ==, 0x82); 450 g_assert_cmphex(cppr, ==, priority); 451 452 /* check irq data is what was configured */ 453 reg32 = qtest_readl(qts, xive_get_queue_addr(end_index)); 454 g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff)); 455 456 /* End Of Interrupt */ 457 set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0); 458 pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET); 459 g_assert_cmpuint(pq, ==, XIVE_ESB_RESET); 460 461 /* reset CPPR */ 462 set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, 0xFF); 463 reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0); 464 nsr = reg32 >> 24; 465 cppr = (reg32 >> 16) & 0xFF; 466 lsmfb = reg32 & 0xFF; 467 g_assert_cmphex(nsr, ==, 0x00); 468 g_assert_cmphex(cppr, ==, 0xFF); 469 g_assert_cmphex(lsmfb, ==, 0xFF); 470 } 471 472 static void test_xive(void) 473 { 474 QTestState *qts; 475 476 qts = qtest_initf("-M powernv10 -smp %d,cores=1,threads=%d -nographic " 477 "-nodefaults -serial mon:stdio -S " 478 "-d guest_errors -trace '*xive*'", 479 SMT, SMT); 480 init_xive(qts); 481 482 test_hw_irq(qts); 483 484 /* omit reset_state here and use settings from test_hw_irq */ 485 test_pull_thread_ctx_to_odd_thread_cl(qts); 486 487 reset_state(qts); 488 test_hw_group_irq(qts); 489 490 reset_state(qts); 491 test_hw_group_irq_backlog(qts); 492 493 reset_state(qts); 494 test_flush_sync_inject(qts); 495 496 reset_state(qts); 497 test_nvpg_bar(qts); 498 499 qtest_quit(qts); 500 } 501 502 int main(int argc, char **argv) 503 { 504 g_test_init(&argc, &argv, NULL); 505 qtest_add_func("xive2", test_xive); 506 return g_test_run(); 507 } 508