Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 4552

kernel-2.6.18-194.11.1.el5.src.rpm

From: Bhavna Sarathy <bnagendr@redhat.com>
Date: Thu, 22 Oct 2009 20:00:17 -0400
Subject: [xen] support interrupt remapping on M-C
Message-id: <20091022200237.3419.52246.sendpatchset@localhost.localdomain>
Patchwork-id: 21201
O-Subject: [RHEL5.5 PATCH 2/5] Support interrupt remapping on M-C
Bugzilla: 518474 526766
RH-Acked-by: Christopher Lalancette <clalance@redhat.com>

Resolves BZ 526766 and 518474

diff --git a/drivers/passthrough/amd/iommu_acpi.c b/drivers/passthrough/amd/iommu_acpi.c
index 06f3b9f..a54227c 100644
--- a/drivers/passthrough/amd/iommu_acpi.c
+++ b/drivers/passthrough/amd/iommu_acpi.c
@@ -28,6 +28,53 @@ extern unsigned long amd_iommu_page_entries;
 extern unsigned short ivrs_bdf_entries;
 extern struct ivrs_mappings *ivrs_mappings;
 extern unsigned short last_bdf;
+extern int ioapic_bdf[MAX_IO_APICS];
+unsigned int parse_ivrs_table_error;
+
+static void add_ivrs_mapping_entry(
+            u16 bdf, u16 alias_id, u8 flags, struct amd_iommu *iommu)
+{
+    u8 sys_mgt, lint1_pass, lint0_pass, nmi_pass, ext_int_pass, init_pass;
+    ASSERT( ivrs_mappings != NULL );
+    
+    /* setup requestor id */
+    ivrs_mappings[bdf].dte_requestor_id = alias_id;
+
+    /* override flags for range of devices */
+    sys_mgt = get_field_from_byte(flags,
+                                  AMD_IOMMU_ACPI_SYS_MGT_MASK,
+                                  AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
+    lint1_pass = get_field_from_byte(flags,
+                                     AMD_IOMMU_ACPI_LINT1_PASS_MASK,
+                                     AMD_IOMMU_ACPI_LINT1_PASS_SHIFT);
+    lint0_pass = get_field_from_byte(flags,
+                                     AMD_IOMMU_ACPI_LINT0_PASS_MASK,
+                                     AMD_IOMMU_ACPI_LINT0_PASS_SHIFT);
+    nmi_pass = get_field_from_byte(flags,
+                                   AMD_IOMMU_ACPI_NMI_PASS_MASK,
+                                   AMD_IOMMU_ACPI_NMI_PASS_SHIFT);
+    ext_int_pass = get_field_from_byte(flags,
+                                       AMD_IOMMU_ACPI_EINT_PASS_MASK,
+                                       AMD_IOMMU_ACPI_EINT_PASS_SHIFT);
+    init_pass = get_field_from_byte(flags,
+                                    AMD_IOMMU_ACPI_INIT_PASS_MASK,
+                                    AMD_IOMMU_ACPI_INIT_PASS_SHIFT);
+    
+    ivrs_mappings[bdf].dte_sys_mgt_enable = sys_mgt;
+    ivrs_mappings[bdf].dte_lint1_pass = lint1_pass;
+    ivrs_mappings[bdf].dte_lint0_pass = lint0_pass;
+    ivrs_mappings[bdf].dte_nmi_pass = nmi_pass;
+    ivrs_mappings[bdf].dte_ext_int_pass = ext_int_pass;
+    ivrs_mappings[bdf].dte_init_pass = init_pass;
+    
+    /* allocate per-device interrupt remapping table */
+    if ( ivrs_mappings[alias_id].intremap_table == NULL )
+        ivrs_mappings[alias_id].intremap_table =
+            amd_iommu_alloc_intremap_table();
+    /* assgin iommu hardware */
+    ivrs_mappings[bdf].iommu = iommu;
+}
+
 
 static struct amd_iommu * __init find_iommu_from_bdf_cap(
     u16 bdf, u8 cap_offset)
@@ -368,11 +415,7 @@ static u16 __init parse_ivhd_device_select(
     }
 
     /* override flags for device */
-    ivrs_mappings[bdf].dte_sys_mgt_enable =
-        get_field_from_byte(ivhd_device->header.flags,
-                            AMD_IOMMU_ACPI_SYS_MGT_MASK,
-                            AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
-    ivrs_mappings[bdf].iommu = iommu;
+    add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu);
 
     return sizeof(struct acpi_ivhd_device_header);
 }
