All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] xen-qemu: register virtual iommu device on qemu pci bus
@ 2011-12-14 15:38 Wei Wang2
  2011-12-15 17:33   ` Ian Jackson
  0 siblings, 1 reply; 5+ messages in thread
From: Wei Wang2 @ 2011-12-14 15:38 UTC (permalink / raw)
  To: xen-devel; +Cc: Keir Fraser, Jan Beulich

[-- Attachment #1: Type: text/plain, Size: 193 bytes --]

Attached patch is for qemu to register iommu device on pci bus. Guest OS 
requires this to access iommu pci config space in some cases.
Thanks,
Wei

Signed-off-by: Wei Wang <wei.wang2@amd.com>

[-- Attachment #2: qemu-iommuv2.diff --]
[-- Type: text/x-diff, Size: 6577 bytes --]

diff --git a/hw/pass-through.c b/hw/pass-through.c
index 919937f..d6f35d8 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -4402,5 +4414,94 @@ int pt_init(PCIBus *e_bus)
     memset(&dpci_infos, 0, sizeof(struct dpci_infos));
     dpci_infos.e_bus      = e_bus;
 
+    amd_iommu_init(e_bus);
     return 0;
 }
+
+static void amd_iommu_pci_write_config(PCIDevice *d, uint32_t address,
+                                       uint32_t val, int len)
+{
+    struct amd_iommu_config *iommu_config;
+    uint64_t msi_addr;
+    uint32_t msi_data;
+    uint8_t offset_msi_data, vector, en;
+    uint8_t dest_mode, dest, delivery_mode, trig_mode;
+
+    pci_default_write_config(d, address, val, len);
+
+    iommu_config = (struct amd_iommu_config *)d->config;
+
+    offset_msi_data = iommu_config->cap.next_ptr + sizeof(uint32_t) +
+                      sizeof(uint64_t);
+
+    if ( address == offset_msi_data )
+    {
+        msi_addr = (uint64_t)iommu_config->msi.addr_high << 32 | 
+                   iommu_config->msi.addr_low;
+        msi_data = val;
+        vector = msi_data & 0xFF;
+        en = iommu_config->msi.msg_ctrl & 0x1;
+
+        if ( !vector || !en )
+            return;
+
+        dest_mode = (msi_addr >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
+        dest = (msi_addr >> MSI_TARGET_CPU_SHIFT) & 0xff;
+        delivery_mode = (msi_data >> MSI_DATA_DELIVERY_SHIFT) & 0x7;
+        trig_mode = (msi_data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+
+        xc_domain_update_iommu_msi(xc_handle, domid, vector, dest, 
+                                   dest_mode, delivery_mode, trig_mode);
+    }
+}
+
+#ifndef PCI_CAP_ID_SEC
+#define PCI_CAP_ID_SEC                  0x0F
+#endif
+#define PCI_CLASS_SYSTEM_AMD_IOMMU      0x0806
+#define PCI_DEVICE_AMD_IOMMU_V2         0xFFFF
+#define IOMMU_CAP_FLAGS_IOTLB           0
+#define IOMMU_CAP_FLAGS_EFRSUP          3
+#define IOMMU_CAP_TYPE                  0x3
+#define IOMMU_CAP_REV                   0x1
+
+extern int guest_iommu;
+void amd_iommu_init(PCIBus *bus)
+{
+    PCIDevice *amd_iommu;
+    struct amd_iommu_config *cfg;
+    struct pt_dev *assigned_device = NULL;
+
+    if ( !guest_iommu )
+        return;
+
+    amd_iommu = pci_register_device(bus, "AMD IOMMU v2", 
+                                    sizeof(struct PCIDevice), -1,
+                                    NULL, amd_iommu_pci_write_config);
+    if ( amd_iommu == NULL )
+    {
+        PT_LOG("Error: couldn't register amd iommu device\n");
+        return;
+    }
+
+    cfg = (struct amd_iommu_config *)amd_iommu->config;
+
+    pci_config_set_vendor_id((uint8_t *)cfg, PCI_VENDOR_ID_AMD);
+    pci_config_set_device_id((uint8_t *)cfg, PCI_DEVICE_AMD_IOMMU_V2);
+    pci_config_set_class((uint8_t *)cfg, PCI_CLASS_SYSTEM_AMD_IOMMU);
+
+    cfg->status       =   PCI_STATUS_CAPABILITIES;
+    cfg->cap_ptr      =   sizeof(struct amd_iommu_config) - 
+                          sizeof(iommu_capability_t)- sizeof(msi_capability_t);
+
+    cfg->cap.id       = PCI_CAP_ID_SEC;
+    cfg->cap.cap_info = IOMMU_CAP_REV << 3 | IOMMU_CAP_TYPE;
+
+    cfg->cap.flags   |= 1 << IOMMU_CAP_FLAGS_IOTLB;
+    cfg->cap.flags   |= 1 << IOMMU_CAP_FLAGS_EFRSUP;
+
+    cfg->cap.next_ptr = cfg->cap_ptr + sizeof(iommu_capability_t);
+    cfg->msi.id       = PCI_CAP_ID_MSI;
+    cfg->msi.msg_ctrl = PCI_MSI_FLAGS_64BIT;
+}
+
diff --git a/hw/pass-through.h b/hw/pass-through.h
index 884139c..c089987 100644
--- a/hw/pass-through.h
+++ b/hw/pass-through.h
@@ -402,6 +402,58 @@ struct pt_reg_info_tbl {
     } u;
 };
 
+#pragma pack(1)
+/* AMD IOMMU v2 support */
+typedef struct iommu_capability_block {
+    uint8_t     id;
+    uint8_t     next_ptr;
+    uint8_t     cap_info;
+    uint8_t     flags;
+    uint32_t    base_low;
+    uint32_t    base_high;
+    uint32_t    range;
+    uint32_t    misc;
+} iommu_capability_t;
+
+typedef struct msi_capability_block {
+    uint8_t     id;
+    uint8_t     next_ptr;
+    uint16_t    msg_ctrl;
+    uint32_t    addr_low;
+    uint32_t    addr_high;
+    uint32_t    msi_data;
+} msi_capability_t;
+
+struct amd_iommu_config {
+    uint16_t    vendor_id;
+    uint16_t    device_id;
+    uint16_t    command;
+    uint16_t    status;
+    uint8_t     revision;
+    uint8_t     api;
+    uint8_t     subclass;
+    uint8_t     class;
+    uint8_t     cache_line_size;
+    uint8_t     latency_timer;
+    uint8_t     header_type;
+    uint8_t     bist;
+    uint32_t    base_address_regs[6];
+    uint32_t    reserved1;
+    uint16_t    subsystem_vendor_id;
+    uint16_t    subsystem_id;
+    uint32_t    rom_addr;
+    uint8_t     cap_ptr;
+    uint8_t     reserved3[3];
+    uint32_t    reserved4;
+    uint8_t     interrupt_line;
+    uint8_t     interrupt_pin;
+    uint8_t     min_gnt;
+    uint8_t     max_lat;
+    iommu_capability_t cap;
+    msi_capability_t   msi;
+};
+#pragma pack()
+
 static inline pciaddr_t pt_pci_base_addr(pciaddr_t base)
 {
     if ( base & PCI_ADDRESS_SPACE_IO )
@@ -422,6 +474,6 @@ PCIBus *intel_pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid,
            uint16_t did, const char *name, uint16_t revision);
 void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, int len);
 uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len);
-
+void amd_iommu_init(PCIBus *bus);
 #endif /* __PASSTHROUGH_H__ */
 
diff --git a/vl.c b/vl.c
index be8587a..43a0111 100644
--- a/vl.c
+++ b/vl.c
@@ -217,6 +217,7 @@ int cirrus_vga_enabled = 1;
 int std_vga_enabled = 0;
 int vmsvga_enabled = 0;
 int gfx_passthru = 0;
+int guest_iommu = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
@@ -4295,6 +4296,7 @@ enum {
     QEMU_OPTION_acpi,
     QEMU_OPTION_vcpus,
     QEMU_OPTION_vcpu_avail,
+    QEMU_OPTION_guest_iommu,
 
     /* Debug/Expert options: */
     QEMU_OPTION_serial,
@@ -4468,6 +4470,7 @@ static const QEMUOption qemu_options[] = {
     { "vncunused", 0, QEMU_OPTION_vncunused },
     { "vcpus", HAS_ARG, QEMU_OPTION_vcpus },
     { "vcpu_avail", HAS_ARG, QEMU_OPTION_vcpu_avail },
+    { "iommu", 0, QEMU_OPTION_guest_iommu},
 #if defined(CONFIG_XEN) && !defined(CONFIG_DM)
     { "xen-domid", HAS_ARG, QEMU_OPTION_xen_domid },
     { "xen-create", 0, QEMU_OPTION_xen_create },
@@ -5595,6 +5598,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_gfx_passthru:
                 select_vgahw("passthrough");
                 break;
+            case QEMU_OPTION_guest_iommu:
+                guest_iommu = 1;
+                break;
             }
         }
     }

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-12-16 10:33 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-14 15:38 [PATCH] xen-qemu: register virtual iommu device on qemu pci bus Wei Wang2
2011-12-15 17:33 ` [Qemu-devel] [Xen-devel] " Ian Jackson
2011-12-15 17:33   ` Ian Jackson
2011-12-16 10:33   ` [Qemu-devel] " Wei Wang2
2011-12-16 10:33     ` Wei Wang2

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.