aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-04-17 13:16:39 +0100
committerKeir Fraser <keir.fraser@citrix.com>2009-04-17 13:16:39 +0100
commit7fdf62c44f22dd684b7c8747c32a33ef1e622ad6 (patch)
tree5437214b7fb4ad6ff0f77fa4be85c32be478d937
parentede78f509c7f2b79d741e450bfca7b8d4a262b94 (diff)
downloadxen-7fdf62c44f22dd684b7c8747c32a33ef1e622ad6.tar.gz
xen-7fdf62c44f22dd684b7c8747c32a33ef1e622ad6.tar.bz2
xen-7fdf62c44f22dd684b7c8747c32a33ef1e622ad6.zip
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 <wei.wang2@amd.com>
-rw-r--r--xen/drivers/passthrough/amd/iommu_intr.c34
1 files changed, 34 insertions, 0 deletions
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;
}