@@ -382,7 +425,6 @@ static u16 __init parse_ivhd_device_range(
     u16 header_length, u16 block_length, struct amd_iommu *iommu)
 {
     u16 dev_length, first_bdf, last_bdf, bdf;
-    u8 sys_mgt;
 
     dev_length = sizeof(struct acpi_ivhd_device_range);
     if ( header_length < (block_length + dev_length) )
@@ -418,15 +460,8 @@ static u16 __init parse_ivhd_device_range(
 
     amd_iov_info(" Dev_Id Range: 0x%x -> 0x%x\n", first_bdf, last_bdf);
 
-    /* override flags for range of devices */
-    sys_mgt = get_field_from_byte(ivhd_device->header.flags,
-                                  AMD_IOMMU_ACPI_SYS_MGT_MASK,
-                                  AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
     for ( bdf = first_bdf; bdf <= last_bdf; bdf++ )
-    {
-        ivrs_mappings[bdf].dte_sys_mgt_enable = sys_mgt;
-        ivrs_mappings[bdf].iommu = iommu;
-    }
+        add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu);
 
     return dev_length;
 }
@@ -461,16 +496,7 @@ static u16 __init parse_ivhd_device_alias(
     amd_iov_info(" Dev_Id Alias: 0x%x\n", alias_id);
 
     /* override requestor_id and flags for device */
-    ivrs_mappings[bdf].dte_requestor_id = alias_id;
-    ivrs_mappings[bdf].dte_sys_mgt_enable =
-        get_field_from_byte(ivhd_device->header.flags,
-                            AMD_IOMMU_ACPI_SYS_MGT_MASK,
-                            AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
-    ivrs_mappings[bdf].iommu = iommu;
-
-    ivrs_mappings[alias_id].dte_sys_mgt_enable =
-        ivrs_mappings[bdf].dte_sys_mgt_enable;
-    ivrs_mappings[alias_id].iommu = iommu;
+    add_ivrs_mapping_entry(bdf, alias_id, ivhd_device->header.flags, iommu);
 
     return dev_length;
 }
@@ -481,7 +507,6 @@ static u16 __init parse_ivhd_device_alias_range(
 {
 
     u16 dev_length, first_bdf, last_bdf, alias_id, bdf;
-    u8 sys_mgt;
 
     dev_length = sizeof(struct acpi_ivhd_device_alias_range);
     if ( header_length < (block_length + dev_length) )
@@ -526,17 +551,9 @@ static u16 __init parse_ivhd_device_alias_range(
     amd_iov_info(" Dev_Id Alias: 0x%x\n", alias_id);
 
     /* override requestor_id and flags for range of devices */
-    sys_mgt = get_field_from_byte(ivhd_device->header.flags,
-                                  AMD_IOMMU_ACPI_SYS_MGT_MASK,
-                                  AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
     for ( bdf = first_bdf; bdf <= last_bdf; bdf++ )
-    {
-        ivrs_mappings[bdf].dte_requestor_id = alias_id;
-        ivrs_mappings[bdf].dte_sys_mgt_enable = sys_mgt;
-        ivrs_mappings[bdf].iommu = iommu;
-    }
-    ivrs_mappings[alias_id].dte_sys_mgt_enable = sys_mgt;
-    ivrs_mappings[alias_id].iommu = iommu;
+        add_ivrs_mapping_entry(bdf, alias_id, ivhd_device->header.flags, 
+                               iommu);
 
     return dev_length;
 }
@@ -562,11 +579,7 @@ static u16 __init parse_ivhd_device_extended(
     }
 
     /* override flags for device */
-    ivrs_mappings[bdf].dte_sys_mgt_enable =
-        get_field_from_byte(ivhd_device->header.flags,
-                            AMD_IOMMU_ACPI_SYS_MGT_MASK,
-                            AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
-    ivrs_mappings[bdf].iommu = iommu;
+    add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu);
 
     return dev_length;
 }
@@ -576,7 +589,6 @@ static u16 __init parse_ivhd_device_extended_range(
     u16 header_length, u16 block_length, struct amd_iommu *iommu)
 {
     u16 dev_length, first_bdf, last_bdf, bdf;
-    u8 sys_mgt;
 
     dev_length = sizeof(struct acpi_ivhd_device_extended_range);
     if ( header_length < (block_length + dev_length) )
@@ -614,18 +626,39 @@ static u16 __init parse_ivhd_device_extended_range(
             first_bdf, last_bdf);
 
     /* override flags for range of devices */
-    sys_mgt = get_field_from_byte(ivhd_device->header.flags,
-                                  AMD_IOMMU_ACPI_SYS_MGT_MASK,
-                                  AMD_IOMMU_ACPI_SYS_MGT_SHIFT);
     for ( bdf = first_bdf; bdf <= last_bdf; bdf++ )
-    {
-        ivrs_mappings[bdf].dte_sys_mgt_enable = sys_mgt;
-        ivrs_mappings[bdf].iommu = iommu;
-    }
+        add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu);
 
     return dev_length;
 }
 
+static u16 __init parse_ivhd_device_special(
+                  union acpi_ivhd_device *ivhd_device,
+                  u16 header_length, u16 block_length, struct amd_iommu *iommu)
+{
+    u16 dev_length, bdf;
+    
+    dev_length = sizeof(struct acpi_ivhd_device_special);
+    if ( header_length < (block_length + dev_length) )
+    {
+        amd_iov_error("IVHD Error: Invalid Device_Entry Length!\n");
+        return 0;
+    }
+    
+    bdf = ivhd_device->special.dev_id;
+    if ( bdf >= ivrs_bdf_entries )
+    {
+        amd_iov_error("IVHD Error: Invalid Device_Entry Dev_Id 0x%x\n", bdf);
+        return 0;
+    }
+    
+    add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu);
+    /* set device id of ioapic */
+    ioapic_bdf[ivhd_device->special.handle] = bdf;
+    return dev_length;
+ }
+ 
+
 static int __init parse_ivhd_block(struct acpi_ivhd_block_header *ivhd_block)
 {
     union acpi_ivhd_device *ivhd_device;
@@ -701,6 +734,11 @@ static int __init parse_ivhd_block(struct acpi_ivhd_block_header *ivhd_block)
                 ivhd_device,
                 ivhd_block->header.length, block_length, iommu);
             break;
+        case AMD_IOMMU_ACPI_IVHD_DEV_SPECIAL:
+            dev_length = parse_ivhd_device_special(
+                ivhd_device,
+                ivhd_block->header.length, block_length, iommu);
+            break;
         default:
             amd_iov_error("IVHD Error: Invalid Device Type!\n");
             dev_length = 0;
@@ -822,6 +860,8 @@ static int __init parse_ivrs_table(unsigned long phys_addr,
         length += ivrs_block->length;
     }
 
+    /* this will be used in amd_iommu_update_ivrs_mapping_acpi() */
+    parse_ivrs_table_error = error;    
     return error;
 }
 
@@ -925,6 +965,10 @@ static int __init get_last_bdf_ivhd(void *ivhd)
             UPDATE_LAST_BDF(ivhd_device->extended_range.trailer.dev_id)
             dev_length = sizeof(struct acpi_ivhd_device_extended_range);
             break;
+        case AMD_IOMMU_ACPI_IVHD_DEV_SPECIAL:
+            UPDATE_LAST_BDF(ivhd_device->special.dev_id)
+            dev_length = sizeof(struct acpi_ivhd_device_special);
+            break;
         default:
             amd_iov_error("IVHD Error: Invalid Device Type!\n");
             dev_length = 0;
@@ -979,5 +1023,11 @@ int __init amd_iommu_get_ivrs_dev_entries(void)
 
 int __init amd_iommu_update_ivrs_mapping_acpi(void)
 {
-    return acpi_table_parse(ACPI_IVRS, parse_ivrs_table);
+    /* note that acpi_table_parse() function doesn't return value from
+     * parse_ivrs_table(). So we have to get the value from a global variable
+     * parse_ivrs_table_error. 
+     */
+    acpi_table_parse(ACPI_IVRS, parse_ivrs_table);
+
+    return parse_ivrs_table_error;
 }
diff --git a/drivers/passthrough/amd/iommu_init.c b/drivers/passthrough/amd/iommu_init.c
index 1754418..2e29af7 100644
--- a/drivers/passthrough/amd/iommu_init.c
+++ b/drivers/passthrough/amd/iommu_init.c
@@ -589,12 +589,6 @@ static void __init deallocate_iommu_table_struct(
     }
 }
 
