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