[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Move iommu code to arch-generic locations, and also clean up some VT-d code.
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |