IOAPIC irqs are line-based irqs comparing to MSI ones (which are memory-based). To make it complete, let's also test IOAPIC interrupts in the IR testcase. Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> --- lib/x86/intel-iommu.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/x86/intel-iommu.h | 3 +++ x86/intel-iommu.c | 38 +++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c index 0585248..1629920 100644 --- a/lib/x86/intel-iommu.c +++ b/lib/x86/intel-iommu.c @@ -284,6 +284,21 @@ struct vtd_msi_data { } __attribute__ ((packed)); typedef struct vtd_msi_data vtd_msi_data_t; +struct vtd_ioapic_entry { + uint64_t vector:8; + uint64_t __zeros:3; + uint64_t index_15:1; + uint64_t delivery_status:1; + uint64_t polarity:1; + uint64_t remote_irr:1; + uint64_t trigger_mode:1; + uint64_t mask:1; + uint64_t __zeros_2:31; + uint64_t interrupt_format:1; + uint64_t index_0_14:15; +} __attribute__ ((packed)); +typedef struct vtd_ioapic_entry vtd_ioapic_entry_t; + /** * vtd_setup_msi - setup MSI message for a device * @@ -316,6 +331,31 @@ bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id) *(uint32_t *)&msi_data); } +void vtd_setup_ioapic_irq(struct pci_dev *dev, int vector, + int dest_id, trigger_mode_t trigger) +{ + vtd_ioapic_entry_t entry = {}; + vtd_irte_t *irte = phys_to_virt(vtd_ir_table()); + ioapic_redir_entry_t *entry_2 = (ioapic_redir_entry_t *)&entry; + uint16_t index = vtd_intr_index_alloc(); + uint8_t line; + + assert(dev); + assert(sizeof(vtd_ioapic_entry_t) == 8); + + vtd_setup_irte(dev, irte + index, vector, + dest_id, trigger); + + entry.vector = vector; + entry.trigger_mode = trigger; + entry.index_15 = (index >> 15) & 1; + entry.interrupt_format = 1; + entry.index_0_14 = index & 0x7fff; + + line = pci_intx_line(dev); + ioapic_write_redir(line, *entry_2); +} + void vtd_init(void) { setup_vm(); diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h index e3e956d..885be53 100644 --- a/lib/x86/intel-iommu.h +++ b/lib/x86/intel-iommu.h @@ -22,6 +22,7 @@ #include "desc.h" #include "pci.h" #include "asm/io.h" +#include "apic.h" #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL #define VTD_PAGE_SHIFT PAGE_SHIFT @@ -142,5 +143,7 @@ static inline uint64_t vtd_readq(unsigned int reg) void vtd_init(void); void vtd_map_range(uint16_t sid, phys_addr_t iova, phys_addr_t pa, size_t size); bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id); +void vtd_setup_ioapic_irq(struct pci_dev *dev, int vector, + int dest_id, trigger_mode_t trigger); #endif diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c index 59171a1..5a65232 100644 --- a/x86/intel-iommu.c +++ b/x86/intel-iommu.c @@ -16,6 +16,7 @@ #define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test") #define VTD_TEST_IR_MSI ("IR MSI") +#define VTD_TEST_IR_IOAPIC ("IR IOAPIC") void vtd_test_dmar(struct pci_edu_dev *dev) { @@ -67,22 +68,48 @@ static void edu_isr(isr_regs_t *regs) static void vtd_test_ir(struct pci_edu_dev *dev) { -#define VTD_TEST_VECTOR (0xee) +#define VTD_TEST_VECTOR_IOAPIC (0xed) +#define VTD_TEST_VECTOR_MSI (0xee) + struct pci_dev *pci_dev = &dev->pci_dev; + report_prefix_push("vtd_ir"); + irq_enable(); + + /* This will enable INTx */ + pci_msi_set_enable(pci_dev, false); + vtd_setup_ioapic_irq(pci_dev, VTD_TEST_VECTOR_IOAPIC, + 0, TRIGGER_EDGE); + handle_irq(VTD_TEST_VECTOR_IOAPIC, edu_isr); + + edu_intr_recved = false; + wmb(); + /* Manually trigger INTR */ + edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1); + + while (!edu_intr_recved) + cpu_relax(); + + /* Clear INTR bits */ + edu_reg_writel(dev, EDU_REG_INTR_RAISE, 0); + + /* We are good as long as we reach here */ + report(VTD_TEST_IR_IOAPIC, edu_intr_recved == true); + /* * Setup EDU PCI device MSI, using interrupt remapping. By * default, EDU device is using INTx. */ - if (!vtd_setup_msi(&dev->pci_dev, VTD_TEST_VECTOR, 0)) { + if (!vtd_setup_msi(pci_dev, VTD_TEST_VECTOR_MSI, 0)) { printf("edu device does not support MSI, skip test\n"); report_skip(VTD_TEST_IR_MSI); return; } - handle_irq(VTD_TEST_VECTOR, edu_isr); - irq_enable(); + handle_irq(VTD_TEST_VECTOR_MSI, edu_isr); + edu_intr_recved = false; + wmb(); /* Manually trigger INTR */ edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1); @@ -93,7 +120,7 @@ static void vtd_test_ir(struct pci_edu_dev *dev) edu_reg_writel(dev, EDU_REG_INTR_RAISE, 0); /* We are good as long as we reach here */ - report(VTD_TEST_IR_MSI, true); + report(VTD_TEST_IR_MSI, edu_intr_recved == true); report_prefix_pop(); } @@ -122,6 +149,7 @@ int main(int argc, char *argv[]) printf("Please specify \"-device edu\" to do " "further IOMMU tests.\n"); report_skip(VTD_TEST_DMAR_4B); + report_skip(VTD_TEST_IR_IOAPIC); report_skip(VTD_TEST_IR_MSI); } else { vtd_test_dmar(&dev); -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html