Skip to contentSkip to conversation

amd iommu: IOMMUv2 support

PATCH In review Wei Wang 2 participants 6 messages Nov 18, 2011

lore
Share & tools
lore

Wei Wang

author
#0 lore raw

PATCH 1/1 amd iommu: IOMMUv2 support

This patch set adds basic supports for amd next generation iommu (IOMMUv2) hardware. IOMMUv2 supports various new features advertised by iommu extended feature register. It introduces guest level IO translation and supports state-of-the-art ATS/ATC devices with demand paging capability. Please refer to AMD IOMMU Architectural Specification [1] for more details.

Thanks,
Wei

[1] http://support.amd.com/us/Processor_TechDocs/48882.pdf

author
#1 lore raw

PATCH 1/1 amd iommu: Advertise iommu extended feature bits to xen

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321541520 -3600
# Node ID ac472579595524317ab2f7e5ef545e67f4c9c6f0 # Parent dbdc840f8f62db58321b5009e5e0f7833066386f amd iommu: Advertise iommu extended feature bits to xen.

xen/drivers/passthrough/amd/iommu_detect.c +41 -0
diff -r dbdc840f8f62 -r ac4725795955 xen/drivers/passthrough/amd/iommu_detect.c
@@ -62,6 +62,47 @@ static int __init get_iommu_capabilities
     return 0;
 }
 