-static void __init deallocate_iommu_tables(struct amd_iommu *iommu)
-{
-    deallocate_iommu_table_struct(&iommu->cmd_buffer);
-    deallocate_iommu_table_struct(&iommu->event_log);
-}
-
 static int __init allocate_iommu_table_struct(struct table_struct *table,
                                               const char *name)
 {
@@ -614,39 +608,42 @@ static int __init allocate_iommu_table_struct(struct table_struct *table,
     return 0;
 }
 
-static int __init allocate_iommu_tables(struct amd_iommu *iommu)
+static int __init allocate_cmd_buffer(struct amd_iommu *iommu)
 {
     /* allocate 'command buffer' in power of 2 increments of 4K */
     iommu->cmd_buffer_tail = 0;
-    iommu->cmd_buffer.alloc_size = PAGE_SIZE << get_order_from_bytes(
-        PAGE_ALIGN(amd_iommu_cmd_buffer_entries * IOMMU_CMD_BUFFER_ENTRY_SIZE));
-    iommu->cmd_buffer.entries =
-        iommu->cmd_buffer.alloc_size / IOMMU_CMD_BUFFER_ENTRY_SIZE;
-
-    if ( allocate_iommu_table_struct(&iommu->cmd_buffer, "Command Buffer") != 0 )
-        goto error_out;
+    iommu->cmd_buffer.alloc_size = PAGE_SIZE <<
+        get_order_from_bytes(
+            PAGE_ALIGN(amd_iommu_cmd_buffer_entries *
+                       IOMMU_CMD_BUFFER_ENTRY_SIZE));
+    iommu->cmd_buffer.entries = iommu->cmd_buffer.alloc_size /
+        IOMMU_CMD_BUFFER_ENTRY_SIZE;
+
+    return (allocate_iommu_table_struct(&iommu->cmd_buffer, "Command Buffer"));
+}
 
+static int __init allocate_event_log(struct amd_iommu *iommu)
+{
     /* allocate 'event log' in power of 2 increments of 4K */
     iommu->event_log_head = 0;
-    iommu->event_log.alloc_size = PAGE_SIZE << get_order_from_bytes(
-        PAGE_ALIGN(amd_iommu_event_log_entries * IOMMU_EVENT_LOG_ENTRY_SIZE));
-    iommu->event_log.entries =
-        iommu->event_log.alloc_size / IOMMU_EVENT_LOG_ENTRY_SIZE;
-
-    if ( allocate_iommu_table_struct(&iommu->event_log, "Event Log") != 0 )
-        goto error_out;
-
-    return 0;
-
- error_out:
-    deallocate_iommu_tables(iommu);
-    return -ENOMEM;
+    iommu->event_log.alloc_size = PAGE_SIZE <<
+        get_order_from_bytes(
+            PAGE_ALIGN(amd_iommu_event_log_entries *
+                       IOMMU_EVENT_LOG_ENTRY_SIZE));
+    iommu->event_log.entries = iommu->event_log.alloc_size /
+        IOMMU_EVENT_LOG_ENTRY_SIZE;
+
+    return (allocate_iommu_table_struct(&iommu->event_log, "Event Log"));
 }
 
+
 int __init amd_iommu_init_one(struct amd_iommu *iommu)
 {
 
-    if ( allocate_iommu_tables(iommu) != 0 )
+    if ( allocate_cmd_buffer(iommu) != 0 )
+        goto error_out;
+
+    if ( allocate_event_log(iommu) != 0 )
         goto error_out;
 
     if ( map_iommu_mmio_region(iommu) != 0 )
@@ -665,17 +662,36 @@ error_out:
 void __init amd_iommu_init_cleanup(void)
 {
     struct amd_iommu *iommu, *next;
+    int bdf;
 
     list_for_each_entry_safe ( iommu, next, &amd_iommu_head, list )
     {
         list_del(&iommu->list);
         if ( iommu->enabled )
         {
-            deallocate_iommu_tables(iommu);
+            deallocate_iommu_table_struct(&iommu->cmd_buffer);
+            deallocate_iommu_table_struct(&iommu->event_log);
             unmap_iommu_mmio_region(iommu);
         }
         xfree(iommu);
     }
+
+    /* free interrupt remapping table */
+    for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
+    {
+        if ( ivrs_mappings[bdf].intremap_table )
+            amd_iommu_free_intremap_table(bdf);
+    }
+
+    /* free device table */
+    deallocate_iommu_table_struct(&device_table);
+
+    /* free IVRS_mappings */
+    if ( ivrs_mappings )
+    {
+        xfree(ivrs_mappings);
+        ivrs_mappings = NULL;
+    }
 }
 
 static int __init init_ivrs_mapping(void)
@@ -701,43 +717,109 @@ static int __init init_ivrs_mapping(void)
         ivrs_mappings[bdf].dte_allow_exclusion = IOMMU_CONTROL_DISABLED;
         ivrs_mappings[bdf].unity_map_enable = IOMMU_CONTROL_DISABLED;
         ivrs_mappings[bdf].iommu = NULL;
+
+        ivrs_mappings[bdf].intremap_table = NULL;
+        ivrs_mappings[bdf].dte_lint1_pass = IOMMU_CONTROL_DISABLED;
+        ivrs_mappings[bdf].dte_lint0_pass = IOMMU_CONTROL_DISABLED;
+        ivrs_mappings[bdf].dte_nmi_pass = IOMMU_CONTROL_DISABLED;
+        ivrs_mappings[bdf].dte_ext_int_pass = IOMMU_CONTROL_DISABLED;
+        ivrs_mappings[bdf].dte_init_pass = IOMMU_CONTROL_DISABLED;
+
+        spin_lock_init(&ivrs_mappings[bdf].intremap_lock);
     }
     return 0;
 }
 
 static int __init amd_iommu_setup_device_table(void)
 {
+    int bdf;
+    void *intr_tb, *dte;
+    int sys_mgt, dev_ex, lint1_pass, lint0_pass, nmi_pass, ext_int_pass,
+        init_pass;
+    int iommu_intremap = 1;
+    
+    BUG_ON(ivrs_bdf_entries == 0);
+    
     /* allocate 'device table' on a 4K boundary */
     device_table.alloc_size = PAGE_SIZE << get_order_from_bytes(
         PAGE_ALIGN(ivrs_bdf_entries * IOMMU_DEV_TABLE_ENTRY_SIZE));
     device_table.entries = device_table.alloc_size / IOMMU_DEV_TABLE_ENTRY_SIZE;
 
-    return ( allocate_iommu_table_struct(&device_table, "Device Table") );
+    if ( allocate_iommu_table_struct(&device_table, "Device Table") != 0 )
+        return -ENOMEM;
+
+    /* add device table entries */
+    for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ ) 
+    {
+        intr_tb = ivrs_mappings[bdf].intremap_table;
+        
+        if ( intr_tb )
+        {
+            sys_mgt = ivrs_mappings[bdf].dte_sys_mgt_enable;
+            dev_ex = ivrs_mappings[bdf].dte_allow_exclusion;
+            
+            /* get interrupt remapping settings */
+            lint1_pass = ivrs_mappings[bdf].dte_lint1_pass;
+            lint0_pass = ivrs_mappings[bdf].dte_lint0_pass;
+            nmi_pass = ivrs_mappings[bdf].dte_nmi_pass;
+            ext_int_pass = ivrs_mappings[bdf].dte_ext_int_pass;
+            init_pass = ivrs_mappings[bdf].dte_init_pass;
+
+            /* add device table entry */
+            dte = device_table.buffer + (bdf * IOMMU_DEV_TABLE_ENTRY_SIZE);
+            amd_iommu_add_dev_table_entry(
+                dte, sys_mgt, dev_ex, lint1_pass, lint0_pass,
+                nmi_pass, ext_int_pass, init_pass);
+            
+            iommu_intremap = 1;
+
+            amd_iommu_set_intremap_table(
+                dte, (u64)virt_to_maddr(intr_tb), iommu_intremap);
+
+            amd_iov_info("Add device table entry at DTE:0x%x, "
+                          "intremap_table:%"PRIx64"\n", bdf,
+                          (u64)virt_to_maddr(intr_tb));
+        }
+    }
+    
+    return 0;
 }
 
