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 report_prefix_push("vtd_dmar"); 25 26 #define DMA_TEST_WORD (0x12345678) 27 /* Modify the first 4 bytes of the page */ 28 *(uint32_t *)page = DMA_TEST_WORD; 29 30 /* 31 * Map the newly allocated page into IOVA address 0 (size 4K) 32 * of the device address space. Root entry and context entry 33 * will be automatically created when needed. 34 */ 35 vtd_map_range(dev->pci_dev.bdf, 0, virt_to_phys(page), PAGE_SIZE); 36 37 /* 38 * DMA the first 4 bytes of the page to EDU device buffer 39 * offset 0. 40 */ 41 edu_dma(dev, 0, 4, 0, false); 42 43 /* 44 * DMA the first 4 bytes of EDU device buffer into the page 45 * with offset 4 (so it'll be using 4-7 bytes). 46 */ 47 edu_dma(dev, 4, 4, 0, true); 48 49 /* 50 * Check data match between 0-3 bytes and 4-7 bytes of the 51 * page. 52 */ 53 report(VTD_TEST_DMAR_4B, *((uint32_t *)page + 1) == DMA_TEST_WORD); 54 55 free_page(page); 56 57 report_prefix_pop(); 58 } 59 60 static volatile bool edu_intr_recved; 61 62 static void edu_isr(isr_regs_t *regs) 63 { 64 edu_intr_recved = true; 65 eoi(); 66 } 67 68 static void vtd_test_ir(struct pci_edu_dev *dev) 69 { 70 #define VTD_TEST_VECTOR (0xee) 71 report_prefix_push("vtd_ir"); 72 73 /* 74 * Setup EDU PCI device MSI, using interrupt remapping. By 75 * default, EDU device is using INTx. 76 */ 77 if (!vtd_setup_msi(&dev->pci_dev, VTD_TEST_VECTOR, 0)) { 78 printf("edu device does not support MSI, skip test\n"); 79 report_skip(VTD_TEST_IR_MSI); 80 return; 81 } 82 83 handle_irq(VTD_TEST_VECTOR, edu_isr); 84 irq_enable(); 85 86 /* Manually trigger INTR */ 87 edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1); 88 89 while (!edu_intr_recved) 90 cpu_relax(); 91 92 /* Clear INTR bits */ 93 edu_reg_writel(dev, EDU_REG_INTR_RAISE, 0); 94 95 /* We are good as long as we reach here */ 96 report(VTD_TEST_IR_MSI, true); 97 98 report_prefix_pop(); 99 } 100 101 int main(int argc, char *argv[]) 102 { 103 struct pci_edu_dev dev; 104 105 vtd_init(); 106 107 report_prefix_push("vtd_init"); 108 109 report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0); 110 report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI); 111 report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT); 112 report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE); 113 report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR); 114 report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR); 115 report("DMAR support 39 bits address width", 116 vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW); 117 report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS); 118 119 report_prefix_pop(); 120 121 if (!edu_init(&dev)) { 122 printf("Please specify \"-device edu\" to do " 123 "further IOMMU tests.\n"); 124 report_skip(VTD_TEST_DMAR_4B); 125 report_skip(VTD_TEST_IR_MSI); 126 } else { 127 vtd_test_dmar(&dev); 128 vtd_test_ir(&dev); 129 } 130 131 return report_summary(); 132 } 133