From: Wei Wang2 <wei.wang2@amd.com>
To: xen-devel@lists.xensource.com
Cc: Keir Fraser <keir@xen.org>, Jan Beulich <JBeulich@suse.com>
Subject: [PATCH] xen-qemu: register virtual iommu device on qemu pci bus
Date: Wed, 14 Dec 2011 16:38:04 +0100 [thread overview]
Message-ID: <201112141638.05345.wei.wang2@amd.com> (raw)
[-- 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
next reply other threads:[~2011-12-14 15:38 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-14 15:38 Wei Wang2 [this message]
2011-12-15 17:33 ` [Qemu-devel] [Xen-devel] [PATCH] xen-qemu: register virtual iommu device on qemu pci bus 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201112141638.05345.wei.wang2@amd.com \
--to=wei.wang2@amd.com \
--cc=JBeulich@suse.com \
--cc=keir@xen.org \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.