diff --git a/xen/drivers/passthrough/amd/iommu_acpi.c b/xen/drivers/passthrough/amd/iommu_acpi.c
index 79c1f8c..8bad2bc 100644
--- a/xen/drivers/passthrough/amd/iommu_acpi.c
+++ b/xen/drivers/passthrough/amd/iommu_acpi.c
@@ -821,13 +821,29 @@ static u16 __init parse_ivhd_device_special(
     return dev_length;
 }
 
+static inline size_t
+get_ivhd_header_size(const struct acpi_ivrs_hardware *ivhd_block)
+{
+    switch ( ivhd_block->header.type )
+    {
+    case ACPI_IVRS_TYPE_HARDWARE:
+        return offsetof(struct acpi_ivrs_hardware, efr_image);
+    case ACPI_IVRS_TYPE_HARDWARE_11H:
+        return sizeof(struct acpi_ivrs_hardware);
+    default:
+        break;
+    }
+    return 0;
+}
+
 static int __init parse_ivhd_block(const struct acpi_ivrs_hardware *ivhd_block)
 {
     const union acpi_ivhd_device *ivhd_device;
     u16 block_length, dev_length;
+    size_t hdr_size = get_ivhd_header_size(ivhd_block) ;
     struct amd_iommu *iommu;
 
-    if ( ivhd_block->header.length < sizeof(*ivhd_block) )
+    if ( ivhd_block->header.length < hdr_size )
     {
         AMD_IOMMU_DEBUG("IVHD Error: Invalid Block Length!\n");
         return -ENODEV;
@@ -845,7 +861,7 @@ static int __init parse_ivhd_block(const struct acpi_ivrs_hardware *ivhd_block)
     }
 
     /* parse Device Entries */
-    block_length = sizeof(*ivhd_block);
+    block_length = hdr_size;
     while ( ivhd_block->header.length >=
             (block_length + sizeof(struct acpi_ivrs_de_header)) )
     {
@@ -914,34 +930,6 @@ static int __init parse_ivhd_block(const struct acpi_ivrs_hardware *ivhd_block)
     return 0;
 }
 
-static int __init parse_ivrs_block(const struct acpi_ivrs_header *ivrs_block)
-{
-    const struct acpi_ivrs_hardware *ivhd_block;
-    const struct acpi_ivrs_memory *ivmd_block;
-
-    switch ( ivrs_block->type )
-    {
-    case ACPI_IVRS_TYPE_HARDWARE:
-        ivhd_block = container_of(ivrs_block, const struct acpi_ivrs_hardware,
-                                  header);
-        return parse_ivhd_block(ivhd_block);
-
-    case ACPI_IVRS_TYPE_MEMORY_ALL:
-    case ACPI_IVRS_TYPE_MEMORY_ONE:
-    case ACPI_IVRS_TYPE_MEMORY_RANGE:
-    case ACPI_IVRS_TYPE_MEMORY_IOMMU:
-        ivmd_block = container_of(ivrs_block, const struct acpi_ivrs_memory,
-                                  header);
-        return parse_ivmd_block(ivmd_block);
-
-    default:
-        AMD_IOMMU_DEBUG("IVRS Error: Invalid Block Type!\n");
-        return -ENODEV;
-    }
-
-    return 0;
-}
-
 static void __init dump_acpi_table_header(struct acpi_table_header *table)
 {
     int i;
@@ -978,6 +966,25 @@ static void __init dump_acpi_table_header(struct acpi_table_header *table)
 
 }
 
+#define to_ivhd_block(hdr) \
+    container_of(hdr, const struct acpi_ivrs_hardware, header)
+#define to_ivmd_block(hdr) \
+    container_of(hdr, const struct acpi_ivrs_memory, header)
+
+static inline bool_t is_ivhd_block(u8 type)
+{
+    return ( type == ACPI_IVRS_TYPE_HARDWARE ||
+             type == ACPI_IVRS_TYPE_HARDWARE_11H );
+}
+
+static inline bool_t is_ivmd_block(u8 type) \
+{
+    return ( type == ACPI_IVRS_TYPE_MEMORY_ALL ||
+             type == ACPI_IVRS_TYPE_MEMORY_ONE ||
+             type == ACPI_IVRS_TYPE_MEMORY_RANGE ||
+             type == ACPI_IVRS_TYPE_MEMORY_IOMMU );
+}
+
 static int __init parse_ivrs_table(struct acpi_table_header *table)
 {
     const struct acpi_ivrs_header *ivrs_block;
@@ -1010,7 +1017,10 @@ static int __init parse_ivrs_table(struct acpi_table_header *table)
             return -ENODEV;
         }
 
-        error = parse_ivrs_block(ivrs_block);
+        if ( ivrs_block->type == ivhd_type )
+            error = parse_ivhd_block(to_ivhd_block(ivrs_block));
+        else if ( is_ivmd_block (ivrs_block->type) )
+            error = parse_ivmd_block(to_ivmd_block(ivrs_block));
         length += ivrs_block->length;
     }
 
