116c0b05fSPeter Xu /* 216c0b05fSPeter Xu * Intel IOMMU unit test. 316c0b05fSPeter Xu * 416c0b05fSPeter Xu * Copyright (C) 2016 Red Hat, Inc. 516c0b05fSPeter Xu * 616c0b05fSPeter Xu * Authors: 716c0b05fSPeter Xu * Peter Xu <peterx@redhat.com>, 816c0b05fSPeter Xu * 916c0b05fSPeter Xu * This work is licensed under the terms of the GNU LGPL, version 2 or 1016c0b05fSPeter Xu * later. 1116c0b05fSPeter Xu */ 1216c0b05fSPeter Xu 1316c0b05fSPeter Xu #include "intel-iommu.h" 14*92d2c192SPeter Xu #include "pci-edu.h" 15*92d2c192SPeter Xu 16*92d2c192SPeter Xu #define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test") 17*92d2c192SPeter Xu 18*92d2c192SPeter Xu void vtd_test_dmar(struct pci_edu_dev *dev) 19*92d2c192SPeter Xu { 20*92d2c192SPeter Xu void *page = alloc_page(); 21*92d2c192SPeter Xu 22*92d2c192SPeter Xu #define DMA_TEST_WORD (0x12345678) 23*92d2c192SPeter Xu /* Modify the first 4 bytes of the page */ 24*92d2c192SPeter Xu *(uint32_t *)page = DMA_TEST_WORD; 25*92d2c192SPeter Xu 26*92d2c192SPeter Xu /* 27*92d2c192SPeter Xu * Map the newly allocated page into IOVA address 0 (size 4K) 28*92d2c192SPeter Xu * of the device address space. Root entry and context entry 29*92d2c192SPeter Xu * will be automatically created when needed. 30*92d2c192SPeter Xu */ 31*92d2c192SPeter Xu vtd_map_range(dev->pci_dev.bdf, 0, virt_to_phys(page), PAGE_SIZE); 32*92d2c192SPeter Xu 33*92d2c192SPeter Xu /* 34*92d2c192SPeter Xu * DMA the first 4 bytes of the page to EDU device buffer 35*92d2c192SPeter Xu * offset 0. 36*92d2c192SPeter Xu */ 37*92d2c192SPeter Xu edu_dma(dev, 0, 4, 0, false); 38*92d2c192SPeter Xu 39*92d2c192SPeter Xu /* 40*92d2c192SPeter Xu * DMA the first 4 bytes of EDU device buffer into the page 41*92d2c192SPeter Xu * with offset 4 (so it'll be using 4-7 bytes). 42*92d2c192SPeter Xu */ 43*92d2c192SPeter Xu edu_dma(dev, 4, 4, 0, true); 44*92d2c192SPeter Xu 45*92d2c192SPeter Xu /* 46*92d2c192SPeter Xu * Check data match between 0-3 bytes and 4-7 bytes of the 47*92d2c192SPeter Xu * page. 48*92d2c192SPeter Xu */ 49*92d2c192SPeter Xu report(VTD_TEST_DMAR_4B, *((uint32_t *)page + 1) == DMA_TEST_WORD); 50*92d2c192SPeter Xu 51*92d2c192SPeter Xu free_page(page); 52*92d2c192SPeter Xu } 5316c0b05fSPeter Xu 5416c0b05fSPeter Xu int main(int argc, char *argv[]) 5516c0b05fSPeter Xu { 56*92d2c192SPeter Xu struct pci_edu_dev dev; 57*92d2c192SPeter Xu 5816c0b05fSPeter Xu vtd_init(); 5916c0b05fSPeter Xu 6016c0b05fSPeter Xu report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0); 6116c0b05fSPeter Xu report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI); 6216c0b05fSPeter Xu report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT); 6316c0b05fSPeter Xu report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE); 6416c0b05fSPeter Xu report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR); 6516c0b05fSPeter Xu report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR); 66*92d2c192SPeter Xu report("DMAR support 39 bits address width", 67*92d2c192SPeter Xu vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW); 68*92d2c192SPeter Xu report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS); 69*92d2c192SPeter Xu 70*92d2c192SPeter Xu if (!edu_init(&dev)) { 71*92d2c192SPeter Xu printf("Please specify \"-device edu\" to do " 72*92d2c192SPeter Xu "further IOMMU tests.\n"); 73*92d2c192SPeter Xu report_skip(VTD_TEST_DMAR_4B); 74*92d2c192SPeter Xu } else 75*92d2c192SPeter Xu vtd_test_dmar(&dev); 7616c0b05fSPeter Xu 7716c0b05fSPeter Xu return report_summary(); 7816c0b05fSPeter Xu } 79