-int __init amd_iommu_setup_shared_tables(void)
+int __init amd_iommu_init(void)
 {
-    BUG_ON( !ivrs_bdf_entries );
+    struct amd_iommu *iommu;
 
-    if (init_ivrs_mapping() != 0 )
+    BUG_ON( !iommu_found() );
+
+    /* find the max BDF in IRVS table. It will be used in init_ivrs_mapping */
+    ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
+
+    if ( !ivrs_bdf_entries )
         goto error_out;
 
-    if ( amd_iommu_setup_device_table() != 0 )
+    if ( init_ivrs_mapping() != 0 )
         goto error_out;
 
-    if ( amd_iommu_setup_intremap_table() != 0 )
+    /* start to read and store IVRS info into ivrs_mapping structure */
+    if ( amd_iommu_update_ivrs_mapping_acpi() != 0 )
         goto error_out;
 
+    /* initialize io-apic interrupt remapping entries */
+    if ( amd_iommu_setup_ioapic_remapping() != 0 )
+        goto error_out;
+    
+    /* allocate and initiliaze a global device table shared by all iommus */
+    if ( amd_iommu_setup_device_table() != 0 )
+        goto error_out;
+
+    for_each_amd_iommu ( iommu )
+        if ( amd_iommu_init_one(iommu) != 0 )
+            goto error_out;
     return 0;
 
 error_out:
-    deallocate_intremap_table();
-    deallocate_iommu_table_struct(&device_table);
-
-    if ( ivrs_mappings )
-    {
-        xfree(ivrs_mappings);
-        ivrs_mappings = NULL;
-    }
-    return -ENOMEM;
+    amd_iommu_init_cleanup();
+    return -ENODEV;
 }
+
+
diff --git a/drivers/passthrough/amd/iommu_intr.c b/drivers/passthrough/amd/iommu_intr.c
index 4774431..3700737 100644
--- a/drivers/passthrough/amd/iommu_intr.c
+++ b/drivers/passthrough/amd/iommu_intr.c
@@ -22,17 +22,26 @@
 #include <asm/amd-iommu.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 
+int ioapic_bdf[MAX_IO_APICS];
 #define INTREMAP_TABLE_ORDER    1
-static DEFINE_SPINLOCK(int_remap_table_lock);
-void *int_remap_table = NULL;
+extern struct ivrs_mappings *ivrs_mappings;
+extern unsigned short ivrs_bdf_entries;
 
-static u8 *get_intremap_entry(u8 vector, u8 dm)
+static int get_intremap_requestor_id(int bdf)
+{
+    ASSERT( bdf < ivrs_bdf_entries );
+    return ivrs_mappings[bdf].dte_requestor_id;
+}
+
+static u8 *get_intremap_entry(int bdf, u8 vector, u8 dm)
 {
     u8 *table;
     int offset = 0;
-    table = (u8*)int_remap_table;
 
-    BUG_ON( !table );
+
+    table = (u8*)ivrs_mappings[bdf].intremap_table;
+    ASSERT( table != NULL );
+
     offset = (dm << INT_REMAP_INDEX_DM_SHIFT) & INT_REMAP_INDEX_DM_MASK;
     offset |= (vector << INT_REMAP_INDEX_VECTOR_SHIFT ) & 
         INT_REMAP_INDEX_VECTOR_MASK;
@@ -83,6 +92,8 @@ void invalidate_interrupt_table(struct amd_iommu *iommu, u16 device_id)
 }
 
 static void update_intremap_entry_from_ioapic(
+    int bdf,
+    struct amd_iommu *iommu,
     struct IO_APIC_route_entry *ioapic_rte,
     unsigned int rte_upper, unsigned int value)
 {
@@ -90,42 +101,47 @@ static void update_intremap_entry_from_ioapic(
     u32* entry;
     u8 delivery_mode, dest, vector, dest_mode;
     struct IO_APIC_route_entry *rte = ioapic_rte;
+    int req_id;
+
 
-    spin_lock_irqsave(&int_remap_table_lock, flags);
+    req_id = get_intremap_requestor_id(bdf);
 
+    /* only remap interrupt vector when lower 32 bits in ioapic ire changed */
     if ( rte_upper )
     {
-        dest = (value >> 24) & 0xFF;
         delivery_mode = rte->delivery_mode;
         vector = rte->vector;
         dest_mode = rte->dest_mode;
-        entry = (u32*)get_intremap_entry((u8)rte->vector,
-                                        (u8)rte->delivery_mode);
+        dest = rte->dest.logical.logical_dest;
+        
+        spin_lock_irqsave(&ivrs_mappings[req_id].intremap_lock, flags);
+        entry = (u32*)get_intremap_entry(req_id, vector, delivery_mode);
         update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
+        spin_unlock_irqrestore(&ivrs_mappings[req_id].intremap_lock, flags);
+        
+        if ( iommu->enabled )
+        {
+            spin_lock_irqsave(&iommu->lock, flags);
+            invalidate_interrupt_table(iommu, req_id);
+            flush_command_buffer(iommu);
+            spin_unlock_irqrestore(&iommu->lock, flags);
+        }
     }
-
-    spin_unlock_irqrestore(&int_remap_table_lock, flags);
-    return;
 }
 
+
 extern int nr_ioapic_registers[MAX_IO_APICS];
 extern int nr_ioapics;
 
-int __init amd_iommu_setup_intremap_table(void)
+int __init amd_iommu_setup_ioapic_remapping(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);
-        if ( int_remap_table == NULL )
-            return -ENOMEM;
-        memset(int_remap_table, 0, PAGE_SIZE * (1UL << INTREMAP_TABLE_ORDER));
-    }
+    u16 bdf, req_id, bus, devfn;
+    struct amd_iommu *iommu;
 
     /* Read ioapic entries and update interrupt remapping table accordingly */
     for ( apic = 0; apic < nr_ioapics; apic++ )