@@ -1083,9 +1093,7 @@ static int __init detect_iommu_acpi(struct acpi_table_header *table)
         if ( table->length < (length + ivrs_block->length) )
             return -ENODEV;
         if ( ivrs_block->type == ACPI_IVRS_TYPE_HARDWARE &&
-             amd_iommu_detect_one_acpi(
-                 container_of(ivrs_block, const struct acpi_ivrs_hardware,
-                              header)) != 0 )
+             amd_iommu_detect_one_acpi(to_ivhd_block(ivrs_block)) != 0 )
             return -ENODEV;
         length += ivrs_block->length;
     }
@@ -1102,15 +1110,16 @@ static int __init get_last_bdf_ivhd(
 {
     const union acpi_ivhd_device *ivhd_device;
     u16 block_length, dev_length;
+    size_t hdr_size = get_ivhd_header_size(ivhd_block) ;
     int last_bdf = 0;
 
-    if ( ivhd_block->header.length < sizeof(*ivhd_block) )
+    if ( ivhd_block->header.length < hdr_size )
     {
         AMD_IOMMU_DEBUG("IVHD Error: Invalid Block Length!\n");
         return -ENODEV;
     }
 
-    block_length = sizeof(*ivhd_block);
+    block_length = hdr_size;
     while ( ivhd_block->header.length >=
             (block_length + sizeof(struct acpi_ivrs_de_header)) )
     {
@@ -1177,11 +1186,9 @@ static int __init get_last_bdf_acpi(struct acpi_table_header *table)
         ivrs_block = (struct acpi_ivrs_header *)((u8 *)table + length);
         if ( table->length < (length + ivrs_block->length) )
             return -ENODEV;
-        if ( ivrs_block->type == ACPI_IVRS_TYPE_HARDWARE )
+        if ( ivrs_block->type == ivhd_type )
         {
-            int ret = get_last_bdf_ivhd(
-                 container_of(ivrs_block, const struct acpi_ivrs_hardware,
-                              header));
+            int ret = get_last_bdf_ivhd(to_ivhd_block(ivrs_block));
 
             if ( ret < 0 )
                 return ret;
@@ -1207,8 +1214,51 @@ int __init amd_iommu_get_ivrs_dev_entries(void)
 
 int __init amd_iommu_update_ivrs_mapping_acpi(void)
 {
-    if ( unlikely(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) )
-        return -EPERM;
-
     return acpi_table_parse(ACPI_SIG_IVRS, parse_ivrs_table);
 }
+
+static int __init
+get_supported_ivhd_type(struct acpi_table_header *table)
+{
+    size_t length = sizeof(struct acpi_table_ivrs);
+    const struct acpi_ivrs_header *ivrs_block, *blk = NULL;
+
+    while ( table->length > (length + sizeof(*ivrs_block)) )
+    {
+        ivrs_block = (struct acpi_ivrs_header *)((u8 *)table + length);
+
+        if ( table->length < (length + ivrs_block->length) )
+        {
+            AMD_IOMMU_DEBUG("IVRS Error: "
+                            "Table Length Exceeded: %#x -> %#lx\n",
+                            table->length,
+                            (length + ivrs_block->length));
+            return -ENODEV;
+        }
+
+        if ( is_ivhd_block(ivrs_block->type) &&
+            (!blk || blk->type < ivrs_block->type) )
+        {
+            AMD_IOMMU_DEBUG("IVRS Block: Found type %#x flags %#x len %#x id %#x\n",
+                            ivrs_block->type, ivrs_block->flags,
+                            ivrs_block->length, ivrs_block->device_id);
+            blk = ivrs_block;
+        }
+        length += ivrs_block->length;
+    }
+
+    if ( !blk )
+    {
+        printk(XENLOG_ERR "Cannot find supported IVHD type.\n");
+        return -ENODEV;
+    }
+
+    AMD_IOMMU_DEBUG("Using IVHD type %#x\n", blk->type);
+
+    return blk->type;
+}
+
+int __init amd_iommu_get_supported_ivhd_type(void)
+{
+    return acpi_table_parse(ACPI_SIG_IVRS, get_supported_ivhd_type);
+}
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
index 4536106..ba505c3 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -35,6 +35,7 @@ static int __initdata nr_amd_iommus;
 static struct tasklet amd_iommu_irq_tasklet;
 
 unsigned int __read_mostly ivrs_bdf_entries;
+u8 __read_mostly ivhd_type;
 static struct radix_tree_root ivrs_maps;
 struct list_head amd_iommu_head;
 struct table_struct device_table;
@@ -1232,8 +1233,15 @@ int __init amd_iommu_init(void)
          amd_sp5100_erratum28() )
         goto error_out;
 
-    ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
+    /* We implies no IOMMU if ACPI indicates no MSI. */
+    if ( unlikely(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) )
+        goto error_out;
 
+    ivhd_type = amd_iommu_get_supported_ivhd_type();
+    if ( ivhd_type < 0 )
+        goto error_out;
+
+    ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
     if ( !ivrs_bdf_entries )
         goto error_out;
 
diff --git a/xen/include/acpi/actbl2.h b/xen/include/acpi/actbl2.h
index 4341a30..d2327d2 100644
--- a/xen/include/acpi/actbl2.h
+++ b/xen/include/acpi/actbl2.h
@@ -589,6 +589,7 @@ struct acpi_ivrs_header {
 
 enum acpi_ivrs_type {
 	ACPI_IVRS_TYPE_HARDWARE = 0x10,
+	ACPI_IVRS_TYPE_HARDWARE_11H = 0x11,
 	ACPI_IVRS_TYPE_MEMORY_ALL /* _MEMORY1 */ = 0x20,
 	ACPI_IVRS_TYPE_MEMORY_ONE /* _MEMORY2 */ = 0x21,
 	ACPI_IVRS_TYPE_MEMORY_RANGE /* _MEMORY3 */ = 0x22,
@@ -622,7 +623,9 @@ struct acpi_ivrs_hardware {
 	u64 base_address;	/* IOMMU control registers */
 	u16 pci_segment_group;
 	u16 info;		/* MSI number and unit ID */
-	u32 reserved;
+	u32 iommu_attr;
+	u64 efr_image;		/* Extd feature register */
+	u64 reserved;
 };
 
 /* Masks for Info field above */
diff --git a/xen/include/asm-x86/amd-iommu.h b/xen/include/asm-x86/amd-iommu.h
index e9fa9c2..4ad9bff 100644
--- a/xen/include/asm-x86/amd-iommu.h
+++ b/xen/include/asm-x86/amd-iommu.h
@@ -126,6 +126,7 @@ struct ivrs_mappings {
 };
 
 extern unsigned int ivrs_bdf_entries;
+extern u8 ivhd_type;
 
 struct ivrs_mappings *get_ivrs_mappings(u16 seg);
 int iterate_ivrs_mappings(int (*)(u16 seg, struct ivrs_mappings *));
diff --git a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
index 9c51172..e6065d3 100644
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -42,6 +42,7 @@ struct acpi_ivrs_hardware;
 
 /* amd-iommu-detect functions */
 int amd_iommu_get_ivrs_dev_entries(void);
+int amd_iommu_get_supported_ivhd_type(void);
 int amd_iommu_detect_one_acpi(const struct acpi_ivrs_hardware *);
 int amd_iommu_detect_acpi(void);
 void get_iommu_features(struct amd_iommu *iommu);
