xref: /openbmc/qemu/tests/qtest/riscv-iommu-test.c (revision d36f165d)
1 /*
2  * QTest testcase for RISC-V IOMMU
3  *
4  * Copyright (c) 2024 Ventana Micro Systems Inc.
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
7  * option) any later version.  See the COPYING file in the top-level directory.
8  *
9  */
10 
11 #include "qemu/osdep.h"
12 #include "libqtest-single.h"
13 #include "qemu/module.h"
14 #include "libqos/qgraph.h"
15 #include "libqos/riscv-iommu.h"
16 #include "hw/pci/pci_regs.h"
17 
18 static uint32_t riscv_iommu_read_reg32(QRISCVIOMMU *r_iommu, int reg_offset)
19 {
20     return qpci_io_readl(&r_iommu->dev, r_iommu->reg_bar, reg_offset);
21 }
22 
23 static uint64_t riscv_iommu_read_reg64(QRISCVIOMMU *r_iommu, int reg_offset)
24 {
25     return qpci_io_readq(&r_iommu->dev, r_iommu->reg_bar, reg_offset);
26 }
27 
28 static void riscv_iommu_write_reg32(QRISCVIOMMU *r_iommu, int reg_offset,
29                                     uint32_t val)
30 {
31     qpci_io_writel(&r_iommu->dev, r_iommu->reg_bar, reg_offset, val);
32 }
33 
34 static void riscv_iommu_write_reg64(QRISCVIOMMU *r_iommu, int reg_offset,
35                                     uint64_t val)
36 {
37     qpci_io_writeq(&r_iommu->dev, r_iommu->reg_bar, reg_offset, val);
38 }
39 
40 static void test_pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
41 {
42     QRISCVIOMMU *r_iommu = obj;
43     QPCIDevice *dev = &r_iommu->dev;
44     uint16_t vendorid, deviceid, classid;
45 
46     vendorid = qpci_config_readw(dev, PCI_VENDOR_ID);
47     deviceid = qpci_config_readw(dev, PCI_DEVICE_ID);
48     classid = qpci_config_readw(dev, PCI_CLASS_DEVICE);
49 
50     g_assert_cmpuint(vendorid, ==, RISCV_IOMMU_PCI_VENDOR_ID);
51     g_assert_cmpuint(deviceid, ==, RISCV_IOMMU_PCI_DEVICE_ID);
52     g_assert_cmpuint(classid, ==, RISCV_IOMMU_PCI_DEVICE_CLASS);
53 }
54 
55 static void test_reg_reset(void *obj, void *data, QGuestAllocator *t_alloc)
56 {
57     QRISCVIOMMU *r_iommu = obj;
58     uint64_t cap;
59     uint32_t reg;
60 
61     cap = riscv_iommu_read_reg64(r_iommu, RISCV_IOMMU_REG_CAP);
62     g_assert_cmpuint(cap & RISCV_IOMMU_CAP_VERSION, ==, 0x10);
63 
64     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_CQCSR);
65     g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_CQEN, ==, 0);
66     g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_CIE, ==, 0);
67     g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_CQON, ==, 0);
68     g_assert_cmpuint(reg & RISCV_IOMMU_CQCSR_BUSY, ==, 0);
69 
70     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_FQCSR);
71     g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_FQEN, ==, 0);
72     g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_FIE, ==, 0);
73     g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_FQON, ==, 0);
74     g_assert_cmpuint(reg & RISCV_IOMMU_FQCSR_BUSY, ==, 0);
75 
76     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_PQCSR);
77     g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_PQEN, ==, 0);
78     g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_PIE, ==, 0);
79     g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_PQON, ==, 0);
80     g_assert_cmpuint(reg & RISCV_IOMMU_PQCSR_BUSY, ==, 0);
81 
82     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_DDTP);
83     g_assert_cmpuint(reg & RISCV_IOMMU_DDTP_BUSY, ==, 0);
84     g_assert_cmpuint(reg & RISCV_IOMMU_DDTP_MODE, ==,
85                      RISCV_IOMMU_DDTP_MODE_OFF);
86 
87     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_IPSR);
88     g_assert_cmpuint(reg, ==, 0);
89 }
90 
91 /*
92  * Common timeout-based poll for CQCSR, FQCSR and PQCSR. All
93  * their ON bits are mapped as RISCV_IOMMU_QUEUE_ACTIVE (16),
94  */
95 static void qtest_wait_for_queue_active(QRISCVIOMMU *r_iommu,
96                                         uint32_t queue_csr)
97 {
98     QTestState *qts = global_qtest;
99     guint64 timeout_us = 2 * 1000 * 1000;
100     gint64 start_time = g_get_monotonic_time();
101     uint32_t reg;
102 
103     for (;;) {
104         qtest_clock_step(qts, 100);
105 
106         reg = riscv_iommu_read_reg32(r_iommu, queue_csr);
107         if (reg & RISCV_IOMMU_QUEUE_ACTIVE) {
108             break;
109         }
110         g_assert(g_get_monotonic_time() - start_time <= timeout_us);
111     }
112 }
113 
114 /*
115  * Goes through the queue activation procedures of chapter 6.2,
116  * "Guidelines for initialization", of the RISCV-IOMMU spec.
117  */
118 static void test_iommu_init_queues(void *obj, void *data,
119                                    QGuestAllocator *t_alloc)
120 {
121     QRISCVIOMMU *r_iommu = obj;
122     uint64_t reg64, q_addr;
123     uint32_t reg;
124     int k = 2;
125 
126     reg64 = riscv_iommu_read_reg64(r_iommu, RISCV_IOMMU_REG_CAP);
127     g_assert_cmpuint(reg64 & RISCV_IOMMU_CAP_VERSION, ==, 0x10);
128 
129     /*
130      * Program the command queue. Write 0xF to civ, fiv, pmiv and
131      * piv. With the current PCI device impl we expect 2 writable
132      * bits for each (k = 2) since we have N = 4 total vectors (2^k).
133      */
134     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_IVEC, 0xFFFF);
135     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_IVEC);
136     g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_CIV, ==, 0x3);
137     g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_FIV, ==, 0x30);
138     g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_PMIV, ==, 0x300);
139     g_assert_cmpuint(reg & RISCV_IOMMU_REG_IVEC_PIV, ==, 0x3000);
140 
141     /* Alloc a 4*16 bytes buffer and use it to set cqb */
142     q_addr = guest_alloc(t_alloc, 4 * 16);
143     reg64 = 0;
144     deposit64(reg64, RISCV_IOMMU_CQB_PPN_START,
145               RISCV_IOMMU_CQB_PPN_LEN, q_addr);
146     deposit64(reg64, RISCV_IOMMU_CQB_LOG2SZ_START,
147               RISCV_IOMMU_CQB_LOG2SZ_LEN, k - 1);
148     riscv_iommu_write_reg64(r_iommu, RISCV_IOMMU_REG_CQB, reg64);
149 
150     /* cqt = 0, cqcsr.cqen = 1, poll cqcsr.cqon until it reads 1 */
151     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_CQT, 0);
152 
153     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_CQCSR);
154     reg |= RISCV_IOMMU_CQCSR_CQEN;
155     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_CQCSR, reg);
156 
157     qtest_wait_for_queue_active(r_iommu, RISCV_IOMMU_REG_CQCSR);
158 
159     /*
160      * Program the fault queue. Alloc a 4*32 bytes (instead of 4*16)
161      * buffer and use it to set fqb.
162      */
163     q_addr = guest_alloc(t_alloc, 4 * 32);
164     reg64 = 0;
165     deposit64(reg64, RISCV_IOMMU_FQB_PPN_START,
166               RISCV_IOMMU_FQB_PPN_LEN, q_addr);
167     deposit64(reg64, RISCV_IOMMU_FQB_LOG2SZ_START,
168               RISCV_IOMMU_FQB_LOG2SZ_LEN, k - 1);
169     riscv_iommu_write_reg64(r_iommu, RISCV_IOMMU_REG_FQB, reg64);
170 
171     /* fqt = 0, fqcsr.fqen = 1, poll fqcsr.fqon until it reads 1 */
172     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_FQT, 0);
173 
174     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_FQCSR);
175     reg |= RISCV_IOMMU_FQCSR_FQEN;
176     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_FQCSR, reg);
177 
178     qtest_wait_for_queue_active(r_iommu, RISCV_IOMMU_REG_FQCSR);
179 
180     /*
181      * Program the page-request queue. Alloc a 4*16 bytes buffer
182      * and use it to set pqb.
183      */
184     q_addr = guest_alloc(t_alloc, 4 * 16);
185     reg64 = 0;
186     deposit64(reg64, RISCV_IOMMU_PQB_PPN_START,
187               RISCV_IOMMU_PQB_PPN_LEN, q_addr);
188     deposit64(reg64, RISCV_IOMMU_PQB_LOG2SZ_START,
189               RISCV_IOMMU_PQB_LOG2SZ_LEN, k - 1);
190     riscv_iommu_write_reg64(r_iommu, RISCV_IOMMU_REG_PQB, reg64);
191 
192     /* pqt = 0, pqcsr.pqen = 1, poll pqcsr.pqon until it reads 1 */
193     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_PQT, 0);
194 
195     reg = riscv_iommu_read_reg32(r_iommu, RISCV_IOMMU_REG_PQCSR);
196     reg |= RISCV_IOMMU_PQCSR_PQEN;
197     riscv_iommu_write_reg32(r_iommu, RISCV_IOMMU_REG_PQCSR, reg);
198 
199     qtest_wait_for_queue_active(r_iommu, RISCV_IOMMU_REG_PQCSR);
200 }
201 
202 static void register_riscv_iommu_test(void)
203 {
204     qos_add_test("pci_config", "riscv-iommu-pci", test_pci_config, NULL);
205     qos_add_test("reg_reset", "riscv-iommu-pci", test_reg_reset, NULL);
206     qos_add_test("iommu_init_queues", "riscv-iommu-pci",
207                  test_iommu_init_queues, NULL);
208 }
209 
210 libqos_init(register_riscv_iommu_test);
211