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