From: Keir Fraser Date: Fri, 17 Apr 2009 12:16:39 +0000 (+0100) Subject: AMD IOMMU: Fix ioapic interrupt remapping X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~13969 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=7fdf62c44f22dd684b7c8747c32a33ef1e622ad6;p=xen.git AMD IOMMU: Fix ioapic interrupt remapping A few ioapic redirection entries are initialized by hypervisor before enabling iommu hardware. This patch copies those entries from ioapic redirection table into interrupt remapping table after interrupt remapping table has been allocated. Signed-off-by: Wei Wang --- diff --git a/xen/drivers/passthrough/amd/iommu_intr.c b/xen/drivers/passthrough/amd/iommu_intr.c index c3a9dc81b8..4774431204 100644 --- a/xen/drivers/passthrough/amd/iommu_intr.c +++ b/xen/drivers/passthrough/amd/iommu_intr.c @@ -108,8 +108,17 @@ static void update_intremap_entry_from_ioapic( return; } +extern int nr_ioapic_registers[MAX_IO_APICS]; +extern int nr_ioapics; + int __init amd_iommu_setup_intremap_table(void) { + struct IO_APIC_route_entry rte = {0}; + unsigned long flags; + u32* entry; + int apic, pin; + u8 delivery_mode, dest, vector, dest_mode; + if ( int_remap_table == NULL ) { int_remap_table = __alloc_amd_iommu_tables(INTREMAP_TABLE_ORDER); @@ -118,6 +127,31 @@ int __init amd_iommu_setup_intremap_table(void) memset(int_remap_table, 0, PAGE_SIZE * (1UL << INTREMAP_TABLE_ORDER)); } + /* Read ioapic entries and update interrupt remapping table accordingly */ + for ( apic = 0; apic < nr_ioapics; apic++ ) + { + for ( pin = 0; pin < nr_ioapic_registers[apic]; pin++ ) + { + *(((int *)&rte) + 1) = io_apic_read(apic, 0x11 + 2 * pin); + *(((int *)&rte) + 0) = io_apic_read(apic, 0x10 + 2 * pin); + + if ( rte.mask == 1 ) + continue; + + delivery_mode = rte.delivery_mode; + vector = rte.vector; + dest_mode = rte.dest_mode; + if ( dest_mode == 0 ) + dest = rte.dest.physical.physical_dest & 0xf; + else + dest = rte.dest.logical.logical_dest & 0xff; + + spin_lock_irqsave(&int_remap_table_lock, flags); + entry = (u32*)get_intremap_entry(vector, delivery_mode); + update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest); + spin_unlock_irqrestore(&int_remap_table_lock, flags); + } + } return 0; }