+void __init get_iommu_features(struct amd_iommu *iommu)
+{
+    u32 low, high;
+    int i = 0 ;
+    char * feature_str[] = {
+        "- Prefetch Pages Command", 
+        "- Peripheral Page Service Request", 
+        "- X2APIC Supported", 
+        "- NX bit Supported", 
+        "- Guest Translation", 
+        "- Reserved bit [5]",
+        "- Invalidate All Command", 
+        "- Guest APIC supported", 
+        "- Hardware Error Registers", 
+        "- Performance Counters", 
+        NULL
+    };
+
+    ASSERT( iommu->mmio_base );
+
+    if ( !iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
+    {
+        iommu->features = 0;
+        return;
+    }
+
+    low = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
+    high = readl(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET + 4);
+
+    iommu->features = ((u64)high << 32) | low;
+
+    printk("AMD-Vi: IOMMU Extended Features:\n");
+
+    while ( feature_str[i] )
+    {
+        if ( iommu_has_feature(iommu, i) )
+            printk( " %s\n", feature_str[i]);
+        i++;
+    }
+}
+
 int __init amd_iommu_detect_one_acpi(void *ivhd)
 {
     struct amd_iommu *iommu;
xen/drivers/passthrough/amd/iommu_init.c +2 -0
diff -r dbdc840f8f62 -r ac4725795955 xen/drivers/passthrough/amd/iommu_init.c
@@ -684,6 +684,8 @@ static int __init amd_iommu_init_one(str
     iommu->dev_table.entries = device_table.entries;
     iommu->dev_table.buffer = device_table.buffer;
 
+    get_iommu_features(iommu);
+
     enable_iommu(iommu);
     printk("AMD-Vi: IOMMU %d Enabled.\n", nr_amd_iommus );
     nr_amd_iommus++;
xen/include/asm-x86/amd-iommu.h +1 -0
diff -r dbdc840f8f62 -r ac4725795955 xen/include/asm-x86/amd-iommu.h
@@ -54,6 +54,7 @@ struct amd_iommu {
     iommu_cap_t cap;
 
     u8 ht_flags;
+    u64 features;
 
     void *mmio_base;
     unsigned long mmio_base_phys;
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +21 -0
diff -r dbdc840f8f62 -r ac4725795955 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -54,6 +54,7 @@
 #define PCI_CAP_HT_TUNNEL_SHIFT	25
 #define PCI_CAP_NP_CACHE_MASK	0x04000000
 #define PCI_CAP_NP_CACHE_SHIFT	26
+#define PCI_CAP_EFRSUP_SHIFT    27
 #define PCI_CAP_RESET_MASK	0x80000000
 #define PCI_CAP_RESET_SHIFT	31
 
@@ -327,6 +328,26 @@
 #define IOMMU_EXCLUSION_LIMIT_HIGH_MASK		0xFFFFFFFF
 #define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT	0
 
+/* Extended Feature Register*/
+#define IOMMU_EXT_FEATURE_MMIO_OFFSET                   0x30
+#define IOMMU_EXT_FEATURE_PREFSUP_SHIFT                 0x0
+#define IOMMU_EXT_FEATURE_PPRSUP_SHIFT                  0x1
+#define IOMMU_EXT_FEATURE_XTSUP_SHIFT                   0x2
+#define IOMMU_EXT_FEATURE_NXSUP_SHIFT                   0x3
+#define IOMMU_EXT_FEATURE_GTSUP_SHIFT                   0x4
+#define IOMMU_EXT_FEATURE_IASUP_SHIFT                   0x6
+#define IOMMU_EXT_FEATURE_GASUP_SHIFT                   0x7
+#define IOMMU_EXT_FEATURE_HESUP_SHIFT                   0x8
+#define IOMMU_EXT_FEATURE_PCSUP_SHIFT                   0x9
+#define IOMMU_EXT_FEATURE_HATS_SHIFT                    0x10
+#define IOMMU_EXT_FEATURE_HATS_MASK                     0x00000C00
+#define IOMMU_EXT_FEATURE_GATS_SHIFT                    0x12
+#define IOMMU_EXT_FEATURE_GATS_MASK                     0x00003000
+#define IOMMU_EXT_FEATURE_GLXSUP                        0x14
+
+#define IOMMU_EXT_FEATURE_PASMAX_SHIFT                  0x0
+#define IOMMU_EXT_FEATURE_PASMAX_MASK                   0x0000001F
+
 /* Status Register*/
 #define IOMMU_STATUS_MMIO_OFFSET		0x2020
 #define IOMMU_STATUS_EVENT_OVERFLOW_MASK	0x00000001
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +9 -0
diff -r dbdc840f8f62 -r ac4725795955 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -43,6 +43,7 @@
 int amd_iommu_get_ivrs_dev_entries(void);
 int amd_iommu_detect_one_acpi(void *ivhd);
 int amd_iommu_detect_acpi(void);
+void get_iommu_features(struct amd_iommu *iommu);
 
 /* amd-iommu-init functions */
 int amd_iommu_init(void);
@@ -187,4 +188,12 @@ static inline int iommu_has_cap(struct a
     return iommu->cap.header & mask;
 }
 
+static inline int iommu_has_feature(struct amd_iommu *iommu, uint32_t bit)
+{
+    if ( iommu_has_cap(iommu, PCI_CAP_EFRSUP_SHIFT) )
+        return  iommu->features & (1U << bit);
+
+    return 0;
+}
+
 #endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */
author
#2 lore raw

PATCH 1/1 amd iommu: Fix incorrect definitions

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321541523 -3600
# Node ID 135678ae1bbc02171294c21e2a5469d898d2a353 # Parent ac472579595524317ab2f7e5ef545e67f4c9c6f0 amd iommu: Fix incorrect definitions.

xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +2 -4
diff -r ac4725795955 -r 135678ae1bbc xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -293,10 +293,8 @@
 #define IOMMU_CONTROL_EVENT_LOG_INT_SHIFT		3
 #define IOMMU_CONTROL_COMP_WAIT_INT_MASK		0x00000010
 #define IOMMU_CONTROL_COMP_WAIT_INT_SHIFT		4
-#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_MASK	0x00000020
-#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_SHIFT	5
-#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_MASK		0x000000C0
-#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_SHIFT	6
+#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_MASK		0x000000E0
+#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_SHIFT	5
 #define IOMMU_CONTROL_PASS_POSTED_WRITE_MASK		0x00000100
 #define IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT		8
 #define IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_MASK	0x00000200
author
#3 lore raw

PATCH 1/1 amd iommu: Factor out iommu command handling functions,

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321610860 -3600
# Node ID 6ef12cc262fb3ac11f9ea58707afb4f7778017ac # Parent 135678ae1bbc02171294c21e2a5469d898d2a353 amd iommu: Factor out iommu command handling functions, and move them into a new file.

xen/drivers/passthrough/amd/Makefile +1 -0
diff -r 135678ae1bbc -r 6ef12cc262fb xen/drivers/passthrough/amd/Makefile
@@ -4,3 +4,4 @@ obj-y += iommu_map.o
 obj-y += pci_amd_iommu.o
 obj-bin-y += iommu_acpi.init.o
 obj-y += iommu_intr.o
+obj-y += iommu_cmd.o
xen/drivers/passthrough/amd/iommu_cmd.c new file +382 -0

382 lines not on this page · raw message

xen/drivers/passthrough/amd/iommu_init.c +2 -3
diff -r 135678ae1bbc -r 6ef12cc262fb xen/drivers/passthrough/amd/iommu_init.c
@@ -933,9 +933,8 @@ static int _invalidate_all_devices(
         if ( iommu )
         {
             spin_lock_irqsave(&iommu->lock, flags);
-            invalidate_dev_table_entry(iommu, req_id);
-            invalidate_interrupt_table(iommu, req_id);
-            flush_command_buffer(iommu);
+            amd_iommu_flush_device(iommu, req_id);
+            amd_iommu_flush_intremap(iommu, req_id);
             spin_unlock_irqrestore(&iommu->lock, flags);
         }
     }
xen/drivers/passthrough/amd/iommu_intr.c +4 -23
diff -r 135678ae1bbc -r 6ef12cc262fb xen/drivers/passthrough/amd/iommu_intr.c
@@ -96,22 +96,6 @@ static void update_intremap_entry(u32* e
                             INT_REMAP_ENTRY_VECTOR_SHIFT, entry);
 }
 
-void invalidate_interrupt_table(struct amd_iommu *iommu, u16 device_id)
-{
-    u32 cmd[4], entry;
-
-    cmd[3] = cmd[2] = 0;
-    set_field_in_reg_u32(device_id, 0,
-                         IOMMU_INV_INT_TABLE_DEVICE_ID_MASK,
-                         IOMMU_INV_INT_TABLE_DEVICE_ID_SHIFT, &entry);
-    cmd[0] = entry;
-    set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_INT_TABLE, 0,
-                         IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT,
-                         &entry);
-    cmd[1] = entry;
-    send_iommu_command(iommu, cmd);
-}
-
 static void update_intremap_entry_from_ioapic(
     int bdf,
     struct amd_iommu *iommu,
@@ -144,8 +128,7 @@ static void update_intremap_entry_from_i
     if ( iommu->enabled )
     {
         spin_lock_irqsave(&iommu->lock, flags);
-        invalidate_interrupt_table(iommu, req_id);
-        flush_command_buffer(iommu);
+        amd_iommu_flush_intremap(iommu, req_id);
         spin_unlock_irqrestore(&iommu->lock, flags);
     }
 }
@@ -202,8 +185,7 @@ int __init amd_iommu_setup_ioapic_remapp
             if ( iommu->enabled )
             {
                 spin_lock_irqsave(&iommu->lock, flags);
-                invalidate_interrupt_table(iommu, req_id);
-                flush_command_buffer(iommu);
+                amd_iommu_flush_intremap(iommu, req_id);
                 spin_unlock_irqrestore(&iommu->lock, flags);
             }
         }
@@ -347,10 +329,9 @@ done:
     if ( iommu->enabled )
     {
         spin_lock_irqsave(&iommu->lock, flags);
-        invalidate_interrupt_table(iommu, req_id);
+        amd_iommu_flush_intremap(iommu, req_id);
         if ( alias_id != req_id )
-            invalidate_interrupt_table(iommu, alias_id);
-        flush_command_buffer(iommu);
+            amd_iommu_flush_intremap(iommu, alias_id);
         spin_unlock_irqrestore(&iommu->lock, flags);
     }
 }
