Skip to contentSkip to conversation

Enable PCI passthru for HVM guest

PATCH In review Wei Wang2 1 participant 1 message Nov 30, 2007

lore
Share & tools
lore

Wei Wang2

author
#0 lore raw

PATCH 1/4 Enable PCI passthru for HVM guest

1-cleanup.patch:
code cleanup, bug fix, minor enhancements to exsiting amd-iommu codes

xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c +47 -22
diff -r 3057f813da14 xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c
@@ -49,14 +49,16 @@ int __init get_iommu_last_downstream_bus
     iommu->downstream_bus_present[bus] = 1;
     dev = PCI_SLOT(iommu->first_devfn);
     multi_func = PCI_FUNC(iommu->first_devfn) > 0;
-    for ( devfn = iommu->first_devfn; devfn <= iommu->last_devfn; ++devfn ) {
+    for ( devfn = iommu->first_devfn; devfn <= iommu->last_devfn; ++devfn )
+    {
         /* skipping to next device#? */
-        if ( dev != PCI_SLOT(devfn) ) {
+        if ( dev != PCI_SLOT(devfn) )
+        {
             dev = PCI_SLOT(devfn);
             multi_func = 0;
         }
         func = PCI_FUNC(devfn);
- 
+
         if ( !VALID_PCI_VENDOR_ID(
             read_pci_config_16(bus, dev, func, PCI_VENDOR_ID)) )
             continue;
@@ -67,7 +69,8 @@ int __init get_iommu_last_downstream_bus
             multi_func = IS_PCI_MULTI_FUNCTION(hdr_type);
 
         if ( (func == 0 || multi_func) &&
-            IS_PCI_TYPE1_HEADER(hdr_type) ) {
+            IS_PCI_TYPE1_HEADER(hdr_type) )
+        {
             if (!valid_bridge_bus_config(bus, dev, func,
                 &sec_bus, &sub_bus))
                 return -ENODEV;
@@ -86,28 +89,37 @@ int __init get_iommu_capabilities(u8 bus
 int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
             struct amd_iommu *iommu)
 {
-    u32 cap_header, cap_range;
+    u32 cap_header, cap_range, misc_info;
     u64 mmio_bar;
 
     /* remove it when BIOS available */
+#if HACK_BIOS_SETTINGS 
+    /* set MMIO base address for IOMMU */
+    static u32 mmio_hi = 0x0;
+    static u32 mmio_lo = 0xF0010001;
+
     write_pci_config(bus, dev, func,
-        cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET, 0x00000000);
+             cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET, mmio_hi);
     write_pci_config(bus, dev, func,
-        cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET, 0x40000001);
+             cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET, mmio_lo);
+    mmio_lo += 0x10000;
+#endif
     /* remove it when BIOS available */
 
     mmio_bar = (u64)read_pci_config(bus, dev, func,
              cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32;
     mmio_bar |= read_pci_config(bus, dev, func,
-            cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET) &
-            PCI_CAP_MMIO_BAR_LOW_MASK;
-    iommu->mmio_base_phys = (unsigned long)mmio_bar;
-
-    if ( (mmio_bar == 0) || ( (mmio_bar & 0x3FFF) != 0 ) ) {
-        dprintk(XENLOG_ERR ,
-                "AMD IOMMU: Invalid MMIO_BAR = 0x%"PRIx64"\n", mmio_bar);
+            cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET); 
+    iommu->mmio_base_phys = mmio_bar & (u64)~0x3FFF;
+
+    if ((mmio_bar & 0x1) == 0 || iommu->mmio_base_phys == 0 )
+    {
+          IOV_DPRINTK(XENLOG_ERR IOVPREFIX,
+                "Invalid MMIO_BAR = 0x%"PRIx64"\n", mmio_bar);
         return -ENODEV;
     }
+
+    iommu->device_id = (bus << 8) | PCI_DEVFN(dev, func);
 
     cap_header = read_pci_config(bus, dev, func, cap_ptr);
     iommu->revision = get_field_from_reg_u32(cap_header,
@@ -133,6 +145,11 @@ int __init get_iommu_capabilities(u8 bus
                 PCI_CAP_LAST_DEVICE_MASK,
                 PCI_CAP_LAST_DEVICE_SHIFT);
 
+    misc_info = read_pci_config(bus, dev, func,
+            cap_ptr + PCI_CAP_MISC_INFO_OFFSET);
+    iommu->msi_number = get_field_from_reg_u32(misc_info,
+                PCI_CAP_MSI_NUMBER_MASK,
+                PCI_CAP_MSI_NUMBER_SHIFT);
     return 0;
 }
 
@@ -147,16 +164,19 @@ static int __init scan_caps_for_iommu(in
     cap_ptr = read_pci_config_byte(bus, dev, func,
             PCI_CAPABILITY_LIST);
     while ( cap_ptr >= PCI_MIN_CAP_OFFSET &&
-        count < PCI_MAX_CAP_BLOCKS && !error ) {
+        count < PCI_MAX_CAP_BLOCKS && !error )
+    {
         cap_ptr &= PCI_CAP_PTR_MASK;
         cap_header = read_pci_config(bus, dev, func, cap_ptr);
         cap_id = get_field_from_reg_u32(cap_header,
                 PCI_CAP_ID_MASK, PCI_CAP_ID_SHIFT);
 
-        if ( cap_id == PCI_CAP_ID_SECURE_DEVICE ) {
+        if ( cap_id == PCI_CAP_ID_SECURE_DEVICE )
+        {
             cap_type = get_field_from_reg_u32(cap_header,
                     PCI_CAP_TYPE_MASK, PCI_CAP_TYPE_SHIFT);
-            if ( cap_type == PCI_CAP_TYPE_IOMMU ) {
+            if ( cap_type == PCI_CAP_TYPE_IOMMU )
+            {
                 error = iommu_detect_callback(
                         bus, dev, func, cap_ptr);
             }
@@ -164,7 +184,8 @@ static int __init scan_caps_for_iommu(in
 
         cap_ptr = get_field_from_reg_u32(cap_header,
                 PCI_CAP_NEXT_PTR_MASK, PCI_CAP_NEXT_PTR_SHIFT);
-        ++count;    }
+        ++count;
+    }
 
     return error;
 }
@@ -178,7 +199,8 @@ static int __init scan_functions_for_iom
     func = 0;
     count = 1;
     while ( VALID_PCI_VENDOR_ID(read_pci_config_16(bus, dev, func,
-            PCI_VENDOR_ID)) && !error && func < count ) {
+            PCI_VENDOR_ID)) && !error && func < count )
+    {
         hdr_type = read_pci_config_byte(bus, dev, func,
                 PCI_HEADER_TYPE);
 
@@ -186,7 +208,8 @@ static int __init scan_functions_for_iom
             count = PCI_MAX_FUNC_COUNT;
 
         if ( IS_PCI_TYPE0_HEADER(hdr_type) ||
-            IS_PCI_TYPE1_HEADER(hdr_type) ) {
+            IS_PCI_TYPE1_HEADER(hdr_type) )
+        {
             error =  scan_caps_for_iommu(bus, dev, func,
                     iommu_detect_callback);
         }
@@ -201,8 +224,10 @@ int __init scan_for_iommu(iommu_detect_c
 {
     int bus, dev, error = 0;
 
-    for ( bus = 0; bus < PCI_MAX_BUS_COUNT && !error; ++bus ) {
-        for ( dev = 0; dev < PCI_MAX_DEV_COUNT && !error; ++dev ) {
+    for ( bus = 0; bus < PCI_MAX_BUS_COUNT && !error; ++bus )
+    {
+        for ( dev = 0; dev < PCI_MAX_DEV_COUNT && !error; ++dev )
+        {
             error =  scan_functions_for_iommu(bus, dev,
                   iommu_detect_callback);
         }
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c +75 -11

120 lines not on this page · raw message

xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c +82 -31

224 lines not on this page · raw message

xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c +215 -103

497 lines not on this page · raw message

xen/include/asm-x86/amd-iommu.h +10 -0
diff -r 3057f813da14 xen/include/asm-x86/amd-iommu.h
@@ -32,6 +32,11 @@ extern struct list_head amd_iommu_head;
 extern struct list_head amd_iommu_head;
 
 extern int __init amd_iommu_detect(void);
+extern int amd_iommu_domain_init(struct domain *domain);
+extern int amd_iommu_map_page(struct domain *d, unsigned long gfn,
+        unsigned long mfn);
+extern int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
+
 
 struct table_struct {
     void *buffer;
@@ -47,6 +52,9 @@ struct amd_iommu {
     int ht_tunnel_support;
     int not_present_cached;
     u8  revision;
+    u8  msi_number;
+
+    u16 device_id;
 
     u8  root_bus;
     u8  first_devfn;
@@ -61,6 +69,8 @@ struct amd_iommu {
     struct table_struct dev_table;
     struct table_struct cmd_buffer;
     u32 cmd_buffer_tail;
+    struct table_struct event_log;
+    u32 event_log_head;
 
     int exclusion_enabled;
     unsigned long exclusion_base;
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +22 -0
diff -r 3057f813da14 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -35,6 +35,9 @@
 /* IOMMU Command Buffer entries: in power of 2 increments, minimum of 256 */
 #define IOMMU_CMD_BUFFER_DEFAULT_ENTRIES	512
 
+/* IOMMU Event Log entries: in power of 2 increments, minimum of 256 */
+#define IOMMU_EVENT_LOG_DEFAULT_ENTRIES     512
+
 #define BITMAP_ENTRIES_PER_BYTE		8
 
 #define PTE_PER_TABLE_SHIFT		9
@@ -118,6 +121,10 @@
 #define PCI_CAP_LAST_DEVICE_MASK	0xFF000000
 #define PCI_CAP_LAST_DEVICE_SHIFT	24
 
+#define PCI_CAP_MISC_INFO_OFFSET        0x10
+#define PCI_CAP_MSI_NUMBER_MASK         0x0000001F
+#define PCI_CAP_MSI_NUMBER_SHIFT        0
+
 /* Device Table */
 #define IOMMU_DEV_TABLE_BASE_LOW_OFFSET		0x00
 #define IOMMU_DEV_TABLE_BASE_HIGH_OFFSET	0x04
@@ -262,6 +269,10 @@
 #define IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT	12
 #define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK	0xFFFFFFFF
 #define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT	0
+
+/* INVALIDATE_DEVTAB_ENTRY command */
+#define IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_MASK   0x0000FFFF
+#define IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_SHIFT  0
 
 /* Event Log */
 #define IOMMU_EVENT_LOG_BASE_LOW_OFFSET		0x10
@@ -415,5 +426,16 @@
 #define IOMMU_PAGE_TABLE_LEVEL_4        4
 #define IOMMU_IO_WRITE_ENABLED          1
 #define IOMMU_IO_READ_ENABLED           1
+#define IOVPREFIX                   "AMD IOV: "
+#define CONFIG_AMD_IOMMU_DEBUG  1
+
+/* HT1100 enablement */
+#define ENABLE_HT1100       1
+#define SET_FC_IN_PTE       1
+#define HACK_BIOS_SETTINGS      1
+#define HACK_MMIO_ON_CPU1       0
+#define HACK_ISOC_SETTINGS      0
+#define HACK_ISOC_ON_CPU1       0
+/* HT1100 enablement */
 
 #endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +19 -8
diff -r 3057f813da14 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -27,11 +27,23 @@
     list_for_each_entry(amd_iommu, \
         &amd_iommu_head, list)
 
+#define for_each_pdev(domain, pdev) \
+    list_for_each_entry(pdev, \
+         &(domain->arch.hvm_domain.hvm_iommu.pdev_list), list)
+
 #define DMA_32BIT_MASK  0x00000000ffffffffULL
 #define PAGE_ALIGN(addr)    (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 #define PAGE_SHIFT_4K                   (12)
 #define PAGE_SIZE_4K                    (1UL << PAGE_SHIFT_4K)
 #define PAGE_MASK_4K                    (((u64)-1) << PAGE_SHIFT_4K)
+
+#ifdef CONFIG_AMD_IOMMU_DEBUG
+#define IOV_DPRINTK dprintk
+#define IOV_GDPRINTK gdprintk
+#else
+#define IOV_DPRINTK(s, a...)
+#define IOV_GDPRINTK(s, a...)
+#endif
 
 typedef int (*iommu_detect_callback_ptr_t)(u8 bus, u8 dev, u8 func, u8 cap_ptr);
 
@@ -46,24 +58,23 @@ void __init unmap_iommu_mmio_region(stru
 void __init unmap_iommu_mmio_region(struct amd_iommu *iommu);
 void __init register_iommu_dev_table_in_mmio_space(struct amd_iommu *iommu);
 void __init register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu);
+void __init register_iommu_event_log_in_mmio_space(struct amd_iommu *iommu);
+
 void __init enable_iommu(struct amd_iommu *iommu);
 
 /* mapping functions */
-int amd_iommu_map_page(struct domain *d, unsigned long gfn,
-        unsigned long mfn);
-int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
+void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry);
 
 /* device table functions */
 void amd_iommu_set_dev_table_entry(u32 *dte,
         u64 root_ptr, u16 domain_id, u8 paging_mode);
+void invalidate_dev_table_entry(struct amd_iommu *iommu,
+            u16 devic_id);
+int amd_iommu_is_dte_page_translation_valid(u32 *entry);
 
 /* send cmd to iommu */
 int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]);
-
-/* iommu domain funtions */
-int amd_iommu_domain_init(struct domain *domain);
-void amd_iommu_setup_domain_device(struct domain *domain,
-    struct amd_iommu *iommu, int requestor_id);
+void flush_command_buffer(struct amd_iommu *iommu);
 
 /* find iommu for bdf */
 struct amd_iommu *find_iommu_for_device(int bus, int devfn);

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