1 /* 2 * Intel IOMMU unit test. 3 * 4 * Copyright (C) 2016 Red Hat, Inc. 5 * 6 * Authors: 7 * Peter Xu <peterx@redhat.com>, 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2 or 10 * later. 11 */ 12 13 #include "intel-iommu.h" 14 #include "pci-edu.h" 15 #include "x86/apic.h" 16 17 #define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test") 18 #define VTD_TEST_IR_MSI ("IR MSI") 19 20 void vtd_test_dmar(struct pci_edu_dev *dev) 21 { 22 void *page = alloc_page(); 23 24 #define DMA_TEST_WORD (0x12345678) 25 /* Modify the first 4 bytes of the page */ 26 *(uint32_t *)page = DMA_TEST_WORD; 27 28 /* 29 * Map the newly allocated page into IOVA address 0 (size 4K) 30 * of the device address space. Root entry and context entry 31 * will be automatically created when needed. 32 */ 33 vtd_map_range(dev->pci_dev.bdf, 0, virt_to_phys(page), PAGE_SIZE); 34 35 /* 36 * DMA the first 4 bytes of the page to EDU device buffer 37 * offset 0. 38 */ 39 edu_dma(dev, 0, 4, 0, false); 40 41 /* 42 * DMA the first 4 bytes of EDU device buffer into the page 43 * with offset 4 (so it'll be using 4-7 bytes). 44 */ 45 edu_dma(dev, 4, 4, 0, true); 46 47 /* 48 * Check data match between 0-3 bytes and 4-7 bytes of the 49 * page. 50 */ 51 report(VTD_TEST_DMAR_4B, *((uint32_t *)page + 1) == DMA_TEST_WORD); 52 53 free_page(page); 54 } 55 56 static volatile bool edu_intr_recved; 57 58 static void edu_isr(isr_regs_t *regs) 59 { 60 edu_intr_recved = true; 61 eoi(); 62 } 63 64 static void vtd_test_ir(struct pci_edu_dev *dev) 65 { 66 #define VTD_TEST_VECTOR (0xee) 67 /* 68 * Setup EDU PCI device MSI, using interrupt remapping. By 69 * default, EDU device is using INTx. 70 */ 71 if (!vtd_setup_msi(&dev->pci_dev, VTD_TEST_VECTOR, 0)) { 72 printf("edu device does not support MSI, skip test\n"); 73 report_skip(VTD_TEST_IR_MSI); 74 return; 75 } 76 77 handle_irq(VTD_TEST_VECTOR, edu_isr); 78 irq_enable(); 79 80 /* Manually trigger INTR */ 81 edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1); 82 83 while (!edu_intr_recved) 84 cpu_relax(); 85 86 /* Clear INTR bits */ 87 edu_reg_writel(dev, EDU_REG_INTR_RAISE, 0); 88 89 /* We are good as long as we reach here */ 90 report(VTD_TEST_IR_MSI, true); 91 } 92 93 int main(int argc, char *argv[]) 94 { 95 struct pci_edu_dev dev; 96 97 vtd_init(); 98 99 report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0); 100 report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI); 101 report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT); 102 report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE); 103 report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR); 104 report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR); 105 report("DMAR support 39 bits address width", 106 vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW); 107 report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS); 108 109 if (!edu_init(&dev)) { 110 printf("Please specify \"-device edu\" to do " 111 "further IOMMU tests.\n"); 112 report_skip(VTD_TEST_DMAR_4B); 113 report_skip(VTD_TEST_IR_MSI); 114 } else { 115 vtd_test_dmar(&dev); 116 vtd_test_ir(&dev); 117 } 118 119 return report_summary(); 120 } 121