@@ -138,6 +154,19 @@ int __init amd_iommu_setup_intremap_table(void)
             if ( rte.mask == 1 )
                 continue;
 
+            bdf = ioapic_bdf[IO_APIC_ID(apic)];
+            bus = bdf >> 8;
+            devfn = bdf & 0xFF;
+            iommu = find_iommu_for_device(bus, devfn);
+            
+            if ( !iommu )
+            {
+                amd_iov_info("failed to find iommu for ioapic device "
+                             "id = 0x%x\n", bdf);
+                continue;
+            }
+            
+            req_id = get_intremap_requestor_id(bdf);
             delivery_mode = rte.delivery_mode;
             vector = rte.vector;
             dest_mode = rte.dest_mode;
@@ -146,12 +175,23 @@ int __init amd_iommu_setup_intremap_table(void)
             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);
+            spin_lock_irqsave(&ivrs_mappings[req_id].intremap_lock, flags);
+            entry = (u32*)get_intremap_entry(req_id, vector, delivery_mode);
+            update_intremap_entry(entry, vector, delivery_mode, dest_mode, 
+                                  dest);
+            spin_unlock_irqrestore(&ivrs_mappings[req_id].intremap_lock,
+                                   flags);
+
+            if ( iommu->enabled )
+              {
+                  spin_lock_irqsave(&iommu->lock, flags);
+                  invalidate_interrupt_table(iommu, req_id);
+                  flush_command_buffer(iommu);
+                  spin_unlock_irqrestore(&iommu->lock, flags);
+              }
         }
     }
+
     return 0;
 }
 
@@ -161,12 +201,24 @@ void amd_iommu_ioapic_update_ire(
     struct IO_APIC_route_entry ioapic_rte = { 0 };
     unsigned int rte_upper = (reg & 1) ? 1 : 0;
     int saved_mask;
+    u16 bus, devfn, bdf;
+    struct amd_iommu *iommu;
 
     *IO_APIC_BASE(apic) = reg;
     *(IO_APIC_BASE(apic)+4) = value;
 
-    if ( int_remap_table == NULL )
+    /* get device id of ioapic devices */
+    bdf = ioapic_bdf[IO_APIC_ID(apic)];
+    bus = bdf >> 8;
+    devfn = bdf & 0xFF;
+    iommu = find_iommu_for_device(bus, devfn);
+    if ( !iommu )
+    {
+        amd_iov_error(
+            "Fail to find iommu for ioapic device id = 0x%x\n", bdf);
         return;
+    }
+
     if ( !rte_upper )
         return;
 
@@ -184,7 +236,9 @@ void amd_iommu_ioapic_update_ire(
     *(IO_APIC_BASE(apic)+4) = *(((int *)&ioapic_rte)+0);
     ioapic_rte.mask = saved_mask;
 
-    update_intremap_entry_from_ioapic(&ioapic_rte, rte_upper, value);
+    
+    update_intremap_entry_from_ioapic(bdf, iommu, 
+                                      &ioapic_rte, rte_upper, value);
 
     /* unmask the interrupt after we have updated the intremap table */
     *IO_APIC_BASE(apic) = reg;
@@ -196,26 +250,51 @@ static void update_intremap_entry_from_msi_msg(
 {
     unsigned long flags;
     u32* entry;
-    u16 dev_id;
+    u16 dev_id, alias_id, bus, devfn, req_id;
 
     u8 delivery_mode, dest, vector, dest_mode;
 
     dev_id = (pdev->bus << 8) | pdev->devfn;
+    bus = pdev->bus;
+    devfn = pdev->devfn;
+    req_id = get_dma_requestor_id(dev_id);
 
-    spin_lock_irqsave(&int_remap_table_lock, flags);
+    spin_lock_irqsave(&ivrs_mappings[req_id].intremap_lock, flags);
     dest_mode = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
     delivery_mode = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1;
     vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK;
     dest = (msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff;
 
-    entry = (u32*)get_intremap_entry((u8)vector, (u8)delivery_mode);
+    entry = (u32*)get_intremap_entry(req_id, (u8)vector, (u8)delivery_mode);
     update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
-    spin_unlock_irqrestore(&int_remap_table_lock, flags);
+    spin_unlock_irqrestore(&ivrs_mappings[req_id].intremap_lock, flags);
+    
+    /*
+     * In some special cases, a pci-e device(e.g SATA controller in IDE mode)
+     * will use alias id to index interrupt remapping table.
+     * We have to setup a secondary interrupt remapping entry to satisfy those
+     * devices.
+     */
+    alias_id = get_intremap_requestor_id(dev_id);
+    if ( ( dev_id != alias_id ) &&
+         ivrs_mappings[alias_id].intremap_table != NULL )
+    {
+        spin_lock_irqsave(&ivrs_mappings[alias_id].intremap_lock, flags);
+        entry = (u32*)get_intremap_entry(alias_id, vector, delivery_mode);
+        update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
+        invalidate_interrupt_table(iommu, alias_id);
+        spin_unlock_irqrestore(&ivrs_mappings[alias_id].intremap_lock, flags);
+    }
 
-    spin_lock_irqsave(&iommu->lock, flags);
-    invalidate_interrupt_table(iommu, dev_id);
-    flush_command_buffer(iommu);
-    spin_unlock_irqrestore(&iommu->lock, flags);
+    if ( iommu->enabled )
+    {
+        spin_lock_irqsave(&iommu->lock, flags);
+        invalidate_interrupt_table(iommu, dev_id);
+        if ( alias_id != req_id )
+            invalidate_interrupt_table(iommu, alias_id);
+        flush_command_buffer(iommu);
+        spin_unlock_irqrestore(&iommu->lock, flags);
+    }
 
     return;
 }
@@ -228,19 +307,29 @@ void amd_iommu_msi_msg_update_ire(
 
     iommu = find_iommu_for_device(pdev->bus, pdev->devfn);
 
-    if ( !iommu || !int_remap_table )
+    if ( !iommu )
         return;
 
     update_intremap_entry_from_msi_msg(iommu, pdev, msg);
 }
 
-int __init deallocate_intremap_table(void)
+void __init amd_iommu_free_intremap_table(int bdf)
 {
-    if ( int_remap_table )
+    void *tb = ivrs_mappings[bdf].intremap_table;
+
+    if ( tb )
     {
-        __free_amd_iommu_tables(int_remap_table, INTREMAP_TABLE_ORDER);
-        int_remap_table = NULL;
+        __free_amd_iommu_tables(tb, INTREMAP_TABLE_ORDER);
+        ivrs_mappings[bdf].intremap_table = NULL;
     }
+}
 
-    return 0;
+void* __init amd_iommu_alloc_intremap_table(void)
+{
+    void *tb;
+    tb = __alloc_amd_iommu_tables(INTREMAP_TABLE_ORDER);
+    BUG_ON(tb == NULL);
+    memset(tb, 0, PAGE_SIZE * (1UL << INTREMAP_TABLE_ORDER));
+    return tb;
 }
+
diff --git a/drivers/passthrough/amd/iommu_map.c b/drivers/passthrough/amd/iommu_map.c
index d5ecf65..44d43e4 100644
--- a/drivers/passthrough/amd/iommu_map.c
+++ b/drivers/passthrough/amd/iommu_map.c
@@ -254,72 +254,19 @@ static void amd_iommu_set_page_directory_entry(u32 *pde,
     pde[0] = entry;
 }
 
-void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u64 intremap_ptr,
-                                   u16 domain_id, u8 sys_mgt, u8 dev_ex,
-                                   u8 paging_mode)
+void amd_iommu_set_root_page_table(
+    u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode, u8 valid)
 {
     u64 addr_hi, addr_lo;
     u32 entry;
-
-    dte[7] = dte[6] = 0;
-
-    addr_lo = intremap_ptr & DMA_32BIT_MASK;
-    addr_hi = intremap_ptr >> 32;
-
-    set_field_in_reg_u32((u32)addr_hi, 0,
-                        IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_MASK,
-                        IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                        IOMMU_DEV_TABLE_INIT_PASSTHRU_MASK,
-                        IOMMU_DEV_TABLE_INIT_PASSTHRU_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                        IOMMU_DEV_TABLE_EINT_PASSTHRU_MASK,
-                        IOMMU_DEV_TABLE_EINT_PASSTHRU_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                        IOMMU_DEV_TABLE_NMI_PASSTHRU_MASK,
-                        IOMMU_DEV_TABLE_NMI_PASSTHRU_SHIFT, &entry);
-    /* Fixed and arbitrated interrupts remapepd */
-    set_field_in_reg_u32(2, entry,
-                        IOMMU_DEV_TABLE_INT_CONTROL_MASK,
-                        IOMMU_DEV_TABLE_INT_CONTROL_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                        IOMMU_DEV_TABLE_LINT0_ENABLE_MASK,
-                        IOMMU_DEV_TABLE_LINT0_ENABLE_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                        IOMMU_DEV_TABLE_LINT1_ENABLE_MASK,
-                        IOMMU_DEV_TABLE_LINT1_ENABLE_SHIFT, &entry);
-    dte[5] = entry;
-
-    set_field_in_reg_u32((u32)addr_lo >> 6, 0,
-                        IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_MASK,
-                        IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_SHIFT, &entry);
-    /* 2048 entries */
-    set_field_in_reg_u32(0xB, entry,
-                         IOMMU_DEV_TABLE_INT_TABLE_LENGTH_MASK,
-                         IOMMU_DEV_TABLE_INT_TABLE_LENGTH_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                         IOMMU_DEV_TABLE_INT_VALID_MASK,
-                         IOMMU_DEV_TABLE_INT_VALID_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
-                         IOMMU_DEV_TABLE_INT_TABLE_IGN_UNMAPPED_MASK,
-                         IOMMU_DEV_TABLE_INT_TABLE_IGN_UNMAPPED_SHIFT, &entry);
-    dte[4] = entry;
-
-    set_field_in_reg_u32(sys_mgt, 0,
-                         IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK,
-                         IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT, &entry);
-    set_field_in_reg_u32(dev_ex, entry,
-                         IOMMU_DEV_TABLE_ALLOW_EXCLUSION_MASK,
-                         IOMMU_DEV_TABLE_ALLOW_EXCLUSION_SHIFT, &entry);
-    dte[3] = entry;
-
     set_field_in_reg_u32(domain_id, 0,
                          IOMMU_DEV_TABLE_DOMAIN_ID_MASK,
                          IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT, &entry);
     dte[2] = entry;
-
+    
     addr_lo = root_ptr & DMA_32BIT_MASK;
     addr_hi = root_ptr >> 32;
+    
     set_field_in_reg_u32((u32)addr_hi, 0,
                          IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK,
                          IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT, &entry);
@@ -330,7 +277,7 @@ void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u64 intremap_ptr,
                          IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK,
                          IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT, &entry);
     dte[1] = entry;
-
+    
     set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
                          IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK,
                          IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT, &entry);
@@ -340,12 +287,91 @@ void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u64 intremap_ptr,
     set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
                          IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
                          IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &entry);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+    set_field_in_reg_u32(valid ? IOMMU_CONTROL_ENABLED :
+                         IOMMU_CONTROL_DISABLED, entry,
                          IOMMU_DEV_TABLE_VALID_MASK,
                          IOMMU_DEV_TABLE_VALID_SHIFT, &entry);
     dte[0] = entry;
 }
 
