xref: /openbmc/qemu/tests/qtest/pnv-xive2-test.c (revision f7ceab1e)
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