xref: /qemu/tests/qtest/pnv-xive2-test.c (revision c2b7fade9f9bca1cc0ca91ab614ea5cee3629e2e)
131bfbc00SFrederic Barrat /*
231bfbc00SFrederic Barrat  * QTest testcase for PowerNV 10 interrupt controller (xive2)
331bfbc00SFrederic Barrat  *  - Test irq to hardware thread
431bfbc00SFrederic Barrat  *  - Test 'Pull Thread Context to Odd Thread Reporting Line'
5*c2b7fadeSFrederic Barrat  *  - Test irq to hardware group
6*c2b7fadeSFrederic Barrat  *  - Test irq to hardware group going through backlog
731bfbc00SFrederic Barrat  *
831bfbc00SFrederic Barrat  * Copyright (c) 2024, IBM Corporation.
931bfbc00SFrederic Barrat  *
1031bfbc00SFrederic Barrat  * SPDX-License-Identifier: GPL-2.0-or-later
1131bfbc00SFrederic Barrat  */
1231bfbc00SFrederic Barrat #include "qemu/osdep.h"
1331bfbc00SFrederic Barrat #include "libqtest.h"
1431bfbc00SFrederic Barrat 
1531bfbc00SFrederic Barrat #include "pnv-xive2-common.h"
1631bfbc00SFrederic Barrat #include "hw/intc/pnv_xive2_regs.h"
1731bfbc00SFrederic Barrat #include "hw/ppc/xive_regs.h"
1831bfbc00SFrederic Barrat #include "hw/ppc/xive2_regs.h"
1931bfbc00SFrederic Barrat 
2031bfbc00SFrederic Barrat #define SMT                     4 /* some tests will break if less than 4 */
2131bfbc00SFrederic Barrat 
2231bfbc00SFrederic Barrat 
2331bfbc00SFrederic Barrat static void set_table(QTestState *qts, uint64_t type, uint64_t addr)
2431bfbc00SFrederic Barrat {
2531bfbc00SFrederic Barrat     uint64_t vsd, size, log_size;
2631bfbc00SFrederic Barrat 
2731bfbc00SFrederic Barrat     /*
2831bfbc00SFrederic Barrat      * First, let's make sure that all the resources used fit in the
2931bfbc00SFrederic Barrat      * given table.
3031bfbc00SFrederic Barrat      */
3131bfbc00SFrederic Barrat     switch (type) {
3231bfbc00SFrederic Barrat     case VST_ESB:
3331bfbc00SFrederic Barrat         size = MAX_IRQS / 4;
3431bfbc00SFrederic Barrat         break;
3531bfbc00SFrederic Barrat     case VST_EAS:
3631bfbc00SFrederic Barrat         size = MAX_IRQS * 8;
3731bfbc00SFrederic Barrat         break;
3831bfbc00SFrederic Barrat     case VST_END:
3931bfbc00SFrederic Barrat         size = MAX_ENDS * 32;
4031bfbc00SFrederic Barrat         break;
4131bfbc00SFrederic Barrat     case VST_NVP:
4231bfbc00SFrederic Barrat     case VST_NVG:
4331bfbc00SFrederic Barrat     case VST_NVC:
4431bfbc00SFrederic Barrat         size = MAX_VPS * 32;
4531bfbc00SFrederic Barrat         break;
4631bfbc00SFrederic Barrat     case VST_SYNC:
4731bfbc00SFrederic Barrat         size = 64 * 1024;
4831bfbc00SFrederic Barrat         break;
4931bfbc00SFrederic Barrat     default:
5031bfbc00SFrederic Barrat         g_assert_not_reached();
5131bfbc00SFrederic Barrat     }
5231bfbc00SFrederic Barrat 
5331bfbc00SFrederic Barrat     g_assert_cmpuint(size, <=, XIVE_VST_SIZE);
5431bfbc00SFrederic Barrat     log_size = ctzl(XIVE_VST_SIZE) - 12;
5531bfbc00SFrederic Barrat 
5631bfbc00SFrederic Barrat     vsd = ((uint64_t) VSD_MODE_EXCLUSIVE) << 62 | addr | log_size;
5731bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_ADDR, type << 48);
5831bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_VC_VSD_TABLE_DATA, vsd);
5931bfbc00SFrederic Barrat 
6031bfbc00SFrederic Barrat     if (type != VST_EAS && type != VST_IC && type != VST_ERQ) {
6131bfbc00SFrederic Barrat         pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_ADDR, type << 48);
6231bfbc00SFrederic Barrat         pnv_xive_xscom_write(qts, X_PC_VSD_TABLE_DATA, vsd);
6331bfbc00SFrederic Barrat     }
6431bfbc00SFrederic Barrat }
6531bfbc00SFrederic Barrat 
6631bfbc00SFrederic Barrat static void set_tima8(QTestState *qts, uint32_t pir, uint32_t offset,
6731bfbc00SFrederic Barrat                       uint8_t b)
6831bfbc00SFrederic Barrat {
6931bfbc00SFrederic Barrat     uint64_t ic_addr;
7031bfbc00SFrederic Barrat 
7131bfbc00SFrederic Barrat     ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
7231bfbc00SFrederic Barrat     qtest_writeb(qts, ic_addr + offset, b);
7331bfbc00SFrederic Barrat }
7431bfbc00SFrederic Barrat 
7531bfbc00SFrederic Barrat static void set_tima32(QTestState *qts, uint32_t pir, uint32_t offset,
7631bfbc00SFrederic Barrat                        uint32_t l)
7731bfbc00SFrederic Barrat {
7831bfbc00SFrederic Barrat     uint64_t ic_addr;
7931bfbc00SFrederic Barrat 
8031bfbc00SFrederic Barrat     ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
8131bfbc00SFrederic Barrat     qtest_writel(qts, ic_addr + offset, l);
8231bfbc00SFrederic Barrat }
8331bfbc00SFrederic Barrat 
8431bfbc00SFrederic Barrat static uint8_t get_tima8(QTestState *qts, uint32_t pir, uint32_t offset)
8531bfbc00SFrederic Barrat {
8631bfbc00SFrederic Barrat     uint64_t ic_addr;
8731bfbc00SFrederic Barrat 
8831bfbc00SFrederic Barrat     ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
8931bfbc00SFrederic Barrat     return qtest_readb(qts, ic_addr + offset);
9031bfbc00SFrederic Barrat }
9131bfbc00SFrederic Barrat 
9231bfbc00SFrederic Barrat static uint16_t get_tima16(QTestState *qts, uint32_t pir, uint32_t offset)
9331bfbc00SFrederic Barrat {
9431bfbc00SFrederic Barrat     uint64_t ic_addr;
9531bfbc00SFrederic Barrat 
9631bfbc00SFrederic Barrat     ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
9731bfbc00SFrederic Barrat     return qtest_readw(qts, ic_addr + offset);
9831bfbc00SFrederic Barrat }
9931bfbc00SFrederic Barrat 
10031bfbc00SFrederic Barrat static uint32_t get_tima32(QTestState *qts, uint32_t pir, uint32_t offset)
10131bfbc00SFrederic Barrat {
10231bfbc00SFrederic Barrat     uint64_t ic_addr;
10331bfbc00SFrederic Barrat 
10431bfbc00SFrederic Barrat     ic_addr = XIVE_IC_TM_INDIRECT + (pir << XIVE_PAGE_SHIFT);
10531bfbc00SFrederic Barrat     return qtest_readl(qts, ic_addr + offset);
10631bfbc00SFrederic Barrat }
10731bfbc00SFrederic Barrat 
10831bfbc00SFrederic Barrat static void reset_pool_threads(QTestState *qts)
10931bfbc00SFrederic Barrat {
11031bfbc00SFrederic Barrat     uint8_t first_group = 0;
11131bfbc00SFrederic Barrat     int i;
11231bfbc00SFrederic Barrat 
11331bfbc00SFrederic Barrat     for (i = 0; i < SMT; i++) {
11431bfbc00SFrederic Barrat         uint32_t nvp_idx = 0x100 + i;
11531bfbc00SFrederic Barrat         set_nvp(qts, nvp_idx, first_group);
11631bfbc00SFrederic Barrat         set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD0, 0x000000ff);
11731bfbc00SFrederic Barrat         set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD1, 0);
11831bfbc00SFrederic Barrat         set_tima32(qts, i, TM_QW2_HV_POOL + TM_WORD2, TM_QW2W2_VP | nvp_idx);
11931bfbc00SFrederic Barrat     }
12031bfbc00SFrederic Barrat }
12131bfbc00SFrederic Barrat 
12231bfbc00SFrederic Barrat static void reset_hw_threads(QTestState *qts)
12331bfbc00SFrederic Barrat {
12431bfbc00SFrederic Barrat     uint8_t first_group = 0;
12531bfbc00SFrederic Barrat     uint32_t w1 = 0x000000ff;
12631bfbc00SFrederic Barrat     int i;
12731bfbc00SFrederic Barrat 
12831bfbc00SFrederic Barrat     if (SMT >= 4) {
12931bfbc00SFrederic Barrat         /* define 2 groups of 2, part of a bigger group of size 4 */
13031bfbc00SFrederic Barrat         set_nvg(qts, 0x80, 0x02);
13131bfbc00SFrederic Barrat         set_nvg(qts, 0x82, 0x02);
13231bfbc00SFrederic Barrat         set_nvg(qts, 0x81, 0);
13331bfbc00SFrederic Barrat         first_group = 0x01;
13431bfbc00SFrederic Barrat         w1 = 0x000300ff;
13531bfbc00SFrederic Barrat     }
13631bfbc00SFrederic Barrat 
13731bfbc00SFrederic Barrat     for (i = 0; i < SMT; i++) {
13831bfbc00SFrederic Barrat         set_nvp(qts, 0x80 + i, first_group);
13931bfbc00SFrederic Barrat         set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0, 0x00ff00ff);
14031bfbc00SFrederic Barrat         set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD1, w1);
14131bfbc00SFrederic Barrat         set_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD2, 0x80000000);
14231bfbc00SFrederic Barrat     }
14331bfbc00SFrederic Barrat }
14431bfbc00SFrederic Barrat 
14531bfbc00SFrederic Barrat static void reset_state(QTestState *qts)
14631bfbc00SFrederic Barrat {
14731bfbc00SFrederic Barrat     size_t mem_used = XIVE_MEM_END - XIVE_MEM_START;
14831bfbc00SFrederic Barrat 
14931bfbc00SFrederic Barrat     qtest_memset(qts, XIVE_MEM_START, 0, mem_used);
15031bfbc00SFrederic Barrat     reset_hw_threads(qts);
15131bfbc00SFrederic Barrat     reset_pool_threads(qts);
15231bfbc00SFrederic Barrat }
15331bfbc00SFrederic Barrat 
15431bfbc00SFrederic Barrat static void init_xive(QTestState *qts)
15531bfbc00SFrederic Barrat {
15631bfbc00SFrederic Barrat     uint64_t val1, val2, range;
15731bfbc00SFrederic Barrat 
15831bfbc00SFrederic Barrat     /*
15931bfbc00SFrederic Barrat      * We can take a few shortcuts here, as we know the default values
16031bfbc00SFrederic Barrat      * used for xive initialization
16131bfbc00SFrederic Barrat      */
16231bfbc00SFrederic Barrat 
16331bfbc00SFrederic Barrat     /*
16431bfbc00SFrederic Barrat      * Set the BARs.
16531bfbc00SFrederic Barrat      * We reuse the same values used by firmware to ease debug.
16631bfbc00SFrederic Barrat      */
16731bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_CQ_IC_BAR, XIVE_IC_BAR);
16831bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_CQ_TM_BAR, XIVE_TM_BAR);
16931bfbc00SFrederic Barrat 
17031bfbc00SFrederic Barrat     /* ESB and NVPG use 2 pages per resource. The others only one page */
17131bfbc00SFrederic Barrat     range = (MAX_IRQS << 17) >> 25;
17231bfbc00SFrederic Barrat     val1 = XIVE_ESB_BAR | range;
17331bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_CQ_ESB_BAR, val1);
17431bfbc00SFrederic Barrat 
17531bfbc00SFrederic Barrat     range = (MAX_ENDS << 16) >> 25;
17631bfbc00SFrederic Barrat     val1 = XIVE_END_BAR | range;
17731bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_CQ_END_BAR, val1);
17831bfbc00SFrederic Barrat 
17931bfbc00SFrederic Barrat     range = (MAX_VPS << 17) >> 25;
18031bfbc00SFrederic Barrat     val1 = XIVE_NVPG_BAR | range;
18131bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_CQ_NVPG_BAR, val1);
18231bfbc00SFrederic Barrat 
18331bfbc00SFrederic Barrat     range = (MAX_VPS << 16) >> 25;
18431bfbc00SFrederic Barrat     val1 = XIVE_NVC_BAR | range;
18531bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_CQ_NVC_BAR, val1);
18631bfbc00SFrederic Barrat 
18731bfbc00SFrederic Barrat     /*
18831bfbc00SFrederic Barrat      * Enable hw threads.
18931bfbc00SFrederic Barrat      * We check the value written. Useless with current
19031bfbc00SFrederic Barrat      * implementation, but it validates the xscom read path and it's
19131bfbc00SFrederic Barrat      * what the hardware procedure says
19231bfbc00SFrederic Barrat      */
19331bfbc00SFrederic Barrat     val1 = 0xF000000000000000ull; /* core 0, 4 threads */
19431bfbc00SFrederic Barrat     pnv_xive_xscom_write(qts, X_TCTXT_EN0, val1);
19531bfbc00SFrederic Barrat     val2 = pnv_xive_xscom_read(qts, X_TCTXT_EN0);
19631bfbc00SFrederic Barrat     g_assert_cmphex(val1, ==, val2);
19731bfbc00SFrederic Barrat 
19831bfbc00SFrederic Barrat     /* Memory tables */
19931bfbc00SFrederic Barrat     set_table(qts, VST_ESB, XIVE_ESB_MEM);
20031bfbc00SFrederic Barrat     set_table(qts, VST_EAS, XIVE_EAS_MEM);
20131bfbc00SFrederic Barrat     set_table(qts, VST_END, XIVE_END_MEM);
20231bfbc00SFrederic Barrat     set_table(qts, VST_NVP, XIVE_NVP_MEM);
20331bfbc00SFrederic Barrat     set_table(qts, VST_NVG, XIVE_NVG_MEM);
20431bfbc00SFrederic Barrat     set_table(qts, VST_NVC, XIVE_NVC_MEM);
20531bfbc00SFrederic Barrat     set_table(qts, VST_SYNC, XIVE_SYNC_MEM);
20631bfbc00SFrederic Barrat 
20731bfbc00SFrederic Barrat     reset_hw_threads(qts);
20831bfbc00SFrederic Barrat     reset_pool_threads(qts);
20931bfbc00SFrederic Barrat }
21031bfbc00SFrederic Barrat 
21131bfbc00SFrederic Barrat static void test_hw_irq(QTestState *qts)
21231bfbc00SFrederic Barrat {
21331bfbc00SFrederic Barrat     uint32_t irq = 2;
21431bfbc00SFrederic Barrat     uint32_t irq_data = 0x600df00d;
21531bfbc00SFrederic Barrat     uint32_t end_index = 5;
21631bfbc00SFrederic Barrat     uint32_t target_pir = 1;
21731bfbc00SFrederic Barrat     uint32_t target_nvp = 0x80 + target_pir;
21831bfbc00SFrederic Barrat     uint8_t priority = 5;
21931bfbc00SFrederic Barrat     uint32_t reg32;
22031bfbc00SFrederic Barrat     uint16_t reg16;
22131bfbc00SFrederic Barrat     uint8_t pq, nsr, cppr;
22231bfbc00SFrederic Barrat 
22331bfbc00SFrederic Barrat     printf("# ============================================================\n");
22431bfbc00SFrederic Barrat     printf("# Testing irq %d to hardware thread %d\n", irq, target_pir);
22531bfbc00SFrederic Barrat 
22631bfbc00SFrederic Barrat     /* irq config */
22731bfbc00SFrederic Barrat     set_eas(qts, irq, end_index, irq_data);
22831bfbc00SFrederic Barrat     set_end(qts, end_index, target_nvp, priority, false /* group */);
22931bfbc00SFrederic Barrat 
23031bfbc00SFrederic Barrat     /* enable and trigger irq */
23131bfbc00SFrederic Barrat     get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
23231bfbc00SFrederic Barrat     set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
23331bfbc00SFrederic Barrat 
23431bfbc00SFrederic Barrat     /* check irq is raised on cpu */
23531bfbc00SFrederic Barrat     pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
23631bfbc00SFrederic Barrat     g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
23731bfbc00SFrederic Barrat 
23831bfbc00SFrederic Barrat     reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
23931bfbc00SFrederic Barrat     nsr = reg32 >> 24;
24031bfbc00SFrederic Barrat     cppr = (reg32 >> 16) & 0xFF;
24131bfbc00SFrederic Barrat     g_assert_cmphex(nsr, ==, 0x80);
24231bfbc00SFrederic Barrat     g_assert_cmphex(cppr, ==, 0xFF);
24331bfbc00SFrederic Barrat 
24431bfbc00SFrederic Barrat     /* ack the irq */
24531bfbc00SFrederic Barrat     reg16 = get_tima16(qts, target_pir, TM_SPC_ACK_HV_REG);
24631bfbc00SFrederic Barrat     nsr = reg16 >> 8;
24731bfbc00SFrederic Barrat     cppr = reg16 & 0xFF;
24831bfbc00SFrederic Barrat     g_assert_cmphex(nsr, ==, 0x80);
24931bfbc00SFrederic Barrat     g_assert_cmphex(cppr, ==, priority);
25031bfbc00SFrederic Barrat 
25131bfbc00SFrederic Barrat     /* check irq data is what was configured */
25231bfbc00SFrederic Barrat     reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
25331bfbc00SFrederic Barrat     g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
25431bfbc00SFrederic Barrat 
25531bfbc00SFrederic Barrat     /* End Of Interrupt */
25631bfbc00SFrederic Barrat     set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
25731bfbc00SFrederic Barrat     pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
25831bfbc00SFrederic Barrat     g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
25931bfbc00SFrederic Barrat 
26031bfbc00SFrederic Barrat     /* reset CPPR */
26131bfbc00SFrederic Barrat     set_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
26231bfbc00SFrederic Barrat     reg32 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
26331bfbc00SFrederic Barrat     nsr = reg32 >> 24;
26431bfbc00SFrederic Barrat     cppr = (reg32 >> 16) & 0xFF;
26531bfbc00SFrederic Barrat     g_assert_cmphex(nsr, ==, 0x00);
26631bfbc00SFrederic Barrat     g_assert_cmphex(cppr, ==, 0xFF);
26731bfbc00SFrederic Barrat }
26831bfbc00SFrederic Barrat 
26931bfbc00SFrederic Barrat #define XIVE_ODD_CL 0x80
27031bfbc00SFrederic Barrat static void test_pull_thread_ctx_to_odd_thread_cl(QTestState *qts)
27131bfbc00SFrederic Barrat {
27231bfbc00SFrederic Barrat     uint32_t target_pir = 1;
27331bfbc00SFrederic Barrat     uint32_t target_nvp = 0x80 + target_pir;
27431bfbc00SFrederic Barrat     Xive2Nvp nvp;
27531bfbc00SFrederic Barrat     uint8_t cl_pair[XIVE_REPORT_SIZE];
27631bfbc00SFrederic Barrat     uint32_t qw1w0, qw3w0, qw1w2, qw2w2;
27731bfbc00SFrederic Barrat     uint8_t qw3b8;
27831bfbc00SFrederic Barrat     uint32_t cl_word;
27931bfbc00SFrederic Barrat     uint32_t word2;
28031bfbc00SFrederic Barrat 
28131bfbc00SFrederic Barrat     printf("# ============================================================\n");
28231bfbc00SFrederic Barrat     printf("# Testing 'Pull Thread Context to Odd Thread Reporting Line'\n");
28331bfbc00SFrederic Barrat 
28431bfbc00SFrederic Barrat     /* clear odd cache line prior to pull operation */
28531bfbc00SFrederic Barrat     memset(cl_pair, 0, sizeof(cl_pair));
28631bfbc00SFrederic Barrat     get_nvp(qts, target_nvp, &nvp);
28731bfbc00SFrederic Barrat     set_cl_pair(qts, &nvp, cl_pair);
28831bfbc00SFrederic Barrat 
28931bfbc00SFrederic Barrat     /* Read some values from TIMA that we expect to see in cacheline */
29031bfbc00SFrederic Barrat     qw1w0 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD0);
29131bfbc00SFrederic Barrat     qw3w0 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD0);
29231bfbc00SFrederic Barrat     qw1w2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2);
29331bfbc00SFrederic Barrat     qw2w2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2);
29431bfbc00SFrederic Barrat     qw3b8 = get_tima8(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2);
29531bfbc00SFrederic Barrat 
29631bfbc00SFrederic Barrat     /* Execute the pull operation */
29731bfbc00SFrederic Barrat     set_tima8(qts, target_pir, TM_SPC_PULL_PHYS_CTX_OL, 0);
29831bfbc00SFrederic Barrat 
29931bfbc00SFrederic Barrat     /* Verify odd cache line values match TIMA after pull operation */
30031bfbc00SFrederic Barrat     get_cl_pair(qts, &nvp, cl_pair);
30131bfbc00SFrederic Barrat     memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD0], 4);
30231bfbc00SFrederic Barrat     g_assert_cmphex(qw1w0, ==, be32_to_cpu(cl_word));
30331bfbc00SFrederic Barrat     memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD0], 4);
30431bfbc00SFrederic Barrat     g_assert_cmphex(qw3w0, ==, be32_to_cpu(cl_word));
30531bfbc00SFrederic Barrat     memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW1_OS + TM_WORD2], 4);
30631bfbc00SFrederic Barrat     g_assert_cmphex(qw1w2, ==, be32_to_cpu(cl_word));
30731bfbc00SFrederic Barrat     memcpy(&cl_word, &cl_pair[XIVE_ODD_CL + TM_QW2_HV_POOL + TM_WORD2], 4);
30831bfbc00SFrederic Barrat     g_assert_cmphex(qw2w2, ==, be32_to_cpu(cl_word));
30931bfbc00SFrederic Barrat     g_assert_cmphex(qw3b8, ==,
31031bfbc00SFrederic Barrat                     cl_pair[XIVE_ODD_CL + TM_QW3_HV_PHYS + TM_WORD2]);
31131bfbc00SFrederic Barrat 
31231bfbc00SFrederic Barrat     /* Verify that all TIMA valid bits for target thread are cleared */
31331bfbc00SFrederic Barrat     word2 = get_tima32(qts, target_pir, TM_QW1_OS + TM_WORD2);
31431bfbc00SFrederic Barrat     g_assert_cmphex(xive_get_field32(TM_QW1W2_VO, word2), ==, 0);
31531bfbc00SFrederic Barrat     word2 = get_tima32(qts, target_pir, TM_QW2_HV_POOL + TM_WORD2);
31631bfbc00SFrederic Barrat     g_assert_cmphex(xive_get_field32(TM_QW2W2_VP, word2), ==, 0);
31731bfbc00SFrederic Barrat     word2 = get_tima32(qts, target_pir, TM_QW3_HV_PHYS + TM_WORD2);
31831bfbc00SFrederic Barrat     g_assert_cmphex(xive_get_field32(TM_QW3W2_VT, word2), ==, 0);
31931bfbc00SFrederic Barrat }
320*c2b7fadeSFrederic Barrat 
321*c2b7fadeSFrederic Barrat static void test_hw_group_irq(QTestState *qts)
322*c2b7fadeSFrederic Barrat {
323*c2b7fadeSFrederic Barrat     uint32_t irq = 100;
324*c2b7fadeSFrederic Barrat     uint32_t irq_data = 0xdeadbeef;
325*c2b7fadeSFrederic Barrat     uint32_t end_index = 23;
326*c2b7fadeSFrederic Barrat     uint32_t chosen_one;
327*c2b7fadeSFrederic Barrat     uint32_t target_nvp = 0x81; /* group size = 4 */
328*c2b7fadeSFrederic Barrat     uint8_t priority = 6;
329*c2b7fadeSFrederic Barrat     uint32_t reg32;
330*c2b7fadeSFrederic Barrat     uint16_t reg16;
331*c2b7fadeSFrederic Barrat     uint8_t pq, nsr, cppr;
332*c2b7fadeSFrederic Barrat 
333*c2b7fadeSFrederic Barrat     printf("# ============================================================\n");
334*c2b7fadeSFrederic Barrat     printf("# Testing irq %d to hardware group of size 4\n", irq);
335*c2b7fadeSFrederic Barrat 
336*c2b7fadeSFrederic Barrat     /* irq config */
337*c2b7fadeSFrederic Barrat     set_eas(qts, irq, end_index, irq_data);
338*c2b7fadeSFrederic Barrat     set_end(qts, end_index, target_nvp, priority, true /* group */);
339*c2b7fadeSFrederic Barrat 
340*c2b7fadeSFrederic Barrat     /* enable and trigger irq */
341*c2b7fadeSFrederic Barrat     get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
342*c2b7fadeSFrederic Barrat     set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
343*c2b7fadeSFrederic Barrat 
344*c2b7fadeSFrederic Barrat     /* check irq is raised on cpu */
345*c2b7fadeSFrederic Barrat     pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
346*c2b7fadeSFrederic Barrat     g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
347*c2b7fadeSFrederic Barrat 
348*c2b7fadeSFrederic Barrat     /* find the targeted vCPU */
349*c2b7fadeSFrederic Barrat     for (chosen_one = 0; chosen_one < SMT; chosen_one++) {
350*c2b7fadeSFrederic Barrat         reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
351*c2b7fadeSFrederic Barrat         nsr = reg32 >> 24;
352*c2b7fadeSFrederic Barrat         if (nsr == 0x82) {
353*c2b7fadeSFrederic Barrat             break;
354*c2b7fadeSFrederic Barrat         }
355*c2b7fadeSFrederic Barrat     }
356*c2b7fadeSFrederic Barrat     g_assert_cmphex(chosen_one, <, SMT);
357*c2b7fadeSFrederic Barrat     cppr = (reg32 >> 16) & 0xFF;
358*c2b7fadeSFrederic Barrat     g_assert_cmphex(nsr, ==, 0x82);
359*c2b7fadeSFrederic Barrat     g_assert_cmphex(cppr, ==, 0xFF);
360*c2b7fadeSFrederic Barrat 
361*c2b7fadeSFrederic Barrat     /* ack the irq */
362*c2b7fadeSFrederic Barrat     reg16 = get_tima16(qts, chosen_one, TM_SPC_ACK_HV_REG);
363*c2b7fadeSFrederic Barrat     nsr = reg16 >> 8;
364*c2b7fadeSFrederic Barrat     cppr = reg16 & 0xFF;
365*c2b7fadeSFrederic Barrat     g_assert_cmphex(nsr, ==, 0x82);
366*c2b7fadeSFrederic Barrat     g_assert_cmphex(cppr, ==, priority);
367*c2b7fadeSFrederic Barrat 
368*c2b7fadeSFrederic Barrat     /* check irq data is what was configured */
369*c2b7fadeSFrederic Barrat     reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
370*c2b7fadeSFrederic Barrat     g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
371*c2b7fadeSFrederic Barrat 
372*c2b7fadeSFrederic Barrat     /* End Of Interrupt */
373*c2b7fadeSFrederic Barrat     set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
374*c2b7fadeSFrederic Barrat     pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
375*c2b7fadeSFrederic Barrat     g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
376*c2b7fadeSFrederic Barrat 
377*c2b7fadeSFrederic Barrat     /* reset CPPR */
378*c2b7fadeSFrederic Barrat     set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
379*c2b7fadeSFrederic Barrat     reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
380*c2b7fadeSFrederic Barrat     nsr = reg32 >> 24;
381*c2b7fadeSFrederic Barrat     cppr = (reg32 >> 16) & 0xFF;
382*c2b7fadeSFrederic Barrat     g_assert_cmphex(nsr, ==, 0x00);
383*c2b7fadeSFrederic Barrat     g_assert_cmphex(cppr, ==, 0xFF);
384*c2b7fadeSFrederic Barrat }
385*c2b7fadeSFrederic Barrat 
386*c2b7fadeSFrederic Barrat static void test_hw_group_irq_backlog(QTestState *qts)
387*c2b7fadeSFrederic Barrat {
388*c2b7fadeSFrederic Barrat     uint32_t irq = 31;
389*c2b7fadeSFrederic Barrat     uint32_t irq_data = 0x01234567;
390*c2b7fadeSFrederic Barrat     uint32_t end_index = 129;
391*c2b7fadeSFrederic Barrat     uint32_t target_nvp = 0x81; /* group size = 4 */
392*c2b7fadeSFrederic Barrat     uint32_t chosen_one = 3;
393*c2b7fadeSFrederic Barrat     uint8_t blocking_priority, priority = 3;
394*c2b7fadeSFrederic Barrat     uint32_t reg32;
395*c2b7fadeSFrederic Barrat     uint16_t reg16;
396*c2b7fadeSFrederic Barrat     uint8_t pq, nsr, cppr, lsmfb, i;
397*c2b7fadeSFrederic Barrat 
398*c2b7fadeSFrederic Barrat     printf("# ============================================================\n");
399*c2b7fadeSFrederic Barrat     printf("# Testing irq %d to hardware group of size 4 going through " \
400*c2b7fadeSFrederic Barrat            "backlog\n",
401*c2b7fadeSFrederic Barrat            irq);
402*c2b7fadeSFrederic Barrat 
403*c2b7fadeSFrederic Barrat     /*
404*c2b7fadeSFrederic Barrat      * set current priority of all threads in the group to something
405*c2b7fadeSFrederic Barrat      * higher than what we're about to trigger
406*c2b7fadeSFrederic Barrat      */
407*c2b7fadeSFrederic Barrat     blocking_priority = priority - 1;
408*c2b7fadeSFrederic Barrat     for (i = 0; i < SMT; i++) {
409*c2b7fadeSFrederic Barrat         set_tima8(qts, i, TM_QW3_HV_PHYS + TM_CPPR, blocking_priority);
410*c2b7fadeSFrederic Barrat     }
411*c2b7fadeSFrederic Barrat 
412*c2b7fadeSFrederic Barrat     /* irq config */
413*c2b7fadeSFrederic Barrat     set_eas(qts, irq, end_index, irq_data);
414*c2b7fadeSFrederic Barrat     set_end(qts, end_index, target_nvp, priority, true /* group */);
415*c2b7fadeSFrederic Barrat 
416*c2b7fadeSFrederic Barrat     /* enable and trigger irq */
417*c2b7fadeSFrederic Barrat     get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_SET_PQ_00);
418*c2b7fadeSFrederic Barrat     set_esb(qts, irq, XIVE_TRIGGER_PAGE, 0, 0);
419*c2b7fadeSFrederic Barrat 
420*c2b7fadeSFrederic Barrat     /* check irq is raised on cpu */
421*c2b7fadeSFrederic Barrat     pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
422*c2b7fadeSFrederic Barrat     g_assert_cmpuint(pq, ==, XIVE_ESB_PENDING);
423*c2b7fadeSFrederic Barrat 
424*c2b7fadeSFrederic Barrat     /* check no interrupt is pending on the 2 possible targets */
425*c2b7fadeSFrederic Barrat     for (i = 0; i < SMT; i++) {
426*c2b7fadeSFrederic Barrat         reg32 = get_tima32(qts, i, TM_QW3_HV_PHYS + TM_WORD0);
427*c2b7fadeSFrederic Barrat         nsr = reg32 >> 24;
428*c2b7fadeSFrederic Barrat         cppr = (reg32 >> 16) & 0xFF;
429*c2b7fadeSFrederic Barrat         lsmfb = reg32 & 0xFF;
430*c2b7fadeSFrederic Barrat         g_assert_cmphex(nsr, ==, 0x0);
431*c2b7fadeSFrederic Barrat         g_assert_cmphex(cppr, ==, blocking_priority);
432*c2b7fadeSFrederic Barrat         g_assert_cmphex(lsmfb, ==, priority);
433*c2b7fadeSFrederic Barrat     }
434*c2b7fadeSFrederic Barrat 
435*c2b7fadeSFrederic Barrat     /* lower priority of one thread */
436*c2b7fadeSFrederic Barrat     set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, priority + 1);
437*c2b7fadeSFrederic Barrat 
438*c2b7fadeSFrederic Barrat     /* check backlogged interrupt is presented */
439*c2b7fadeSFrederic Barrat     reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
440*c2b7fadeSFrederic Barrat     nsr = reg32 >> 24;
441*c2b7fadeSFrederic Barrat     cppr = (reg32 >> 16) & 0xFF;
442*c2b7fadeSFrederic Barrat     g_assert_cmphex(nsr, ==, 0x82);
443*c2b7fadeSFrederic Barrat     g_assert_cmphex(cppr, ==, priority + 1);
444*c2b7fadeSFrederic Barrat 
445*c2b7fadeSFrederic Barrat     /* ack the irq */
446*c2b7fadeSFrederic Barrat     reg16 = get_tima16(qts, chosen_one, TM_SPC_ACK_HV_REG);
447*c2b7fadeSFrederic Barrat     nsr = reg16 >> 8;
448*c2b7fadeSFrederic Barrat     cppr = reg16 & 0xFF;
449*c2b7fadeSFrederic Barrat     g_assert_cmphex(nsr, ==, 0x82);
450*c2b7fadeSFrederic Barrat     g_assert_cmphex(cppr, ==, priority);
451*c2b7fadeSFrederic Barrat 
452*c2b7fadeSFrederic Barrat     /* check irq data is what was configured */
453*c2b7fadeSFrederic Barrat     reg32 = qtest_readl(qts, xive_get_queue_addr(end_index));
454*c2b7fadeSFrederic Barrat     g_assert_cmphex((reg32 & 0x7fffffff), ==, (irq_data & 0x7fffffff));
455*c2b7fadeSFrederic Barrat 
456*c2b7fadeSFrederic Barrat     /* End Of Interrupt */
457*c2b7fadeSFrederic Barrat     set_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_STORE_EOI, 0);
458*c2b7fadeSFrederic Barrat     pq = get_esb(qts, irq, XIVE_EOI_PAGE, XIVE_ESB_GET);
459*c2b7fadeSFrederic Barrat     g_assert_cmpuint(pq, ==, XIVE_ESB_RESET);
460*c2b7fadeSFrederic Barrat 
461*c2b7fadeSFrederic Barrat     /* reset CPPR */
462*c2b7fadeSFrederic Barrat     set_tima8(qts, chosen_one, TM_QW3_HV_PHYS + TM_CPPR, 0xFF);
463*c2b7fadeSFrederic Barrat     reg32 = get_tima32(qts, chosen_one, TM_QW3_HV_PHYS + TM_WORD0);
464*c2b7fadeSFrederic Barrat     nsr = reg32 >> 24;
465*c2b7fadeSFrederic Barrat     cppr = (reg32 >> 16) & 0xFF;
466*c2b7fadeSFrederic Barrat     lsmfb = reg32 & 0xFF;
467*c2b7fadeSFrederic Barrat     g_assert_cmphex(nsr, ==, 0x00);
468*c2b7fadeSFrederic Barrat     g_assert_cmphex(cppr, ==, 0xFF);
469*c2b7fadeSFrederic Barrat     g_assert_cmphex(lsmfb, ==, 0xFF);
470*c2b7fadeSFrederic Barrat }
471*c2b7fadeSFrederic Barrat 
47231bfbc00SFrederic Barrat static void test_xive(void)
47331bfbc00SFrederic Barrat {
47431bfbc00SFrederic Barrat     QTestState *qts;
47531bfbc00SFrederic Barrat 
47631bfbc00SFrederic Barrat     qts = qtest_initf("-M powernv10 -smp %d,cores=1,threads=%d -nographic "
47731bfbc00SFrederic Barrat                       "-nodefaults -serial mon:stdio -S "
47831bfbc00SFrederic Barrat                       "-d guest_errors -trace '*xive*'",
47931bfbc00SFrederic Barrat                       SMT, SMT);
48031bfbc00SFrederic Barrat     init_xive(qts);
48131bfbc00SFrederic Barrat 
48231bfbc00SFrederic Barrat     test_hw_irq(qts);
48331bfbc00SFrederic Barrat 
48431bfbc00SFrederic Barrat     /* omit reset_state here and use settings from test_hw_irq */
48531bfbc00SFrederic Barrat     test_pull_thread_ctx_to_odd_thread_cl(qts);
48631bfbc00SFrederic Barrat 
48731bfbc00SFrederic Barrat     reset_state(qts);
488*c2b7fadeSFrederic Barrat     test_hw_group_irq(qts);
489*c2b7fadeSFrederic Barrat 
490*c2b7fadeSFrederic Barrat     reset_state(qts);
491*c2b7fadeSFrederic Barrat     test_hw_group_irq_backlog(qts);
492*c2b7fadeSFrederic Barrat 
493*c2b7fadeSFrederic Barrat     reset_state(qts);
49431bfbc00SFrederic Barrat     test_flush_sync_inject(qts);
49531bfbc00SFrederic Barrat 
49631bfbc00SFrederic Barrat     qtest_quit(qts);
49731bfbc00SFrederic Barrat }
49831bfbc00SFrederic Barrat 
49931bfbc00SFrederic Barrat int main(int argc, char **argv)
50031bfbc00SFrederic Barrat {
50131bfbc00SFrederic Barrat     g_test_init(&argc, &argv, NULL);
50231bfbc00SFrederic Barrat     qtest_add_func("xive2", test_xive);
50331bfbc00SFrederic Barrat     return g_test_run();
50431bfbc00SFrederic Barrat }
505