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