+void amd_iommu_set_intremap_table(u32 *dte, u64 intremap_ptr, u8 int_valid)
+{
+    u64 addr_hi, addr_lo;
+    u32 entry;
+    
+    addr_lo = intremap_ptr & DMA_32BIT_MASK;
+    addr_hi = intremap_ptr >> 32;
+    
+    entry = dte[5];
+    set_field_in_reg_u32((u32)addr_hi, entry,
+                         IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_MASK,
+                         IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_SHIFT, &entry);
+    /* Fixed and arbitrated interrupts remapepd */
+    set_field_in_reg_u32(2, entry,
+                         IOMMU_DEV_TABLE_INT_CONTROL_MASK,
+                         IOMMU_DEV_TABLE_INT_CONTROL_SHIFT, &entry);
+    dte[5] = entry;
+    
+    set_field_in_reg_u32((u32)addr_lo >> 6, 0,
+                         IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_MASK,
+                         IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_SHIFT, &entry);
+    /* 2048 entries */
+    set_field_in_reg_u32(0xB, entry,
+                         IOMMU_DEV_TABLE_INT_TABLE_LENGTH_MASK,
+                         IOMMU_DEV_TABLE_INT_TABLE_LENGTH_SHIFT, &entry);
+    /* ignore unmapped interrupts */
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+                         IOMMU_DEV_TABLE_INT_TABLE_IGN_UNMAPPED_MASK,
+                         IOMMU_DEV_TABLE_INT_TABLE_IGN_UNMAPPED_SHIFT, &entry);
+    set_field_in_reg_u32(int_valid ? IOMMU_CONTROL_ENABLED :
+                         IOMMU_CONTROL_DISABLED, entry,
+                         IOMMU_DEV_TABLE_INT_VALID_MASK,
+                         IOMMU_DEV_TABLE_INT_VALID_SHIFT, &entry);
+    dte[4] = entry;
+}
+
+void amd_iommu_add_dev_table_entry(
+     u32 *dte, u8 sys_mgt, u8 dev_ex, u8 lint1_pass, u8 lint0_pass,
+     u8 nmi_pass, u8 ext_int_pass, u8 init_pass)
+{
+  u32 entry;
+
+  dte[7] = dte[6] = dte[4] = dte[2] = dte[1] = dte[0] = 0;
+
+
+  set_field_in_reg_u32(init_pass ? IOMMU_CONTROL_ENABLED :
+                       IOMMU_CONTROL_DISABLED, 0,
+                       IOMMU_DEV_TABLE_INIT_PASSTHRU_MASK,
+                       IOMMU_DEV_TABLE_INIT_PASSTHRU_SHIFT, &entry);
+  set_field_in_reg_u32(ext_int_pass ? IOMMU_CONTROL_ENABLED :
+                       IOMMU_CONTROL_DISABLED, entry,
+                       IOMMU_DEV_TABLE_EINT_PASSTHRU_MASK,
+                       IOMMU_DEV_TABLE_EINT_PASSTHRU_SHIFT, &entry);
+  set_field_in_reg_u32(nmi_pass ? IOMMU_CONTROL_ENABLED :
+                       IOMMU_CONTROL_DISABLED, entry,
+                       IOMMU_DEV_TABLE_NMI_PASSTHRU_MASK,
+                       IOMMU_DEV_TABLE_NMI_PASSTHRU_SHIFT, &entry);
+  set_field_in_reg_u32(lint0_pass ? IOMMU_CONTROL_ENABLED :
+                       IOMMU_CONTROL_DISABLED, entry,
+                       IOMMU_DEV_TABLE_LINT0_ENABLE_MASK,
+                       IOMMU_DEV_TABLE_LINT0_ENABLE_SHIFT, &entry);
+  set_field_in_reg_u32(lint1_pass ? IOMMU_CONTROL_ENABLED :
+                       IOMMU_CONTROL_DISABLED, entry,
+                       IOMMU_DEV_TABLE_LINT1_ENABLE_MASK,
+                       IOMMU_DEV_TABLE_LINT1_ENABLE_SHIFT, &entry);
+  dte[5] = entry;
+
+  set_field_in_reg_u32(sys_mgt, 0,
+                       IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK,
+                       IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT, &entry);
+  set_field_in_reg_u32(dev_ex, entry,
+                       IOMMU_DEV_TABLE_ALLOW_EXCLUSION_MASK,
+                       IOMMU_DEV_TABLE_ALLOW_EXCLUSION_SHIFT, &entry);
+  dte[3] = entry;
+}
+
+
+
 u64 amd_iommu_get_next_table_from_pte(u32 *entry)
 {
     u64 addr_lo, addr_hi, ptr;
diff --git a/drivers/passthrough/amd/pci_amd_iommu.c b/drivers/passthrough/amd/pci_amd_iommu.c
index 1d842aa..7556963 100644
--- a/drivers/passthrough/amd/pci_amd_iommu.c
+++ b/drivers/passthrough/amd/pci_amd_iommu.c
@@ -28,32 +28,6 @@ extern unsigned short ivrs_bdf_entries;
 extern struct ivrs_mappings *ivrs_mappings;
 extern void *int_remap_table;
 
-int __init amd_iommu_init(void)
-{
-    struct amd_iommu *iommu;
-
-    BUG_ON( !iommu_found() );
-
-    ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
-
-    if ( !ivrs_bdf_entries )
-        goto error_out;
-
-    if ( amd_iommu_setup_shared_tables() != 0 )
-        goto error_out;
-
-    amd_iommu_update_ivrs_mapping_acpi();
-
-    for_each_amd_iommu ( iommu )
-        if ( amd_iommu_init_one(iommu) != 0 )
-            goto error_out;
-    return 0;
-
-error_out:
-    amd_iommu_init_cleanup();
-    return -ENODEV;
-}
-
 struct amd_iommu *find_iommu_for_device(int bus, int devfn)
 {
     u16 bdf = (bus << 8) | devfn;
@@ -61,46 +35,59 @@ struct amd_iommu *find_iommu_for_device(int bus, int devfn)
     return ivrs_mappings[bdf].iommu;
 }
 
+/*
+ * Some devices will use alias id and original device id to index interrupt
+ * table and I/O page table respectively. Such devices will have
+ * both alias entry and select entry in IVRS structure.                       
+
+ * Return original device id, if device has valid interrupt remapping
+ * table setup for both select entry and alias entry.
+*/
+int get_dma_requestor_id(u16 bdf)
+{
+    int req_id;
+
+    BUG_ON ( bdf >= ivrs_bdf_entries );
+    req_id = ivrs_mappings[bdf].dte_requestor_id;
+    if ( (ivrs_mappings[bdf].intremap_table != NULL) &&
+         (ivrs_mappings[req_id].intremap_table != NULL) )
+        req_id = bdf;
+
+    return req_id;
+}
+
 static void amd_iommu_setup_domain_device(
     struct domain *domain, struct amd_iommu *iommu, int bdf)
 {
     void *dte;
     unsigned long flags;
-    int req_id;
-    u8 sys_mgt, dev_ex;
+    int req_id, valid;
     struct hvm_iommu *hd = domain_hvm_iommu(domain);
 
-    BUG_ON( !hd->root_table || !hd->paging_mode || !int_remap_table );
+    BUG_ON( !hd->root_table || !hd->paging_mode || !iommu->dev_table.buffer );
 
+    valid = 1;
     /* get device-table entry */
-    req_id = ivrs_mappings[bdf].dte_requestor_id;
+    req_id = get_dma_requestor_id(bdf);
     dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
 
     spin_lock_irqsave(&iommu->lock, flags);
     if ( !amd_iommu_is_dte_page_translation_valid((u32 *)dte) )
     {
         /* bind DTE to domain page-tables */
-        sys_mgt = ivrs_mappings[req_id].dte_sys_mgt_enable;
-        dev_ex = ivrs_mappings[req_id].dte_allow_exclusion;
-
-        amd_iommu_set_dev_table_entry((u32 *)dte,
-                                      (u64)page_to_maddr(hd->root_table),
-                                      (u64)virt_to_maddr(int_remap_table),
-                                      hd->domain_id, sys_mgt, dev_ex,
-                                      hd->paging_mode);
+        amd_iommu_set_root_page_table(
+            (u32 *)dte, page_to_maddr(hd->root_table), hd->domain_id,
+            hd->paging_mode, valid);
 
         invalidate_dev_table_entry(iommu, req_id);
-        invalidate_interrupt_table(iommu, req_id);
         flush_command_buffer(iommu);
-        amd_iov_info("Enable DTE:0x%x, "
-                "root_table:%"PRIx64", interrupt_table:%"PRIx64", "
-                "domain_id:%d, paging_mode:%d\n",
-                req_id, (u64)page_to_maddr(hd->root_table),
-                (u64)virt_to_maddr(int_remap_table), hd->domain_id,
-                hd->paging_mode);
+        
+        amd_iov_info("Setup I/O page table at DTE:0x%x, root_table:%"PRIx64","
+                     "domain_id:%d, paging_mode:%d\n", req_id,
+                     page_to_maddr(hd->root_table), hd->domain_id, 
+                     hd->paging_mode);
     }
     spin_unlock_irqrestore(&iommu->lock, flags);
-
 }
 
 static void amd_iommu_setup_dom0_devices(struct domain *d)
@@ -158,6 +145,7 @@ int amd_iov_detect(void)
         printk ("AMD-Vi: Error initialization!\n");
         return -ENODEV;
     }