xen/drivers/passthrough/amd/iommu_map.c +1 -323

348 lines not on this page · raw message

xen/drivers/passthrough/amd/pci_amd_iommu.c +3 -4
diff -r 135678ae1bbc -r 6ef12cc262fb xen/drivers/passthrough/amd/pci_amd_iommu.c
@@ -118,8 +118,7 @@ static void amd_iommu_setup_domain_devic
              iommu_has_cap(iommu, PCI_CAP_IOTLB_SHIFT) )
             iommu_dte_set_iotlb((u32 *)dte, dte_i);
 
-        invalidate_dev_table_entry(iommu, req_id);
-        flush_command_buffer(iommu);
+        amd_iommu_flush_device(iommu, req_id);
 
         AMD_IOMMU_DEBUG("Setup I/O page table: device id = 0x%04x, "
                         "root table = 0x%"PRIx64", "
@@ -310,8 +309,8 @@ void amd_iommu_disable_domain_device(str
              iommu_has_cap(iommu, PCI_CAP_IOTLB_SHIFT) )
             iommu_dte_set_iotlb((u32 *)dte, 0);
 
-        invalidate_dev_table_entry(iommu, req_id);
-        flush_command_buffer(iommu);
+        amd_iommu_flush_device(iommu, req_id);
+
         AMD_IOMMU_DEBUG("Disable: device id = 0x%04x, "
                         "domain = %d, paging mode = %d\n",
                         req_id,  domain_hvm_iommu(domain)->domain_id,
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +7 -10
diff -r 135678ae1bbc -r 6ef12cc262fb xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -53,12 +53,6 @@ int amd_iommu_update_ivrs_mapping_acpi(v
 int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
                        unsigned int flags);
 int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
-void amd_iommu_flush_pages(struct domain *d, unsigned long gfn,
-                           unsigned int order);
-void amd_iommu_flush_all_pages(struct domain *d);
-void amd_iommu_flush_iotlb(struct pci_dev *pdev, uint64_t gaddr,
-                           unsigned int order);
-
 u64 amd_iommu_get_next_table_from_pte(u32 *entry);
 int amd_iommu_reserve_domain_unity_map(struct domain *domain,
                                        u64 phys_addr, unsigned long size,
@@ -75,11 +69,15 @@ void amd_iommu_set_root_page_table(
     u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode, u8 valid);
 void iommu_dte_set_iotlb(u32 *dte, u8 i);
 void iommu_dte_add_device_entry(u32 *dte, struct ivrs_mappings *ivrs_dev);
-void invalidate_dev_table_entry(struct amd_iommu *iommu, u16 devic_id);
 
 /* send cmd to iommu */
-int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]);
-void flush_command_buffer(struct amd_iommu *iommu);
+void amd_iommu_flush_all_pages(struct domain *d);
+void amd_iommu_flush_pages(struct domain *d, unsigned long gfn,
+                           unsigned int order);
+void amd_iommu_flush_iotlb(struct pci_dev *pdev, uint64_t gaddr,
+                           unsigned int order);
+void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf);
+void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf);
 
 /* find iommu for bdf */
 struct amd_iommu *find_iommu_for_device(int seg, int bdf);
