Skip to contentSkip to conversation

amd iommu: support ATS device passthru on IOMMUv2 systems

RFC PATCH Superseded Wei Wang 5 participants 37 messages Dec 14, 2011 – Dec 16, 2011

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Wei Wang

author
#0 lore raw

RFC PATCH 1/1 amd iommu: support ATS device passthru on IOMMUv2 systems

ATS devices with PRI and PASID capabilities can communicate with iommuv2 to do 2 level (nested) DMA translation and IO demand paging. To do that, both iommu driver and ats device have to been enabled in guest OS. This patch set adds initial iommu emulation for hvm guests to support ATS device passthru. Please review.
Thanks,

Wei

author
#1 lore raw

PATCH 1/1 amd iommu: Refactoring iommu ring buffer definition

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323863478 -3600
# Node ID a3d2f93d82940a391de00717ddbf842f821fcea5
# Parent 846725c81ed924e03bf4e6d65f912be089c54a06
amd iommu: Refactoring iommu ring buffer definition.
Introduce struct ring_buffer to represent iommu cmd buffer, event log and ppr log

xen/drivers/passthrough/amd/iommu_cmd.c +4 -4
diff -r 846725c81ed9 -r a3d2f93d8294 xen/drivers/passthrough/amd/iommu_cmd.c
@@ -29,7 +29,7 @@ static int queue_iommu_command(struct am
     u32 tail, head, *cmd_buffer;
     int i;
 
-    tail = iommu->cmd_buffer_tail;
+    tail = iommu->cmd_buffer.tail;
     if ( ++tail == iommu->cmd_buffer.entries )
         tail = 0;
 
@@ -40,13 +40,13 @@ static int queue_iommu_command(struct am
     if ( head != tail )
     {
         cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +
-                             (iommu->cmd_buffer_tail *
+                             (iommu->cmd_buffer.tail *
                              IOMMU_CMD_BUFFER_ENTRY_SIZE));
 
         for ( i = 0; i < IOMMU_CMD_BUFFER_U32_PER_ENTRY; i++ )
             cmd_buffer[i] = cmd[i];
 
-        iommu->cmd_buffer_tail = tail;
+        iommu->cmd_buffer.tail = tail;
         return 1;
     }
 
@@ -57,7 +57,7 @@ static void commit_iommu_command_buffer(
 {
     u32 tail;
 
-    set_field_in_reg_u32(iommu->cmd_buffer_tail, 0,
+    set_field_in_reg_u32(iommu->cmd_buffer.tail, 0,
                          IOMMU_CMD_BUFFER_TAIL_MASK,
                          IOMMU_CMD_BUFFER_TAIL_SHIFT, &tail);
     writel(tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET);
xen/drivers/passthrough/amd/iommu_init.c +70 -56

191 lines not on this page · raw message

xen/include/asm-x86/amd-iommu.h +33 -4
diff -r 846725c81ed9 -r a3d2f93d8294 xen/include/asm-x86/amd-iommu.h
@@ -30,12 +30,43 @@
 
 extern struct list_head amd_iommu_head;
 
+#pragma pack(1)
+typedef struct event_entry
+{
+    uint32_t data[4];
+} event_entry_t;
+
+typedef struct ppr_entry
+{
+    uint32_t data[4];
+} ppr_entry_t;
+
+typedef struct cmd_entry
+{
+    uint32_t data[4];
+} cmd_entry_t;
+
+typedef struct dev_entry
+{
+    uint32_t data[8];
+} dev_entry_t;
+#pragma pack()
+
 struct table_struct {
     void *buffer;
     unsigned long entries;
     unsigned long alloc_size;
 };
 
+struct ring_buffer {
+    void *buffer;
+    unsigned long entries;
+    unsigned long alloc_size;
+    unsigned long entry_size;
+    uint32_t tail;
+    uint32_t head;
+};
+
 typedef struct iommu_cap {
     uint32_t header;                    /* offset 00h */
     uint32_t base_low;                  /* offset 04h */
@@ -60,10 +91,8 @@ struct amd_iommu {
     unsigned long mmio_base_phys;
 
     struct table_struct dev_table;
-    struct table_struct cmd_buffer;
-    u32 cmd_buffer_tail;
-    struct table_struct event_log;
-    u32 event_log_head;
+    struct ring_buffer cmd_buffer;
+    struct ring_buffer event_log;
 
     int exclusion_enable;
     int exclusion_allow_all;
author
#2 lore raw

PATCH 1/1 amd iommu: Introduces new helper functions to simplify iommu bitwise operations

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323863482 -3600
# Node ID b190e3362524a0e160e9892cd600447cee2a022e
# Parent a3d2f93d82940a391de00717ddbf842f821fcea5
amd iommu: Introduces new helper functions to simplify iommu bitwise operations

xen/drivers/passthrough/amd/iommu_cmd.c +4 -8
diff -r a3d2f93d8294 -r b190e3362524 xen/drivers/passthrough/amd/iommu_cmd.c
@@ -33,10 +33,8 @@ static int queue_iommu_command(struct am
     if ( ++tail == iommu->cmd_buffer.entries )
         tail = 0;
 
-    head = get_field_from_reg_u32(readl(iommu->mmio_base + 
-                                        IOMMU_CMD_BUFFER_HEAD_OFFSET),
-                                  IOMMU_CMD_BUFFER_HEAD_MASK,
-                                  IOMMU_CMD_BUFFER_HEAD_SHIFT);
+    head = iommu_get_rb_pointer(readl(iommu->mmio_base + 
+                                      IOMMU_CMD_BUFFER_HEAD_OFFSET));
     if ( head != tail )
     {
         cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +
@@ -55,11 +53,9 @@ static int queue_iommu_command(struct am
 
 static void commit_iommu_command_buffer(struct amd_iommu *iommu)
 {
-    u32 tail;
+    u32 tail = 0;
 
-    set_field_in_reg_u32(iommu->cmd_buffer.tail, 0,
-                         IOMMU_CMD_BUFFER_TAIL_MASK,
-                         IOMMU_CMD_BUFFER_TAIL_SHIFT, &tail);
+    iommu_set_rb_pointer(&tail, iommu->cmd_buffer.tail);
     writel(tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET);
 }
 
xen/drivers/passthrough/amd/iommu_init.c +23 -27

109 lines not on this page · raw message

xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +80 -0

85 lines not on this page · raw message

author
#3 lore raw

PATCH 1/1 amd iommu: Add iommu emulation for hvm guest

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323863897 -3600
# Node ID ea52a2b93dffe708084fdc6ee663bd5eee8c1031
# Parent b190e3362524a0e160e9892cd600447cee2a022e
amd iommu: Add iommu emulation for hvm guest
ATS device driver that support PASID [1] and PRI [2] capabilites needs to work with iommu driver in OS. If we want passthru ATS device to hvm guests using unmodified OS, we have to expose iommu functionality to HVM guest.

[1] http://www.pcisig.com/specifications/pciexpress/specifications/ECN-PASID-ATS-2011-03-31.pdf
[2] http://www.pcisig.com/members/downloads/specifications/iov/ats_r1.1_26Jan09.pdf

xen/drivers/passthrough/amd/Makefile +1 -0
diff -r b190e3362524 -r ea52a2b93dff xen/drivers/passthrough/amd/Makefile
@@ -5,3 +5,4 @@ obj-y += pci_amd_iommu.o
 obj-bin-y += iommu_acpi.init.o
 obj-y += iommu_intr.o
 obj-y += iommu_cmd.o
+obj-y += iommu_guest.o
xen/drivers/passthrough/amd/iommu_cmd.c +12 -0
diff -r b190e3362524 -r ea52a2b93dff xen/drivers/passthrough/amd/iommu_cmd.c
@@ -398,3 +398,15 @@ void amd_iommu_flush_all_caches(struct a
     invalidate_iommu_all(iommu);
     flush_command_buffer(iommu);
 }
+
+void amd_iommu_send_guest_cmd(struct amd_iommu *iommu, u32 cmd[])
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&iommu->lock, flags);
+
+    send_iommu_command(iommu, cmd);
+    flush_command_buffer(iommu);
+
+    spin_unlock_irqrestore(&iommu->lock, flags);
+}
xen/drivers/passthrough/amd/iommu_guest.c new file +953 -0

953 lines not on this page · raw message

xen/drivers/passthrough/amd/iommu_map.c +47 -0

53 lines not on this page · raw message

xen/drivers/passthrough/amd/pci_amd_iommu.c +3 -0
diff -r b190e3362524 -r ea52a2b93dff xen/drivers/passthrough/amd/pci_amd_iommu.c
@@ -260,6 +260,8 @@ static int amd_iommu_domain_init(struct 
 
     hd->domain_id = d->domain_id;
 
+    guest_iommu_init(d);
+
     return 0;
 }
 
@@ -443,6 +445,7 @@ static void deallocate_iommu_page_tables
 
 static void amd_iommu_domain_destroy(struct domain *d)
 {
+    guest_iommu_destroy(d);
     deallocate_iommu_page_tables(d);
     amd_iommu_flush_all_pages(d);
 }
xen/include/asm-x86/amd-iommu.h +59 -0

69 lines not on this page · raw message

xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +44 -2

100 lines not on this page · raw message

xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +10 -0
diff -r b190e3362524 -r ea52a2b93dff xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -71,6 +71,8 @@ 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 iommu_dte_set_guest_cr3(u32 *dte, u16 dom_id, u64 gcr3, 
+                             int gv, unsigned int glx);
 
 /* send cmd to iommu */
 void amd_iommu_flush_all_pages(struct domain *d);
@@ -106,6 +108,14 @@ void amd_iommu_resume(void);
 void amd_iommu_suspend(void);
 void amd_iommu_crash_shutdown(void);
 
+/* guest iommu support */
+void amd_iommu_send_guest_cmd(struct amd_iommu *iommu, u32 cmd[]);
+void guest_iommu_add_ppr_log(struct domain *d, u32 entry[]);
+void guest_iommu_add_event_log(struct domain *d, u32 entry[]);
+int guest_iommu_init(struct domain* d);
+void guest_iommu_destroy(struct domain *d);
+int guest_iommu_set_base(struct domain *d, uint64_t base);
+
 static inline u32 get_field_from_reg_u32(u32 reg_value, u32 mask, u32 shift)
 {
     u32 field;
xen/include/xen/hvm/iommu.h +1 -0
diff -r b190e3362524 -r ea52a2b93dff xen/include/xen/hvm/iommu.h
@@ -47,6 +47,7 @@ struct hvm_iommu {
     int domain_id;
     int paging_mode;
     struct page_info *root_table;
+    struct guest_iommu *g_iommu;
 
     /* iommu_ops */
     const struct iommu_ops *platform_ops;
author
#8 lore raw

PATCH 1/1 amd iommu: Enable ppr log

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875319 -3600
# Node ID d3aa7f936872abacb7e059393fa8963db35c4045
# Parent ea52a2b93dffe708084fdc6ee663bd5eee8c1031
amd iommu: Enable ppr log.
IOMMUv2 writes peripheral page service request (PPR) records into ppr log to report DMA page request from ATS devices to OS.

xen/drivers/passthrough/amd/iommu_init.c +84 -4
diff -r ea52a2b93dff -r d3aa7f936872 xen/drivers/passthrough/amd/iommu_init.c
@@ -178,6 +178,34 @@ static void register_iommu_event_log_in_
     writel(entry, iommu->mmio_base+IOMMU_EVENT_LOG_BASE_HIGH_OFFSET);
 }
 
+static void register_iommu_ppr_log_in_mmio_space(struct amd_iommu *iommu)
+{
+    u64 addr_64, addr_lo, addr_hi;
+    u32 power_of2_entries;
+    u32 entry;
+
+    ASSERT ( iommu->ppr_log.buffer );
+
+    addr_64 = (u64)virt_to_maddr(iommu->ppr_log.buffer);
+    addr_lo = addr_64 & DMA_32BIT_MASK;
+    addr_hi = addr_64 >> 32;
+
+    entry = 0;
+    iommu_set_addr_lo_to_reg(&entry, addr_lo >> PAGE_SHIFT);
+    writel(entry, iommu->mmio_base + IOMMU_PPR_LOG_BASE_LOW_OFFSET);
+
+    power_of2_entries = get_order_from_bytes(iommu->ppr_log.alloc_size) +
+                        IOMMU_PPR_LOG_POWER_OF2_ENTRIES_PER_PAGE;
+
+    entry = 0;
+    iommu_set_addr_hi_to_reg(&entry, addr_hi);
+    set_field_in_reg_u32(power_of2_entries, entry,
+                        IOMMU_PPR_LOG_LENGTH_MASK,
+                        IOMMU_PPR_LOG_LENGTH_SHIFT, &entry);
+    writel(entry, iommu->mmio_base + IOMMU_PPR_LOG_BASE_HIGH_OFFSET);
+}
+
+
 static void set_iommu_translation_control(struct amd_iommu *iommu,
                                                  int enable)
 {
@@ -278,6 +306,35 @@ static void set_iommu_event_log_control(
     writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
 }
 
+static void set_iommu_ppr_log_control(struct amd_iommu *iommu,
+                                      int enable)
+{
+    u32 entry;
+
+    entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+
+    /*reset head and tail pointer manually before enablement */
+    if ( enable )
+    {
+        writel(0x0, iommu->mmio_base + IOMMU_PPR_LOG_HEAD_OFFSET);
+        writel(0x0, iommu->mmio_base + IOMMU_PPR_LOG_TAIL_OFFSET);
+
+        iommu_set_bit(&entry, IOMMU_CONTROL_PPR_ENABLE_SHIFT);
+        iommu_set_bit(&entry, IOMMU_CONTROL_PPR_INT_SHIFT);
+        iommu_set_bit(&entry, IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT);
+    }
+    else
+    {
+        iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_ENABLE_SHIFT);
+        iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_INT_SHIFT);
+        iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT);
+    }
+
+    writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+    if ( enable )
+        AMD_IOMMU_DEBUG("PPR Log Enabled.\n");
+}
+
 static void parse_event_log_entry(struct amd_iommu *, u32 entry[]);
 
 static int amd_iommu_read_event_log(struct amd_iommu *iommu)
@@ -585,12 +642,19 @@ static void enable_iommu(struct amd_iomm
     register_iommu_event_log_in_mmio_space(iommu);
     register_iommu_exclusion_range(iommu);
 
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+        register_iommu_ppr_log_in_mmio_space(iommu);
+
     iommu_msi_set_affinity(irq_to_desc(iommu->irq), &cpu_online_map);
     amd_iommu_msi_enable(iommu, IOMMU_CONTROL_ENABLED);
 
     set_iommu_ht_flags(iommu);
     set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_ENABLED);
     set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
+
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+        set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_ENABLED);
+
     set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
 
     if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
@@ -672,16 +736,29 @@ static void * __init allocate_event_log(
                                 IOMMU_EVENT_LOG_DEFAULT_ENTRIES, "Event Log");
 }
 
+static void * __init allocate_ppr_log(struct amd_iommu *iommu)
+{
+    /* allocate 'ppr log' in power of 2 increments of 4K */
+    return allocate_ring_buffer(&iommu->ppr_log, sizeof(ppr_entry_t),
+                                IOMMU_PPR_LOG_DEFAULT_ENTRIES, "PPR Log");
+}
+
 static int __init amd_iommu_init_one(struct amd_iommu *iommu)
 {
+    if ( map_iommu_mmio_region(iommu) != 0 )
+        goto error_out;
+
+    get_iommu_features(iommu);
+
     if ( allocate_cmd_buffer(iommu) == NULL )
         goto error_out;
 
     if ( allocate_event_log(iommu) == NULL )
         goto error_out;
 
-    if ( map_iommu_mmio_region(iommu) != 0 )
-        goto error_out;
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+        if ( allocate_ppr_log(iommu) == NULL )
+            goto error_out;
 
     if ( set_iommu_interrupt_handler(iommu) == 0 )
         goto error_out;
@@ -694,8 +771,6 @@ 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++;
@@ -718,6 +793,7 @@ static void __init amd_iommu_init_cleanu
         {
             deallocate_ring_buffer(&iommu->cmd_buffer);
             deallocate_ring_buffer(&iommu->event_log);
+            deallocate_ring_buffer(&iommu->ppr_log);
             unmap_iommu_mmio_region(iommu);
         }
         xfree(iommu);
@@ -916,6 +992,10 @@ static void disable_iommu(struct amd_iom
     amd_iommu_msi_enable(iommu, IOMMU_CONTROL_DISABLED);
     set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_DISABLED);
     set_iommu_event_log_control(iommu, IOMMU_CONTROL_DISABLED);
+
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
+        set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_DISABLED);
+
     set_iommu_translation_control(iommu, IOMMU_CONTROL_DISABLED);
 
     iommu->enabled = 0;
xen/include/asm-x86/amd-iommu.h +1 -0
diff -r ea52a2b93dff -r d3aa7f936872 xen/include/asm-x86/amd-iommu.h
@@ -94,6 +94,7 @@ struct amd_iommu {
     struct table_struct dev_table;
     struct ring_buffer cmd_buffer;
     struct ring_buffer event_log;
+    struct ring_buffer ppr_log;
 
     int exclusion_enable;
     int exclusion_allow_all;
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +3 -0
diff -r ea52a2b93dff -r d3aa7f936872 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -27,6 +27,9 @@
 /* IOMMU Event Log entries: in power of 2 increments, minimum of 256 */
 #define IOMMU_EVENT_LOG_DEFAULT_ENTRIES     512
 
+/* IOMMU PPR Log entries: in power of 2 increments, minimum of 256 */
+#define IOMMU_PPR_LOG_DEFAULT_ENTRIES       512
+
 #define PTE_PER_TABLE_SHIFT		9
 #define PTE_PER_TABLE_SIZE		(1 << PTE_PER_TABLE_SHIFT)
 #define PTE_PER_TABLE_MASK		(~(PTE_PER_TABLE_SIZE - 1))
author
#9 lore raw

PATCH 1/1 amd iommu: Enable guest level translation

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875770 -3600
# Node ID be3f15ae6a4153504bbb3376291a2383684afee5
# Parent d3aa7f936872abacb7e059393fa8963db35c4045
amd iommu: Enable guest level translation.
Similar to nested paging for SVM, IOMMUv2 supports two level translations for DMA. This patch enables this feature.

xen/drivers/passthrough/amd/iommu_init.c +23 -0
diff -r d3aa7f936872 -r be3f15ae6a41 xen/drivers/passthrough/amd/iommu_init.c
@@ -220,6 +220,23 @@ static void set_iommu_translation_contro
     writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
 }
 
+static void set_iommu_guest_translation_control(struct amd_iommu *iommu,
+                                                int enable)
+{
+    u32 entry;
+
+    entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+
+    enable ?
+        iommu_set_bit(&entry, IOMMU_CONTROL_GT_ENABLE_SHIFT):
+        iommu_clear_bit(&entry, IOMMU_CONTROL_GT_ENABLE_SHIFT);
+
+    writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
+
+    if ( enable )
+        AMD_IOMMU_DEBUG("Guest Translation Enabled.\n");
+}
+
 static void set_iommu_command_buffer_control(struct amd_iommu *iommu,
                                                     int enable)
 {
@@ -655,6 +672,9 @@ static void enable_iommu(struct amd_iomm
     if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
         set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_ENABLED);
 
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_GTSUP_SHIFT) )
+        set_iommu_guest_translation_control(iommu, IOMMU_CONTROL_ENABLED);
+
     set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
 
     if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_IASUP_SHIFT) )
@@ -996,6 +1016,9 @@ static void disable_iommu(struct amd_iom
     if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_PPRSUP_SHIFT) )
         set_iommu_ppr_log_control(iommu, IOMMU_CONTROL_DISABLED);
 
+    if ( iommu_has_feature(iommu, IOMMU_EXT_FEATURE_GTSUP_SHIFT) )
+        set_iommu_guest_translation_control(iommu, IOMMU_CONTROL_DISABLED);
+
     set_iommu_translation_control(iommu, IOMMU_CONTROL_DISABLED);
 
     iommu->enabled = 0;
author
#10 lore raw

PATCH 1/1 amd iommu: add ppr log processing into iommu interrupt handling

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875771 -3600
# Node ID fbed4e6011fce13d3a521bbc339f4959bf32a06c
# Parent be3f15ae6a4153504bbb3376291a2383684afee5
amd iommu: add ppr log processing into iommu interrupt handling PPR log and event log share the same interrupt source. Interrupt handler should check both of them.

xen/drivers/passthrough/amd/iommu_init.c +121 -43
diff -r be3f15ae6a41 -r fbed4e6011fc xen/drivers/passthrough/amd/iommu_init.c
@@ -352,75 +352,91 @@ static void set_iommu_ppr_log_control(st
         AMD_IOMMU_DEBUG("PPR Log Enabled.\n");
 }
 
-static void parse_event_log_entry(struct amd_iommu *, u32 entry[]);
+/* read event log or ppr log from iommu ring buffer */
+static int iommu_read_log(struct amd_iommu *iommu, 
+                          struct ring_buffer *log,
+                          void (*parse_func)(struct amd_iommu *, u32 *))
+{
+    u32 tail, head, *entry, tail_offest, head_offset;
 
-static int amd_iommu_read_event_log(struct amd_iommu *iommu)
-{
-    u32 tail, head, *event_log;
-
-    BUG_ON( !iommu );
+    BUG_ON( !iommu || ((log != &iommu->event_log) && 
+            (log != &iommu->ppr_log)) );
 
     /* make sure there's an entry in the log */
-    tail = readl(iommu->mmio_base + IOMMU_EVENT_LOG_TAIL_OFFSET);
-    tail = get_field_from_reg_u32(tail,
-                                  IOMMU_EVENT_LOG_TAIL_MASK,
-                                  IOMMU_EVENT_LOG_TAIL_SHIFT);
+    tail_offest = ( log == &iommu->event_log ) ?
+        IOMMU_EVENT_LOG_TAIL_OFFSET:
+        IOMMU_PPR_LOG_TAIL_OFFSET;
 
-    while ( tail != iommu->event_log.head )
+    head_offset = ( log == &iommu->event_log ) ?
+        IOMMU_EVENT_LOG_HEAD_OFFSET:
+        IOMMU_PPR_LOG_HEAD_OFFSET;
+
+    tail = readl(iommu->mmio_base + tail_offest);
+    tail = iommu_get_rb_pointer(tail);
+
+    while ( tail != log->head )
     {
         /* read event log entry */
-        event_log = (u32 *)(iommu->event_log.buffer +
-                           (iommu->event_log.head *
-                           IOMMU_EVENT_LOG_ENTRY_SIZE));
+        entry = (u32 *)(log->buffer + log->head * log->entry_size);
 
-        parse_event_log_entry(iommu, event_log);
-
-        if ( ++iommu->event_log.head == iommu->event_log.entries )
-            iommu->event_log.head = 0;
+        parse_func(iommu, entry);
+        if ( ++log->head == log->entries )
+            log->head = 0;
 
         /* update head pointer */
-        set_field_in_reg_u32(iommu->event_log.head, 0,
-                             IOMMU_EVENT_LOG_HEAD_MASK,
-                             IOMMU_EVENT_LOG_HEAD_SHIFT, &head);
-        writel(head, iommu->mmio_base + IOMMU_EVENT_LOG_HEAD_OFFSET);
+        head = 0;
+        iommu_set_rb_pointer(&head, log->head);
+
+        writel(head, iommu->mmio_base + head_offset);
     }
 
     return 0;
 }
 
-static void amd_iommu_reset_event_log(struct amd_iommu *iommu)
+/* reset event log or ppr log when overflow */
+static void iommu_reset_log(struct amd_iommu *iommu,
+                            struct ring_buffer *log,
+                            void (*ctrl_func)(struct amd_iommu *iommu, int))
 {
     u32 entry;
-    int log_run;
+    int log_run, run_bit, of_bit;
     int loop_count = 1000;
 
+    BUG_ON( !iommu || ((log != &iommu->event_log) && 
+            (log != &iommu->ppr_log)) );
+
+    run_bit = ( log == &iommu->event_log ) ?
+        IOMMU_STATUS_EVENT_LOG_RUN_SHIFT:
+        IOMMU_STATUS_PPR_LOG_RUN_SHIFT;
+
+    of_bit = ( log == &iommu->event_log ) ?
+        IOMMU_STATUS_EVENT_OVERFLOW_SHIFT:
+        IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT;
+
     /* wait until EventLogRun bit = 0 */
     do {
         entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
-        log_run = iommu_get_bit(entry, IOMMU_STATUS_EVENT_LOG_RUN_SHIFT);
+        log_run = iommu_get_bit(entry, run_bit);
         loop_count--;
     } while ( log_run && loop_count );
 
     if ( log_run )
     {
-        AMD_IOMMU_DEBUG("Warning: EventLogRun bit is not cleared"
-                        "before reset!\n");
+        AMD_IOMMU_DEBUG("Warning: Log Run bit %d is not cleared"
+                        "before reset! \n", run_bit);
         return;
     }
 
-    set_iommu_event_log_control(iommu, IOMMU_CONTROL_DISABLED);
+    ctrl_func(iommu, IOMMU_CONTROL_DISABLED);
 
-    /* read event log for debugging */
-    amd_iommu_read_event_log(iommu);
     /*clear overflow bit */
-    iommu_clear_bit(&entry, IOMMU_STATUS_EVENT_OVERFLOW_SHIFT);
-
-    writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
+    iommu_clear_bit(&entry, of_bit);
+    writel(entry, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
 
     /*reset event log base address */
-    iommu->event_log.head = 0;
+    log->head = 0;
 
-    set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
+    ctrl_func(iommu, IOMMU_CONTROL_ENABLED);
 }
 
 static void iommu_msi_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
@@ -592,30 +608,93 @@ static void parse_event_log_entry(struct
     }
 }
 
-static void amd_iommu_page_fault(int irq, void *dev_id,
-                             struct cpu_user_regs *regs)
+static void iommu_check_event_log(struct amd_iommu *iommu)
 {
     u32 entry;
     unsigned long flags;
-    struct amd_iommu *iommu = dev_id;
 
     spin_lock_irqsave(&iommu->lock, flags);
-    amd_iommu_read_event_log(iommu);
+
+    iommu_read_log(iommu, &iommu->event_log, parse_event_log_entry);
 
     /*check event overflow */
     entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
 
     if ( iommu_get_bit(entry, IOMMU_STATUS_EVENT_OVERFLOW_SHIFT) )
-        amd_iommu_reset_event_log(iommu);
+        iommu_reset_log(iommu, &iommu->event_log, set_iommu_event_log_control);
 
     /* reset interrupt status bit */
     entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
     iommu_set_bit(&entry, IOMMU_STATUS_EVENT_LOG_INT_SHIFT);
 
-    writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
+    writel(entry, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+
     spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
+void parse_ppr_log_entry(struct amd_iommu *iommu, u32 entry[])
+{
+
+    u16 device_id;
+    u8 bus, devfn;
+    struct pci_dev *pdev;
+    struct domain *d;
+
+    /* here device_id is physical value */
+    device_id = iommu_get_devid_from_cmd(entry[0]);
+    bus = device_id >> 8;
+    devfn = device_id & 0xFF;
+
+    local_irq_enable();
+
+    spin_lock(&pcidevs_lock);
+    pdev = pci_get_pdev(0, bus, devfn);
+    spin_unlock(&pcidevs_lock);
+
+    local_irq_disable();
+
+    if ( pdev == NULL )
+        return; 
+
+    d = pdev->domain;
+
+    guest_iommu_add_ppr_log(d, entry);
+}
+
+static void iommu_check_ppr_log(struct amd_iommu *iommu)
+{
+    u32 entry;
+    unsigned long flags;
+
+    spin_lock_irqsave(&iommu->lock, flags);
+
+    iommu_read_log(iommu, &iommu->ppr_log, parse_ppr_log_entry);
+
+    /*check event overflow */
+    entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+
+    if ( iommu_get_bit(entry, IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT) )
+        iommu_reset_log(iommu, &iommu->ppr_log, set_iommu_ppr_log_control);
+
+    /* reset interrupt status bit */
+    entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+    iommu_set_bit(&entry, IOMMU_STATUS_PPR_LOG_INT_SHIFT);
+
+    writel(entry, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+
+    spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void iommu_interrupt_handler(int irq, void *dev_id,
+                                    struct cpu_user_regs *regs)
+{
+    struct amd_iommu *iommu = dev_id;
+    iommu_check_event_log(iommu);
+
+    if ( iommu->ppr_log.buffer != NULL )
+        iommu_check_ppr_log(iommu);
+}
+
 static int __init set_iommu_interrupt_handler(struct amd_iommu *iommu)
 {
     int irq, ret;
@@ -628,8 +707,7 @@ static int __init set_iommu_interrupt_ha
     }
     
     irq_desc[irq].handler = &iommu_msi_type;
-    ret = request_irq(irq, amd_iommu_page_fault, 0,
-                             "amd_iommu", iommu);
+    ret = request_irq(irq, iommu_interrupt_handler, 0, "amd_iommu", iommu);
     if ( ret )
     {
         irq_desc[irq].handler = &no_irq_type;
author
#11 lore raw

PATCH 1/1 amd iommu: Add 2 hypercalls for libxc

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875772 -3600
# Node ID ef5698887d044ad58293bee3549eaa20310c2b17 # Parent fbed4e6011fce13d3a521bbc339f4959bf32a06c amd iommu: Add 2 hypercalls for libxc

iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest space. Hypervisor needs this vector to inject msi into guest when PPR logging happens.

iommu_bind_bdf: used by xl to bind guest bdf number to machine bdf number. IOMMU emulations codes receives commands from guest iommu driver and forwards them to host iommu. But virtual device id from guest should be converted into physical before sending to real hardware.

Signed -off-by: Wei Wang <[email protected]>

xen/drivers/passthrough/amd/iommu_guest.c +57 -2
diff -r fbed4e6011fc -r ef5698887d04 xen/drivers/passthrough/amd/iommu_guest.c
@@ -50,12 +50,27 @@
 
 static unsigned int machine_bdf(struct domain *d, uint16_t guest_bdf)
 {
-    return guest_bdf;
+    struct pci_dev *pdev;
+    uint16_t mbdf = 0;
+
+    for_each_pdev( d, pdev )
+    {
+        if ( pdev->gbdf == guest_bdf )
+        {
+            mbdf = PCI_BDF2(pdev->bus, pdev->devfn);
+            break;
+        }
+    }
+    return mbdf;
 }
 
 static uint16_t guest_bdf(struct domain *d, uint16_t machine_bdf)
 {
-    return machine_bdf;
+    struct pci_dev *pdev;
+
+    pdev = pci_get_pdev_by_domain(d, 0, PCI_BUS(machine_bdf),
+                                  PCI_DEVFN2(machine_bdf));
+    return pdev->gbdf;
 }
 
 static inline struct guest_iommu *domain_iommu(struct domain *d)
@@ -951,3 +966,43 @@ const struct hvm_mmio_handler iommu_mmio
     .read_handler = guest_iommu_mmio_read,
     .write_handler = guest_iommu_mmio_write
 };
+
+/* iommu hypercall handler */
+int iommu_bind_bdf(struct domain* d, uint16_t gbdf, uint16_t mbdf)
+{
+    struct pci_dev *pdev;
+    int ret = -ENODEV;
+
+    if ( !iommu_found() )
+        return 0;
+
+    spin_lock(&pcidevs_lock);
+
+    for_each_pdev( d, pdev )
+    {
+        if ( (pdev->bus != PCI_BUS(mbdf) ) || 
+             (pdev->devfn != PCI_DEVFN2(mbdf)) )
+            continue;
+
+        pdev->gbdf = gbdf;
+        ret = 0;
+    }
+
+    spin_unlock(&pcidevs_lock);
+    return ret;
+}
+
+void iommu_set_msi(struct domain* d, uint16_t vector, uint16_t dest,
+                   uint16_t dest_mode, uint16_t delivery_mode, 
+                   uint16_t trig_mode)
+{
+    struct guest_iommu *iommu = domain_iommu(d);
+
+    if ( !iommu_found() )
+        return;
+
+    iommu->msi.vector = vector;
+    iommu->msi.dest = dest;
+    iommu->msi.dest_mode = dest_mode;
+    iommu->msi.trig_mode = trig_mode;
+}
xen/drivers/passthrough/iommu.c +34 -0
diff -r fbed4e6011fc -r ef5698887d04 xen/drivers/passthrough/iommu.c
@@ -640,6 +640,40 @@ int iommu_do_domctl(
         put_domain(d);
         break;
 
+#ifndef __ia64__ 
+    case XEN_DOMCTL_guest_iommu_op:
+    {
+        xen_domctl_guest_iommu_op_t * guest_op;
+
+        if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
+        {
+            gdprintk(XENLOG_ERR,
+                    "XEN_DOMCTL_guest_iommu_op: get_domain_by_id() failed\n");
+            ret = -EINVAL;
+            break;
+        }
+
+        guest_op = &(domctl->u.guest_iommu_op);
+        switch ( guest_op->op )
+        {
+            case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI:
+                iommu_set_msi(d, guest_op->u.msi.vector, 
+                              guest_op->u.msi.dest,
+                              guest_op->u.msi.dest_mode, 
+                              guest_op->u.msi.delivery_mode,
+                              guest_op->u.msi.trig_mode);
+                ret = 0;
+                break;
+            case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF:
+                ret = iommu_bind_bdf(d, guest_op->u.bdf_bind.g_bdf,
+                                     guest_op->u.bdf_bind.m_bdf);
+                break;
+        }
+        put_domain(d);
+        break;
+    }
+#endif
+
     default:
         ret = -ENOSYS;
         break;
xen/include/public/domctl.h +27 -0
diff -r fbed4e6011fc -r ef5698887d04 xen/include/public/domctl.h
@@ -848,6 +848,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+#if defined(__i386__) || defined(__x86_64__)
+/* Support for guest iommu emulation */
+struct xen_domctl_guest_iommu_op {
+    /* XEN_DOMCTL_GUEST_IOMMU_OP_* */
+#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI               0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF              1
+    uint8_t op;
+    union {
+        struct iommu_msi {
+        uint8_t  vector;
+        uint8_t  dest;
+        uint8_t  dest_mode;
+        uint8_t  delivery_mode;
+        uint8_t  trig_mode;
+        } msi;
+        struct bdf_bind { 
+            uint32_t            g_bdf;
+            uint32_t            m_bdf;
+        } bdf_bind;
+    } u;
+};
+typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_guest_iommu_op_t);
+#endif
+
 struct xen_domctl {
     uint32_t cmd;
 #define XEN_DOMCTL_createdomain                   1
@@ -912,6 +937,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_getvcpuextstate               63
 #define XEN_DOMCTL_set_access_required           64
 #define XEN_DOMCTL_audit_p2m                     65
+#define XEN_DOMCTL_guest_iommu_op                66
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -963,6 +989,7 @@ struct xen_domctl {
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
         struct xen_domctl_vcpuextstate      vcpuextstate;
+        struct xen_domctl_guest_iommu_op    guest_iommu_op;
 #endif
         struct xen_domctl_set_access_required access_required;
         struct xen_domctl_audit_p2m         audit_p2m;
xen/include/xen/iommu.h +8 -0
diff -r fbed4e6011fc -r ef5698887d04 xen/include/xen/iommu.h
@@ -164,6 +164,14 @@ int iommu_do_domctl(struct xen_domctl *,
 void iommu_iotlb_flush(struct domain *d, unsigned long gfn, unsigned int page_count);
 void iommu_iotlb_flush_all(struct domain *d);
 
+#ifndef __ia64_
+/* Only used by AMD IOMMU */
+void iommu_set_msi(struct domain* d, uint16_t vector, uint16_t dest,
+                   uint16_t dest_mode, uint16_t delivery_mode, 
+                   uint16_t trig_mode);
+int iommu_bind_bdf(struct domain* d, uint16_t gbdf, uint16_t mbdf);
+#endif
+
 /*
  * The purpose of the iommu_dont_flush_iotlb optional cpu flag is to
  * avoid unecessary iotlb_flush in the low level IOMMU code.
xen/include/xen/pci.h +3 -0
diff -r fbed4e6011fc -r ef5698887d04 xen/include/xen/pci.h
@@ -63,6 +63,9 @@ struct pci_dev {
     const u8 devfn;
     struct pci_dev_info info;
     u64 vf_rlen[6];
+
+    /* used by amd iomm to represent bdf value in guest space */
+    u16 gbdf;
 };
 
 #define for_each_pdev(domain, pdev) \
author
#16 lore raw

PATCH 1/1 amd iommu: Add a hypercall for hvmloader

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875773 -3600
# Node ID 52dbaf1fb0e0364fad40f9be330f80e157c935e4 # Parent ef5698887d044ad58293bee3549eaa20310c2b17 amd iommu: Add a hypercall for hvmloader.
IOMMU MMIO base address is dynamically allocated by firmware. This patch allows hvmloader to notify hypervisor where the iommu mmio pages are.

xen/arch/x86/hvm/hvm.c +4 -0
diff -r ef5698887d04 -r 52dbaf1fb0e0 xen/arch/x86/hvm/hvm.c
@@ -65,6 +65,7 @@
 #include <public/memory.h>
 #include <asm/mem_event.h>
 #include <public/mem_event.h>
+#include <asm/hvm/svm/amd-iommu-proto.h>
 
 bool_t __read_mostly hvm_enabled;
 
@@ -3676,6 +3677,9 @@ long do_hvm_op(unsigned long op, XEN_GUE
             case HVM_PARAM_BUFIOREQ_EVTCHN:
                 rc = -EINVAL;
                 break;
+            case HVM_PARAM_IOMMU_BASE:
+                rc = guest_iommu_set_base(d, a.value);
+                break;
             }
 
             if ( rc == 0 ) 
xen/include/public/hvm/params.h +5 -1
diff -r ef5698887d04 -r 52dbaf1fb0e0 xen/include/public/hvm/params.h
@@ -142,6 +142,10 @@
 /* Boolean: Enable nestedhvm (hvm only) */
 #define HVM_PARAM_NESTEDHVM    24
 
-#define HVM_NR_PARAMS          27
+#ifndef __ia64__
+#define HVM_PARAM_IOMMU_BASE   27
+#endif
+
+#define HVM_NR_PARAMS          28
 
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
author
#17 lore raw

PATCH 1/1 amd iommu: add iommu mmio handler

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875774 -3600
# Node ID f33af4d61321d074a4c624d909204fce5945f61b # Parent 52dbaf1fb0e0364fad40f9be330f80e157c935e4 amd iommu: add iommu mmio handler.

xen/arch/x86/hvm/intercept.c +2 -1
diff -r 52dbaf1fb0e0 -r f33af4d61321 xen/arch/x86/hvm/intercept.c
@@ -38,7 +38,8 @@ hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] =
     &hpet_mmio_handler,
     &vlapic_mmio_handler,
     &vioapic_mmio_handler,
-    &msixtbl_mmio_handler
+    &msixtbl_mmio_handler,
+    &iommu_mmio_handler
 };
 
 static int hvm_mmio_access(struct vcpu *v,
xen/include/asm-x86/hvm/io.h +2 -1
diff -r 52dbaf1fb0e0 -r f33af4d61321 xen/include/asm-x86/hvm/io.h
@@ -69,8 +69,9 @@ extern const struct hvm_mmio_handler hpe
 extern const struct hvm_mmio_handler vlapic_mmio_handler;
 extern const struct hvm_mmio_handler vioapic_mmio_handler;
 extern const struct hvm_mmio_handler msixtbl_mmio_handler;
+extern const struct hvm_mmio_handler iommu_mmio_handler;
 
-#define HVM_MMIO_HANDLER_NR 4
+#define HVM_MMIO_HANDLER_NR 5
 
 int hvm_io_intercept(ioreq_t *p, int type);
 void register_io_handler(
author
#18 lore raw

PATCH 1/1 amd iommu: Enable FC bit in iommu host level PTE

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875775 -3600
# Node ID 001681ff1a0c09c4d04fd8bd45e8d26805686246 # Parent f33af4d61321d074a4c624d909204fce5945f61b amd iommu: Enable FC bit in iommu host level PTE

xen/drivers/passthrough/amd/iommu_map.c +5 -0
diff -r f33af4d61321 -r 001681ff1a0c xen/drivers/passthrough/amd/iommu_map.c
@@ -83,6 +83,11 @@ static bool_t set_iommu_pde_present(u32 
     set_field_in_reg_u32(ir, entry,
                          IOMMU_PDE_IO_READ_PERMISSION_MASK,
                          IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);
+
+    /* IOMMUv2 needs FC bit enabled  */
+    if ( next_level == IOMMU_PAGING_MODE_LEVEL_0 )
+        set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+                             IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT, &entry);
     pde[1] = entry;
 
     /* mark next level as 'present' */
author
#19 lore raw

PATCH 1/1 amd iommu: Add a new flag to indication iommuv2 feature enabled or not

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875776 -3600
# Node ID 9a93e064dd3c467ce4b87ddef8739a3573ef547c
# Parent 001681ff1a0c09c4d04fd8bd45e8d26805686246
amd iommu: Add a new flag to indication iommuv2 feature enabled or not. Hypercalls should return early on non-iommuv2 systems.

xen/drivers/passthrough/amd/iommu_guest.c +9 -4
diff -r 001681ff1a0c -r 9a93e064dd3c xen/drivers/passthrough/amd/iommu_guest.c
@@ -48,6 +48,8 @@
         (reg)->hi = (val >> 32) & 0xFFFFFFFF; \
     } while(0)
 
+extern bool_t iommuv2_enabled;
+
 static unsigned int machine_bdf(struct domain *d, uint16_t guest_bdf)
 {
     struct pci_dev *pdev;
@@ -839,6 +841,9 @@ int guest_iommu_set_base(struct domain *
     p2m_type_t t;
     struct guest_iommu *iommu = domain_iommu(d);
 
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
+        return 1;
+
     iommu->mmio_base = base;
     base >>= PAGE_SHIFT;
 
@@ -898,7 +903,7 @@ int guest_iommu_init(struct domain* d)
     struct guest_iommu *iommu;
     struct hvm_iommu *hd  = domain_hvm_iommu(d);
 
-    if ( !is_hvm_domain(d) )
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
         return 0;
 
     iommu = xzalloc(struct guest_iommu);
@@ -940,7 +945,7 @@ void guest_iommu_destroy(struct domain *
 {
     struct guest_iommu *iommu;
 
-    if ( !is_hvm_domain(d) )
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
         return;
 
     iommu = domain_iommu(d);
@@ -973,7 +978,7 @@ int iommu_bind_bdf(struct domain* d, uin
     struct pci_dev *pdev;
     int ret = -ENODEV;
 
-    if ( !iommu_found() )
+    if ( !iommu_found() || !iommuv2_enabled )
         return 0;
 
     spin_lock(&pcidevs_lock);
@@ -998,7 +1003,7 @@ void iommu_set_msi(struct domain* d, uin
 {
     struct guest_iommu *iommu = domain_iommu(d);
 
-    if ( !iommu_found() )
+    if ( !iommu_found() || !iommuv2_enabled )
         return;
 
     iommu->msi.vector = vector;
xen/drivers/passthrough/amd/iommu_init.c +5 -0
diff -r 001681ff1a0c -r 9a93e064dd3c xen/drivers/passthrough/amd/iommu_init.c
@@ -36,6 +36,7 @@ unsigned short ivrs_bdf_entries;
 static struct radix_tree_root ivrs_maps;
 struct list_head amd_iommu_head;
 struct table_struct device_table;
+bool_t iommuv2_enabled;
 
 static int iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
 {
@@ -759,6 +760,10 @@ static void enable_iommu(struct amd_iomm
         amd_iommu_flush_all_caches(iommu);
 
     iommu->enabled = 1;
+
+    if ( iommu->features )
+        iommuv2_enabled = 1;
+
     spin_unlock_irqrestore(&iommu->lock, flags);
 
 }
author
#22 lore raw

PATCH 1/1 hvmloader: Build IVRS table

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876140 -3600
# Node ID 42ecb2ba593c2827b2dc4e54360f8c6a42a4dbfc # Parent 9a93e064dd3c467ce4b87ddef8739a3573ef547c
hvmloader: Build IVRS table.

tools/firmware/hvmloader/acpi/acpi2_0.h +54 -0
diff -r 9a93e064dd3c -r 42ecb2ba593c tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -389,6 +389,60 @@ struct acpi_20_madt_intsrcovr {
 #define ACPI_2_0_WAET_REVISION 0x01
 #define ACPI_1_0_FADT_REVISION 0x01
 
+#define IVRS_SIGNATURE ASCII32('I','V','R','S')
+#define IVRS_REVISION           1
+#define IVRS_VASIZE             64
+#define IVRS_PASIZE             52
+#define IVRS_GVASIZE            64
+
+#define IVHD_BLOCK_TYPE         0x10
+#define IVHD_FLAG_HTTUNEN       (1 << 0)
+#define IVHD_FLAG_PASSPW        (1 << 1)
+#define IVHD_FLAG_RESPASSPW     (1 << 2)
+#define IVHD_FLAG_ISOC          (1 << 3)
+#define IVHD_FLAG_IOTLBSUP      (1 << 4)
+#define IVHD_FLAG_COHERENT      (1 << 5)
+#define IVHD_FLAG_PREFSUP       (1 << 6)
+#define IVHD_FLAG_PPRSUP        (1 << 7)
+
+#define IVHD_EFR_GTSUP          (1 << 2)
+#define IVHD_EFR_IASUP          (1 << 5)
+
+#define IVHD_SELECT_4_BYTE      0x2
+
+struct ivrs_ivhd_block
+{
+    uint8_t    type;
+    uint8_t    flags;
+    uint16_t   length;
+    uint16_t   devid;
+    uint16_t   cap_offset;
+    uint64_t   iommu_base_addr;
+    uint16_t   pci_segment;
+    uint16_t   iommu_info;
+    uint32_t   reserved;
+};
+
+/* IVHD 4-byte device entries */
+struct ivrs_ivhd_device
+{
+   uint8_t  type;
+   uint16_t dev_id;
+   uint8_t  flags;
+};
+
+#define PT_DEV_MAX_NR           32
+#define IOMMU_CAP_OFFSET        0x40
+struct acpi_40_ivrs
+{
+    struct acpi_header                      header;
+    uint32_t                                iv_info;
+    uint32_t                                reserved[2];
+    struct ivrs_ivhd_block                  ivhd_block;
+    struct ivrs_ivhd_device                 ivhd_device[PT_DEV_MAX_NR];
+};
+
+
 #pragma pack ()
 
 struct acpi_config {
tools/firmware/hvmloader/acpi/build.c +81 -0

105 lines not on this page · raw message

tools/firmware/hvmloader/pci.c +30 -1
diff -r 9a93e064dd3c -r 42ecb2ba593c tools/firmware/hvmloader/pci.c
@@ -34,11 +34,17 @@ unsigned long pci_mem_end = PCI_MEM_END;
 enum virtual_vga virtual_vga = VGA_none;
 unsigned long igd_opregion_pgbase = 0;
 
+/* support up to 32 passthrough devices */
+#define PT_DEV_MAX_NR           32
+uint32_t ptdev_bdf[PT_DEV_MAX_NR];
+uint32_t ptdev_nr;
+uint32_t iommu_bdf;
+
 void pci_setup(void)
 {
     uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd, mmio_total = 0;
     uint32_t vga_devfn = 256;
-    uint16_t class, vendor_id, device_id;
+    uint16_t class, vendor_id, device_id, sub_vendor_id;
     unsigned int bar, pin, link, isa_irq;
 
     /* Resources assignable to PCI devices via BARs. */
@@ -72,11 +78,34 @@ void pci_setup(void)
         class     = pci_readw(devfn, PCI_CLASS_DEVICE);
         vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
         device_id = pci_readw(devfn, PCI_DEVICE_ID);
+        sub_vendor_id = pci_readw(devfn, PCI_SUBSYSTEM_VENDOR_ID);
+
         if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
             continue;
 
         ASSERT((devfn != PCI_ISA_DEVFN) ||
                ((vendor_id == 0x8086) && (device_id == 0x7000)));
+        /* Found amd iommu device. */
+        if ( class == 0x0806 && vendor_id == 0x1022 )
+        {
+            iommu_bdf = devfn;
+            printf("Found iommu devfn %x class %x\n", iommu_bdf, class);
+            continue;
+        }
+
+        /* IVRS: Detecting passthrough devices.
+         * sub_vendor_id != citrix && sub_vendor_id != qemu */
+        if ( sub_vendor_id != 0x5853 && sub_vendor_id != 0x1af4 )
+        {
+            /* found amd iommu device */
+            if ( ptdev_nr < PT_DEV_MAX_NR )
+            {
+                ptdev_bdf[ptdev_nr] = devfn;
+                ptdev_nr ++;
+            }
+            else
+                printf("Number of passthru devices > PT_DEV_MAX_NR \n");
+        }
 
         switch ( class )
         {
xen/include/public/hvm/hvm_info_table.h +3 -0
diff -r 9a93e064dd3c -r 42ecb2ba593c xen/include/public/hvm/hvm_info_table.h
@@ -67,6 +67,9 @@ struct hvm_info_table {
 
     /* Bitmap of which CPUs are online at boot time. */
     uint8_t     vcpu_online[(HVM_MAX_VCPUS + 7)/8];
+
+    /* guest iommu enabled */
+    uint8_t     iommu_enabled;
 };
 
 #endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */
author
#24 lore raw

PATCH 1/1 libxc: add wrappers for new hypercalls

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876141 -3600
# Node ID 04573463beff7fc9696f5ecdb940920dcc2ec0ca # Parent 42ecb2ba593c2827b2dc4e54360f8c6a42a4dbfc
libxc: add wrappers for new hypercalls

tools/libxc/xc_domain.c +49 -0
diff -r 42ecb2ba593c -r 04573463beff tools/libxc/xc_domain.c
@@ -1352,6 +1352,55 @@ int xc_domain_bind_pt_isa_irq(
                                   PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq));
 }
 
+int xc_domain_update_iommu_msi(
+    xc_interface *xch,
+    uint32_t domid,
+    uint8_t vector,
+    uint8_t dest,
+    uint8_t dest_mode,
+    uint8_t delivery_mode,
+    uint8_t trig_mode)
+{
+    int rc;
+    DECLARE_DOMCTL;
+    xen_domctl_guest_iommu_op_t * iommu_op;
+
+    domctl.cmd = XEN_DOMCTL_guest_iommu_op;
+    domctl.domain = (domid_t)domid;
+
+    iommu_op = &(domctl.u.guest_iommu_op);
+    iommu_op->op = XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI;
+    iommu_op->u.msi.vector = vector;
+    iommu_op->u.msi.dest = dest;
+    iommu_op->u.msi.dest_mode = dest_mode;
+    iommu_op->u.msi.delivery_mode = delivery_mode;
+    iommu_op->u.msi.trig_mode = trig_mode;
+
+    rc = do_domctl(xch, &domctl);
+    return rc;
+}
+
+int xc_domain_bind_pt_bdf(xc_interface *xch,
+                          uint32_t domid,
+                          uint32_t gbdf,
+                          uint32_t mbdf)
+{
+    int rc;
+    DECLARE_DOMCTL;
+    xen_domctl_guest_iommu_op_t * guest_op;
+
+    domctl.cmd = XEN_DOMCTL_guest_iommu_op;
+    domctl.domain = (domid_t)domid;
+
+    guest_op = &(domctl.u.guest_iommu_op);
+    guest_op->op = XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF;
+    guest_op->u.bdf_bind.g_bdf = gbdf;
+    guest_op->u.bdf_bind.m_bdf = mbdf;
+
+    rc = do_domctl(xch, &domctl);
+    return rc;
+}
+
 int xc_domain_memory_mapping(
     xc_interface *xch,
     uint32_t domid,
tools/libxc/xenctrl.h +13 -0
diff -r 42ecb2ba593c -r 04573463beff tools/libxc/xenctrl.h
@@ -1697,6 +1697,19 @@ int xc_domain_bind_pt_isa_irq(xc_interfa
                               uint32_t domid,
                               uint8_t machine_irq);
 
+int xc_domain_bind_pt_bdf(xc_interface *xch,
+                          uint32_t domid,
+                          uint32_t gbdf,
+                          uint32_t mbdf);
+
+int xc_domain_update_iommu_msi(xc_interface *xch,
+                               uint32_t domid,
+                               uint8_t vector,
+                               uint8_t dest,
+                               uint8_t dest_mode,
+                               uint8_t delivery_mode,
+                               uint8_t trig_mode);
+
 int xc_domain_set_machine_address_size(xc_interface *xch,
 				       uint32_t domid,
 				       unsigned int width);
author
#25 lore raw

PATCH 1/1 libxl: bind virtual bdf to physical bdf after device assignment

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876142 -3600
# Node ID f9575683f10a08a86a9c73226581610fa3f7be4b
# Parent 04573463beff7fc9696f5ecdb940920dcc2ec0ca
libxl: bind virtual bdf to physical bdf after device assignment

tools/libxl/libxl_pci.c +7 -0
diff -r 04573463beff -r f9575683f10a tools/libxl/libxl_pci.c
@@ -735,6 +735,13 @@ out:
             LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_assign_device failed");
             return ERROR_FAIL;
         }
+        if (LIBXL__DOMAIN_IS_TYPE(gc,  domid, HVM)) {
+            rc = xc_domain_bind_pt_bdf(ctx->xch, domid, pcidev->vdevfn, pcidev_encode_bdf(pcidev));
+            if ( rc ) {
+            LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_bind_pt_bdf failed");
+            return ERROR_FAIL;
+            }
+        }
     }
 
     if (!starting)
author
#27 lore raw

PATCH 1/1 libxl: Introduce a new guest config file parameter

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876143 -3600
# Node ID 93658ca85035d6a4e56e2e6602c02859974d30a4 # Parent f9575683f10a08a86a9c73226581610fa3f7be4b
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.

tools/libxl/libxl_create.c +1 -0
diff -r f9575683f10a -r 93658ca85035 tools/libxl/libxl_create.c
@@ -99,6 +99,7 @@ int libxl_init_build_info(libxl_ctx *ctx
         b_info->u.hvm.vpt_align = 1;
         b_info->u.hvm.timer_mode = 1;
         b_info->u.hvm.nested_hvm = 0;
+        b_info->u.hvm.iommu = 0;
         break;
     case LIBXL_DOMAIN_TYPE_PV:
         b_info->u.pv.slack_memkb = 8 * 1024;
tools/libxl/libxl_dom.c +4 -0
diff -r f9575683f10a -r 93658ca85035 tools/libxl/libxl_dom.c
@@ -266,6 +266,10 @@ static int hvm_build_set_params(xc_inter
     va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
     va_hvm->apic_mode = info->u.hvm.apic;
     va_hvm->nr_vcpus = info->max_vcpus;
+
+    if ( info->u.hvm.iommu )
+         va_hvm->iommu_enabled = 1;
+
     memcpy(va_hvm->vcpu_online, &info->cur_vcpus, sizeof(info->cur_vcpus));
     for (i = 0, sum = 0; i < va_hvm->length; i++)
         sum += ((uint8_t *) va_hvm)[i];
tools/libxl/libxl_types.idl +1 -0
diff -r f9575683f10a -r 93658ca85035 tools/libxl/libxl_types.idl
@@ -184,6 +184,7 @@ libxl_domain_build_info = Struct("domain
                                        ("vpt_align", bool),
                                        ("timer_mode", integer),
                                        ("nested_hvm", bool),
+                                       ("iommu", bool),
                                        ])),
                  ("pv", Struct(None, [("kernel", libxl_file_reference),
                                       ("slack_memkb", uint32),
tools/libxl/xl_cmdimpl.c +3 -0
diff -r f9575683f10a -r 93658ca85035 tools/libxl/xl_cmdimpl.c
@@ -360,6 +360,7 @@ static void printf_info(int domid,
         printf("\t\t\t(vpt_align %d)\n", b_info->u.hvm.vpt_align);
         printf("\t\t\t(timer_mode %d)\n", b_info->u.hvm.timer_mode);
         printf("\t\t\t(nestedhvm %d)\n", b_info->u.hvm.nested_hvm);
+        printf("\t\t\t(iommu %d)\n", b_info->u.hvm.iommu);
 
         printf("\t\t\t(device_model %s)\n", dm_info->device_model ? : "default");
         printf("\t\t\t(videoram %d)\n", dm_info->videoram);
@@ -764,6 +765,8 @@ static void parse_config_data(const char
             b_info->u.hvm.timer_mode = l;
         if (!xlu_cfg_get_long (config, "nestedhvm", &l, 0))
             b_info->u.hvm.nested_hvm = l;
+        if (!xlu_cfg_get_long (config, "iommu", &l, 0))
+            b_info->u.hvm.iommu = l;
         break;
     case LIBXL_DOMAIN_TYPE_PV:
     {
author
#29 lore raw

PATCH 1/1 libxl: add iommu parameter to qemu-dm

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876144 -3600
# Node ID 24f4a0a23da71c58f457f0bf98aa8238dd45332d # Parent 93658ca85035d6a4e56e2e6602c02859974d30a4
libxl: add iommu parameter to qemu-dm.
When iomm = 0, virtual iommu device will be disabled.

tools/libxl/libxl_dm.c +6 -0
diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_dm.c
@@ -194,6 +194,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         flexarray_vappend(dm_args, "-loadvm", info->saved_state, NULL);
@@ -404,6 +407,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         /* This file descriptor is meant to be used by QEMU */
tools/libxl/libxl_types.idl +1 -0
diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_types.idl
@@ -254,6 +254,7 @@ The password never expires"""),
     ("extra",            libxl_string_list, False, "extra parameters pass directly to qemu, NULL terminated"),
     ("extra_pv",         libxl_string_list, False, "extra parameters pass directly to qemu for PV guest, NULL terminated"),
     ("extra_hvm",        libxl_string_list, False, "extra parameters pass directly to qemu for HVM guest, NULL terminated"),
+    ("iommu",            bool,              False, "guest iommu enabled or disabled"),
     ],
     comment=
 """Device Model information.
tools/libxl/xl_cmdimpl.c +3 -0
diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/xl_cmdimpl.c
@@ -386,6 +386,7 @@ static void printf_info(int domid,
         printf("\t\t\t(spicedisable_ticketing %d)\n",
                     dm_info->spicedisable_ticketing);
         printf("\t\t\t(spiceagent_mouse %d)\n", dm_info->spiceagent_mouse);
+        printf("\t\t\t(iommu %d)\n", dm_info->iommu);
         printf("\t\t)\n");
         break;
     case LIBXL_DOMAIN_TYPE_PV:
@@ -1217,6 +1218,8 @@ skip_vfb:
         xlu_cfg_replace_string (config, "soundhw", &dm_info->soundhw, 0);
         if (!xlu_cfg_get_long (config, "xen_platform_pci", &l, 0))
             dm_info->xen_platform_pci = l;
+        if (!xlu_cfg_get_long (config, "iommu", &l, 0))
+            dm_info->iommu = l;
     }
 
     dm_info->type = c_info->type;
#12 lore raw

Re: [PATCH 07 of 16] amd iommu: Add 2 hypercalls for libxc

In reply to Wei Wang
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875772 -3600
# Node ID ef5698887d044ad58293bee3549eaa20310c2b17 # Parent fbed4e6011fce13d3a521bbc339f4959bf32a06c amd iommu: Add 2 hypercalls for libxc

Quoted 5 lines

iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest
space. Hypervisor needs this vector to inject msi into guest when PPR logging
happens.

And this cannot be done with the existing MSI emulation?

Quoted 6 lines

iommu_bind_bdf: used by xl to bind guest bdf number to machine bdf number. IOMMU emulations codes receives commands from guest iommu driver and forwards
them to host iommu. But virtual device id from guest should be converted into
physical before sending to real hardware.

The whole logic here needs to take the segment into account. No new code should again ignore the segment numbers.

xen/include/public/domctl.h struct xen_domctl_set_access_required { · line 852

Quoted 8 lines
xen/include/public/domctl.h +1 -0
@@ -848,6 +848,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required 
 xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+#if defined(__i386__) || defined(__x86_64__)

What is x86-specific about these?

Jan

Quoted 27 lines
xen/include/public/domctl.h +24 -0
+/* Support for guest iommu emulation */
+struct xen_domctl_guest_iommu_op {
+    /* XEN_DOMCTL_GUEST_IOMMU_OP_* */
+#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI               0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF              1
+    uint8_t op;
+    union {
+        struct iommu_msi {
+        uint8_t  vector;
+        uint8_t  dest;
+        uint8_t  dest_mode;
+        uint8_t  delivery_mode;
+        uint8_t  trig_mode;
+        } msi;
+        struct bdf_bind { 
+            uint32_t            g_bdf;
+            uint32_t            m_bdf;
+        } bdf_bind;
+    } u;
+};
+typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_guest_iommu_op_t);
+#endif
+
 struct xen_domctl {
     uint32_t cmd;

#define XEN_DOMCTL_createdomain 1

author
#13 lore raw

Re: [PATCH 07 of 16] amd iommu: Add 2 hypercalls for libxc

Quoted 9 lines · On Wednesday 14 December 2011 17:44:18 Jan Beulich wrote:
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875772 -3600
# Node ID ef5698887d044ad58293bee3549eaa20310c2b17 # Parent fbed4e6011fce13d3a521bbc339f4959bf32a06c amd iommu: Add 2 hypercalls for libxc

Quoted 7 lines
Quoted 5 lines

iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest
space. Hypervisor needs this vector to inject msi into guest when PPR logging
happens.

And this cannot be done with the existing MSI emulation?

It looks like MSI emulation are used for passthru devices. I only add virtual amd iommu device and do not passthru amd iommu device. So no physcal msi are required and therefore complicate msi emulation might not be very necessary?

Quoted 9 lines
Quoted 6 lines

iommu_bind_bdf: used by xl to bind guest bdf number to machine bdf number. IOMMU emulations codes receives commands from guest iommu driver and forwards
them to host iommu. But virtual device id from guest should be converted into
physical before sending to real hardware.

The whole logic here needs to take the segment into account. No new code should again ignore the segment numbers.

Sure, I will fix that.

Quoted 10 lines

xen/include/public/domctl.h struct xen_domctl_set_access_required { · line 852

Quoted 8 lines
xen/include/public/domctl.h +1 -0
@@ -848,6 +848,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required
 xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+#if defined(__i386__) || defined(__x86_64__)

What is x86-specific about these?

These hypercalls are only used by AMD. so ia64 should be avoided

Thanks,
Wei

Quoted 29 lines

Jan

Quoted 27 lines
xen/include/public/domctl.h +24 -0
+/* Support for guest iommu emulation */
+struct xen_domctl_guest_iommu_op {
+    /* XEN_DOMCTL_GUEST_IOMMU_OP_* */
+#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI               0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF              1
+    uint8_t op;
+    union {
+        struct iommu_msi {
+        uint8_t  vector;
+        uint8_t  dest;
+        uint8_t  dest_mode;
+        uint8_t  delivery_mode;
+        uint8_t  trig_mode;
+        } msi;
+        struct bdf_bind {
+            uint32_t            g_bdf;
+            uint32_t            m_bdf;
+        } bdf_bind;
+    } u;
+};
+typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_guest_iommu_op_t);
+#endif
+
 struct xen_domctl {
     uint32_t cmd;

#define XEN_DOMCTL_createdomain 1

#14 lore raw

Re: [PATCH 07 of 16] amd iommu: Add 2 hypercalls for libxc

Quoted 17 lines
Quoted 1 line
Quoted 1 line · On 14.12.11 at 17:57, Wei Wang2 <[email protected]> wrote:
Quoted 15 lines · On Wednesday 14 December 2011 17:44:18 Jan Beulich wrote:
Quoted 14 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875772 -3600
# Node ID ef5698887d044ad58293bee3549eaa20310c2b17 # Parent fbed4e6011fce13d3a521bbc339f4959bf32a06c amd iommu: Add 2 hypercalls for libxc

iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest
space. Hypervisor needs this vector to inject msi into guest when PPR logging
happens.

Quoted 5 lines
Quoted 1 line

And this cannot be done with the existing MSI emulation?

It looks like MSI emulation are used for passthru devices. I only add virtual amd iommu device and do not passthru amd iommu device. So no physcal msi are required and therefore complicate msi emulation might not be very necessary?

Makes sense.

Quoted 11 lines
Quoted 10 lines

xen/include/public/domctl.h struct xen_domctl_set_access_required { · line 852

Quoted 8 lines
xen/include/public/domctl.h +1 -0
@@ -848,6 +848,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required
 xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+#if defined(__i386__) || defined(__x86_64__)

What is x86-specific about these?

These hypercalls are only used by AMD. so ia64 should be avoided

Currently. But is there anything in them that makes them unusable for other IOMMUs in the future (from what I can tell only PCI and MSI are fundamentally required, which are certainly present on other platforms)? After all, this is just a type definition and a few manifest constants - I'm not asking that their implementation should be done for other than the case you care about right now.

Jan

author
#15 lore raw

Re: [PATCH 07 of 16] amd iommu: Add 2 hypercalls for libxc

Quoted 38 lines · On Wednesday 14 December 2011 18:03:54 Jan Beulich wrote:
Quoted 18 lines
Quoted 1 line
Quoted 1 line · On 14.12.11 at 17:57, Wei Wang2 <[email protected]> wrote:
Quoted 15 lines · On Wednesday 14 December 2011 17:44:18 Jan Beulich wrote:
Quoted 14 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875772 -3600
# Node ID ef5698887d044ad58293bee3549eaa20310c2b17 # Parent fbed4e6011fce13d3a521bbc339f4959bf32a06c amd iommu: Add 2 hypercalls for libxc

iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest
space. Hypervisor needs this vector to inject msi into guest when PPR logging
happens.

Quoted 6 lines
Quoted 1 line

And this cannot be done with the existing MSI emulation?

It looks like MSI emulation are used for passthru devices. I only add virtual amd iommu device and do not passthru amd iommu device. So no physcal msi are required and therefore complicate msi emulation might not be very necessary?

Makes sense.

Quoted 11 lines
Quoted 10 lines

xen/include/public/domctl.h struct xen_domctl_set_access_required { · line 852

Quoted 8 lines
xen/include/public/domctl.h +1 -0
@@ -848,6 +848,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required
 xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+#if defined(__i386__) || defined(__x86_64__)

What is x86-specific about these?

Quoted 8 lines
Quoted 1 line

These hypercalls are only used by AMD. so ia64 should be avoided

Currently. But is there anything in them that makes them unusable for other IOMMUs in the future (from what I can tell only PCI and MSI are fundamentally required, which are certainly present on other platforms)? After all, this is just a type definition and a few manifest constants - I'm not asking that their implementation should be done for other than the case you care about right now.

Ok, I will change this in the next version. Indeed there is nothing special for x86 in these two hcalls.
Thanks,
Wei

Quoted 1 line

Jan

#35 lore raw
In reply to Wei Wang
Quoted 6 lines
Quoted 1 line
Quoted 1 line · Wei Wang

ATS devices with PRI and PASID capabilities can communicate with iommuv2 to do 2 level (nested) DMA translation and IO demand paging. To do that, both iommu driver and ats device have to been enabled in guest OS. This patch set

adds initial iommu emulation for hvm guests to support ATS device passthru.

I could take care of the first 6 patches in this series, as they're only touching AMD IOMMU code and look sensible to me. I'm not sure though whether this is a good idea without knowing the disposition of the other 10 patches (particularly the relative large 3rd patch doesn't seem to make sense without it later getting hooked up).

Please let me know,
Jan

author
#36 lore raw
Quoted 10 lines · On Thursday 15 December 2011 11:23:58 Jan Beulich wrote:
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Wang

ATS devices with PRI and PASID capabilities can communicate with iommuv2 to do 2 level (nested) DMA translation and IO demand paging. To do that, both iommu driver and ats device have to been enabled in guest OS. This patch set

adds initial iommu emulation for hvm guests to support ATS device passthru.

Quoted 8 lines

I could take care of the first 6 patches in this series, as they're only touching AMD IOMMU code and look sensible to me. I'm not sure though whether this is a good idea without knowing the disposition of the other 10 patches (particularly the relative large 3rd patch doesn't seem to make sense without it later getting hooked up).

Please let me know,
Jan

Actually, the amd specific patches implement the most IOMMUv2 support. Thanks for looking at this. We had thought about how to integrate IOMMUv2 for ATS device passthru. Since guest OS requires iommu to be presented in this case, we could go for either PV interface or full emulation. The iommuv2 driver has just been submitted to Linux mailing list, so this might be too early for pv iommu drivers... Using mmio handler in xen, we can avoid any guest OS changes and can get better performance than using qemu-dm. So this might be the only approach we intend to use at the moment.

But yes, eventually, the iommu emulation is driven by hypercalls. It would be great that tools maintainers could check this in the meantime. so, Ian, could I invite you to take a look at this?

Many thanks,
Wei

#23 lore raw

Re: [PATCH 12 of 16] hvmloader: Build IVRS table

In reply to Wei Wang
Quoted 1 line · Wei Wang

hvmloader: Build IVRS table.

Is there a good reference for what is in this table?

Quoted 7 lines

diff -r 9a93e064dd3c -r 42ecb2ba593c
xen/include/public/hvm/hvm_info_table.h
--- a/xen/include/public/hvm/hvm_info_table.h Wed Dec 14 16:16:16
2011 +0100
+++ b/xen/include/public/hvm/hvm_info_table.h Wed Dec 14 16:22:20
2011 +0100

xen/include/public/hvm/hvm_info_table.h struct hvm_info_table { · line 75

Quoted 9 lines
xen/include/public/hvm/hvm_info_table.h +3 -0
@@ -67,6 +67,9 @@ struct hvm_info_table {
 
     /* Bitmap of which CPUs are online at boot time. */
     uint8_t     vcpu_online[(HVM_MAX_VCPUS + 7)/8];
+
+    /* guest iommu enabled */
+    uint8_t     iommu_enabled;
 };
 
 #endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */

We would like to remove the hvm info table. Please could you do this via xenstore (like Paul Durrant recently did for acpi s3 support) .

Ian.

#4 lore raw

Re: [PATCH 03 of 16] amd iommu: Add iommu emulation for hvm guest

In reply to Wei Wang

Hi,

Quoted 5 lines · Wei Wang
xen/drivers/passthrough/amd/iommu_guest.c new file +5 -0
+static struct page_info* guest_iommu_get_page(struct list_head *pglist,
+                                              unsigned int entry_size,
+                                              unsigned int pos)
+{
+    int idx;

xen/drivers/passthrough/amd/iommu_guest.c line 150

Quoted 10 lines
xen/drivers/passthrough/amd/iommu_guest.c new file +10 -0
+    struct list_head *head;
+    struct guest_pages *gpage = NULL;
+
+    idx = (pos * entry_size) >> PAGE_SHIFT;
+    list_for_each( head, pglist )
+    {
+        gpage = list_entry(head, struct guest_pages, list);
+        if ( (--idx) < 0 )
+            break;
+    }

Given that you allocate all these elements together, and free them, all together, why not just use an array instead of a linked list?

Cheers,

Tim.

#20 lore raw

Re: [PATCH 11 of 16] amd iommu: Add a new flag to indication iommuv2 feature enabled or not

In reply to Wei Wang
Quoted 23 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875776 -3600
# Node ID 9a93e064dd3c467ce4b87ddef8739a3573ef547c
# Parent 001681ff1a0c09c4d04fd8bd45e8d26805686246
amd iommu: Add a new flag to indication iommuv2 feature enabled or not. Hypercalls should return early on non-iommuv2 systems.

diff -r 001681ff1a0c -r 9a93e064dd3c xen/drivers/passthrough/amd/iommu_guest.c

xen/drivers/passthrough/amd/iommu_guest.c +2 -0
@@ -48,6 +48,8 @@
         (reg)->hi = (val >> 32) & 0xFFFFFFFF; \
     } while(0)
 
+extern bool_t iommuv2_enabled;
+
 static unsigned int machine_bdf(struct domain *d, uint16_t guest_bdf)
 {
     struct pci_dev *pdev;

xen/drivers/passthrough/amd/iommu_guest.c int guest_iommu_set_base(struct domain * · line 845

Quoted 5 lines
xen/drivers/passthrough/amd/iommu_guest.c +2 -0
@@ -839,6 +841,9 @@ int guest_iommu_set_base(struct domain *
     p2m_type_t t;
     struct guest_iommu *iommu = domain_iommu(d);
 
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
+        return 1;

Shouldn't that that be || ? (And likewise below)

Cheers,

Tim.

Quoted 68 lines
xen/drivers/passthrough/amd/iommu_guest.c +5 -4
+
     iommu->mmio_base = base;
     base >>= PAGE_SHIFT;
 
@@ -898,7 +903,7 @@ int guest_iommu_init(struct domain* d)
     struct guest_iommu *iommu;
     struct hvm_iommu *hd  = domain_hvm_iommu(d);
 
-    if ( !is_hvm_domain(d) )
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
         return 0;
 
     iommu = xzalloc(struct guest_iommu);
@@ -940,7 +945,7 @@ void guest_iommu_destroy(struct domain *
 {
     struct guest_iommu *iommu;
 
-    if ( !is_hvm_domain(d) )
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
         return;
 
     iommu = domain_iommu(d);
@@ -973,7 +978,7 @@ int iommu_bind_bdf(struct domain* d, uin
     struct pci_dev *pdev;
     int ret = -ENODEV;
 
-    if ( !iommu_found() )
+    if ( !iommu_found() || !iommuv2_enabled )
         return 0;
 
     spin_lock(&pcidevs_lock);
@@ -998,7 +1003,7 @@ void iommu_set_msi(struct domain* d, uin
 {
     struct guest_iommu *iommu = domain_iommu(d);
 
-    if ( !iommu_found() )
+    if ( !iommu_found() || !iommuv2_enabled )
         return;
 
     iommu->msi.vector = vector;

diff -r 001681ff1a0c -r 9a93e064dd3c xen/drivers/passthrough/amd/iommu_init.c

xen/drivers/passthrough/amd/iommu_init.c +5 -0
@@ -36,6 +36,7 @@ unsigned short ivrs_bdf_entries;
 static struct radix_tree_root ivrs_maps;
 struct list_head amd_iommu_head;
 struct table_struct device_table;
+bool_t iommuv2_enabled;
 
 static int iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
 {
@@ -759,6 +760,10 @@ static void enable_iommu(struct amd_iomm
         amd_iommu_flush_all_caches(iommu);
 
     iommu->enabled = 1;
+
+    if ( iommu->features )
+        iommuv2_enabled = 1;
+
     spin_unlock_irqrestore(&iommu->lock, flags);
 
 }

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

author
#21 lore raw

Re: [PATCH 11 of 16] amd iommu: Add a new flag to indication iommuv2 feature enabled or not

Quoted 28 lines · On Thursday 15 December 2011 14:39:15 Tim Deegan wrote:
Quoted 27 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323875776 -3600
# Node ID 9a93e064dd3c467ce4b87ddef8739a3573ef547c
# Parent 001681ff1a0c09c4d04fd8bd45e8d26805686246
amd iommu: Add a new flag to indication iommuv2 feature enabled or not. Hypercalls should return early on non-iommuv2 systems.

diff -r 001681ff1a0c -r 9a93e064dd3c
xen/drivers/passthrough/amd/iommu_guest.c ---
a/xen/drivers/passthrough/amd/iommu_guest.c Wed Dec 14 16:16:15 2011
+0100 +++ b/xen/drivers/passthrough/amd/iommu_guest.c Wed Dec 14 16:16:16
2011 +0100 @@ -48,6 +48,8 @@

         (reg)->hi = (val >> 32) & 0xFFFFFFFF; \
     } while(0)
xen/drivers/passthrough/amd/iommu_guest.c +2 -0
+extern bool_t iommuv2_enabled;
+
 static unsigned int machine_bdf(struct domain *d, uint16_t guest_bdf)
 {
     struct pci_dev *pdev;
@@ -839,6 +841,9 @@ int guest_iommu_set_base(struct domain *
     p2m_type_t t;
     struct guest_iommu *iommu = domain_iommu(d);
 
Quoted 4 lines

xen/drivers/passthrough/amd/iommu_guest.c int guest_iommu_set_base(struct domain * · line 845

Quoted 2 lines
xen/drivers/passthrough/amd/iommu_guest.c +2 -0
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
+        return 1;

Shouldn't that that be || ? (And likewise below)

Oops... I will fix that.

Thanks.
Wei

Quoted 73 lines

Cheers,

Tim.

Quoted 69 lines
xen/drivers/passthrough/amd/iommu_guest.c +5 -4
+
     iommu->mmio_base = base;
     base >>= PAGE_SHIFT;
 
@@ -898,7 +903,7 @@ int guest_iommu_init(struct domain* d)
     struct guest_iommu *iommu;
     struct hvm_iommu *hd  = domain_hvm_iommu(d);
 
-    if ( !is_hvm_domain(d) )
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
         return 0;
 
     iommu = xzalloc(struct guest_iommu);
@@ -940,7 +945,7 @@ void guest_iommu_destroy(struct domain *
 {
     struct guest_iommu *iommu;
 
-    if ( !is_hvm_domain(d) )
+    if ( !is_hvm_domain(d) && !iommuv2_enabled )
         return;
 
     iommu = domain_iommu(d);
@@ -973,7 +978,7 @@ int iommu_bind_bdf(struct domain* d, uin
     struct pci_dev *pdev;
     int ret = -ENODEV;
 
-    if ( !iommu_found() )
+    if ( !iommu_found() || !iommuv2_enabled )
         return 0;
 
     spin_lock(&pcidevs_lock);
@@ -998,7 +1003,7 @@ void iommu_set_msi(struct domain* d, uin
 {
     struct guest_iommu *iommu = domain_iommu(d);
 
-    if ( !iommu_found() )
+    if ( !iommu_found() || !iommuv2_enabled )
         return;
 
     iommu->msi.vector = vector;

diff -r 001681ff1a0c -r 9a93e064dd3c xen/drivers/passthrough/amd/iommu_init.c ---
a/xen/drivers/passthrough/amd/iommu_init.c Wed Dec 14 16:16:15 2011 +0100
+++ b/xen/drivers/passthrough/amd/iommu_init.c Wed Dec 14 16:16:16 2011
+0100 @@ -36,6 +36,7 @@ unsigned short ivrs_bdf_entries;
static struct radix_tree_root ivrs_maps; struct list_head amd_iommu_head;
struct table_struct device_table;

xen/drivers/passthrough/amd/iommu_init.c +5 -0
+bool_t iommuv2_enabled;
 
 static int iommu_has_ht_flag(struct amd_iommu *iommu, u8 mask)
 {
@@ -759,6 +760,10 @@ static void enable_iommu(struct amd_iomm
         amd_iommu_flush_all_caches(iommu);
 
     iommu->enabled = 1;
+
+    if ( iommu->features )
+        iommuv2_enabled = 1;
+
     spin_unlock_irqrestore(&iommu->lock, flags);
 
 }

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

author
#5 lore raw

Re: [PATCH 03 of 16] amd iommu: Add iommu emulation for hvm guest

In reply to Tim Deegan
Quoted 22 lines · On Thursday 15 December 2011 14:35:55 Tim Deegan wrote:

Hi,

Quoted 5 lines · Wei Wang
xen/drivers/passthrough/amd/iommu_guest.c new file +5 -0
+static struct page_info* guest_iommu_get_page(struct list_head *pglist,
+                                              unsigned int entry_size,
+                                              unsigned int pos)
+{
+    int idx;

xen/drivers/passthrough/amd/iommu_guest.c line 150

Quoted 10 lines
xen/drivers/passthrough/amd/iommu_guest.c new file +10 -0
+    struct list_head *head;
+    struct guest_pages *gpage = NULL;
+
+    idx = (pos * entry_size) >> PAGE_SHIFT;
+    list_for_each( head, pglist )
+    {
+        gpage = list_entry(head, struct guest_pages, list);
+        if ( (--idx) < 0 )
+            break;
+    }

Given that you allocate all these elements together, and free them, all together, why not just use an array instead of a linked list?

Quoted 3 lines

Cheers,

Tim.

The numbers of element might be variant. But array should also work, considering iommu tables has max. length of 2MB, the array length is small.

Thanks,
Wei

#6 lore raw

Re: [PATCH 03 of 16] amd iommu: Add iommu emulation for hvm guest

Quoted 24 lines
Quoted 1 line
Quoted 1 line · On 15.12.11 at 15:09, Wei Wang2 <[email protected]> wrote:
Quoted 22 lines · On Thursday 15 December 2011 14:35:55 Tim Deegan wrote:

Hi,

Quoted 5 lines · Wei Wang
xen/drivers/passthrough/amd/iommu_guest.c new file +5 -0
+static struct page_info* guest_iommu_get_page(struct list_head *pglist,
+                                              unsigned int entry_size,
+                                              unsigned int pos)
+{
+    int idx;

xen/drivers/passthrough/amd/iommu_guest.c line 150

Quoted 10 lines
xen/drivers/passthrough/amd/iommu_guest.c new file +10 -0
+    struct list_head *head;
+    struct guest_pages *gpage = NULL;
+
+    idx = (pos * entry_size) >> PAGE_SHIFT;
+    list_for_each( head, pglist )
+    {
+        gpage = list_entry(head, struct guest_pages, list);
+        if ( (--idx) < 0 )
+            break;
+    }

Given that you allocate all these elements together, and free them, all together, why not just use an array instead of a linked list?

Quoted 5 lines
Quoted 3 lines

Cheers,

Tim.

The numbers of element might be variant. But array should also work, considering iommu tables has max. length of 2MB, the array length is small.

Small enough so the array would fit in a single page?

Jan

#26 lore raw

Re: [PATCH 14 of 16] libxl: bind virtual bdf to physical bdf after device assignment

In reply to Wei Wang
Quoted 13 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876142 -3600
# Node ID f9575683f10a08a86a9c73226581610fa3f7be4b
# Parent 04573463beff7fc9696f5ecdb940920dcc2ec0ca
libxl: bind virtual bdf to physical bdf after device assignment

diff -r 04573463beff -r f9575683f10a tools/libxl/libxl_pci.c

tools/libxl/libxl_pci.c out: · line 742

Quoted 8 lines
tools/libxl/libxl_pci.c +5 -0
@@ -735,6 +735,13 @@ out:
             LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_assign_device failed");
             return ERROR_FAIL;
         }
+        if (LIBXL__DOMAIN_IS_TYPE(gc,  domid, HVM)) {
+            rc = xc_domain_bind_pt_bdf(ctx->xch, domid, pcidev->vdevfn, pcidev_encode_bdf(pcidev));
+            if ( rc ) {
+            LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_bind_pt_bdf failed");
+            return ERROR_FAIL;

Indentation here is off.

Quoted 11 lines
tools/libxl/libxl_pci.c +2 -0
+            }
+        }
     }
 
     if (!starting)

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

author
#7 lore raw

Re: [PATCH 03 of 16] amd iommu: Add iommu emulation for hvm guest

In reply to Jan Beulich
Quoted 29 lines · On Thursday 15 December 2011 15:13:57 Jan Beulich wrote:
Quoted 29 lines
Quoted 1 line
Quoted 1 line · On 15.12.11 at 15:09, Wei Wang2 <[email protected]> wrote:
Quoted 25 lines · On Thursday 15 December 2011 14:35:55 Tim Deegan wrote:

Hi,

Quoted 5 lines · Wei Wang

+static struct page_info* guest_iommu_get_page(struct list_head
*pglist, + unsigned int
entry_size, + unsigned
int pos) +{

xen/drivers/passthrough/amd/iommu_guest.c new file +1 -0
+    int idx;

xen/drivers/passthrough/amd/iommu_guest.c line 150

Quoted 10 lines
xen/drivers/passthrough/amd/iommu_guest.c new file +10 -0
+    struct list_head *head;
+    struct guest_pages *gpage = NULL;
+
+    idx = (pos * entry_size) >> PAGE_SHIFT;
+    list_for_each( head, pglist )
+    {
+        gpage = list_entry(head, struct guest_pages, list);
+        if ( (--idx) < 0 )
+            break;
+    }

Given that you allocate all these elements together, and free them, all together, why not just use an array instead of a linked list?

Cheers,

Tim.

Quoted 7 lines
Quoted 3 lines

The numbers of element might be variant. But array should also work, considering iommu tables has max. length of 2MB, the array length is small.

Small enough so the array would fit in a single page?

Jan

Well...then, How about that I just save the first gfn of the table base address and mapping gfn + n dynamically? Since all gfns for iommu tables must be contiguous guest space..

Thanks,
Wei

#30 lore raw

Re: [PATCH 16 of 16] libxl: add iommu parameter to qemu-dm

In reply to Wei Wang
Quoted 56 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876144 -3600
# Node ID 24f4a0a23da71c58f457f0bf98aa8238dd45332d # Parent 93658ca85035d6a4e56e2e6602c02859974d30a4
libxl: add iommu parameter to qemu-dm.
When iomm = 0, virtual iommu device will be disabled.

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_dm.c

tools/libxl/libxl_dm.c +6 -0
@@ -194,6 +194,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         flexarray_vappend(dm_args, "-loadvm", info->saved_state, NULL);
@@ -404,6 +407,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         /* This file descriptor is meant to be used by QEMU */

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_types.idl

tools/libxl/libxl_types.idl +1 -0
@@ -254,6 +254,7 @@ The password never expires"""),
     ("extra",            libxl_string_list, False, "extra parameters pass directly to qemu, NULL terminated"),
     ("extra_pv",         libxl_string_list, False, "extra parameters pass directly to qemu for PV guest, NULL terminated"),
     ("extra_hvm",        libxl_string_list, False, "extra parameters pass directly to qemu for HVM guest, NULL terminated"),
+    ("iommu",            bool,              False, "guest iommu enabled or disabled"),
     ],
     comment=
 """Device Model information.

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/xl_cmdimpl.c

tools/libxl/xl_cmdimpl.c +1 -0
@@ -386,6 +386,7 @@ static void printf_info(int domid,
         printf("\t\t\t(spicedisable_ticketing %d)\n",
                     dm_info->spicedisable_ticketing);
         printf("\t\t\t(spiceagent_mouse %d)\n", dm_info->spiceagent_mouse);
+        printf("\t\t\t(iommu %d)\n", dm_info->iommu);
         printf("\t\t)\n");
         break;
     case LIBXL_DOMAIN_TYPE_PV:

tools/libxl/xl_cmdimpl.c skip_vfb: · line 1222

Quoted 5 lines
tools/libxl/xl_cmdimpl.c +2 -0
@@ -1217,6 +1218,8 @@ skip_vfb:
         xlu_cfg_replace_string (config, "soundhw", &dm_info->soundhw, 0);
         if (!xlu_cfg_get_long (config, "xen_platform_pci", &l, 0))
             dm_info->xen_platform_pci = l;
+        if (!xlu_cfg_get_long (config, "iommu", &l, 0))
+            dm_info->iommu = l;

Didn't you already parse this same key into the build_info? Is there ever a possibility of the dm_info and build_info versions of this field differing?

Assuming not I think this setting ought to only live in one place and I think build_info should be that place rather than the dm info. That might need some refactoring in libxl to pass the right struct down.

Also you have only CC'd the hypervisor maintainers on this (and the other?) tool stack patch. Please check MAINTAINERS to see who ought to be CC'd.

Ian.

author
#31 lore raw

Re: [PATCH 16 of 16] libxl: add iommu parameter to qemu-dm

Quoted 70 lines · On Thursday 15 December 2011 15:30:44 Ian Campbell wrote:
Quoted 59 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876144 -3600
# Node ID 24f4a0a23da71c58f457f0bf98aa8238dd45332d # Parent 93658ca85035d6a4e56e2e6602c02859974d30a4
libxl: add iommu parameter to qemu-dm.
When iomm = 0, virtual iommu device will be disabled.

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_dm.c

tools/libxl/libxl_dm.c +6 -0
@@ -194,6 +194,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         flexarray_vappend(dm_args, "-loadvm", info->saved_state, NULL);
@@ -404,6 +407,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         /* This file descriptor is meant to be used by QEMU */

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_types.idl

tools/libxl/libxl_types.idl +0 -0
@@ -254,6 +254,7 @@ The password never expires"""),
     ("extra",            libxl_string_list, False, "extra parameters
 pass directly to qemu, NULL terminated"), ("extra_pv",        

libxl_string_list, False, "extra parameters pass directly to qemu for PV
guest, NULL terminated"), ("extra_hvm", libxl_string_list, False,
"extra parameters pass directly to qemu for HVM guest, NULL terminated"),
+ ("iommu", bool, False, "guest iommu enabled
or disabled"), ],
comment=
"""Device Model information.
diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/xl_cmdimpl.c

tools/libxl/xl_cmdimpl.c +0 -0
@@ -386,6 +386,7 @@ static void printf_info(int domid,
         printf("\t\t\t(spicedisable_ticketing %d)\n",
                     dm_info->spicedisable_ticketing);
         printf("\t\t\t(spiceagent_mouse %d)\n",
 dm_info->spiceagent_mouse); +        printf("\t\t\t(iommu %d)\n",
 dm_info->iommu);
         printf("\t\t)\n");
         break;
     case LIBXL_DOMAIN_TYPE_PV:

tools/libxl/xl_cmdimpl.c skip_vfb: · line 1222

Quoted 5 lines
tools/libxl/xl_cmdimpl.c +2 -0
@@ -1217,6 +1218,8 @@ skip_vfb:
         xlu_cfg_replace_string (config, "soundhw", &dm_info->soundhw,
 0); if (!xlu_cfg_get_long (config, "xen_platform_pci", &l, 0))
 dm_info->xen_platform_pci = l;
+        if (!xlu_cfg_get_long (config, "iommu", &l, 0))
+            dm_info->iommu = l;

Didn't you already parse this same key into the build_info? Is there ever a possibility of the dm_info and build_info versions of this field differing?

Quoted 3 lines

Assuming not I think this setting ought to only live in one place and I think build_info should be that place rather than the dm info. That might need some refactoring in libxl to pass the right struct down.

Yes, I added a new flag in build_info, which will control hvmloader to build IVRS table. And I also need a flag for qemu-dm to decide if virtual iommu device should be registered or not. I just saw other parameters like gfx-passthu are attached to dm_info, so I do the same thing for iommu. Also I cannot make a reference of libxl_domain_build_info in libxl__build_device_model_args.

Quoted 3 lines

Also you have only CC'd the hypervisor maintainers on this (and the other?) tool stack patch. Please check MAINTAINERS to see who ought to be CC'd.

Thanks, I cc'd them to Ian Jackson.

Quoted 1 line

Ian.

Wei

#28 lore raw

Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter

In reply to Wei Wang

Wei Wang writes ("[Xen-devel] [PATCH 15 of 16] libxl: Introduce a new guest config file parameter"):

Quoted 3 lines

libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.

This needs documenting. And that means you need to explain why a user might want to turn this off, or on - not just say "it enables or disables guest iommu emulation".

Ian.

#32 lore raw

Re: [PATCH 16 of 16] libxl: add iommu parameter to qemu-dm

In reply to Wei Wang2
Quoted 71 lines · On Thu, 2011-12-15 at 14:52 +0000, Wei Wang2 wrote:
Quoted 69 lines · On Thursday 15 December 2011 15:30:44 Ian Campbell wrote:
Quoted 59 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876144 -3600
# Node ID 24f4a0a23da71c58f457f0bf98aa8238dd45332d # Parent 93658ca85035d6a4e56e2e6602c02859974d30a4
libxl: add iommu parameter to qemu-dm.
When iomm = 0, virtual iommu device will be disabled.

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_dm.c

tools/libxl/libxl_dm.c +6 -0
@@ -194,6 +194,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         flexarray_vappend(dm_args, "-loadvm", info->saved_state, NULL);
@@ -404,6 +407,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         /* This file descriptor is meant to be used by QEMU */

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_types.idl

tools/libxl/libxl_types.idl +0 -0
@@ -254,6 +254,7 @@ The password never expires"""),
     ("extra",            libxl_string_list, False, "extra parameters
 pass directly to qemu, NULL terminated"), ("extra_pv",        

libxl_string_list, False, "extra parameters pass directly to qemu for PV
guest, NULL terminated"), ("extra_hvm", libxl_string_list, False,
"extra parameters pass directly to qemu for HVM guest, NULL terminated"),
+ ("iommu", bool, False, "guest iommu enabled
or disabled"), ],
comment=
"""Device Model information.
diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/xl_cmdimpl.c

tools/libxl/xl_cmdimpl.c +0 -0
@@ -386,6 +386,7 @@ static void printf_info(int domid,
         printf("\t\t\t(spicedisable_ticketing %d)\n",
                     dm_info->spicedisable_ticketing);
         printf("\t\t\t(spiceagent_mouse %d)\n",
 dm_info->spiceagent_mouse); +        printf("\t\t\t(iommu %d)\n",
 dm_info->iommu);
         printf("\t\t)\n");
         break;
     case LIBXL_DOMAIN_TYPE_PV:

tools/libxl/xl_cmdimpl.c skip_vfb: · line 1222

Quoted 5 lines
tools/libxl/xl_cmdimpl.c +2 -0
@@ -1217,6 +1218,8 @@ skip_vfb:
         xlu_cfg_replace_string (config, "soundhw", &dm_info->soundhw,
 0); if (!xlu_cfg_get_long (config, "xen_platform_pci", &l, 0))
 dm_info->xen_platform_pci = l;
+        if (!xlu_cfg_get_long (config, "iommu", &l, 0))
+            dm_info->iommu = l;

Didn't you already parse this same key into the build_info? Is there ever a possibility of the dm_info and build_info versions of this field differing?

Quoted 8 lines
Quoted 3 lines

Assuming not I think this setting ought to only live in one place and I think build_info should be that place rather than the dm info. That might need some refactoring in libxl to pass the right struct down.

Yes, I added a new flag in build_info, which will control hvmloader to build IVRS table. And I also need a flag for qemu-dm to decide if virtual iommu device should be registered or not. I just saw other parameters like gfx-passthu are attached to dm_info, so I do the same thing for iommu.

gfx-passthru is only in dm_info

Quoted 2 lines

Also I cannot make a reference of libxl_domain_build_info in libxl__build_device_model_args.

You just need to plumb the variable through. This is apparently just the first time we have need of it.

Quoted 9 lines
Quoted 3 lines

Also you have only CC'd the hypervisor maintainers on this (and the other?) tool stack patch. Please check MAINTAINERS to see who ought to be CC'd.

Thanks, I cc'd them to Ian Jackson.

Quoted 1 line

Ian.

Wei

author
#33 lore raw

Re: [PATCH 16 of 16] libxl: add iommu parameter to qemu-dm

Quoted 82 lines · On Thursday 15 December 2011 17:59:19 Ian Campbell wrote:
Quoted 75 lines · On Thu, 2011-12-15 at 14:52 +0000, Wei Wang2 wrote:
Quoted 70 lines · On Thursday 15 December 2011 15:30:44 Ian Campbell wrote:
Quoted 59 lines · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1323876144 -3600
# Node ID 24f4a0a23da71c58f457f0bf98aa8238dd45332d # Parent 93658ca85035d6a4e56e2e6602c02859974d30a4
libxl: add iommu parameter to qemu-dm.
When iomm = 0, virtual iommu device will be disabled.

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_dm.c

tools/libxl/libxl_dm.c +3 -0
@@ -194,6 +194,9 @@ static char ** libxl__build_device_model
         if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         flexarray_vappend(dm_args, "-loadvm", info->saved_state,

NULL); @@ -404,6 +407,9 @@ static char ** libxl__build_device_model

if (info->gfx_passthru) {
             flexarray_append(dm_args, "-gfx_passthru");
         }
tools/libxl/libxl_dm.c +3 -0
+        if (info->iommu) {
+            flexarray_append(dm_args, "-iommu");
+        }
     }
     if (info->saved_state) {
         /* This file descriptor is meant to be used by QEMU */

diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/libxl_types.idl

tools/libxl/libxl_types.idl +0 -0
@@ -254,6 +254,7 @@ The password never expires"""),
     ("extra",            libxl_string_list, False, "extra parameters
 pass directly to qemu, NULL terminated"), ("extra_pv",

libxl_string_list, False, "extra parameters pass directly to qemu for
PV guest, NULL terminated"), ("extra_hvm", libxl_string_list,
False, "extra parameters pass directly to qemu for HVM guest, NULL
terminated"), + ("iommu", bool, False,
"guest iommu enabled or disabled"), ],
comment=
"""Device Model information.
diff -r 93658ca85035 -r 24f4a0a23da7 tools/libxl/xl_cmdimpl.c

tools/libxl/xl_cmdimpl.c +0 -0
@@ -386,6 +386,7 @@ static void printf_info(int domid,
         printf("\t\t\t(spicedisable_ticketing %d)\n",
                     dm_info->spicedisable_ticketing);
         printf("\t\t\t(spiceagent_mouse %d)\n",
 dm_info->spiceagent_mouse); +        printf("\t\t\t(iommu %d)\n",
 dm_info->iommu);
         printf("\t\t)\n");
         break;
     case LIBXL_DOMAIN_TYPE_PV:

tools/libxl/xl_cmdimpl.c skip_vfb: · line 1222

Quoted 5 lines
tools/libxl/xl_cmdimpl.c +2 -0
@@ -1217,6 +1218,8 @@ skip_vfb:
         xlu_cfg_replace_string (config, "soundhw",
 &dm_info->soundhw, 0); if (!xlu_cfg_get_long (config,
 "xen_platform_pci", &l, 0)) dm_info->xen_platform_pci = l;
+        if (!xlu_cfg_get_long (config, "iommu", &l, 0))
+            dm_info->iommu = l;

Didn't you already parse this same key into the build_info? Is there ever a possibility of the dm_info and build_info versions of this field differing?

Quoted 3 lines

Assuming not I think this setting ought to only live in one place and I think build_info should be that place rather than the dm info. That might need some refactoring in libxl to pass the right struct down.

Quoted 5 lines

Yes, I added a new flag in build_info, which will control hvmloader to build IVRS table. And I also need a flag for qemu-dm to decide if virtual iommu device should be registered or not. I just saw other parameters like gfx-passthu are attached to dm_info, so I do the same thing for iommu.

Quoted 7 lines

gfx-passthru is only in dm_info

Quoted 2 lines

Also I cannot make a reference of libxl_domain_build_info in libxl__build_device_model_args.

You just need to plumb the variable through. This is apparently just the first time we have need of it.

Ok, that sounds doable. I will fix that in the next version. Thanks,
Wei

Quoted 15 lines
Quoted 10 lines
Quoted 4 lines

Also you have only CC'd the hypervisor maintainers on this (and the other?) tool stack patch. Please check MAINTAINERS to see who ought to be CC'd.

Thanks, I cc'd them to Ian Jackson.

Quoted 1 line

Ian.

Wei

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#34 lore raw

Re: [PATCH 16 of 16] libxl: add iommu parameter to qemu-dm

Quoted 9 lines · On Thu, 2011-12-15 at 17:10 +0000, Wei Wang2 wrote:
Quoted 6 lines
Quoted 4 lines

Also I cannot make a reference of libxl_domain_build_info in libxl__build_device_model_args.

You just need to plumb the variable through. This is apparently just

the

Quoted 1 line

first time we have need of it.

Ok, that sounds doable. I will fix that in the next version.

Thanks.

I actually don't think libxl_device_model_info should really be exposed to users of the library. That stuff all belongs in the build_info and should be turned into dm config as necessary internally by the library.

However I don't expect you to take on that change!

Ian.