+
     return 0;
 }
 
@@ -234,7 +222,7 @@ static void amd_iommu_disable_domain_device(
     unsigned long flags;
     int req_id;
 
-    req_id = ivrs_mappings[bdf].dte_requestor_id;
+    req_id = get_dma_requestor_id(bdf);
     dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
 
     spin_lock_irqsave(&iommu->lock, flags); 
@@ -292,7 +280,7 @@ static int reassign_device( struct domain *source, struct domain *target,
 static int amd_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
 {
     int bdf = (bus << 8) | devfn;
-    int req_id = ivrs_mappings[bdf].dte_requestor_id;
+    int req_id = get_dma_requestor_id(bdf);
 
     amd_iommu_sync_p2m(d);
 
@@ -414,8 +402,8 @@ static int amd_iommu_group_id(u8 bus, u8 devfn)
     int rt;
     int bdf = (bus << 8) | devfn;
     rt = ( bdf < ivrs_bdf_entries ) ?
-        ivrs_mappings[bdf].dte_requestor_id :
-        bdf;
+      get_dma_requestor_id(bdf) :
+      bdf;
     return rt;
 }
 
diff --git a/include/asm-x86/amd-iommu.h b/include/asm-x86/amd-iommu.h
index cdc99dd..767ca2d 100644
--- a/include/asm-x86/amd-iommu.h
+++ b/include/asm-x86/amd-iommu.h
@@ -92,5 +92,16 @@ struct ivrs_mappings {
     unsigned long addr_range_start;
     unsigned long addr_range_length;
     struct amd_iommu *iommu;
+
+    /* per device interrupt remapping table */
+    void *intremap_table;
+    spinlock_t intremap_lock;
+
+    /* interrupt remapping settings */
+    u8 dte_lint1_pass;
+    u8 dte_lint0_pass;
+    u8 dte_nmi_pass;
+    u8 dte_ext_int_pass;
+    u8 dte_init_pass;
 };
 #endif /* _ASM_X86_64_AMD_IOMMU_H */
diff --git a/include/asm-x86/hvm/svm/amd-iommu-acpi.h b/include/asm-x86/hvm/svm/amd-iommu-acpi.h
index 440d520..dc614cc 100644
--- a/include/asm-x86/hvm/svm/amd-iommu-acpi.h
+++ b/include/asm-x86/hvm/svm/amd-iommu-acpi.h
@@ -43,6 +43,7 @@
 #define AMD_IOMMU_ACPI_IVHD_DEV_ALIAS_RANGE    67
 #define AMD_IOMMU_ACPI_IVHD_DEV_EXT_SELECT 70
 #define AMD_IOMMU_ACPI_IVHD_DEV_EXT_RANGE  71
+#define AMD_IOMMU_ACPI_IVHD_DEV_SPECIAL    72
 
 /* IVHD IOMMU Flags */
 #define AMD_IOMMU_ACPI_COHERENT_MASK       0x20
@@ -151,6 +152,13 @@ struct acpi_ivhd_device_extended_range {
    struct acpi_ivhd_device_trailer trailer;
 };
 
+struct acpi_ivhd_device_special {
+   struct acpi_ivhd_device_header header;
+   u8  handle;
+   u16 dev_id;
+   u8  variety;
+};
+
 union acpi_ivhd_device {
    struct acpi_ivhd_device_header header;
    struct acpi_ivhd_device_range range;
@@ -158,6 +166,7 @@ union acpi_ivhd_device {
    struct acpi_ivhd_device_alias_range alias_range;
    struct acpi_ivhd_device_extended extended;
    struct acpi_ivhd_device_extended_range extended_range;
+   struct acpi_ivhd_device_special special;
 };
 
 struct acpi_ivmd_block_header {
diff --git a/include/asm-x86/hvm/svm/amd-iommu-proto.h b/include/asm-x86/hvm/svm/amd-iommu-proto.h
index cf2d60f..77d4baa 100644
--- a/include/asm-x86/hvm/svm/amd-iommu-proto.h
+++ b/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -67,10 +67,17 @@ int amd_iommu_sync_p2m(struct domain *d);
 void invalidate_all_iommu_pages(struct domain *d);
 
 /* device table functions */
-void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u64 intremap_ptr,
-        u16 domain_id, u8 sys_mgt, u8 dev_ex, u8 paging_mode);
+void amd_iommu_add_dev_table_entry(
+     u32 *dte, u8 sys_mgt, u8 dev_ex, u8 lint1_pass, u8 lint0_pass,
+     u8 nmi_pass, u8 ext_int_pass, u8 init_pass);
 int amd_iommu_is_dte_page_translation_valid(u32 *entry);
+int get_dma_requestor_id(u16 bdf);
 void invalidate_dev_table_entry(struct amd_iommu *iommu, u16 devic_id);
+void amd_iommu_set_intremap_table(
+     u32 *dte, u64 intremap_ptr, u8 int_valid);
+void amd_iommu_set_root_page_table(
+     u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode, u8 valid);
+
 
 /* send cmd to iommu */
 int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]);
@@ -81,11 +88,16 @@ struct amd_iommu *find_iommu_for_device(int bus, int devfn);
 
 /*interrupt remapping */
 int __init amd_iommu_setup_intremap_table(void);
-int __init deallocate_intremap_table(void);
+void __init amd_iommu_free_intremap_table(int bdf);
 void invalidate_interrupt_table(struct amd_iommu *iommu, u16 device_id);
 void amd_iommu_ioapic_update_ire(unsigned int apic, unsigned int reg, unsigned
                                 int value);
 void amd_iommu_msi_msg_update_ire(struct msi_desc *msi_desc, struct msi_msg *msg);
+void * __init amd_iommu_alloc_intremap_table(void);
+int __init amd_iommu_setup_ioapic_remapping(void);
+void*__init amd_iommu_alloc_intremap_table(void);
+void __init amd_iommu_free_intremap_table(int bdf);
+
 
 static inline u32 get_field_from_reg_u32(u32 reg_value, u32 mask, u32 shift)
 {