@@ -88,7 +86,6 @@ struct amd_iommu *find_iommu_for_device(
 int amd_iommu_setup_ioapic_remapping(void);
 void *amd_iommu_alloc_intremap_table(void);
 int amd_iommu_free_intremap_table(u16 seg, struct ivrs_mappings *);
-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(
author
#4 lore raw

PATCH 1/1 amd iommu: Support INVALIDATE_IOMMU_ALL command

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321612881 -3600
# Node ID 9d4fecddb805b0780e2eeab9f1f69cc585eac7b8
# Parent 6ef12cc262fb3ac11f9ea58707afb4f7778017ac
amd iommu: Support INVALIDATE_IOMMU_ALL command.
It is one of the new architectural commands supported by iommu v2.It instructs iommu to clear all address translation and interrupt remapping caches for all devices and all domains.

xen/drivers/passthrough/amd/iommu_cmd.c +22 -0
diff -r 6ef12cc262fb -r 9d4fecddb805 xen/drivers/passthrough/amd/iommu_cmd.c
@@ -277,6 +277,20 @@ static void invalidate_interrupt_table(s
     send_iommu_command(iommu, cmd);
 }
 
+void invalidate_iommu_all(struct amd_iommu *iommu)
+{
+    u32 cmd[4], entry;
+
+    cmd[3] = cmd[2] = cmd[0] = 0;
+
+    set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_IOMMU_ALL, 0,
+                         IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT,
+                         &entry);
+    cmd[1] = entry;
+
+    send_iommu_command(iommu, cmd);
+}
+
 void amd_iommu_flush_iotlb(struct pci_dev *pdev,
                            uint64_t gaddr, unsigned int order)
 {
@@ -380,3 +394,11 @@ void amd_iommu_flush_intremap(struct amd
     invalidate_interrupt_table(iommu, bdf);
     flush_command_buffer(iommu);
 }
+
+void amd_iommu_flush_all_caches(struct amd_iommu *iommu)
+{
+    ASSERT( spin_is_locked(&iommu->lock) );
+
+    invalidate_iommu_all(iommu);
+    flush_command_buffer(iommu);
+}
xen/drivers/passthrough/amd/iommu_init.c +8 -2
diff -r 6ef12cc262fb -r 9d4fecddb805 xen/drivers/passthrough/amd/iommu_init.c
@@ -598,6 +598,9 @@ static void enable_iommu(struct amd_iomm
     set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
     set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
 
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
+        amd_iommu_flush_all_caches(iommu);
+
     iommu->enabled = 1;
     spin_unlock_irqrestore(&iommu->lock, flags);
 
@@ -970,6 +973,9 @@ void amd_iommu_resume(void)
     }
 
     /* flush all cache entries after iommu re-enabled */
-    invalidate_all_devices();
-    invalidate_all_domain_pages();
+    if ( !iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
+    {
+        invalidate_all_devices();
+        invalidate_all_domain_pages();
+    }
 }
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +1 -0
diff -r 6ef12cc262fb -r 9d4fecddb805 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -192,6 +192,7 @@
 #define IOMMU_CMD_INVALIDATE_IOMMU_PAGES	0x3
 #define IOMMU_CMD_INVALIDATE_IOTLB_PAGES	0x4
 #define IOMMU_CMD_INVALIDATE_INT_TABLE		0x5
+#define IOMMU_CMD_INVALIDATE_IOMMU_ALL      0x8
 
 /* COMPLETION_WAIT command */
 #define IOMMU_COMP_WAIT_DATA_BUFFER_SIZE	8
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +1 -0
diff -r 6ef12cc262fb -r 9d4fecddb805 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -78,6 +78,7 @@ void amd_iommu_flush_iotlb(struct pci_de
                            unsigned int order);
 void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf);
 void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf);
+void amd_iommu_flush_all_caches(struct amd_iommu *iommu);
 
 /* find iommu for bdf */
 struct amd_iommu *find_iommu_for_device(int seg, int bdf);
#5 lore raw
In reply to Wei Wang
Quoted 5 lines · Wei Wang

This patch set adds basic supports for amd next generation iommu (IOMMUv2) hardware. IOMMUv2 supports various new features advertised by iommu extended feature register. It introduces guest level IO translation and supports state-of-the-art ATS/ATC devices with demand paging capability. Please refer to AMD IOMMU Architectural Specification [1] for more details.

Wei,

When is this hardware likely to be in the hands of customers?
-George