Exercise MRIF-mode MSI writes through iommu-testdev with the destination interrupt-enable bit both clear and set. Each case requires the pending bit to be stored plus the configured notice ID to reach guest memory.
The enable-clear case regresses the notice suppression fixed by the previous patch. The enable-set case provides a control for the existing path. Signed-off-by: Flavien Solt <[email protected]> Reviewed-by: Chao Liu <[email protected]> --- tests/qtest/iommu-riscv-test.c | 102 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/qtest/iommu-riscv-test.c b/tests/qtest/iommu-riscv-test.c index 2638024..85f79ea 100644 --- a/tests/qtest/iommu-riscv-test.c +++ b/tests/qtest/iommu-riscv-test.c @@ -14,6 +14,7 @@ #include "hw/pci/pci_regs.h" #include "hw/misc/iommu-testdev.h" #include "hw/riscv/riscv-iommu-bits.h" +#include "libqos/qos-iommu-testdev.h" #include "libqos/qos-riscv-iommu.h" #include "libqos/riscv-iommu.h" @@ -26,6 +27,13 @@ #define RISCV_BUS_MMIO_LIMIT 0x80000000 #define RISCV_ECAM_ALLOC_PTR 0x30000000 +#define RISCV_MRIF_MSI_IOVA 0x00000000fee00000ull +#define RISCV_MRIF_MSI_PT_GPA (QRIOMMU_SPACE_OFFS + 0x00030000ull) +#define RISCV_MRIF_BASE_GPA (QRIOMMU_SPACE_OFFS + 0x00031000ull) +#define RISCV_MRIF_NOTICE_GPA (QRIOMMU_SPACE_OFFS + 0x00032000ull) +#define RISCV_MRIF_INTID 5u +#define RISCV_MRIF_NOTICE_ID 0x12du + typedef struct RiscvIommuTestState { QTestState *qts; QGenericPCIBus gbus; @@ -264,6 +272,96 @@ static void test_riscv_iommu_nested(void) run_riscv_iommu_translation(&cfg); } +static void riscv_iommu_setup_mrif_context(RiscvIommuTestState *state) +{ + uint64_t dc_addr; + uint64_t msiptp; + uint64_t pte0; + uint64_t pte1; + + qtest_memset(state->qts, QRIOMMU_SPACE_OFFS + QRIOMMU_DDT_BASE, 0, + 0x1000); + qtest_memset(state->qts, RISCV_MRIF_MSI_PT_GPA, 0, 0x1000); + qtest_memset(state->qts, RISCV_MRIF_BASE_GPA, 0, 0x1000); + qtest_memset(state->qts, RISCV_MRIF_NOTICE_GPA, 0, 4); + + dc_addr = QRIOMMU_SPACE_OFFS + QRIOMMU_DDT_BASE + + state->testdev->devfn * sizeof(struct riscv_iommu_dc); + + msiptp = (RISCV_MRIF_MSI_PT_GPA >> 12) | + ((uint64_t)RISCV_IOMMU_DC_MSIPTP_MODE_FLAT << 60); + + qtest_writeq(state->qts, dc_addr + 0, RISCV_IOMMU_DC_TC_V); + qtest_writeq(state->qts, dc_addr + 8, 0); + qtest_writeq(state->qts, dc_addr + 16, 0); + qtest_writeq(state->qts, dc_addr + 24, 0); + qtest_writeq(state->qts, dc_addr + 32, msiptp); + qtest_writeq(state->qts, dc_addr + 40, 0); + qtest_writeq(state->qts, dc_addr + 48, RISCV_MRIF_MSI_IOVA >> 12); + qtest_writeq(state->qts, dc_addr + 56, 0); + + pte0 = RISCV_IOMMU_MSI_PTE_V | + ((uint64_t)RISCV_IOMMU_MSI_PTE_M_MRIF << 1) | + ((RISCV_MRIF_BASE_GPA >> 9) << 7); + pte1 = ((RISCV_MRIF_NOTICE_GPA >> 12) << 10) | RISCV_MRIF_NOTICE_ID; + + qtest_writeq(state->qts, RISCV_MRIF_MSI_PT_GPA, pte0); + qtest_writeq(state->qts, RISCV_MRIF_MSI_PT_GPA + 8, pte1); + + qriommu_program_regs(state->qts, state->iommu_base); +} + +static void run_riscv_iommu_mrif_notice(bool enable_bit) +{ + RiscvIommuTestState state = { 0 }; + uint64_t pending; + uint64_t enabled; + uint32_t notice; + uint32_t dma_result; + + if (!riscv_iommu_test_setup(&state)) { + return; + } + + riscv_iommu_check(state.qts, state.iommu_base, QRIOMMU_TM_BARE); + riscv_iommu_setup_mrif_context(&state); + + enabled = enable_bit ? (1ull << RISCV_MRIF_INTID) : 0; + qtest_writeq(state.qts, RISCV_MRIF_BASE_GPA + 8, enabled); + qpci_io_writel(state.testdev, state.testdev_bar, ITD_REG_DMA_WRITE_VAL, + RISCV_MRIF_INTID); + + dma_result = qos_iommu_testdev_trigger_dma( + state.testdev, state.testdev_bar, RISCV_MRIF_MSI_IOVA, + RISCV_MRIF_NOTICE_GPA, DMA_LEN, qriommu_build_dma_attrs()); + + pending = qtest_readq(state.qts, RISCV_MRIF_BASE_GPA); + notice = qtest_readl(state.qts, RISCV_MRIF_NOTICE_GPA); + + g_test_message("MRIF notice: enable=%u pending=0x%" PRIx64 + " notice=0x%x", enable_bit, pending, notice); + + /* + * Interrupt remapping consumes the original DMA write; the generic + * test device cannot read it back from the supplied physical address. + */ + g_assert_cmpuint(dma_result, ==, ITD_DMA_ERR_MISMATCH); + g_assert_cmpuint(pending & (1ull << RISCV_MRIF_INTID), !=, 0); + g_assert_cmpuint(notice, ==, RISCV_MRIF_NOTICE_ID); + + riscv_iommu_test_teardown(&state); +} + +static void test_riscv_iommu_mrif_notice_enable_clear(void) +{ + run_riscv_iommu_mrif_notice(false); +} + +static void test_riscv_iommu_mrif_notice_enable_set(void) +{ + run_riscv_iommu_mrif_notice(true); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -275,5 +373,9 @@ int main(int argc, char **argv) test_riscv_iommu_g_stage_only); qtest_add_func("/iommu-testdev/translation/ns-nested", test_riscv_iommu_nested); + qtest_add_func("/iommu-testdev/mrif-notice/enable-clear", + test_riscv_iommu_mrif_notice_enable_clear); + qtest_add_func("/iommu-testdev/mrif-notice/enable-set", + test_riscv_iommu_mrif_notice_enable_set); return g_test_run(); } -- 2.54.0
