# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1205750724 0
# Node ID bf8a3fc79093daa3107952dd9b070299851862fe
# Parent af33f2054f47b3cdc9de37e567b11986ca22a7f1
Move iommu code to arch-generic locations, and also clean up some VT-d code.
Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
---
xen/arch/x86/hvm/iommu.c | 145 ---------
xen/drivers/passthrough/vtd/io.c | 296 ------------------
xen/include/asm-x86/hvm/iommu.h | 56 ---
xen/include/asm-x86/hvm/vmx/intel-iommu.h | 460 -----------------------------
xen/include/asm-x86/iommu.h | 109 ------
xen/arch/x86/domain.c | 2
xen/arch/x86/domctl.c | 2
xen/arch/x86/hvm/Makefile | 1
xen/arch/x86/hvm/intercept.c | 2
xen/arch/x86/irq.c | 2
xen/arch/x86/mm/p2m.c | 2
xen/drivers/passthrough/Makefile | 3
xen/drivers/passthrough/amd/iommu_detect.c | 2
xen/drivers/passthrough/amd/iommu_map.c | 2
xen/drivers/passthrough/io.c | 272 +++++++++++++++++
xen/drivers/passthrough/iommu.c | 136 ++++++++
xen/drivers/passthrough/vtd/Makefile | 1
xen/drivers/passthrough/vtd/dmar.h | 2
xen/drivers/passthrough/vtd/extern.h | 2
xen/drivers/passthrough/vtd/intremap.c | 26 -
xen/drivers/passthrough/vtd/iommu.c | 132 ++++++--
xen/drivers/passthrough/vtd/iommu.h | 454 ++++++++++++++++++++++++++++
xen/drivers/passthrough/vtd/qinval.c | 10
xen/drivers/passthrough/vtd/utils.c | 11
xen/drivers/passthrough/vtd/vtd.h | 11
xen/include/asm-x86/fixmap.h | 2
xen/include/asm-x86/hvm/domain.h | 4
xen/include/asm-x86/io_apic.h | 2
xen/include/xen/hvm/iommu.h | 56 +++
xen/include/xen/iommu.h | 115 +++++++
30 files changed, 1158 insertions(+), 1162 deletions(-)
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/arch/x86/domain.c Mon Mar 17 10:45:24 2008 +0000
@@ -46,7 +46,7 @@
#include <asm/debugreg.h>
#include <asm/msr.h>
#include <asm/nmi.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
#ifdef CONFIG_COMPAT
#include <compat/vcpu.h>
#endif
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/arch/x86/domctl.c Mon Mar 17 10:45:24 2008 +0000
@@ -26,7 +26,7 @@
#include <asm/hvm/cacheattr.h>
#include <asm/processor.h>
#include <xsm/xsm.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
long arch_do_domctl(
struct xen_domctl *domctl,
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/arch/x86/hvm/Makefile Mon Mar 17 10:45:24 2008 +0000
@@ -6,7 +6,6 @@ obj-y += i8254.o
obj-y += i8254.o
obj-y += intercept.o
obj-y += io.o
-obj-y += iommu.o
obj-y += irq.o
obj-y += mtrr.o
obj-y += pmtimer.o
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/arch/x86/hvm/intercept.c Mon Mar 17 10:45:24 2008 +0000
@@ -30,7 +30,7 @@
#include <asm/current.h>
#include <io_ports.h>
#include <xen/event.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
extern struct hvm_mmio_handler hpet_mmio_handler;
extern struct hvm_mmio_handler vlapic_mmio_handler;
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/hvm/iommu.c
--- a/xen/arch/x86/hvm/iommu.c Sun Mar 16 14:11:34 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <xen/init.h>
-#include <xen/irq.h>
-#include <xen/spinlock.h>
-#include <xen/sched.h>
-#include <xen/xmalloc.h>
-#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/mm.h>
-#include <asm/iommu.h>
-#include <asm/hvm/vmx/intel-iommu.h>
-
-extern struct iommu_ops intel_iommu_ops;
-extern struct iommu_ops amd_iommu_ops;
-
-int iommu_domain_init(struct domain *domain)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
-
- spin_lock_init(&hd->mapping_lock);
- spin_lock_init(&hd->iommu_list_lock);
- INIT_LIST_HEAD(&hd->pdev_list);
- INIT_LIST_HEAD(&hd->g2m_ioport_list);
-
- if ( !iommu_enabled )
- return 0;
-
- switch ( boot_cpu_data.x86_vendor )
- {
- case X86_VENDOR_INTEL:
- hd->platform_ops = &intel_iommu_ops;
- break;
- case X86_VENDOR_AMD:
- hd->platform_ops = &amd_iommu_ops;
- break;
- default:
- BUG();
- }
-
- return hd->platform_ops->init(domain);
-}
-
-int assign_device(struct domain *d, u8 bus, u8 devfn)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
-
- if ( !iommu_enabled || !hd->platform_ops)
- return 0;
-
- return hd->platform_ops->assign_device(d, bus, devfn);
-}
-
-void iommu_domain_destroy(struct domain *d)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t i;
- struct hvm_iommu *hd = domain_hvm_iommu(d);
- struct list_head *ioport_list, *digl_list, *tmp;
- struct g2m_ioport *ioport;
- struct dev_intx_gsi_link *digl;
-
- if ( !iommu_enabled || !hd->platform_ops)
- return;
-
- if ( hvm_irq_dpci != NULL )
- {
- for ( i = 0; i < NR_IRQS; i++ )
- {
- if ( !hvm_irq_dpci->mirq[i].valid )
- continue;
-
- pirq_guest_unbind(d, i);
- kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]);
-
- list_for_each_safe ( digl_list, tmp,
- &hvm_irq_dpci->mirq[i].digl_list )
- {
- digl = list_entry(digl_list,
- struct dev_intx_gsi_link, list);
- list_del(&digl->list);
- xfree(digl);
- }
- }
-
- d->arch.hvm_domain.irq.dpci = NULL;
- xfree(hvm_irq_dpci);
- }
-
- if ( hd )
- {
- list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list )
- {
- ioport = list_entry(ioport_list, struct g2m_ioport, list);
- list_del(&ioport->list);
- xfree(ioport);
- }
- }
-
- return hd->platform_ops->teardown(d);
-}
-
-int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
-
- if ( !iommu_enabled || !hd->platform_ops)
- return 0;
-
- return hd->platform_ops->map_page(d, gfn, mfn);
-}
-
-int iommu_unmap_page(struct domain *d, unsigned long gfn)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
-
- if ( !iommu_enabled || !hd->platform_ops)
- return 0;
-
- return hd->platform_ops->unmap_page(d, gfn);
-}
-
-void deassign_device(struct domain *d, u8 bus, u8 devfn)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
-
- if ( !iommu_enabled || !hd->platform_ops)
- return;
-
- return hd->platform_ops->reassign_device(d, dom0, bus, devfn);
-}
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/arch/x86/irq.c Mon Mar 17 10:45:24 2008 +0000
@@ -15,7 +15,7 @@
#include <xen/keyhandler.h>
#include <xen/compat.h>
#include <asm/current.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
/* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
int opt_noirqbalance = 0;
diff -r af33f2054f47 -r bf8a3fc79093 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/arch/x86/mm/p2m.c Mon Mar 17 10:45:24 2008 +0000
@@ -27,7 +27,7 @@
#include <asm/page.h>
#include <asm/paging.h>
#include <asm/p2m.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
/* Debugging and auditing of the P2M code? */
#define P2M_AUDIT 0
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/Makefile
--- a/xen/drivers/passthrough/Makefile Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/Makefile Mon Mar 17 10:45:24 2008 +0000
@@ -1,2 +1,5 @@ subdir-$(x86) += vtd
subdir-$(x86) += vtd
subdir-$(x86) += amd
+
+obj-y += iommu.o
+obj-y += io.o
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/amd/iommu_detect.c
--- a/xen/drivers/passthrough/amd/iommu_detect.c Sun Mar 16 14:11:34
2008 +0000
+++ b/xen/drivers/passthrough/amd/iommu_detect.c Mon Mar 17 10:45:24
2008 +0000
@@ -20,7 +20,7 @@
#include <xen/config.h>
#include <xen/errno.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include "../pci-direct.h"
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/amd/iommu_map.c
--- a/xen/drivers/passthrough/amd/iommu_map.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/amd/iommu_map.c Mon Mar 17 10:45:24 2008 +0000
@@ -19,7 +19,7 @@
*/
#include <xen/sched.h>
-#include <asm/hvm/iommu.h>
+#include <xen/hvm/iommu.h>
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/io.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/io.c Mon Mar 17 10:45:24 2008 +0000
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
+ * Copyright (C) Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
+ */
+
+#include <xen/event.h>
+#include <xen/iommu.h>
+
+static void pt_irq_time_out(void *data)
+{
+ struct hvm_mirq_dpci_mapping *irq_map = data;
+ unsigned int guest_gsi, machine_gsi = 0;
+ struct hvm_irq_dpci *dpci = irq_map->dom->arch.hvm_domain.irq.dpci;
+ struct dev_intx_gsi_link *digl;
+ uint32_t device, intx;
+
+ list_for_each_entry ( digl, &irq_map->digl_list, list )
+ {
+ guest_gsi = digl->gsi;
+ machine_gsi = dpci->girq[guest_gsi].machine_gsi;
+ device = digl->device;
+ intx = digl->intx;
+ hvm_pci_intx_deassert(irq_map->dom, device, intx);
+ }
+
+ clear_bit(machine_gsi, dpci->dirq_mask);
+ stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+ spin_lock(&dpci->dirq_lock);
+ dpci->mirq[machine_gsi].pending = 0;
+ spin_unlock(&dpci->dirq_lock);
+ pirq_guest_eoi(irq_map->dom, machine_gsi);
+}
+
+int pt_irq_create_bind_vtd(
+ struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
+{
+ struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ uint32_t machine_gsi, guest_gsi;
+ uint32_t device, intx, link;
+ struct dev_intx_gsi_link *digl;
+
+ if ( hvm_irq_dpci == NULL )
+ {
+ hvm_irq_dpci = xmalloc(struct hvm_irq_dpci);
+ if ( hvm_irq_dpci == NULL )
+ return -ENOMEM;
+
+ memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
+ spin_lock_init(&hvm_irq_dpci->dirq_lock);
+ for ( int i = 0; i < NR_IRQS; i++ )
+ INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
+
+ if ( cmpxchg((unsigned long *)&d->arch.hvm_domain.irq.dpci,
+ 0, (unsigned long)hvm_irq_dpci) != 0 )
+ xfree(hvm_irq_dpci);
+
+ hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ }
+
+ machine_gsi = pt_irq_bind->machine_irq;
+ device = pt_irq_bind->u.pci.device;
+ intx = pt_irq_bind->u.pci.intx;
+ guest_gsi = hvm_pci_intx_gsi(device, intx);
+ link = hvm_pci_intx_link(device, intx);
+ hvm_irq_dpci->link_cnt[link]++;
+
+ digl = xmalloc(struct dev_intx_gsi_link);
+ if ( !digl )
+ return -ENOMEM;
+
+ digl->device = device;
+ digl->intx = intx;
+ digl->gsi = guest_gsi;
+ digl->link = link;
+ list_add_tail(&digl->list,
+ &hvm_irq_dpci->mirq[machine_gsi].digl_list);
+
+ hvm_irq_dpci->girq[guest_gsi].valid = 1;
+ hvm_irq_dpci->girq[guest_gsi].device = device;
+ hvm_irq_dpci->girq[guest_gsi].intx = intx;
+ hvm_irq_dpci->girq[guest_gsi].machine_gsi = machine_gsi;
+
+ /* Bind the same mirq once in the same domain */
+ if ( !hvm_irq_dpci->mirq[machine_gsi].valid )
+ {
+ hvm_irq_dpci->mirq[machine_gsi].valid = 1;
+ hvm_irq_dpci->mirq[machine_gsi].dom = d;
+
+ init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
+ pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
+ /* Deal with gsi for legacy devices */
+ pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
+ }
+
+ gdprintk(XENLOG_INFO VTDPREFIX,
+ "VT-d irq bind: m_irq = %x device = %x intx = %x\n",
+ machine_gsi, device, intx);
+ return 0;
+}
+
+int pt_irq_destroy_bind_vtd(
+ struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
+{
+ struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ uint32_t machine_gsi, guest_gsi;
+ uint32_t device, intx, link;
+ struct list_head *digl_list, *tmp;
+ struct dev_intx_gsi_link *digl;
+
+ if ( hvm_irq_dpci == NULL )
+ return 0;
+
+ machine_gsi = pt_irq_bind->machine_irq;
+ device = pt_irq_bind->u.pci.device;
+ intx = pt_irq_bind->u.pci.intx;
+ guest_gsi = hvm_pci_intx_gsi(device, intx);
+ link = hvm_pci_intx_link(device, intx);
+ hvm_irq_dpci->link_cnt[link]--;
+
+ gdprintk(XENLOG_INFO,
+ "pt_irq_destroy_bind_vtd: machine_gsi=%d, guest_gsi=%d, device=%d,
intx=%d.\n",
+ machine_gsi, guest_gsi, device, intx);
+ memset(&hvm_irq_dpci->girq[guest_gsi], 0, sizeof(struct
hvm_girq_dpci_mapping));
+
+ /* clear the mirq info */
+ if ( hvm_irq_dpci->mirq[machine_gsi].valid )
+ {
+
+ list_for_each_safe ( digl_list, tmp,
+ &hvm_irq_dpci->mirq[machine_gsi].digl_list )
+ {
+ digl = list_entry(digl_list,
+ struct dev_intx_gsi_link, list);
+ if ( digl->device == device &&
+ digl->intx == intx &&
+ digl->link == link &&
+ digl->gsi == guest_gsi )
+ {
+ list_del(&digl->list);
+ xfree(digl);
+ }
+ }
+
+ if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
+ {
+ pirq_guest_unbind(d, machine_gsi);
+ kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+ hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
+ hvm_irq_dpci->mirq[machine_gsi].valid = 0;
+ }
+ }
+
+ gdprintk(XENLOG_INFO,
+ "XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n",
+ machine_gsi, device, intx);
+
+ return 0;
+}
+
+int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ if ( !iommu_enabled || (d == dom0) || (hvm_irq->dpci == NULL) ||
+ !hvm_irq->dpci->mirq[mirq].valid )
+ return 0;
+
+ /*
+ * Set a timer here to avoid situations where the IRQ line is shared, and
+ * the device belonging to the pass-through guest is not yet active. In
+ * this case the guest may not pick up the interrupt (e.g., masked at the
+ * PIC) and we need to detect that.
+ */
+ set_bit(mirq, hvm_irq->dpci->dirq_mask);
+ set_timer(&hvm_irq->dpci->hvm_timer[irq_to_vector(mirq)],
+ NOW() + PT_IRQ_TIME_OUT);
+ vcpu_kick(d->vcpu[0]);
+
+ return 1;
+}
+
+static void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq_dpci *dpci = hvm_irq->dpci;
+ struct dev_intx_gsi_link *digl, *tmp;
+ int i;
+
+ ASSERT(isairq < NR_ISAIRQS);
+ if ( !iommu_enabled || !dpci ||
+ !test_bit(isairq, dpci->isairq_map) )
+ return;
+
+ /* Multiple mirq may be mapped to one isa irq */
+ for ( i = 0; i < NR_IRQS; i++ )
+ {
+ if ( !dpci->mirq[i].valid )
+ continue;
+
+ list_for_each_entry_safe ( digl, tmp,
+ &dpci->mirq[i].digl_list, list )
+ {
+ if ( hvm_irq->pci_link.route[digl->link] == isairq )
+ {
+ hvm_pci_intx_deassert(d, digl->device, digl->intx);
+ spin_lock(&dpci->dirq_lock);
+ if ( --dpci->mirq[i].pending == 0 )
+ {
+ spin_unlock(&dpci->dirq_lock);
+ gdprintk(XENLOG_INFO VTDPREFIX,
+ "hvm_dpci_isairq_eoi:: mirq = %x\n", i);
+ stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
+ pirq_guest_eoi(d, i);
+ }
+ else
+ spin_unlock(&dpci->dirq_lock);
+ }
+ }
+ }
+}
+
+void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
+ union vioapic_redir_entry *ent)
+{
+ struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ uint32_t device, intx, machine_gsi;
+
+ if ( !iommu_enabled || (hvm_irq_dpci == NULL) ||
+ (guest_gsi >= NR_ISAIRQS &&
+ !hvm_irq_dpci->girq[guest_gsi].valid) )
+ return;
+
+ if ( guest_gsi < NR_ISAIRQS )
+ {
+ hvm_dpci_isairq_eoi(d, guest_gsi);
+ return;
+ }
+
+ machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
+ device = hvm_irq_dpci->girq[guest_gsi].device;
+ intx = hvm_irq_dpci->girq[guest_gsi].intx;
+ hvm_pci_intx_deassert(d, device, intx);
+
+ spin_lock(&hvm_irq_dpci->dirq_lock);
+ if ( --hvm_irq_dpci->mirq[machine_gsi].pending == 0 )
+ {
+ spin_unlock(&hvm_irq_dpci->dirq_lock);
+
+ gdprintk(XENLOG_INFO VTDPREFIX,
+ "hvm_dpci_eoi:: mirq = %x\n", machine_gsi);
+ stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+ if ( (ent == NULL) || !ent->fields.mask )
+ pirq_guest_eoi(d, machine_gsi);
+ }
+ else
+ spin_unlock(&hvm_irq_dpci->dirq_lock);
+}
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/iommu.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/iommu.c Mon Mar 17 10:45:24 2008 +0000
@@ -0,0 +1,136 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <xen/sched.h>
+#include <xen/iommu.h>
+
+extern struct iommu_ops intel_iommu_ops;
+extern struct iommu_ops amd_iommu_ops;
+
+int iommu_domain_init(struct domain *domain)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(domain);
+
+ spin_lock_init(&hd->mapping_lock);
+ spin_lock_init(&hd->iommu_list_lock);
+ INIT_LIST_HEAD(&hd->pdev_list);
+ INIT_LIST_HEAD(&hd->g2m_ioport_list);
+
+ if ( !iommu_enabled )
+ return 0;
+
+ switch ( boot_cpu_data.x86_vendor )
+ {
+ case X86_VENDOR_INTEL:
+ hd->platform_ops = &intel_iommu_ops;
+ break;
+ case X86_VENDOR_AMD:
+ hd->platform_ops = &amd_iommu_ops;
+ break;
+ default:
+ BUG();
+ }
+
+ return hd->platform_ops->init(domain);
+}
+
+int assign_device(struct domain *d, u8 bus, u8 devfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return 0;
+
+ return hd->platform_ops->assign_device(d, bus, devfn);
+}
+
+void iommu_domain_destroy(struct domain *d)
+{
+ struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ uint32_t i;
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+ struct list_head *ioport_list, *digl_list, *tmp;
+ struct g2m_ioport *ioport;
+ struct dev_intx_gsi_link *digl;
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return;
+
+ if ( hvm_irq_dpci != NULL )
+ {
+ for ( i = 0; i < NR_IRQS; i++ )
+ {
+ if ( !hvm_irq_dpci->mirq[i].valid )
+ continue;
+
+ pirq_guest_unbind(d, i);
+ kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]);
+
+ list_for_each_safe ( digl_list, tmp,
+ &hvm_irq_dpci->mirq[i].digl_list )
+ {
+ digl = list_entry(digl_list,
+ struct dev_intx_gsi_link, list);
+ list_del(&digl->list);
+ xfree(digl);
+ }
+ }
+
+ d->arch.hvm_domain.irq.dpci = NULL;
+ xfree(hvm_irq_dpci);
+ }
+
+ if ( hd )
+ {
+ list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list )
+ {
+ ioport = list_entry(ioport_list, struct g2m_ioport, list);
+ list_del(&ioport->list);
+ xfree(ioport);
+ }
+ }
+
+ return hd->platform_ops->teardown(d);
+}
+
+int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return 0;
+
+ return hd->platform_ops->map_page(d, gfn, mfn);
+}
+
+int iommu_unmap_page(struct domain *d, unsigned long gfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return 0;
+
+ return hd->platform_ops->unmap_page(d, gfn);
+}
+
+void deassign_device(struct domain *d, u8 bus, u8 devfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return;
+
+ return hd->platform_ops->reassign_device(d, dom0, bus, devfn);
+}
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/Makefile
--- a/xen/drivers/passthrough/vtd/Makefile Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/Makefile Mon Mar 17 10:45:24 2008 +0000
@@ -1,6 +1,5 @@ obj-y += iommu.o
obj-y += iommu.o
obj-y += dmar.o
obj-y += utils.o
-obj-y += io.o
obj-y += qinval.o
obj-y += intremap.o
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/dmar.h
--- a/xen/drivers/passthrough/vtd/dmar.h Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/dmar.h Mon Mar 17 10:45:24 2008 +0000
@@ -22,7 +22,7 @@
#define _DMAR_H_
#include <xen/list.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
extern u8 dmar_host_address_width;
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/extern.h
--- a/xen/drivers/passthrough/vtd/extern.h Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/extern.h Mon Mar 17 10:45:24 2008 +0000
@@ -42,8 +42,6 @@ int invalidate_sync(struct iommu *iommu)
int invalidate_sync(struct iommu *iommu);
int iommu_flush_iec_global(struct iommu *iommu);
int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx);
-void print_iommu_regs(struct acpi_drhd_unit *drhd);
-int vtd_hw_check(void);
struct iommu * ioapic_to_iommu(unsigned int apic_id);
struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id);
void clear_fault_bits(struct iommu *iommu);
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/intremap.c
--- a/xen/drivers/passthrough/vtd/intremap.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/intremap.c Mon Mar 17 10:45:24 2008 +0000
@@ -18,28 +18,10 @@
* Copyright (C) Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
*/
-#include <xen/config.h>
-#include <xen/lib.h>
-#include <xen/init.h>
#include <xen/irq.h>
-#include <xen/delay.h>
#include <xen/sched.h>
-#include <xen/acpi.h>
-#include <xen/keyhandler.h>
-#include <xen/spinlock.h>
-#include <asm/io.h>
-#include <asm/mc146818rtc.h>
-#include <asm/smp.h>
-#include <asm/desc.h>
-#include <mach_apic.h>
-#include <io_ports.h>
-
-#include <xen/spinlock.h>
-#include <xen/xmalloc.h>
-#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
+#include "iommu.h"
#include "dmar.h"
#include "vtd.h"
#include "../pci-direct.h"
@@ -172,7 +154,7 @@ io_apic_read_remap_rte(
struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
- if ( !iommu || !(ir_ctrl->iremap) )
+ if ( !iommu || !ir_ctrl || !(ir_ctrl->iremap) )
{
*IO_APIC_BASE(apic) = reg;
return *(IO_APIC_BASE(apic)+4);
@@ -218,7 +200,7 @@ io_apic_write_remap_rte(
struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
- if ( !iommu || !(ir_ctrl->iremap) )
+ if ( !iommu || !ir_ctrl || !(ir_ctrl->iremap) )
{
*IO_APIC_BASE(apic) = reg;
*(IO_APIC_BASE(apic)+4) = value;
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/io.c
--- a/xen/drivers/passthrough/vtd/io.c Sun Mar 16 14:11:34 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- * Copyright (C) Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
- */
-
-#include <xen/init.h>
-#include <xen/config.h>
-#include <xen/init.h>
-#include <xen/mm.h>
-#include <xen/lib.h>
-#include <xen/errno.h>
-#include <xen/trace.h>
-#include <xen/event.h>
-#include <xen/hypercall.h>
-#include <asm/current.h>
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/apic.h>
-#include <asm/paging.h>
-#include <asm/shadow.h>
-#include <asm/p2m.h>
-#include <asm/hvm/hvm.h>
-#include <asm/hvm/support.h>
-#include <asm/hvm/vpt.h>
-#include <asm/hvm/vpic.h>
-#include <asm/hvm/vlapic.h>
-#include <public/sched.h>
-#include <xen/iocap.h>
-#include <public/hvm/ioreq.h>
-#include <public/domctl.h>
-
-static void pt_irq_time_out(void *data)
-{
- struct hvm_mirq_dpci_mapping *irq_map = data;
- unsigned int guest_gsi, machine_gsi = 0;
- struct hvm_irq_dpci *dpci = irq_map->dom->arch.hvm_domain.irq.dpci;
- struct dev_intx_gsi_link *digl;
- uint32_t device, intx;
-
- list_for_each_entry ( digl, &irq_map->digl_list, list )
- {
- guest_gsi = digl->gsi;
- machine_gsi = dpci->girq[guest_gsi].machine_gsi;
- device = digl->device;
- intx = digl->intx;
- hvm_pci_intx_deassert(irq_map->dom, device, intx);
- }
-
- clear_bit(machine_gsi, dpci->dirq_mask);
- stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]);
- spin_lock(&dpci->dirq_lock);
- dpci->mirq[machine_gsi].pending = 0;
- spin_unlock(&dpci->dirq_lock);
- pirq_guest_eoi(irq_map->dom, machine_gsi);
-}
-
-int pt_irq_create_bind_vtd(
- struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t machine_gsi, guest_gsi;
- uint32_t device, intx, link;
- struct dev_intx_gsi_link *digl;
-
- if ( hvm_irq_dpci == NULL )
- {
- hvm_irq_dpci = xmalloc(struct hvm_irq_dpci);
- if ( hvm_irq_dpci == NULL )
- return -ENOMEM;
-
- memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
- spin_lock_init(&hvm_irq_dpci->dirq_lock);
- for ( int i = 0; i < NR_IRQS; i++ )
- INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
-
- if ( cmpxchg((unsigned long *)&d->arch.hvm_domain.irq.dpci,
- 0, (unsigned long)hvm_irq_dpci) != 0 )
- xfree(hvm_irq_dpci);
-
- hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- }
-
- machine_gsi = pt_irq_bind->machine_irq;
- device = pt_irq_bind->u.pci.device;
- intx = pt_irq_bind->u.pci.intx;
- guest_gsi = hvm_pci_intx_gsi(device, intx);
- link = hvm_pci_intx_link(device, intx);
- hvm_irq_dpci->link_cnt[link]++;
-
- digl = xmalloc(struct dev_intx_gsi_link);
- if ( !digl )
- return -ENOMEM;
-
- digl->device = device;
- digl->intx = intx;
- digl->gsi = guest_gsi;
- digl->link = link;
- list_add_tail(&digl->list,
- &hvm_irq_dpci->mirq[machine_gsi].digl_list);
-
- hvm_irq_dpci->girq[guest_gsi].valid = 1;
- hvm_irq_dpci->girq[guest_gsi].device = device;
- hvm_irq_dpci->girq[guest_gsi].intx = intx;
- hvm_irq_dpci->girq[guest_gsi].machine_gsi = machine_gsi;
-
- /* Bind the same mirq once in the same domain */
- if ( !hvm_irq_dpci->mirq[machine_gsi].valid )
- {
- hvm_irq_dpci->mirq[machine_gsi].valid = 1;
- hvm_irq_dpci->mirq[machine_gsi].dom = d;
-
- init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
- pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
- /* Deal with gsi for legacy devices */
- pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
- }
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "VT-d irq bind: m_irq = %x device = %x intx = %x\n",
- machine_gsi, device, intx);
- return 0;
-}
-
-int pt_irq_destroy_bind_vtd(
- struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t machine_gsi, guest_gsi;
- uint32_t device, intx, link;
- struct list_head *digl_list, *tmp;
- struct dev_intx_gsi_link *digl;
-
- if ( hvm_irq_dpci == NULL )
- return 0;
-
- machine_gsi = pt_irq_bind->machine_irq;
- device = pt_irq_bind->u.pci.device;
- intx = pt_irq_bind->u.pci.intx;
- guest_gsi = hvm_pci_intx_gsi(device, intx);
- link = hvm_pci_intx_link(device, intx);
- hvm_irq_dpci->link_cnt[link]--;
-
- gdprintk(XENLOG_INFO,
- "pt_irq_destroy_bind_vtd: machine_gsi=%d, guest_gsi=%d, device=%d,
intx=%d.\n",
- machine_gsi, guest_gsi, device, intx);
- memset(&hvm_irq_dpci->girq[guest_gsi], 0, sizeof(struct
hvm_girq_dpci_mapping));
-
- /* clear the mirq info */
- if ( hvm_irq_dpci->mirq[machine_gsi].valid )
- {
-
- list_for_each_safe ( digl_list, tmp,
- &hvm_irq_dpci->mirq[machine_gsi].digl_list )
- {
- digl = list_entry(digl_list,
- struct dev_intx_gsi_link, list);
- if ( digl->device == device &&
- digl->intx == intx &&
- digl->link == link &&
- digl->gsi == guest_gsi )
- {
- list_del(&digl->list);
- xfree(digl);
- }
- }
-
- if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
- {
- pirq_guest_unbind(d, machine_gsi);
- kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
- hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
- hvm_irq_dpci->mirq[machine_gsi].valid = 0;
- }
- }
-
- gdprintk(XENLOG_INFO,
- "XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n",
- machine_gsi, device, intx);
-
- return 0;
-}
-
-int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
-{
- struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
-
- if ( !iommu_enabled || (d == dom0) || (hvm_irq->dpci == NULL) ||
- !hvm_irq->dpci->mirq[mirq].valid )
- return 0;
-
- /*
- * Set a timer here to avoid situations where the IRQ line is shared, and
- * the device belonging to the pass-through guest is not yet active. In
- * this case the guest may not pick up the interrupt (e.g., masked at the
- * PIC) and we need to detect that.
- */
- set_bit(mirq, hvm_irq->dpci->dirq_mask);
- set_timer(&hvm_irq->dpci->hvm_timer[irq_to_vector(mirq)],
- NOW() + PT_IRQ_TIME_OUT);
- vcpu_kick(d->vcpu[0]);
-
- return 1;
-}
-
-static void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
-{
- struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
- struct hvm_irq_dpci *dpci = hvm_irq->dpci;
- struct dev_intx_gsi_link *digl, *tmp;
- int i;
-
- ASSERT(isairq < NR_ISAIRQS);
- if ( !iommu_enabled || !dpci ||
- !test_bit(isairq, dpci->isairq_map) )
- return;
-
- /* Multiple mirq may be mapped to one isa irq */
- for ( i = 0; i < NR_IRQS; i++ )
- {
- if ( !dpci->mirq[i].valid )
- continue;
-
- list_for_each_entry_safe ( digl, tmp,
- &dpci->mirq[i].digl_list, list )
- {
- if ( hvm_irq->pci_link.route[digl->link] == isairq )
- {
- hvm_pci_intx_deassert(d, digl->device, digl->intx);
- spin_lock(&dpci->dirq_lock);
- if ( --dpci->mirq[i].pending == 0 )
- {
- spin_unlock(&dpci->dirq_lock);
- gdprintk(XENLOG_INFO VTDPREFIX,
- "hvm_dpci_isairq_eoi:: mirq = %x\n", i);
- stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
- pirq_guest_eoi(d, i);
- }
- else
- spin_unlock(&dpci->dirq_lock);
- }
- }
- }
-}
-
-void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
- union vioapic_redir_entry *ent)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t device, intx, machine_gsi;
-
- if ( !iommu_enabled || (hvm_irq_dpci == NULL) ||
- (guest_gsi >= NR_ISAIRQS &&
- !hvm_irq_dpci->girq[guest_gsi].valid) )
- return;
-
- if ( guest_gsi < NR_ISAIRQS )
- {
- hvm_dpci_isairq_eoi(d, guest_gsi);
- return;
- }
-
- machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
- device = hvm_irq_dpci->girq[guest_gsi].device;
- intx = hvm_irq_dpci->girq[guest_gsi].intx;
- hvm_pci_intx_deassert(d, device, intx);
-
- spin_lock(&hvm_irq_dpci->dirq_lock);
- if ( --hvm_irq_dpci->mirq[machine_gsi].pending == 0 )
- {
- spin_unlock(&hvm_irq_dpci->dirq_lock);
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "hvm_dpci_eoi:: mirq = %x\n", machine_gsi);
- stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
- if ( (ent == NULL) || !ent->fields.mask )
- pirq_guest_eoi(d, machine_gsi);
- }
- else
- spin_unlock(&hvm_irq_dpci->dirq_lock);
-}
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/iommu.c Mon Mar 17 10:45:24 2008 +0000
@@ -19,17 +19,12 @@
* Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx> - adapted to xen
*/
-#include <xen/init.h>
#include <xen/irq.h>
-#include <xen/spinlock.h>
#include <xen/sched.h>
#include <xen/xmalloc.h>
#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/mm.h>
-#include <asm/iommu.h>
-#include <asm/hvm/vmx/intel-iommu.h>
+#include <xen/iommu.h>
+#include "iommu.h"
#include "dmar.h"
#include "../pci-direct.h"
#include "../pci_regs.h"
@@ -72,6 +67,93 @@ static void iommu_domid_release(struct d
d->arch.hvm_domain.hvm_iommu.iommu_domid = 0;
clear_bit(iommu_domid, domid_bitmap);
}
+}
+
+static struct intel_iommu *alloc_intel_iommu(void)
+{
+ struct intel_iommu *intel;
+
+ intel = xmalloc(struct intel_iommu);
+ if ( !intel )
+ {
+ gdprintk(XENLOG_ERR VTDPREFIX,
+ "Allocate intel_iommu failed.\n");
+ return NULL;
+ }
+ memset(intel, 0, sizeof(struct intel_iommu));
+
+ spin_lock_init(&intel->qi_ctrl.qinval_lock);
+ spin_lock_init(&intel->qi_ctrl.qinval_poll_lock);
+
+ spin_lock_init(&intel->ir_ctrl.iremap_lock);
+
+ return intel;
+}
+
+static void free_intel_iommu(struct intel_iommu *intel)
+{
+ if ( intel )
+ {
+ xfree(intel);
+ intel = NULL;
+ }
+}
+
+struct qi_ctrl *iommu_qi_ctrl(struct iommu *iommu)
+{
+ if ( !iommu )
+ return NULL;
+
+ if ( !iommu->intel )
+ {
+ iommu->intel = alloc_intel_iommu();
+ if ( !iommu->intel )
+ {
+ dprintk(XENLOG_ERR VTDPREFIX,
+ "iommu_qi_ctrl: Allocate iommu->intel failed.\n");
+ return NULL;
+ }
+ }
+
+ return &(iommu->intel->qi_ctrl);
+}
+
+struct ir_ctrl *iommu_ir_ctrl(struct iommu *iommu)
+{
+ if ( !iommu )
+ return NULL;
+
+ if ( !iommu->intel )
+ {
+ iommu->intel = alloc_intel_iommu();
+ if ( !iommu->intel )
+ {
+ dprintk(XENLOG_ERR VTDPREFIX,
+ "iommu_ir_ctrl: Allocate iommu->intel failed.\n");
+ return NULL;
+ }
+ }
+
+ return &(iommu->intel->ir_ctrl);
+}
+
+struct iommu_flush *iommu_get_flush(struct iommu *iommu)
+{
+ if ( !iommu )
+ return NULL;
+
+ if ( !iommu->intel )
+ {
+ iommu->intel = alloc_intel_iommu();
+ if ( !iommu->intel )
+ {
+ dprintk(XENLOG_ERR VTDPREFIX,
+ "iommu_get_flush: Allocate iommu->intel failed.\n");
+ return NULL;
+ }
+ }
+
+ return &(iommu->intel->flush);
}
unsigned int x86_clflush_size;
@@ -756,40 +838,34 @@ static int iommu_page_fault_do_one(struc
PCI_SLOT(source_id & 0xFF), PCI_FUNC(source_id & 0xFF), addr,
fault_reason, iommu->reg);
- if (fault_reason < 0x20)
+ if ( fault_reason < 0x20 )
print_vtd_entries(current->domain, iommu, (source_id >> 8),
- (source_id & 0xff), (addr >> PAGE_SHIFT));
+ (source_id & 0xff), (addr >> PAGE_SHIFT));
return 0;
}
static void iommu_fault_status(u32 fault_status)
{
- if (fault_status & DMA_FSTS_PFO)
+ if ( fault_status & DMA_FSTS_PFO )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Fault Overflow\n");
- else
- if (fault_status & DMA_FSTS_PPF)
+ else if ( fault_status & DMA_FSTS_PPF )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Primary Pending Fault\n");
- else
- if (fault_status & DMA_FSTS_AFO)
+ else if ( fault_status & DMA_FSTS_AFO )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Advanced Fault Overflow\n");
- else
- if (fault_status & DMA_FSTS_APF)
+ else if ( fault_status & DMA_FSTS_APF )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Advanced Pending Fault\n");
- else
- if (fault_status & DMA_FSTS_IQE)
+ else if ( fault_status & DMA_FSTS_IQE )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Invalidation Queue Error\n");
- else
- if (fault_status & DMA_FSTS_ICE)
+ else if ( fault_status & DMA_FSTS_ICE )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Invalidation Completion Error\n");
- else
- if (fault_status & DMA_FSTS_ITE)
+ else if ( fault_status & DMA_FSTS_ITE )
dprintk(XENLOG_ERR VTDPREFIX,
"iommu_fault_status: Invalidation Time-out Error\n");
}
@@ -976,8 +1052,6 @@ struct iommu *iommu_alloc(void *hw_data)
{
struct acpi_drhd_unit *drhd = (struct acpi_drhd_unit *) hw_data;
struct iommu *iommu;
- struct qi_ctrl *qi_ctrl;
- struct ir_ctrl *ir_ctrl;
if ( nr_iommus > MAX_IOMMUS )
{
@@ -1014,12 +1088,7 @@ struct iommu *iommu_alloc(void *hw_data)
spin_lock_init(&iommu->lock);
spin_lock_init(&iommu->register_lock);
- qi_ctrl = iommu_qi_ctrl(iommu);
- spin_lock_init(&qi_ctrl->qinval_lock);
- spin_lock_init(&qi_ctrl->qinval_poll_lock);
-
- ir_ctrl = iommu_ir_ctrl(iommu);
- spin_lock_init(&ir_ctrl->iremap_lock);
+ iommu->intel = alloc_intel_iommu();
drhd->iommu = iommu;
return iommu;
@@ -1036,6 +1105,7 @@ static void free_iommu(struct iommu *iom
free_xenheap_page((void *)iommu->root_entry);
if ( iommu->reg )
iounmap(iommu->reg);
+ free_intel_iommu(iommu->intel);
free_irq(iommu->vector);
xfree(iommu);
}
@@ -1063,7 +1133,7 @@ int intel_iommu_domain_init(struct domai
iommu = drhd->iommu ? : iommu_alloc(drhd);
/* calculate AGAW */
- if (guest_width > cap_mgaw(iommu->cap))
+ if ( guest_width > cap_mgaw(iommu->cap) )
guest_width = cap_mgaw(iommu->cap);
adjust_width = guestwidth_to_adjustwidth(guest_width);
agaw = width_to_agaw(adjust_width);
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/iommu.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/iommu.h Mon Mar 17 10:45:24 2008 +0000
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@xxxxxxxxx>
+ */
+
+#ifndef _INTEL_IOMMU_H_
+#define _INTEL_IOMMU_H_
+
+#include <xen/types.h>
+
+/*
+ * Intel IOMMU register specification per version 1.0 public spec.
+ */
+
+#define DMAR_VER_REG 0x0 /* Arch version supported by this IOMMU */
+#define DMAR_CAP_REG 0x8 /* Hardware supported capabilities */
+#define DMAR_ECAP_REG 0x10 /* Extended capabilities supported */
+#define DMAR_GCMD_REG 0x18 /* Global command register */
+#define DMAR_GSTS_REG 0x1c /* Global status register */
+#define DMAR_RTADDR_REG 0x20 /* Root entry table */
+#define DMAR_CCMD_REG 0x28 /* Context command reg */
+#define DMAR_FSTS_REG 0x34 /* Fault Status register */
+#define DMAR_FECTL_REG 0x38 /* Fault control register */
+#define DMAR_FEDATA_REG 0x3c /* Fault event interrupt data register */
+#define DMAR_FEADDR_REG 0x40 /* Fault event interrupt addr register */
+#define DMAR_FEUADDR_REG 0x44 /* Upper address register */
+#define DMAR_AFLOG_REG 0x58 /* Advanced Fault control */
+#define DMAR_PMEN_REG 0x64 /* Enable Protected Memory Region */
+#define DMAR_PLMBASE_REG 0x68 /* PMRR Low addr */
+#define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */
+#define DMAR_PHMBASE_REG 0x70 /* pmrr high base addr */
+#define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */
+#define DMAR_IQH_REG 0x80 /* invalidation queue head */
+#define DMAR_IQT_REG 0x88 /* invalidation queue tail */
+#define DMAR_IQA_REG 0x90 /* invalidation queue addr */
+#define DMAR_IRTA_REG 0xB8 /* intr remap */
+
+#define OFFSET_STRIDE (9)
+#define dmar_readl(dmar, reg) readl(dmar + reg)
+#define dmar_writel(dmar, reg, val) writel(val, dmar + reg)
+#define dmar_readq(dmar, reg) ({ \
+ u32 lo, hi; \
+ lo = dmar_readl(dmar, reg); \
+ hi = dmar_readl(dmar, reg + 4); \
+ (((u64) hi) << 32) + lo; })
+#define dmar_writeq(dmar, reg, val) do {\
+ dmar_writel(dmar, reg, (u32)val); \
+ dmar_writel(dmar, reg + 4, (u32)((u64) val >> 32)); \
+ } while (0)
+
+#define VER_MAJOR(v) (((v) & 0xf0) >> 4)
+#define VER_MINOR(v) ((v) & 0x0f)
+
+/*
+ * Decoding Capability Register
+ */
+#define cap_read_drain(c) (((c) >> 55) & 1)
+#define cap_write_drain(c) (((c) >> 54) & 1)
+#define cap_max_amask_val(c) (((c) >> 48) & 0x3f)
+#define cap_num_fault_regs(c) ((((c) >> 40) & 0xff) + 1)
+#define cap_pgsel_inv(c) (((c) >> 39) & 1)
+
+#define cap_super_page_val(c) (((c) >> 34) & 0xf)
+#define cap_super_offset(c) (((find_first_bit(&cap_super_page_val(c), 4)) \
+ * OFFSET_STRIDE) + 21)
+
+#define cap_fault_reg_offset(c) ((((c) >> 24) & 0x3ff) * 16)
+
+#define cap_isoch(c) (((c) >> 23) & 1)
+#define cap_qos(c) (((c) >> 22) & 1)
+#define cap_mgaw(c) ((((c) >> 16) & 0x3f) + 1)
+#define cap_sagaw(c) (((c) >> 8) & 0x1f)
+#define cap_caching_mode(c) (((c) >> 7) & 1)
+#define cap_phmr(c) (((c) >> 6) & 1)
+#define cap_plmr(c) (((c) >> 5) & 1)
+#define cap_rwbf(c) (((c) >> 4) & 1)
+#define cap_afl(c) (((c) >> 3) & 1)
+#define cap_ndoms(c) (1 << (4 + 2 * ((c) & 0x7)))
+
+/*
+ * Extended Capability Register
+ */
+
+#define ecap_niotlb_iunits(e) ((((e) >> 24) & 0xff) + 1)
+#define ecap_iotlb_offset(e) ((((e) >> 8) & 0x3ff) * 16)
+#define ecap_coherent(e) ((e >> 0) & 0x1)
+#define ecap_queued_inval(e) ((e >> 1) & 0x1)
+#define ecap_dev_iotlb(e) ((e >> 2) & 0x1)
+#define ecap_intr_remap(e) ((e >> 3) & 0x1)
+#define ecap_ext_intr(e) ((e >> 4) & 0x1)
+#define ecap_cache_hints(e) ((e >> 5) & 0x1)
+#define ecap_pass_thru(e) ((e >> 6) & 0x1)
+
+/* IOTLB_REG */
+#define DMA_TLB_FLUSH_GRANU_OFFSET 60
+#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
+#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
+#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
+#define DMA_TLB_IIRG(x) (((x) >> 60) & 7)
+#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
+#define DMA_TLB_DID(x) (((u64)(x & 0xffff)) << 32)
+
+#define DMA_TLB_READ_DRAIN (((u64)1) << 49)
+#define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
+#define DMA_TLB_IVT (((u64)1) << 63)
+
+#define DMA_TLB_IVA_ADDR(x) ((((u64)x) >> 12) << 12)
+#define DMA_TLB_IVA_HINT(x) ((((u64)x) & 1) << 6)
+
+/* GCMD_REG */
+#define DMA_GCMD_TE (((u64)1) << 31)
+#define DMA_GCMD_SRTP (((u64)1) << 30)
+#define DMA_GCMD_SFL (((u64)1) << 29)
+#define DMA_GCMD_EAFL (((u64)1) << 28)
+#define DMA_GCMD_WBF (((u64)1) << 27)
+#define DMA_GCMD_QIE (((u64)1) << 26)
+#define DMA_GCMD_IRE (((u64)1) << 25)
+#define DMA_GCMD_SIRTP (((u64)1) << 24)
+#define DMA_GCMD_CFI (((u64)1) << 23)
+
+/* GSTS_REG */
+#define DMA_GSTS_TES (((u64)1) << 31)
+#define DMA_GSTS_RTPS (((u64)1) << 30)
+#define DMA_GSTS_FLS (((u64)1) << 29)
+#define DMA_GSTS_AFLS (((u64)1) << 28)
+#define DMA_GSTS_WBFS (((u64)1) << 27)
+#define DMA_GSTS_QIES (((u64)1) <<26)
+#define DMA_GSTS_IRES (((u64)1) <<25)
+#define DMA_GSTS_SIRTPS (((u64)1) << 24)
+#define DMA_GSTS_CFIS (((u64)1) <<23)
+
+/* PMEN_REG */
+#define DMA_PMEN_EPM (((u32)1) << 31)
+#define DMA_PMEN_PRS (((u32)1) << 0)
+
+/* CCMD_REG */
+#define DMA_CCMD_INVL_GRANU_OFFSET 61
+#define DMA_CCMD_ICC (((u64)1) << 63)
+#define DMA_CCMD_GLOBAL_INVL (((u64)1) << 61)
+#define DMA_CCMD_DOMAIN_INVL (((u64)2) << 61)
+#define DMA_CCMD_DEVICE_INVL (((u64)3) << 61)
+#define DMA_CCMD_FM(m) (((u64)((m) & 0x3)) << 32)
+#define DMA_CCMD_CIRG(x) ((((u64)3) << 61) & x)
+#define DMA_CCMD_MASK_NOBIT 0
+#define DMA_CCMD_MASK_1BIT 1
+#define DMA_CCMD_MASK_2BIT 2
+#define DMA_CCMD_MASK_3BIT 3
+#define DMA_CCMD_SID(s) (((u64)((s) & 0xffff)) << 16)
+#define DMA_CCMD_DID(d) ((u64)((d) & 0xffff))
+
+#define DMA_CCMD_CAIG_MASK(x) (((u64)x) & ((u64) 0x3 << 59))
+
+/* FECTL_REG */
+#define DMA_FECTL_IM (((u64)1) << 31)
+
+/* FSTS_REG */
+#define DMA_FSTS_PFO ((u64)1 << 0)
+#define DMA_FSTS_PPF ((u64)1 << 1)
+#define DMA_FSTS_AFO ((u64)1 << 2)
+#define DMA_FSTS_APF ((u64)1 << 3)
+#define DMA_FSTS_IQE ((u64)1 << 4)
+#define DMA_FSTS_ICE ((u64)1 << 5)
+#define DMA_FSTS_ITE ((u64)1 << 6)
+#define DMA_FSTS_FAULTS DMA_FSTS_PFO | DMA_FSTS_PPF | DMA_FSTS_AFO |
DMA_FSTS_APF | DMA_FSTS_IQE | DMA_FSTS_ICE | DMA_FSTS_ITE
+#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
+
+/* FRCD_REG, 32 bits access */
+#define DMA_FRCD_F (((u64)1) << 31)
+#define dma_frcd_type(d) ((d >> 30) & 1)
+#define dma_frcd_fault_reason(c) (c & 0xff)
+#define dma_frcd_source_id(c) (c & 0xffff)
+#define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
+
+/*
+ * 0: Present
+ * 1-11: Reserved
+ * 12-63: Context Ptr (12 - (haw-1))
+ * 64-127: Reserved
+ */
+struct root_entry {
+ u64 val;
+ u64 rsvd1;
+};
+#define root_present(root) ((root).val & 1)
+#define set_root_present(root) do {(root).val |= 1;} while(0)
+#define get_context_addr(root) ((root).val & PAGE_MASK_4K)
+#define set_root_value(root, value) \
+ do {(root).val |= ((value) & PAGE_MASK_4K);} while(0)
+
+struct context_entry {
+ u64 lo;
+ u64 hi;
+};
+#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
+#define context_present(c) ((c).lo & 1)
+#define context_fault_disable(c) (((c).lo >> 1) & 1)
+#define context_translation_type(c) (((c).lo >> 2) & 3)
+#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
+#define context_address_width(c) ((c).hi & 7)
+#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
+
+#define context_set_present(c) do {(c).lo |= 1;} while(0)
+#define context_clear_present(c) do {(c).lo &= ~1;} while(0)
+#define context_set_fault_enable(c) \
+ do {(c).lo &= (((u64)-1) << 2) | 1;} while(0)
+
+#define context_set_translation_type(c, val) do { \
+ (c).lo &= (((u64)-1) << 4) | 3; \
+ (c).lo |= (val & 3) << 2; \
+ } while(0)
+#define CONTEXT_TT_MULTI_LEVEL 0
+#define CONTEXT_TT_DEV_IOTLB 1
+#define CONTEXT_TT_PASS_THRU 2
+
+#define context_set_address_root(c, val) \
+ do {(c).lo &= 0xfff; (c).lo |= (val) & PAGE_MASK_4K ;} while(0)
+#define context_set_address_width(c, val) \
+ do {(c).hi &= 0xfffffff8; (c).hi |= (val) & 7;} while(0)
+#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while(0)
+
+/* page table handling */
+#define LEVEL_STRIDE (9)
+#define LEVEL_MASK ((1 << LEVEL_STRIDE) - 1)
+#define agaw_to_level(val) ((val) + 2)
+#define agaw_to_width(val) (30 + val * LEVEL_STRIDE)
+#define width_to_agaw(w) ((w - 30)/LEVEL_STRIDE)
+#define level_to_offset_bits(l) (12 + (l - 1) * LEVEL_STRIDE)
+#define address_level_offset(addr, level) \
+ ((addr >> level_to_offset_bits(level)) & LEVEL_MASK)
+#define level_mask(l) (((u64)(-1)) << level_to_offset_bits(l))
+#define level_size(l) (1 << level_to_offset_bits(l))
+#define align_to_level(addr, l) ((addr + level_size(l) - 1) & level_mask(l))
+
+/*
+ * 0: readable
+ * 1: writable
+ * 2-6: reserved
+ * 7: super page
+ * 8-11: available
+ * 12-63: Host physcial address
+ */
+struct dma_pte {
+ u64 val;
+};
+#define dma_clear_pte(p) do {(p).val = 0;} while(0)
+#define dma_set_pte_readable(p) do {(p).val |= 1;} while(0)
+#define dma_set_pte_writable(p) do {(p).val |= 2;} while(0)
+#define dma_set_pte_superpage(p) do {(p).val |= 8;} while(0)
+#define dma_set_pte_prot(p, prot) do { (p).val = (((p).val >> 2) << 2) |
((prot) & 3);} while (0)
+#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
+#define dma_set_pte_addr(p, addr) do {(p).val |= ((addr) >> PAGE_SHIFT_4K) <<
PAGE_SHIFT_4K;} while(0)
+#define DMA_PTE_READ (1)
+#define DMA_PTE_WRITE (2)
+#define dma_pte_present(p) (((p).val & 3) != 0)
+
+/* interrupt remap entry */
+struct iremap_entry {
+ union {
+ u64 lo_val;
+ struct {
+ u64 p : 1,
+ fpd : 1,
+ dm : 1,
+ rh : 1,
+ tm : 1,
+ dlm : 3,
+ avail : 4,
+ res_1 : 4,
+ vector : 8,
+ res_2 : 8,
+ dst : 32;
+ }lo;
+ };
+ union {
+ u64 hi_val;
+ struct {
+ u64 sid : 16,
+ sq : 2,
+ svt : 2,
+ res_1 : 44;
+ }hi;
+ };
+};
+#define IREMAP_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct iremap_entry))
+#define iremap_present(v) ((v).lo & 1)
+#define iremap_fault_disable(v) (((v).lo >> 1) & 1)
+
+#define iremap_set_present(v) do {(v).lo |= 1;} while(0)
+#define iremap_clear_present(v) do {(v).lo &= ~1;} while(0)
+
+/* queue invalidation entry */
+struct qinval_entry {
+ union {
+ struct {
+ struct {
+ u64 type : 4,
+ granu : 2,
+ res_1 : 10,
+ did : 16,
+ sid : 16,
+ fm : 2,
+ res_2 : 14;
+ }lo;
+ struct {
+ u64 res;
+ }hi;
+ }cc_inv_dsc;
+ struct {
+ struct {
+ u64 type : 4,
+ granu : 2,
+ dw : 1,
+ dr : 1,
+ res_1 : 8,
+ did : 16,
+ res_2 : 32;
+ }lo;
+ struct {
+ u64 am : 6,
+ ih : 1,
+ res_1 : 5,
+ addr : 52;
+ }hi;
+ }iotlb_inv_dsc;
+ struct {
+ struct {
+ u64 type : 4,
+ res_1 : 12,
+ max_invs_pend: 5,
+ res_2 : 11,
+ sid : 16,
+ res_3 : 16;
+ }lo;
+ struct {
+ u64 size : 1,
+ res_1 : 11,
+ addr : 52;
+ }hi;
+ }dev_iotlb_inv_dsc;
+ struct {
+ struct {
+ u64 type : 4,
+ granu : 1,
+ res_1 : 22,
+ im : 5,
+ iidx : 16,
+ res_2 : 16;
+ }lo;
+ struct {
+ u64 res;
+ }hi;
+ }iec_inv_dsc;
+ struct {
+ struct {
+ u64 type : 4,
+ iflag : 1,
+ sw : 1,
+ fn : 1,
+ res_1 : 25,
+ sdata : 32;
+ }lo;
+ struct {
+ u64 res_1 : 2,
+ saddr : 62;
+ }hi;
+ }inv_wait_dsc;
+ }q;
+};
+
+struct poll_info {
+ u64 saddr;
+ u32 udata;
+};
+
+#define QINVAL_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct qinval_entry))
+#define qinval_present(v) ((v).lo & 1)
+#define qinval_fault_disable(v) (((v).lo >> 1) & 1)
+
+#define qinval_set_present(v) do {(v).lo |= 1;} while(0)
+#define qinval_clear_present(v) do {(v).lo &= ~1;} while(0)
+
+#define RESERVED_VAL 0
+
+#define TYPE_INVAL_CONTEXT 0x1
+#define TYPE_INVAL_IOTLB 0x2
+#define TYPE_INVAL_DEVICE_IOTLB 0x3
+#define TYPE_INVAL_IEC 0x4
+#define TYPE_INVAL_WAIT 0x5
+
+#define NOTIFY_TYPE_POLL 1
+#define NOTIFY_TYPE_INTR 1
+#define INTERRUTP_FLAG 1
+#define STATUS_WRITE 1
+#define FENCE_FLAG 1
+
+#define IEC_GLOBAL_INVL 0
+#define IEC_INDEX_INVL 1
+#define IRTA_REG_EIME_SHIFT 11
+#define IRTA_REG_TABLE_SIZE 7 // 4k page = 256 * 16 byte entries
+ // 2^^(IRTA_REG_TABLE_SIZE + 1) = 256
+ // IRTA_REG_TABLE_SIZE = 7
+
+#define VTD_PAGE_TABLE_LEVEL_3 3
+#define VTD_PAGE_TABLE_LEVEL_4 4
+
+#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
+#define MAX_IOMMU_REGS 0xc0
+
+extern struct list_head acpi_drhd_units;
+extern struct list_head acpi_rmrr_units;
+extern struct list_head acpi_ioapic_units;
+
+struct qi_ctrl {
+ struct qinval_entry *qinval; /* queue invalidation page */
+ int qinval_index; /* queue invalidation index */
+ spinlock_t qinval_lock; /* lock for queue invalidation page */
+ spinlock_t qinval_poll_lock; /* lock for queue invalidation poll addr */
+ volatile u32 qinval_poll_status; /* used by poll methord to sync */
+};
+
+struct ir_ctrl {
+ struct iremap_entry *iremap; /* interrupt remap table */
+ int iremap_index; /* interrupt remap index */
+ spinlock_t iremap_lock; /* lock for irq remappping table */
+};
+
+struct iommu_flush {
+ int (*context)(void *iommu, u16 did, u16 source_id,
+ u8 function_mask, u64 type, int non_present_entry_flush);
+ int (*iotlb)(void *iommu, u16 did, u64 addr, unsigned int size_order,
+ u64 type, int non_present_entry_flush);
+};
+
+struct intel_iommu {
+ struct qi_ctrl qi_ctrl;
+ struct ir_ctrl ir_ctrl;
+ struct iommu_flush flush;
+};
+
+#endif
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/qinval.c
--- a/xen/drivers/passthrough/vtd/qinval.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/qinval.c Mon Mar 17 10:45:24 2008 +0000
@@ -19,15 +19,9 @@
*/
-#include <xen/init.h>
-#include <xen/irq.h>
-#include <xen/spinlock.h>
#include <xen/sched.h>
-#include <xen/xmalloc.h>
-#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
+#include "iommu.h"
#include "dmar.h"
#include "vtd.h"
#include "../pci-direct.h"
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/utils.c
--- a/xen/drivers/passthrough/vtd/utils.c Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/utils.c Mon Mar 17 10:45:24 2008 +0000
@@ -17,21 +17,14 @@
* Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
*/
-#include <xen/init.h>
-#include <xen/bitmap.h>
-#include <xen/irq.h>
-#include <xen/spinlock.h>
#include <xen/sched.h>
#include <xen/delay.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
+#include "iommu.h"
#include "dmar.h"
#include "../pci-direct.h"
#include "../pci_regs.h"
#include "msi.h"
-
-#include <xen/mm.h>
-#include <xen/xmalloc.h>
-#include <xen/inttypes.h>
#define INTEL 0x8086
#define SEABURG 0x4000
diff -r af33f2054f47 -r bf8a3fc79093 xen/drivers/passthrough/vtd/vtd.h
--- a/xen/drivers/passthrough/vtd/vtd.h Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/drivers/passthrough/vtd/vtd.h Mon Mar 17 10:45:24 2008 +0000
@@ -21,16 +21,7 @@
#ifndef _VTD_H_
#define _VTD_H_
-#include <xen/list.h>
-#include <asm/iommu.h>
-
-#define VTDPREFIX "[VT-D]"
-
-#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
-#define time_after(a,b) \
- (typecheck(unsigned long, a) && \
- typecheck(unsigned long, b) && \
- ((long)(b) - (long)(a) < 0))
+#include <xen/iommu.h>
struct IO_APIC_route_remap_entry {
union {
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/asm-x86/fixmap.h
--- a/xen/include/asm-x86/fixmap.h Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/include/asm-x86/fixmap.h Mon Mar 17 10:45:24 2008 +0000
@@ -17,7 +17,7 @@
#include <asm/acpi.h>
#include <asm/page.h>
#include <xen/kexec.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
#include <asm/amd-iommu.h>
/*
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/asm-x86/hvm/domain.h
--- a/xen/include/asm-x86/hvm/domain.h Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/include/asm-x86/hvm/domain.h Mon Mar 17 10:45:24 2008 +0000
@@ -21,13 +21,13 @@
#ifndef __ASM_X86_HVM_DOMAIN_H__
#define __ASM_X86_HVM_DOMAIN_H__
-#include <asm/iommu.h>
+#include <xen/iommu.h>
#include <asm/hvm/irq.h>
#include <asm/hvm/vpt.h>
#include <asm/hvm/vlapic.h>
#include <asm/hvm/vioapic.h>
#include <asm/hvm/io.h>
-#include <asm/hvm/iommu.h>
+#include <xen/hvm/iommu.h>
#include <public/hvm/params.h>
#include <public/hvm/save.h>
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/asm-x86/hvm/iommu.h
--- a/xen/include/asm-x86/hvm/iommu.h Sun Mar 16 14:11:34 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- */
-
-#ifndef __ASM_X86_HVM_IOMMU_H__
-#define __ASM_X86_HVM_IOMMU_H__
-
-#include <asm/iommu.h>
-#include <asm/hvm/irq.h>
-#include <asm/hvm/vpt.h>
-#include <asm/hvm/vlapic.h>
-#include <asm/hvm/io.h>
-#include <public/hvm/params.h>
-#include <public/hvm/save.h>
-
-struct g2m_ioport {
- struct list_head list;
- unsigned int gport;
- unsigned int mport;
- unsigned int np;
-};
-
-struct hvm_iommu {
- spinlock_t iommu_list_lock; /* protect iommu specific lists */
- struct list_head pdev_list; /* direct accessed pci devices */
- struct dma_pte *pgd; /* io page directory root */
- spinlock_t mapping_lock; /* io page table lock */
- int agaw; /* adjusted guest address width, 0 is level 2 30-bit */
- struct list_head g2m_ioport_list; /* guest to machine ioport mapping */
- domid_t iommu_domid; /* domain id stored in iommu */
-
- /* amd iommu support */
- int domain_id;
- int paging_mode;
- void *root_table;
-
- /* iommu_ops */
- struct iommu_ops *platform_ops;
-};
-
-#endif // __ASM_X86_HVM_IOMMU_H__
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/asm-x86/hvm/vmx/intel-iommu.h
--- a/xen/include/asm-x86/hvm/vmx/intel-iommu.h Sun Mar 16 14:11:34 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,460 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Ashok Raj <ashok.raj@xxxxxxxxx>
- */
-
-#ifndef _INTEL_IOMMU_H_
-#define _INTEL_IOMMU_H_
-
-#include <xen/types.h>
-
-/*
- * Intel IOMMU register specification per version 1.0 public spec.
- */
-
-#define DMAR_VER_REG 0x0 /* Arch version supported by this IOMMU */
-#define DMAR_CAP_REG 0x8 /* Hardware supported capabilities */
-#define DMAR_ECAP_REG 0x10 /* Extended capabilities supported */
-#define DMAR_GCMD_REG 0x18 /* Global command register */
-#define DMAR_GSTS_REG 0x1c /* Global status register */
-#define DMAR_RTADDR_REG 0x20 /* Root entry table */
-#define DMAR_CCMD_REG 0x28 /* Context command reg */
-#define DMAR_FSTS_REG 0x34 /* Fault Status register */
-#define DMAR_FECTL_REG 0x38 /* Fault control register */
-#define DMAR_FEDATA_REG 0x3c /* Fault event interrupt data register */
-#define DMAR_FEADDR_REG 0x40 /* Fault event interrupt addr register */
-#define DMAR_FEUADDR_REG 0x44 /* Upper address register */
-#define DMAR_AFLOG_REG 0x58 /* Advanced Fault control */
-#define DMAR_PMEN_REG 0x64 /* Enable Protected Memory Region */
-#define DMAR_PLMBASE_REG 0x68 /* PMRR Low addr */
-#define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */
-#define DMAR_PHMBASE_REG 0x70 /* pmrr high base addr */
-#define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */
-#define DMAR_IQH_REG 0x80 /* invalidation queue head */
-#define DMAR_IQT_REG 0x88 /* invalidation queue tail */
-#define DMAR_IQA_REG 0x90 /* invalidation queue addr */
-#define DMAR_IRTA_REG 0xB8 /* intr remap */
-
-#define OFFSET_STRIDE (9)
-#define dmar_readl(dmar, reg) readl(dmar + reg)
-#define dmar_writel(dmar, reg, val) writel(val, dmar + reg)
-#define dmar_readq(dmar, reg) ({ \
- u32 lo, hi; \
- lo = dmar_readl(dmar, reg); \
- hi = dmar_readl(dmar, reg + 4); \
- (((u64) hi) << 32) + lo; })
-#define dmar_writeq(dmar, reg, val) do {\
- dmar_writel(dmar, reg, (u32)val); \
- dmar_writel(dmar, reg + 4, (u32)((u64) val >> 32)); \
- } while (0)
-
-#define VER_MAJOR(v) (((v) & 0xf0) >> 4)
-#define VER_MINOR(v) ((v) & 0x0f)
-
-/*
- * Decoding Capability Register
- */
-#define cap_read_drain(c) (((c) >> 55) & 1)
-#define cap_write_drain(c) (((c) >> 54) & 1)
-#define cap_max_amask_val(c) (((c) >> 48) & 0x3f)
-#define cap_num_fault_regs(c) ((((c) >> 40) & 0xff) + 1)
-#define cap_pgsel_inv(c) (((c) >> 39) & 1)
-
-#define cap_super_page_val(c) (((c) >> 34) & 0xf)
-#define cap_super_offset(c) (((find_first_bit(&cap_super_page_val(c), 4)) \
- * OFFSET_STRIDE) + 21)
-
-#define cap_fault_reg_offset(c) ((((c) >> 24) & 0x3ff) * 16)
-
-#define cap_isoch(c) (((c) >> 23) & 1)
-#define cap_qos(c) (((c) >> 22) & 1)
-#define cap_mgaw(c) ((((c) >> 16) & 0x3f) + 1)
-#define cap_sagaw(c) (((c) >> 8) & 0x1f)
-#define cap_caching_mode(c) (((c) >> 7) & 1)
-#define cap_phmr(c) (((c) >> 6) & 1)
-#define cap_plmr(c) (((c) >> 5) & 1)
-#define cap_rwbf(c) (((c) >> 4) & 1)
-#define cap_afl(c) (((c) >> 3) & 1)
-#define cap_ndoms(c) (1 << (4 + 2 * ((c) & 0x7)))
-
-/*
- * Extended Capability Register
- */
-
-#define ecap_niotlb_iunits(e) ((((e) >> 24) & 0xff) + 1)
-#define ecap_iotlb_offset(e) ((((e) >> 8) & 0x3ff) * 16)
-#define ecap_coherent(e) ((e >> 0) & 0x1)
-#define ecap_queued_inval(e) ((e >> 1) & 0x1)
-#define ecap_dev_iotlb(e) ((e >> 2) & 0x1)
-#define ecap_intr_remap(e) ((e >> 3) & 0x1)
-#define ecap_ext_intr(e) ((e >> 4) & 0x1)
-#define ecap_cache_hints(e) ((e >> 5) & 0x1)
-#define ecap_pass_thru(e) ((e >> 6) & 0x1)
-
-#define PAGE_SHIFT_4K (12)
-#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
-/* IOTLB_REG */
-#define DMA_TLB_FLUSH_GRANU_OFFSET 60
-#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
-#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
-#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
-#define DMA_TLB_IIRG(x) (((x) >> 60) & 7)
-#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
-#define DMA_TLB_DID(x) (((u64)(x & 0xffff)) << 32)
-
-#define DMA_TLB_READ_DRAIN (((u64)1) << 49)
-#define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
-#define DMA_TLB_IVT (((u64)1) << 63)
-
-#define DMA_TLB_IVA_ADDR(x) ((((u64)x) >> 12) << 12)
-#define DMA_TLB_IVA_HINT(x) ((((u64)x) & 1) << 6)
-
-/* GCMD_REG */
-#define DMA_GCMD_TE (((u64)1) << 31)
-#define DMA_GCMD_SRTP (((u64)1) << 30)
-#define DMA_GCMD_SFL (((u64)1) << 29)
-#define DMA_GCMD_EAFL (((u64)1) << 28)
-#define DMA_GCMD_WBF (((u64)1) << 27)
-#define DMA_GCMD_QIE (((u64)1) << 26)
-#define DMA_GCMD_IRE (((u64)1) << 25)
-#define DMA_GCMD_SIRTP (((u64)1) << 24)
-#define DMA_GCMD_CFI (((u64)1) << 23)
-
-/* GSTS_REG */
-#define DMA_GSTS_TES (((u64)1) << 31)
-#define DMA_GSTS_RTPS (((u64)1) << 30)
-#define DMA_GSTS_FLS (((u64)1) << 29)
-#define DMA_GSTS_AFLS (((u64)1) << 28)
-#define DMA_GSTS_WBFS (((u64)1) << 27)
-#define DMA_GSTS_QIES (((u64)1) <<26)
-#define DMA_GSTS_IRES (((u64)1) <<25)
-#define DMA_GSTS_SIRTPS (((u64)1) << 24)
-#define DMA_GSTS_CFIS (((u64)1) <<23)
-
-/* PMEN_REG */
-#define DMA_PMEN_EPM (((u32)1) << 31)
-#define DMA_PMEN_PRS (((u32)1) << 0)
-
-/* CCMD_REG */
-#define DMA_CCMD_INVL_GRANU_OFFSET 61
-#define DMA_CCMD_ICC (((u64)1) << 63)
-#define DMA_CCMD_GLOBAL_INVL (((u64)1) << 61)
-#define DMA_CCMD_DOMAIN_INVL (((u64)2) << 61)
-#define DMA_CCMD_DEVICE_INVL (((u64)3) << 61)
-#define DMA_CCMD_FM(m) (((u64)((m) & 0x3)) << 32)
-#define DMA_CCMD_CIRG(x) ((((u64)3) << 61) & x)
-#define DMA_CCMD_MASK_NOBIT 0
-#define DMA_CCMD_MASK_1BIT 1
-#define DMA_CCMD_MASK_2BIT 2
-#define DMA_CCMD_MASK_3BIT 3
-#define DMA_CCMD_SID(s) (((u64)((s) & 0xffff)) << 16)
-#define DMA_CCMD_DID(d) ((u64)((d) & 0xffff))
-
-#define DMA_CCMD_CAIG_MASK(x) (((u64)x) & ((u64) 0x3 << 59))
-
-/* FECTL_REG */
-#define DMA_FECTL_IM (((u64)1) << 31)
-
-/* FSTS_REG */
-#define DMA_FSTS_PFO ((u64)1 << 0)
-#define DMA_FSTS_PPF ((u64)1 << 1)
-#define DMA_FSTS_AFO ((u64)1 << 2)
-#define DMA_FSTS_APF ((u64)1 << 3)
-#define DMA_FSTS_IQE ((u64)1 << 4)
-#define DMA_FSTS_ICE ((u64)1 << 5)
-#define DMA_FSTS_ITE ((u64)1 << 6)
-#define DMA_FSTS_FAULTS DMA_FSTS_PFO | DMA_FSTS_PPF | DMA_FSTS_AFO |
DMA_FSTS_APF | DMA_FSTS_IQE | DMA_FSTS_ICE | DMA_FSTS_ITE
-#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
-
-/* FRCD_REG, 32 bits access */
-#define DMA_FRCD_F (((u64)1) << 31)
-#define dma_frcd_type(d) ((d >> 30) & 1)
-#define dma_frcd_fault_reason(c) (c & 0xff)
-#define dma_frcd_source_id(c) (c & 0xffff)
-#define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
-
-/*
- * 0: Present
- * 1-11: Reserved
- * 12-63: Context Ptr (12 - (haw-1))
- * 64-127: Reserved
- */
-struct root_entry {
- u64 val;
- u64 rsvd1;
-};
-#define root_present(root) ((root).val & 1)
-#define set_root_present(root) do {(root).val |= 1;} while(0)
-#define get_context_addr(root) ((root).val & PAGE_MASK_4K)
-#define set_root_value(root, value) \
- do {(root).val |= ((value) & PAGE_MASK_4K);} while(0)
-
-struct context_entry {
- u64 lo;
- u64 hi;
-};
-#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
-#define context_present(c) ((c).lo & 1)
-#define context_fault_disable(c) (((c).lo >> 1) & 1)
-#define context_translation_type(c) (((c).lo >> 2) & 3)
-#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
-#define context_address_width(c) ((c).hi & 7)
-#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
-
-#define context_set_present(c) do {(c).lo |= 1;} while(0)
-#define context_clear_present(c) do {(c).lo &= ~1;} while(0)
-#define context_set_fault_enable(c) \
- do {(c).lo &= (((u64)-1) << 2) | 1;} while(0)
-
-#define context_set_translation_type(c, val) do { \
- (c).lo &= (((u64)-1) << 4) | 3; \
- (c).lo |= (val & 3) << 2; \
- } while(0)
-#define CONTEXT_TT_MULTI_LEVEL 0
-#define CONTEXT_TT_DEV_IOTLB 1
-#define CONTEXT_TT_PASS_THRU 2
-
-#define context_set_address_root(c, val) \
- do {(c).lo &= 0xfff; (c).lo |= (val) & PAGE_MASK_4K ;} while(0)
-#define context_set_address_width(c, val) \
- do {(c).hi &= 0xfffffff8; (c).hi |= (val) & 7;} while(0)
-#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while(0)
-
-/* page table handling */
-#define LEVEL_STRIDE (9)
-#define LEVEL_MASK ((1 << LEVEL_STRIDE) - 1)
-#define agaw_to_level(val) ((val) + 2)
-#define agaw_to_width(val) (30 + val * LEVEL_STRIDE)
-#define width_to_agaw(w) ((w - 30)/LEVEL_STRIDE)
-#define level_to_offset_bits(l) (12 + (l - 1) * LEVEL_STRIDE)
-#define address_level_offset(addr, level) \
- ((addr >> level_to_offset_bits(level)) & LEVEL_MASK)
-#define level_mask(l) (((u64)(-1)) << level_to_offset_bits(l))
-#define level_size(l) (1 << level_to_offset_bits(l))
-#define align_to_level(addr, l) ((addr + level_size(l) - 1) & level_mask(l))
-
-/*
- * 0: readable
- * 1: writable
- * 2-6: reserved
- * 7: super page
- * 8-11: available
- * 12-63: Host physcial address
- */
-struct dma_pte {
- u64 val;
-};
-#define dma_clear_pte(p) do {(p).val = 0;} while(0)
-#define dma_set_pte_readable(p) do {(p).val |= 1;} while(0)
-#define dma_set_pte_writable(p) do {(p).val |= 2;} while(0)
-#define dma_set_pte_superpage(p) do {(p).val |= 8;} while(0)
-#define dma_set_pte_prot(p, prot) do { (p).val = (((p).val >> 2) << 2) |
((prot) & 3);} while (0)
-#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
-#define dma_set_pte_addr(p, addr) do {(p).val |= ((addr) >> PAGE_SHIFT_4K) <<
PAGE_SHIFT_4K;} while(0)
-#define DMA_PTE_READ (1)
-#define DMA_PTE_WRITE (2)
-#define dma_pte_present(p) (((p).val & 3) != 0)
-
-/* interrupt remap entry */
-struct iremap_entry {
- union {
- u64 lo_val;
- struct {
- u64 p : 1,
- fpd : 1,
- dm : 1,
- rh : 1,
- tm : 1,
- dlm : 3,
- avail : 4,
- res_1 : 4,
- vector : 8,
- res_2 : 8,
- dst : 32;
- }lo;
- };
- union {
- u64 hi_val;
- struct {
- u64 sid : 16,
- sq : 2,
- svt : 2,
- res_1 : 44;
- }hi;
- };
-};
-#define IREMAP_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct iremap_entry))
-#define iremap_present(v) ((v).lo & 1)
-#define iremap_fault_disable(v) (((v).lo >> 1) & 1)
-
-#define iremap_set_present(v) do {(v).lo |= 1;} while(0)
-#define iremap_clear_present(v) do {(v).lo &= ~1;} while(0)
-
-/* queue invalidation entry */
-struct qinval_entry {
- union {
- struct {
- struct {
- u64 type : 4,
- granu : 2,
- res_1 : 10,
- did : 16,
- sid : 16,
- fm : 2,
- res_2 : 14;
- }lo;
- struct {
- u64 res;
- }hi;
- }cc_inv_dsc;
- struct {
- struct {
- u64 type : 4,
- granu : 2,
- dw : 1,
- dr : 1,
- res_1 : 8,
- did : 16,
- res_2 : 32;
- }lo;
- struct {
- u64 am : 6,
- ih : 1,
- res_1 : 5,
- addr : 52;
- }hi;
- }iotlb_inv_dsc;
- struct {
- struct {
- u64 type : 4,
- res_1 : 12,
- max_invs_pend: 5,
- res_2 : 11,
- sid : 16,
- res_3 : 16;
- }lo;
- struct {
- u64 size : 1,
- res_1 : 11,
- addr : 52;
- }hi;
- }dev_iotlb_inv_dsc;
- struct {
- struct {
- u64 type : 4,
- granu : 1,
- res_1 : 22,
- im : 5,
- iidx : 16,
- res_2 : 16;
- }lo;
- struct {
- u64 res;
- }hi;
- }iec_inv_dsc;
- struct {
- struct {
- u64 type : 4,
- iflag : 1,
- sw : 1,
- fn : 1,
- res_1 : 25,
- sdata : 32;
- }lo;
- struct {
- u64 res_1 : 2,
- saddr : 62;
- }hi;
- }inv_wait_dsc;
- }q;
-};
-
-struct poll_info {
- u64 saddr;
- u32 udata;
-};
-
-#define QINVAL_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct qinval_entry))
-#define qinval_present(v) ((v).lo & 1)
-#define qinval_fault_disable(v) (((v).lo >> 1) & 1)
-
-#define qinval_set_present(v) do {(v).lo |= 1;} while(0)
-#define qinval_clear_present(v) do {(v).lo &= ~1;} while(0)
-
-#define RESERVED_VAL 0
-
-#define TYPE_INVAL_CONTEXT 0x1
-#define TYPE_INVAL_IOTLB 0x2
-#define TYPE_INVAL_DEVICE_IOTLB 0x3
-#define TYPE_INVAL_IEC 0x4
-#define TYPE_INVAL_WAIT 0x5
-
-#define NOTIFY_TYPE_POLL 1
-#define NOTIFY_TYPE_INTR 1
-#define INTERRUTP_FLAG 1
-#define STATUS_WRITE 1
-#define FENCE_FLAG 1
-
-#define IEC_GLOBAL_INVL 0
-#define IEC_INDEX_INVL 1
-#define IRTA_REG_EIME_SHIFT 11
-#define IRTA_REG_TABLE_SIZE 7 // 4k page = 256 * 16 byte entries
- // 2^^(IRTA_REG_TABLE_SIZE + 1) = 256
- // IRTA_REG_TABLE_SIZE = 7
-
-#define VTD_PAGE_TABLE_LEVEL_3 3
-#define VTD_PAGE_TABLE_LEVEL_4 4
-
-#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
-#define MAX_IOMMUS 32
-#define MAX_IOMMU_REGS 0xc0
-
-extern struct list_head acpi_drhd_units;
-extern struct list_head acpi_rmrr_units;
-extern struct list_head acpi_ioapic_units;
-
-struct qi_ctrl {
- struct qinval_entry *qinval; /* queue invalidation page */
- int qinval_index; /* queue invalidation index */
- spinlock_t qinval_lock; /* lock for queue invalidation page */
- spinlock_t qinval_poll_lock; /* lock for queue invalidation poll addr */
- volatile u32 qinval_poll_status; /* used by poll methord to sync */
-};
-
-struct ir_ctrl {
- struct iremap_entry *iremap; /* interrupt remap table */
- int iremap_index; /* interrupt remap index */
- spinlock_t iremap_lock; /* lock for irq remappping table */
-};
-
-struct iommu_flush {
- int (*context)(void *iommu, u16 did, u16 source_id,
- u8 function_mask, u64 type, int non_present_entry_flush);
- int (*iotlb)(void *iommu, u16 did, u64 addr, unsigned int size_order,
- u64 type, int non_present_entry_flush);
-};
-
-struct intel_iommu {
- struct qi_ctrl qi_ctrl;
- struct ir_ctrl ir_ctrl;
- struct iommu_flush flush;
-};
-
-#endif
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/asm-x86/io_apic.h
--- a/xen/include/asm-x86/io_apic.h Sun Mar 16 14:11:34 2008 +0000
+++ b/xen/include/asm-x86/io_apic.h Mon Mar 17 10:45:24 2008 +0000
@@ -6,7 +6,7 @@
#include <asm/mpspec.h>
#include <asm/apicdef.h>
#include <asm/fixmap.h>
-#include <asm/iommu.h>
+#include <xen/iommu.h>
/*
* Intel IO-APIC support for SMP and UP systems.
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/asm-x86/iommu.h
--- a/xen/include/asm-x86/iommu.h Sun Mar 16 14:11:34 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- */
-
-#ifndef _IOMMU_H_
-#define _IOMMU_H_
-
-#include <xen/init.h>
-#include <xen/list.h>
-#include <xen/spinlock.h>
-#include <asm/hvm/vmx/intel-iommu.h>
-#include <public/hvm/ioreq.h>
-#include <public/domctl.h>
-
-extern int vtd_enabled;
-extern int amd_iommu_enabled;
-
-#define iommu_enabled ( amd_iommu_enabled || vtd_enabled )
-#define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu)
-#define domain_vmx_iommu(d) (&d->arch.hvm_domain.hvm_iommu.vmx_iommu)
-#define iommu_qi_ctrl(iommu) (&(iommu->intel.qi_ctrl));
-#define iommu_ir_ctrl(iommu) (&(iommu->intel.ir_ctrl));
-#define iommu_get_flush(iommu) (&(iommu->intel.flush));
-
-/*
- * The PCI interface treats multi-function devices as independent
- * devices. The slot/function address of each device is encoded
- * in a single byte as follows:
- *
- * 15:8 = bus
- * 7:3 = slot
- * 2:0 = function
- */
-#define PCI_DEVFN(slot,func) (((slot & 0x1f) << 3) | (func & 0x07))
-#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
-#define PCI_FUNC(devfn) ((devfn) & 0x07)
-
-struct pci_dev {
- struct list_head list;
- u8 bus;
- u8 devfn;
-};
-
-struct iommu {
- struct list_head list;
- void __iomem *reg; /* Pointer to hardware regs, virtual addr */
- u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
- u64 cap;
- u64 ecap;
- spinlock_t lock; /* protect context, domain ids */
- spinlock_t register_lock; /* protect iommu register handling */
- struct root_entry *root_entry; /* virtual address */
- unsigned int vector;
- struct intel_iommu intel;
-};
-
-int iommu_setup(void);
-int iommu_domain_init(struct domain *d);
-void iommu_domain_destroy(struct domain *d);
-int device_assigned(u8 bus, u8 devfn);
-int assign_device(struct domain *d, u8 bus, u8 devfn);
-void deassign_device(struct domain *d, u8 bus, u8 devfn);
-void reassign_device_ownership(struct domain *source,
- struct domain *target,
- u8 bus, u8 devfn);
-int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
-int iommu_unmap_page(struct domain *d, unsigned long gfn);
-void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry);
-void iommu_set_pgd(struct domain *d);
-void iommu_domain_teardown(struct domain *d);
-int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);
-int dpci_ioport_intercept(ioreq_t *p);
-int pt_irq_create_bind_vtd(struct domain *d,
- xen_domctl_bind_pt_irq_t *pt_irq_bind);
-int pt_irq_destroy_bind_vtd(struct domain *d,
- xen_domctl_bind_pt_irq_t *pt_irq_bind);
-unsigned int io_apic_read_remap_rte(
- unsigned int apic, unsigned int reg);
-void io_apic_write_remap_rte(unsigned int apic,
- unsigned int reg, unsigned int value);
-
-#define PT_IRQ_TIME_OUT MILLISECS(8)
-#define VTDPREFIX "[VT-D]"
-
-struct iommu_ops {
- int (*init)(struct domain *d);
- int (*assign_device)(struct domain *d, u8 bus, u8 devfn);
- void (*teardown)(struct domain *d);
- int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn);
- int (*unmap_page)(struct domain *d, unsigned long gfn);
- void (*reassign_device)(struct domain *s, struct domain *t, u8 bus, u8
devfn);
-};
-
-#endif /* _IOMMU_H_ */
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/xen/hvm/iommu.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/xen/hvm/iommu.h Mon Mar 17 10:45:24 2008 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
+ */
+
+#ifndef __ASM_X86_HVM_IOMMU_H__
+#define __ASM_X86_HVM_IOMMU_H__
+
+#include <xen/iommu.h>
+#include <asm/hvm/irq.h>
+#include <asm/hvm/vpt.h>
+#include <asm/hvm/vlapic.h>
+#include <asm/hvm/io.h>
+#include <public/hvm/params.h>
+#include <public/hvm/save.h>
+
+struct g2m_ioport {
+ struct list_head list;
+ unsigned int gport;
+ unsigned int mport;
+ unsigned int np;
+};
+
+struct hvm_iommu {
+ spinlock_t iommu_list_lock; /* protect iommu specific lists */
+ struct list_head pdev_list; /* direct accessed pci devices */
+ struct dma_pte *pgd; /* io page directory root */
+ spinlock_t mapping_lock; /* io page table lock */
+ int agaw; /* adjusted guest address width, 0 is level 2 30-bit */
+ struct list_head g2m_ioport_list; /* guest to machine ioport mapping */
+ domid_t iommu_domid; /* domain id stored in iommu */
+
+ /* amd iommu support */
+ int domain_id;
+ int paging_mode;
+ void *root_table;
+
+ /* iommu_ops */
+ struct iommu_ops *platform_ops;
+};
+
+#endif // __ASM_X86_HVM_IOMMU_H__
diff -r af33f2054f47 -r bf8a3fc79093 xen/include/xen/iommu.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/xen/iommu.h Mon Mar 17 10:45:24 2008 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
+ */
+
+#ifndef _IOMMU_H_
+#define _IOMMU_H_
+
+#include <xen/init.h>
+#include <xen/list.h>
+#include <xen/spinlock.h>
+#include <public/hvm/ioreq.h>
+#include <public/domctl.h>
+
+extern int vtd_enabled;
+extern int amd_iommu_enabled;
+
+#define iommu_enabled ( amd_iommu_enabled || vtd_enabled )
+#define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu)
+#define domain_vmx_iommu(d) (&d->arch.hvm_domain.hvm_iommu.vmx_iommu)
+
+#define MAX_IOMMUS 32
+
+#define PAGE_SHIFT_4K (12)
+#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices. The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ * 15:8 = bus
+ * 7:3 = slot
+ * 2:0 = function
+ */
+#define PCI_DEVFN(slot,func) (((slot & 0x1f) << 3) | (func & 0x07))
+#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+
+struct pci_dev {
+ struct list_head list;
+ u8 bus;
+ u8 devfn;
+};
+
+struct iommu {
+ struct list_head list;
+ void __iomem *reg; /* Pointer to hardware regs, virtual addr */
+ u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
+ u64 cap;
+ u64 ecap;
+ spinlock_t lock; /* protect context, domain ids */
+ spinlock_t register_lock; /* protect iommu register handling */
+ struct root_entry *root_entry; /* virtual address */
+ unsigned int vector;
+ struct intel_iommu *intel;
+};
+
+int iommu_setup(void);
+int iommu_domain_init(struct domain *d);
+void iommu_domain_destroy(struct domain *d);
+int device_assigned(u8 bus, u8 devfn);
+int assign_device(struct domain *d, u8 bus, u8 devfn);
+void deassign_device(struct domain *d, u8 bus, u8 devfn);
+void reassign_device_ownership(struct domain *source,
+ struct domain *target,
+ u8 bus, u8 devfn);
+int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
+int iommu_unmap_page(struct domain *d, unsigned long gfn);
+void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry);
+void iommu_set_pgd(struct domain *d);
+void iommu_domain_teardown(struct domain *d);
+int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);
+int dpci_ioport_intercept(ioreq_t *p);
+int pt_irq_create_bind_vtd(struct domain *d,
+ xen_domctl_bind_pt_irq_t *pt_irq_bind);
+int pt_irq_destroy_bind_vtd(struct domain *d,
+ xen_domctl_bind_pt_irq_t *pt_irq_bind);
+unsigned int io_apic_read_remap_rte(unsigned int apic, unsigned int reg);
+void io_apic_write_remap_rte(unsigned int apic,
+ unsigned int reg, unsigned int value);
+struct qi_ctrl *iommu_qi_ctrl(struct iommu *iommu);
+struct ir_ctrl *iommu_ir_ctrl(struct iommu *iommu);
+struct iommu_flush *iommu_get_flush(struct iommu *iommu);
+
+#define PT_IRQ_TIME_OUT MILLISECS(8)
+#define VTDPREFIX "[VT-D]"
+
+struct iommu_ops {
+ int (*init)(struct domain *d);
+ int (*assign_device)(struct domain *d, u8 bus, u8 devfn);
+ void (*teardown)(struct domain *d);
+ int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn);
+ int (*unmap_page)(struct domain *d, unsigned long gfn);
+ void (*reassign_device)(struct domain *s, struct domain *t,
+ u8 bus, u8 devfn);
+};
+
+#endif /* _IOMMU_H_ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|