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
set_table(QTestState * qts,uint64_t type,uint64_t addr)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
set_tima8(QTestState * qts,uint32_t pir,uint32_t offset,uint8_t b)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
set_tima32(QTestState * qts,uint32_t pir,uint32_t offset,uint32_t l)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
get_tima8(QTestState * qts,uint32_t pir,uint32_t offset)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
get_tima16(QTestState * qts,uint32_t pir,uint32_t offset)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
get_tima32(QTestState * qts,uint32_t pir,uint32_t offset)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
reset_pool_threads(QTestState * qts)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
reset_hw_threads(QTestState * qts)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
reset_state(QTestState * qts)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
init_xive(QTestState * qts)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
test_hw_irq(QTestState * qts)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
test_pull_thread_ctx_to_odd_thread_cl(QTestState * qts)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 }
test_xive(void)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
main(int argc,char ** argv)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