[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Add AMD IOMMU support into hypervisor



# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1190391347 -3600
# Node ID 844e507d56b82d28f5ea5de32c1bf6a2b3181501
# Parent  a956ef58b0129f6f4e9cb4b54c15985b79fdb55d
Add AMD IOMMU support into hypervisor
Signed-off-by: Wei Wang <wei.wang2@xxxxxxx>
---
 xen/arch/x86/hvm/svm/Makefile                     |    2 
 xen/arch/x86/hvm/svm/amd_iommu/Makefile           |    4 
 xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c |  211 +++++++++
 xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c   |  145 ++++++
 xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c    |  419 +++++++++++++++++
 xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c    |  389 ++++++++++++++++
 xen/arch/x86/hvm/svm/amd_iommu/pci-direct.h       |   48 ++
 xen/arch/x86/hvm/svm/amd_iommu/pci_regs.h         |  513 ++++++++++++++++++++++
 xen/arch/x86/setup.c                              |    2 
 xen/include/asm-x86/amd-iommu.h                   |   70 +++
 xen/include/asm-x86/fixmap.h                      |    3 
 xen/include/asm-x86/hvm/iommu.h                   |    5 
 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h      |  419 +++++++++++++++++
 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h     |   88 +++
 14 files changed, 2318 insertions(+)

diff -r a956ef58b012 -r 844e507d56b8 xen/arch/x86/hvm/svm/Makefile
--- a/xen/arch/x86/hvm/svm/Makefile     Fri Sep 21 17:10:00 2007 +0100
+++ b/xen/arch/x86/hvm/svm/Makefile     Fri Sep 21 17:15:47 2007 +0100
@@ -1,5 +1,7 @@ subdir-$(x86_32) += x86_32
 subdir-$(x86_32) += x86_32
 subdir-$(x86_64) += x86_64
+
+subdir-y += amd_iommu
 
 obj-y += asid.o
 obj-y += emulate.o
diff -r a956ef58b012 -r 844e507d56b8 xen/arch/x86/hvm/svm/amd_iommu/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/Makefile   Fri Sep 21 17:15:47 2007 +0100
@@ -0,0 +1,4 @@
+obj-y += amd-iommu-detect.o
+obj-y += amd-iommu-init.o
+obj-y += amd-iommu-map.o
+obj-y += pci-amd-iommu.o
diff -r a956ef58b012 -r 844e507d56b8 
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <asm/iommu.h>
+#include <asm/amd-iommu.h>
+#include <asm/hvm/svm/amd-iommu-proto.h>
+#include "pci-direct.h"
+#include "pci_regs.h"
+
+static int __init valid_bridge_bus_config(int bus, int dev, int func,
+            int *sec_bus, int *sub_bus)
+{
+    int pri_bus;
+
+    pri_bus = read_pci_config_byte(bus, dev, func, PCI_PRIMARY_BUS);
+    *sec_bus = read_pci_config_byte(bus, dev, func, PCI_SECONDARY_BUS);
+    *sub_bus = read_pci_config_byte(bus, dev, func, PCI_SUBORDINATE_BUS);
+
+    return ( pri_bus == bus && *sec_bus > bus && *sub_bus >= *sec_bus );
+}
+
+int __init get_iommu_last_downstream_bus(struct amd_iommu *iommu)
+{
+    int bus, dev, func;
+    int devfn, hdr_type;
+    int sec_bus, sub_bus;
+    int multi_func;
+
+    bus = iommu->last_downstream_bus = iommu->root_bus;
+    iommu->downstream_bus_present[bus] = 1;
+    dev = PCI_SLOT(iommu->first_devfn);
+    multi_func = PCI_FUNC(iommu->first_devfn) > 0;
+    for ( devfn = iommu->first_devfn; devfn <= iommu->last_devfn; ++devfn ) {
+        /* skipping to next device#? */
+        if ( dev != PCI_SLOT(devfn) ) {
+            dev = PCI_SLOT(devfn);
+            multi_func = 0;
+        }
+        func = PCI_FUNC(devfn);
+ 
+        if ( !VALID_PCI_VENDOR_ID(
+            read_pci_config_16(bus, dev, func, PCI_VENDOR_ID)) )
+            continue;
+
+        hdr_type = read_pci_config_byte(bus, dev, func,
+                PCI_HEADER_TYPE);
+        if ( func == 0 )
+            multi_func = IS_PCI_MULTI_FUNCTION(hdr_type);
+
+        if ( (func == 0 || multi_func) &&
+            IS_PCI_TYPE1_HEADER(hdr_type) ) {
+            if (!valid_bridge_bus_config(bus, dev, func,
+                &sec_bus, &sub_bus))
+                return -ENODEV;
+
+            if ( sub_bus > iommu->last_downstream_bus )
+                iommu->last_downstream_bus = sub_bus;
+            do {
+                iommu->downstream_bus_present[sec_bus] = 1;
+            } while ( sec_bus++ < sub_bus );
+        }
+    }
+
+    return 0;
+}
+
+int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
+            struct amd_iommu *iommu)
+{
+    u32 cap_header, cap_range;
+    u64 mmio_bar;
+
+    /* remove it when BIOS available */
+    write_pci_config(bus, dev, func,
+        cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET, 0x00000000);
+    write_pci_config(bus, dev, func,
+        cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET, 0x40000001);
+    /* remove it when BIOS available */
+
+    mmio_bar = (u64)read_pci_config(bus, dev, func,
+             cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32;
+    mmio_bar |= read_pci_config(bus, dev, func,
+            cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET) &
+            PCI_CAP_MMIO_BAR_LOW_MASK;
+    iommu->mmio_base_phys = (unsigned long)mmio_bar;
+
+    if ( (mmio_bar == 0) || ( (mmio_bar & 0x3FFF) != 0 ) ) {
+        dprintk(XENLOG_ERR ,
+            "AMD IOMMU: Invalid MMIO_BAR = 0x%lx\n", mmio_bar);
+        return -ENODEV;
+    }
+
+    cap_header = read_pci_config(bus, dev, func, cap_ptr);
+    iommu->revision = get_field_from_reg_u32(cap_header,
+                  PCI_CAP_REV_MASK, PCI_CAP_REV_SHIFT);
+    iommu->iotlb_support = get_field_from_reg_u32(cap_header,
+                PCI_CAP_IOTLB_MASK, PCI_CAP_IOTLB_SHIFT);
+    iommu->ht_tunnel_support = get_field_from_reg_u32(cap_header,
+                    PCI_CAP_HT_TUNNEL_MASK,
+                    PCI_CAP_HT_TUNNEL_SHIFT);
+    iommu->not_present_cached = get_field_from_reg_u32(cap_header,
+                    PCI_CAP_NP_CACHE_MASK,
+                    PCI_CAP_NP_CACHE_SHIFT);
+
+    cap_range = read_pci_config(bus, dev, func,
+            cap_ptr + PCI_CAP_RANGE_OFFSET);
+    iommu->root_bus = get_field_from_reg_u32(cap_range,
+                PCI_CAP_BUS_NUMBER_MASK,
+                PCI_CAP_BUS_NUMBER_SHIFT);
+    iommu->first_devfn = get_field_from_reg_u32(cap_range,
+                PCI_CAP_FIRST_DEVICE_MASK,
+                PCI_CAP_FIRST_DEVICE_SHIFT);
+    iommu->last_devfn = get_field_from_reg_u32(cap_range,
+                PCI_CAP_LAST_DEVICE_MASK,
+                PCI_CAP_LAST_DEVICE_SHIFT);
+
+    return 0;
+}
+
+static int __init scan_caps_for_iommu(int bus, int dev, int func,
+            iommu_detect_callback_ptr_t iommu_detect_callback)
+{
+    int cap_ptr, cap_id, cap_type;
+    u32 cap_header;
+    int count, error = 0;
+
+    count = 0;
+    cap_ptr = read_pci_config_byte(bus, dev, func,
+            PCI_CAPABILITY_LIST);
+    while ( cap_ptr >= PCI_MIN_CAP_OFFSET &&
+        count < PCI_MAX_CAP_BLOCKS && !error ) {
+        cap_ptr &= PCI_CAP_PTR_MASK;
+        cap_header = read_pci_config(bus, dev, func, cap_ptr);
+        cap_id = get_field_from_reg_u32(cap_header,
+                PCI_CAP_ID_MASK, PCI_CAP_ID_SHIFT);
+
+        if ( cap_id == PCI_CAP_ID_SECURE_DEVICE ) {
+            cap_type = get_field_from_reg_u32(cap_header,
+                    PCI_CAP_TYPE_MASK, PCI_CAP_TYPE_SHIFT);
+            if ( cap_type == PCI_CAP_TYPE_IOMMU ) {
+                error = iommu_detect_callback(
+                        bus, dev, func, cap_ptr);
+            }
+        }
+
+        cap_ptr = get_field_from_reg_u32(cap_header,
+                PCI_CAP_NEXT_PTR_MASK, PCI_CAP_NEXT_PTR_SHIFT);
+        ++count;    }
+
+    return error;
+}
+
+static int __init scan_functions_for_iommu(int bus, int dev,
+            iommu_detect_callback_ptr_t iommu_detect_callback)
+{
+    int func, hdr_type;
+    int count, error = 0;
+
+    func = 0;
+    count = 1;
+    while ( VALID_PCI_VENDOR_ID(read_pci_config_16(bus, dev, func,
+            PCI_VENDOR_ID)) && !error && func < count ) {
+        hdr_type = read_pci_config_byte(bus, dev, func,
+                PCI_HEADER_TYPE);
+
+        if ( func == 0 && IS_PCI_MULTI_FUNCTION(hdr_type) )
+            count = PCI_MAX_FUNC_COUNT;
+
+        if ( IS_PCI_TYPE0_HEADER(hdr_type) ||
+            IS_PCI_TYPE1_HEADER(hdr_type) ) {
+            error =  scan_caps_for_iommu(bus, dev, func,
+                    iommu_detect_callback);
+        }
+        ++func;
+    }
+
+    return error;
+}
+
+
+int __init scan_for_iommu(iommu_detect_callback_ptr_t iommu_detect_callback)
+{
+    int bus, dev, error = 0;
+
+    for ( bus = 0; bus < PCI_MAX_BUS_COUNT && !error; ++bus ) {
+        for ( dev = 0; dev < PCI_MAX_DEV_COUNT && !error; ++dev ) {
+            error =  scan_functions_for_iommu(bus, dev,
+                  iommu_detect_callback);
+        }
+    }
+
+    return error;
+}
+
diff -r a956ef58b012 -r 844e507d56b8 
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c   Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <asm/amd-iommu.h>
+#include <asm/hvm/svm/amd-iommu-proto.h>
+#include <asm-x86/fixmap.h>
+#include "pci-direct.h"
+#include "pci_regs.h"
+
+extern int nr_amd_iommus;
+
+int __init map_iommu_mmio_region(struct amd_iommu *iommu)
+{
+    unsigned long mfn;
+
+    if ( nr_amd_iommus > MAX_AMD_IOMMUS ) {
+        gdprintk(XENLOG_ERR,
+            "IOMMU: nr_amd_iommus %d > MAX_IOMMUS\n", nr_amd_iommus);
+        return -ENOMEM;
+    }
+
+    iommu->mmio_base = (void *) fix_to_virt(FIX_IOMMU_MMIO_BASE_0 +
+                       nr_amd_iommus * MMIO_PAGES_PER_IOMMU);
+    mfn = (unsigned long)iommu->mmio_base_phys >> PAGE_SHIFT;
+    map_pages_to_xen((unsigned long)iommu->mmio_base, mfn,
+                    MMIO_PAGES_PER_IOMMU, PAGE_HYPERVISOR_NOCACHE);
+
+    memset((u8*)iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH);
+
+    return 0;
+}
+
+void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
+{
+    if ( iommu->mmio_base ) {
+        iounmap(iommu->mmio_base);
+        iommu->mmio_base = NULL;
+    }
+}
+
+void __init register_iommu_dev_table_in_mmio_space(struct amd_iommu *iommu)
+{
+    u64 addr_64, addr_lo, addr_hi;
+    u32 entry;
+
+    addr_64 = (u64)virt_to_maddr(iommu->dev_table.buffer);
+    addr_lo = addr_64 & DMA_32BIT_MASK;
+    addr_hi = addr_64 >> 32;
+
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
+        IOMMU_DEV_TABLE_BASE_LOW_MASK,
+        IOMMU_DEV_TABLE_BASE_LOW_SHIFT, &entry);
+    set_field_in_reg_u32((iommu->dev_table.alloc_size / PAGE_SIZE) - 1,
+        entry, IOMMU_DEV_TABLE_SIZE_MASK,
+        IOMMU_DEV_TABLE_SIZE_SHIFT, &entry);
+    writel(entry, iommu->mmio_base + IOMMU_DEV_TABLE_BASE_LOW_OFFSET);
+
+    set_field_in_reg_u32((u32)addr_hi, 0,
+        IOMMU_DEV_TABLE_BASE_HIGH_MASK,
+        IOMMU_DEV_TABLE_BASE_HIGH_SHIFT, &entry);
+    writel(entry, iommu->mmio_base + IOMMU_DEV_TABLE_BASE_HIGH_OFFSET);
+}
+
+void __init register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu)
+{
+    u64 addr_64, addr_lo, addr_hi;
+    u32 power_of2_entries;
+    u32 entry;
+
+    addr_64 = (u64)virt_to_maddr(iommu->cmd_buffer.buffer);
+    addr_lo = addr_64 & DMA_32BIT_MASK;
+    addr_hi = addr_64 >> 32;
+
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
+        IOMMU_CMD_BUFFER_BASE_LOW_MASK,
+        IOMMU_CMD_BUFFER_BASE_LOW_SHIFT, &entry);
+    writel(entry, iommu->mmio_base + IOMMU_CMD_BUFFER_BASE_LOW_OFFSET);
+
+    power_of2_entries = get_order_from_bytes(iommu->cmd_buffer.alloc_size) +
+        IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE;
+
+    set_field_in_reg_u32((u32)addr_hi, 0,
+        IOMMU_CMD_BUFFER_BASE_HIGH_MASK,
+        IOMMU_CMD_BUFFER_BASE_HIGH_SHIFT, &entry);
+    set_field_in_reg_u32(power_of2_entries, entry,
+        IOMMU_CMD_BUFFER_LENGTH_MASK,
+        IOMMU_CMD_BUFFER_LENGTH_SHIFT, &entry);
+    writel(entry, iommu->mmio_base+IOMMU_CMD_BUFFER_BASE_HIGH_OFFSET);
+}
+
+static void __init set_iommu_translation_control(struct amd_iommu *iommu,
+            int enable)
+{
+    u32 entry;
+
+    entry = readl(iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
+    set_field_in_reg_u32(iommu->ht_tunnel_support ? IOMMU_CONTROL_ENABLED :
+        IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_MASK,
+        IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT, &entry);
+    set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
+        IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_CONTROL_TRANSLATION_ENABLE_MASK,
+        IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT, &entry);
+    writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
+}
+
+static void __init set_iommu_command_buffer_control(struct amd_iommu *iommu,
+            int enable)
+{
+    u32 entry;
+
+    entry = readl(iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
+    set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
+        IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_MASK,
+        IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT, &entry);
+    writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
+}
+
+void __init enable_iommu(struct amd_iommu *iommu)
+{
+    set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_ENABLED);
+    set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
+    printk("AMD IOMMU %d: Enabled\n", nr_amd_iommus);
+}
+
+
diff -r a956ef58b012 -r 844e507d56b8 
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c    Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <asm/hvm/iommu.h>
+#include <asm/amd-iommu.h>
+#include <asm/hvm/svm/amd-iommu-proto.h>
+#include <xen/sched.h>
+
+extern long amd_iommu_poll_comp_wait;
+
+static int queue_iommu_command(struct amd_iommu *iommu, u32 cmd[])
+{
+    u32 tail, head, *cmd_buffer;
+    int i;
+
+    BUG_ON( !iommu || !cmd );
+
+    tail = iommu->cmd_buffer_tail;
+    if ( ++tail == iommu->cmd_buffer.entries ) {
+        tail = 0;
+    }
+    head = get_field_from_reg_u32(
+            readl(iommu->mmio_base+IOMMU_CMD_BUFFER_HEAD_OFFSET),
+            IOMMU_CMD_BUFFER_HEAD_MASK,
+            IOMMU_CMD_BUFFER_HEAD_SHIFT);
+    if ( head != tail ) {
+        cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +
+            (iommu->cmd_buffer_tail * IOMMU_CMD_BUFFER_ENTRY_SIZE));
+        for ( i = 0; i < IOMMU_CMD_BUFFER_U32_PER_ENTRY; ++i ) {
+            cmd_buffer[i] = cmd[i];
+        }
+
+        iommu->cmd_buffer_tail = tail;
+        return 1;
+    }
+
+    return 0;
+}
+
+static void commit_iommu_command_buffer(struct amd_iommu *iommu)
+{
+    u32 tail;
+
+    BUG_ON( !iommu );
+
+    set_field_in_reg_u32(iommu->cmd_buffer_tail, 0,
+        IOMMU_CMD_BUFFER_TAIL_MASK,
+        IOMMU_CMD_BUFFER_TAIL_SHIFT, &tail);
+    writel(tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET);
+}
+
+int send_iommu_command(struct amd_iommu *iommu, u32 cmd[])
+{
+    BUG_ON( !iommu || !cmd );
+
+    if ( queue_iommu_command(iommu, cmd) ) {
+        commit_iommu_command_buffer(iommu);
+        return 1;
+    }
+    return 0;
+}
+
+static void invalidate_iommu_page(struct amd_iommu *iommu,
+            u64 io_addr, u16 domain_id)
+{
+    u64 addr_lo, addr_hi;
+    u32 cmd[4], entry;
+
+    addr_lo = io_addr & DMA_32BIT_MASK;
+    addr_hi = io_addr >> 32;
+
+    set_field_in_reg_u32(domain_id, 0,
+        IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_MASK,
+        IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_IOMMU_PAGES, entry,
+        IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT, &entry);
+    cmd[1] = entry;
+
+    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, 0,
+        IOMMU_INV_IOMMU_PAGES_S_FLAG_MASK,
+        IOMMU_INV_IOMMU_PAGES_S_FLAG_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
+        IOMMU_INV_IOMMU_PAGES_PDE_FLAG_MASK,
+        IOMMU_INV_IOMMU_PAGES_PDE_FLAG_SHIFT, &entry);
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, entry,
+        IOMMU_INV_IOMMU_PAGES_ADDR_LOW_MASK,
+        IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT, &entry);
+    cmd[2] = entry;
+
+    set_field_in_reg_u32((u32)addr_hi, 0,
+        IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK,
+        IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT, &entry);
+    cmd[3] = entry;
+
+    cmd[0] = 0;
+    send_iommu_command(iommu, cmd);
+}
+
+static void flush_command_buffer(struct amd_iommu *iommu)
+{
+    u32 cmd[4], status;
+    int loop_count, comp_wait;
+
+    /* clear 'ComWaitInt' in status register (WIC) */
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,
+        IOMMU_STATUS_COMP_WAIT_INT_MASK,
+        IOMMU_STATUS_COMP_WAIT_INT_SHIFT, &status);
+    writel(status, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+
+    /* send an empty COMPLETION_WAIT command to flush command buffer */
+    cmd[3] = cmd[2] = 0;
+    set_field_in_reg_u32(IOMMU_CMD_COMPLETION_WAIT, 0,
+        IOMMU_CMD_OPCODE_MASK,
+        IOMMU_CMD_OPCODE_SHIFT, &cmd[1]);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,
+        IOMMU_COMP_WAIT_I_FLAG_MASK,
+        IOMMU_COMP_WAIT_I_FLAG_SHIFT, &cmd[0]);
+    send_iommu_command(iommu, cmd);
+
+    /* wait for 'ComWaitInt' to signal comp#endifletion? */
+    if ( amd_iommu_poll_comp_wait ) {
+        loop_count = amd_iommu_poll_comp_wait;
+        do {
+            status = readl(iommu->mmio_base +
+                    IOMMU_STATUS_MMIO_OFFSET);
+            comp_wait = get_field_from_reg_u32(status,
+                    IOMMU_STATUS_COMP_WAIT_INT_MASK,
+                    IOMMU_STATUS_COMP_WAIT_INT_SHIFT);
+            --loop_count;
+        } while ( loop_count && !comp_wait );
+
+        if ( comp_wait ) {
+            /* clear 'ComWaitInt' in status register (WIC) */
+            status &= IOMMU_STATUS_COMP_WAIT_INT_MASK;
+            writel(status, iommu->mmio_base +
+                IOMMU_STATUS_MMIO_OFFSET);
+        } else
+            dprintk(XENLOG_WARNING, "AMD IOMMU: %s(): Warning:"
+                " ComWaitInt bit did not assert!\n",
+                 __FUNCTION__);
+    }
+}
+
+static void clear_page_table_entry_present(u32 *pte)
+{
+    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, pte[0],
+        IOMMU_PTE_PRESENT_MASK,
+        IOMMU_PTE_PRESENT_SHIFT, &pte[0]);
+}
+
+static void set_page_table_entry_present(u32 *pte, u64 page_addr,
+                int iw, int ir)
+{
+    u64 addr_lo, addr_hi;
+    u32 entry;
+
+    addr_lo = page_addr & DMA_32BIT_MASK;
+    addr_hi = page_addr >> 32;
+
+    set_field_in_reg_u32((u32)addr_hi, 0,
+        IOMMU_PTE_ADDR_HIGH_MASK,
+        IOMMU_PTE_ADDR_HIGH_SHIFT, &entry);
+    set_field_in_reg_u32(iw ? IOMMU_CONTROL_ENABLED :
+        IOMMU_CONTROL_DISABLED, entry,
+        IOMMU_PTE_IO_WRITE_PERMISSION_MASK,
+        IOMMU_PTE_IO_WRITE_PERMISSION_SHIFT, &entry);
+    set_field_in_reg_u32(ir ? IOMMU_CONTROL_ENABLED :
+        IOMMU_CONTROL_DISABLED, entry,
+        IOMMU_PTE_IO_READ_PERMISSION_MASK,
+        IOMMU_PTE_IO_READ_PERMISSION_SHIFT, &entry);
+    pte[1] = entry;
+
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
+        IOMMU_PTE_ADDR_LOW_MASK,
+        IOMMU_PTE_ADDR_LOW_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_PAGING_MODE_LEVEL_0, entry,
+        IOMMU_PTE_NEXT_LEVEL_MASK,
+        IOMMU_PTE_NEXT_LEVEL_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_PTE_PRESENT_MASK,
+        IOMMU_PTE_PRESENT_SHIFT, &entry);
+    pte[0] = entry;
+}
+
+
+static void amd_iommu_set_page_directory_entry(u32 *pde, 
+            u64 next_ptr, u8 next_level)
+{
+    u64 addr_lo, addr_hi;
+    u32 entry;
+
+    addr_lo = next_ptr & DMA_32BIT_MASK;
+    addr_hi = next_ptr >> 32;
+
+    /* enable read/write permissions,which will be enforced at the PTE */
+    set_field_in_reg_u32((u32)addr_hi, 0,
+        IOMMU_PDE_ADDR_HIGH_MASK, IOMMU_PDE_ADDR_HIGH_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_PDE_IO_WRITE_PERMISSION_MASK,
+        IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_PDE_IO_READ_PERMISSION_MASK,
+        IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);
+    pde[1] = entry;
+
+    /* mark next level as 'present' */
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
+        IOMMU_PDE_ADDR_LOW_MASK, IOMMU_PDE_ADDR_LOW_SHIFT, &entry);
+    set_field_in_reg_u32(next_level, entry,
+        IOMMU_PDE_NEXT_LEVEL_MASK,
+        IOMMU_PDE_NEXT_LEVEL_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_PDE_PRESENT_MASK,
+        IOMMU_PDE_PRESENT_SHIFT, &entry);
+    pde[0] = entry;
+}
+
+void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u16 domain_id,
+                u8 paging_mode)
+{
+    u64 addr_hi, addr_lo;
+    u32 entry;
+
+    dte[6] = dte[5] = dte[4] = 0;
+
+    set_field_in_reg_u32(IOMMU_DEV_TABLE_SYS_MGT_MSG_FORWARDED, 0,
+        IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK,
+        IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT, &entry);
+    dte[3] = entry;
+
+    set_field_in_reg_u32(domain_id, 0,
+        IOMMU_DEV_TABLE_DOMAIN_ID_MASK,
+        IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT, &entry);
+    dte[2] = entry;
+
+    addr_lo = root_ptr & DMA_32BIT_MASK;
+    addr_hi = root_ptr >> 32;
+    set_field_in_reg_u32((u32)addr_hi, 0,
+        IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK,
+        IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_MASK,
+        IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK,
+        IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT, &entry);
+    dte[1] = entry;
+
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
+        IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK,
+        IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT, &entry);
+    set_field_in_reg_u32(paging_mode, entry,
+        IOMMU_DEV_TABLE_PAGING_MODE_MASK,
+        IOMMU_DEV_TABLE_PAGING_MODE_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
+        IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &entry);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+        IOMMU_DEV_TABLE_VALID_MASK,
+        IOMMU_DEV_TABLE_VALID_SHIFT, &entry);
+    dte[0] = entry;
+}
+
+static void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry)
+{
+    u64 addr_lo, addr_hi, ptr;
+
+    addr_lo = get_field_from_reg_u32(entry[0],
+            IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK,
+            IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT);
+
+    addr_hi = get_field_from_reg_u32(entry[1],
+            IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK,
+            IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT);
+
+    ptr = (addr_hi << 32) | (addr_lo << PAGE_SHIFT);
+    return ptr ? maddr_to_virt((unsigned long)ptr) : NULL;
+}
+
+static int amd_iommu_is_pte_present(u32 *entry)
+{
+    return (get_field_from_reg_u32(entry[0],
+            IOMMU_PDE_PRESENT_MASK,
+            IOMMU_PDE_PRESENT_SHIFT));
+}
+
+static void *get_pte_from_page_tables(void *table, int level,
+        unsigned long io_pfn)
+{
+    unsigned long offset;
+    void *pde = 0;
+
+    BUG_ON( !table );
+
+    while ( level > 0 )
+    {
+        void *next_table = 0;
+        unsigned long next_ptr;
+        offset = io_pfn >> ((PTE_PER_TABLE_SHIFT *
+            (level - IOMMU_PAGING_MODE_LEVEL_1)));
+        offset &= ~PTE_PER_TABLE_MASK;
+        pde = table + (offset * IOMMU_PAGE_TABLE_ENTRY_SIZE);
+
+        if ( level == 1 )
+            break;
+        if ( !pde )
+           return NULL;
+        if ( !amd_iommu_is_pte_present(pde) ) {
+            next_table = alloc_xenheap_page();
+            if ( next_table == NULL )
+                return NULL;
+            memset(next_table, 0, PAGE_SIZE);
+            if ( *(u64*)(pde) == 0 ) {
+                next_ptr = (u64)virt_to_maddr(next_table);
+                amd_iommu_set_page_directory_entry((u32 *)pde,
+                    next_ptr, level - 1);
+            } else
+                free_xenheap_page(next_table);
+        }
+        table = amd_iommu_get_vptr_from_page_table_entry(pde);
+        level--;
+    }
+
+    return pde;
+}
+
+int amd_iommu_map_page(struct domain *d, unsigned long gfn,
+        unsigned long mfn)
+{
+    void *pte;
+    unsigned long flags;
+    u64 maddr;
+    struct hvm_iommu *hd = domain_hvm_iommu(d);
+    int iw, ir;
+
+    BUG_ON( !hd->root_table );
+
+    maddr = (u64)(mfn << PAGE_SHIFT);
+
+    iw = IOMMU_IO_WRITE_ENABLED;
+    ir = IOMMU_IO_READ_ENABLED;
+
+    spin_lock_irqsave(&hd->mapping_lock, flags);
+
+    pte = get_pte_from_page_tables(hd->root_table, hd->paging_mode, gfn);
+
+    if ( pte != 0 ) {
+        set_page_table_entry_present((u32 *)pte, maddr, iw, ir);
+        spin_unlock_irqrestore(&hd->mapping_lock, flags);
+        return 0;
+    } else {
+        dprintk(XENLOG_ERR,
+            "%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n",
+            __FUNCTION__, gfn);
+        spin_unlock_irqrestore(&hd->mapping_lock, flags);
+        return -EIO;
+    }
+}
+
+int amd_iommu_unmap_page(struct domain *d, unsigned long gfn)
+{
+    void *pte;
+    unsigned long flags;
+    u64 io_addr = gfn;
+    int requestor_id;
+    struct amd_iommu *iommu;
+    struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+    BUG_ON( !hd->root_table );
+
+    requestor_id = hd->domain_id;
+    io_addr = (u64)(gfn << PAGE_SHIFT);
+
+    spin_lock_irqsave(&hd->mapping_lock, flags);
+
+    pte = get_pte_from_page_tables(hd->root_table, hd->paging_mode, gfn);
+
+    if ( pte != 0 ) {
+        /* mark PTE as 'page not present' */
+        clear_page_table_entry_present((u32 *)pte);
+        spin_unlock_irqrestore(&hd->mapping_lock, flags);
+
+        /* send INVALIDATE_IOMMU_PAGES command */
+        for_each_amd_iommu(iommu) {
+
+            spin_lock_irqsave(&iommu->lock, flags);
+
+            invalidate_iommu_page(iommu, io_addr, requestor_id);
+            flush_command_buffer(iommu);
+
+            spin_unlock_irqrestore(&iommu->lock, flags);
+        }
+
+        return 0;
+    } else {
+        dprintk(XENLOG_ERR,
+            "%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", 
+            __FUNCTION__, gfn);
+        spin_unlock_irqrestore(&hd->mapping_lock, flags);
+        return -EIO;
+    }
+}
diff -r a956ef58b012 -r 844e507d56b8 
xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c    Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <asm/amd-iommu.h>
+#include <asm/hvm/svm/amd-iommu-proto.h>
+#include <xen/sched.h>
+#include <asm/mm.h>
+#include "pci-direct.h"
+#include "pci_regs.h"
+
+struct list_head amd_iommu_head;
+long amd_iommu_poll_comp_wait = COMPLETION_WAIT_DEFAULT_POLLING_COUNT;
+static long amd_iommu_cmd_buffer_entries = IOMMU_CMD_BUFFER_DEFAULT_ENTRIES;
+int nr_amd_iommus = 0;
+
+/* will set if amd-iommu HW is found */
+int amd_iommu_enabled = 0;
+
+static int enable_amd_iommu = 0;
+boolean_param("enable_amd_iommu", enable_amd_iommu);
+
+static void deallocate_domain_page_tables(struct hvm_iommu *hd)
+{
+    if ( hd->root_table )
+        free_xenheap_page(hd->root_table);
+}
+
+static void deallocate_domain_resources(struct hvm_iommu *hd)
+{
+    deallocate_domain_page_tables(hd);
+}
+
+static void __init init_cleanup(void)
+{
+    struct amd_iommu *iommu;
+
+    dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
+
+    for_each_amd_iommu(iommu) {
+        unmap_iommu_mmio_region(iommu);
+    }
+}
+
+static void __init deallocate_iommu_table_struct(
+            struct table_struct *table)
+{
+    if (table->buffer) {
+        free_xenheap_pages(table->buffer,
+            get_order_from_bytes(table->alloc_size));
+        table->buffer = NULL;
+    }
+}
+
+static void __init deallocate_iommu_resources(struct amd_iommu *iommu)
+{
+    deallocate_iommu_table_struct(&iommu->dev_table);
+    deallocate_iommu_table_struct(&iommu->cmd_buffer);;
+}
+
+static void __init detect_cleanup(void)
+{
+    struct amd_iommu *iommu;
+
+    dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
+
+    for_each_amd_iommu(iommu) {
+        list_del(&iommu->list);
+        deallocate_iommu_resources(iommu);
+        xfree(iommu);
+    }
+}
+
+static int requestor_id_from_bdf(int bdf)
+{
+    /* HACK - HACK */
+    /* account for possible 'aliasing' by parent device */
+   return bdf;
+}
+
+static int __init allocate_iommu_table_struct(struct table_struct *table,
+            const char *name)
+{
+    table->buffer = (void *) alloc_xenheap_pages(
+        get_order_from_bytes(table->alloc_size));
+
+    if ( !table->buffer ) {
+        dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating %s\n", name);
+        return -ENOMEM;
+    }
+    memset(table->buffer, 0, table->alloc_size);
+
+    return 0;
+}
+
+static int __init allocate_iommu_resources(struct amd_iommu *iommu)
+{
+    /* allocate 'device table' on a 4K boundary */
+    iommu->dev_table.alloc_size =
+        PAGE_ALIGN(((iommu->last_downstream_bus + 1) *
+        IOMMU_DEV_TABLE_ENTRIES_PER_BUS) *
+        IOMMU_DEV_TABLE_ENTRY_SIZE);
+    iommu->dev_table.entries =
+        iommu->dev_table.alloc_size / IOMMU_DEV_TABLE_ENTRY_SIZE;
+
+    if (allocate_iommu_table_struct(&iommu->dev_table,
+            "Device Table") != 0)
+        goto error_out;
+
+    /* allocate 'command buffer' in power of 2 increments of 4K */
+    iommu->cmd_buffer_tail = 0;
+    iommu->cmd_buffer.alloc_size =
+        PAGE_SIZE << get_order_from_bytes(
+        PAGE_ALIGN(amd_iommu_cmd_buffer_entries *
+        IOMMU_CMD_BUFFER_ENTRY_SIZE));
+
+   iommu->cmd_buffer.entries =
+        iommu->cmd_buffer.alloc_size / IOMMU_CMD_BUFFER_ENTRY_SIZE;
+
+    if ( allocate_iommu_table_struct(&iommu->cmd_buffer,
+            "Command Buffer") != 0 )
+        goto error_out;
+
+    return 0;
+
+error_out:
+    deallocate_iommu_resources(iommu);
+    return -ENOMEM;
+}
+
+int iommu_detect_callback(u8 bus, u8 dev, u8 func, u8 cap_ptr)
+{
+    struct amd_iommu *iommu;
+
+    iommu = (struct amd_iommu *) xmalloc(struct amd_iommu);
+    if ( !iommu ) {
+        dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating amd_iommu\n");
+        return -ENOMEM;
+    }
+    memset(iommu, 0, sizeof(struct amd_iommu));
+    spin_lock_init(&iommu->lock);
+
+    /* get capability and topology information */
+    if ( get_iommu_capabilities(bus, dev, func, cap_ptr, iommu) != 0 )
+        goto error_out;
+    if ( get_iommu_last_downstream_bus(iommu) != 0 )
+        goto error_out;
+
+    list_add_tail(&iommu->list, &amd_iommu_head);
+
+    /* allocate resources for this IOMMU */
+    if (allocate_iommu_resources(iommu) != 0)
+        goto error_out;
+
+    return 0;
+
+error_out:
+    xfree(iommu);
+    return -ENODEV;
+}
+
+static int __init amd_iommu_init(void)
+{
+    struct amd_iommu *iommu;
+    unsigned long flags;
+
+    for_each_amd_iommu(iommu) {
+        spin_lock_irqsave(&iommu->lock, flags);
+
+        /* register IOMMU data strucures in MMIO space */
+        if (map_iommu_mmio_region(iommu) != 0)
+            goto error_out;
+        register_iommu_dev_table_in_mmio_space(iommu);
+        register_iommu_cmd_buffer_in_mmio_space(iommu);
+
+        /* enable IOMMU translation services */
+        enable_iommu(iommu);
+        nr_amd_iommus++;
+
+        spin_unlock_irqrestore(&iommu->lock, flags);
+    }
+
+    amd_iommu_enabled = 1;
+
+    return 0;
+
+error_out:
+    init_cleanup();
+    return -ENODEV;
+}
+
+struct amd_iommu *find_iommu_for_device(int bus, int devfn)
+{
+    struct amd_iommu *iommu;
+
+    for_each_amd_iommu(iommu) {
+        if ( bus == iommu->root_bus ) {
+            if ( devfn >= iommu->first_devfn &&
+                devfn <= iommu->last_devfn )
+                return iommu;
+        }
+        else if ( bus <= iommu->last_downstream_bus ) {
+            if ( iommu->downstream_bus_present[bus] )
+                return iommu;
+        }
+    }
+
+    return NULL;
+}
+
+void amd_iommu_setup_domain_device(struct domain *domain,
+        struct amd_iommu *iommu, int requestor_id)
+{
+    void *dte;
+    u64 root_ptr;
+    unsigned long flags;
+    struct hvm_iommu *hd = domain_hvm_iommu(domain);
+
+    BUG_ON( !hd->root_table||!hd->paging_mode );
+
+    root_ptr = (u64)virt_to_maddr(hd->root_table);
+    dte = iommu->dev_table.buffer +
+        (requestor_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
+
+    spin_lock_irqsave(&iommu->lock, flags); 
+
+    amd_iommu_set_dev_table_entry((u32 *)dte,
+        root_ptr, hd->domain_id, hd->paging_mode);
+
+    dprintk(XENLOG_INFO, "AMD IOMMU: Set DTE req_id:%x, "
+        "root_ptr:%lx, domain_id:%d, paging_mode:%d\n",
+        requestor_id, root_ptr, hd->domain_id, hd->paging_mode);
+
+    spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+void __init amd_iommu_setup_dom0_devices(void)
+{
+    struct hvm_iommu *hd = domain_hvm_iommu(dom0);
+    struct amd_iommu *iommu;
+    struct pci_dev *pdev;
+    int bus, dev, func;
+    u32 l;
+    int req_id, bdf;
+
+    for ( bus = 0; bus < 256; bus++ ) {
+        for ( dev = 0; dev < 32; dev++ ) {
+            for ( func = 0; func < 8; func++ ) {
+                l = read_pci_config(bus, dev, func, PCI_VENDOR_ID);
+                /* some broken boards return 0 or ~0 if a slot is empty: */
+                if ( l == 0xffffffff || l == 0x00000000 ||
+                    l == 0x0000ffff || l == 0xffff0000 )
+                    continue;
+
+                pdev = xmalloc(struct pci_dev);
+                pdev->bus = bus;
+                pdev->devfn = PCI_DEVFN(dev, func);
+                list_add_tail(&pdev->list, &hd->pdev_list);
+
+                bdf = (bus << 8) | pdev->devfn;
+                req_id = requestor_id_from_bdf(bdf);
+                iommu = find_iommu_for_device(bus, pdev->devfn);
+
+                if ( iommu )
+                    amd_iommu_setup_domain_device(dom0, iommu, req_id);
+            }
+        }
+    }
+}
+
+int amd_iommu_detect(void)
+{
+    unsigned long i;
+
+    if ( !enable_amd_iommu ) {
+        printk("AMD IOMMU: Disabled\n");
+        return 0;
+    }
+
+    INIT_LIST_HEAD(&amd_iommu_head);
+
+    if ( scan_for_iommu(iommu_detect_callback) != 0 ) {
+        dprintk(XENLOG_ERR, "AMD IOMMU: Error detection\n");
+        goto error_out;
+    }
+
+    if ( !iommu_found() ) {
+        printk("AMD IOMMU: Not found!\n");
+        return 0;
+    }
+
+    if ( amd_iommu_init() != 0 ) {
+        dprintk(XENLOG_ERR, "AMD IOMMU: Error initialization\n");
+        goto error_out;
+    }
+
+    if ( amd_iommu_domain_init(dom0) != 0 )
+        goto error_out;
+
+    /* setup 1:1 page table for dom0 */
+    for ( i = 0; i < max_page; i++ )
+        amd_iommu_map_page(dom0, i, i);
+
+    amd_iommu_setup_dom0_devices();
+    return 0;
+
+error_out:
+     detect_cleanup();
+     return -ENODEV;
+
+}
+
+static int allocate_domain_resources(struct hvm_iommu *hd)
+{
+    /* allocate root table */
+    hd->root_table = (void *)alloc_xenheap_page();
+    if ( !hd->root_table )
+        return -ENOMEM;
+    memset((u8*)hd->root_table, 0, PAGE_SIZE);
+
+    return 0;
+}
+
+static int get_paging_mode(unsigned long entries)
+{
+    int level = 1;
+
+    BUG_ON ( !max_page );
+
+    if ( entries > max_page )
+        entries = max_page;
+
+    while ( entries > PTE_PER_TABLE_SIZE ) {
+        entries = PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT;
+        ++level;
+        if ( level > 6 )
+            return -ENOMEM;
+    }
+
+    dprintk(XENLOG_INFO, "AMD IOMMU: paging mode = %d\n", level);
+
+    return level;
+}
+
+int amd_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);
+
+    /* allocate page directroy */
+    if ( allocate_domain_resources(hd) != 0 ) {
+        dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
+        goto error_out;
+    }
+
+    if ( is_hvm_domain(domain) )
+        hd->paging_mode = IOMMU_PAGE_TABLE_LEVEL_4;
+    else
+        hd->paging_mode = get_paging_mode(max_page);
+
+    hd->domain_id = domain->domain_id;
+
+    return 0;
+
+error_out:
+    deallocate_domain_resources(hd);
+    return -ENOMEM;
+}
+
+
diff -r a956ef58b012 -r 844e507d56b8 xen/arch/x86/hvm/svm/amd_iommu/pci-direct.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/pci-direct.h       Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,48 @@
+#ifndef ASM_PCI_DIRECT_H
+#define ASM_PCI_DIRECT_H 1
+
+#include <xen/types.h>
+#include <asm/io.h>
+
+/* Direct PCI access. This is used for PCI accesses in early boot before
+   the PCI subsystem works. */ 
+
+#define PDprintk(x...)
+
+static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
+{
+    u32 v; 
+    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+    v = inl(0xcfc); 
+    if (v != 0xffffffff)
+        PDprintk("%x reading 4 from %x: %x\n", slot, offset, v);
+    return v;
+}
+
+static inline u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
+{
+    u8 v; 
+    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+    v = inb(0xcfc + (offset&3)); 
+    PDprintk("%x reading 1 from %x: %x\n", slot, offset, v);
+    return v;
+}
+
+static inline u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
+{
+    u16 v; 
+    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+    v = inw(0xcfc + (offset&2)); 
+    PDprintk("%x reading 2 from %x: %x\n", slot, offset, v);
+    return v;
+}
+
+static inline void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
+                    u32 val)
+{
+    PDprintk("%x writing to %x: %x\n", slot, offset, val); 
+    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+    outl(val, 0xcfc); 
+}
+
+#endif
diff -r a956ef58b012 -r 844e507d56b8 xen/arch/x86/hvm/svm/amd_iommu/pci_regs.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/pci_regs.h Fri Sep 21 17:15:47 2007 +0100
@@ -0,0 +1,513 @@
+/*
+ *     pci_regs.h
+ *
+ *     PCI standard defines
+ *     Copyright 1994, Drew Eckhardt
+ *     Copyright 1997--1999 Martin Mares <mj@xxxxxx>
+ *
+ *     For more information, please consult the following manuals (look at
+ *     http://www.pcisig.com/ for how to get them):
+ *
+ *     PCI BIOS Specification
+ *     PCI Local Bus Specification
+ *     PCI to PCI Bridge Specification
+ *     PCI System Design Guide
+ *
+ *     For hypertransport information, please consult the following manuals
+ *     from http://www.hypertransport.org
+ *
+ *     The Hypertransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID          0x00    /* 16 bits */
+#define PCI_DEVICE_ID          0x02    /* 16 bits */
+#define PCI_COMMAND            0x04    /* 16 bits */
+#define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space 
*/
+#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER    0x4     /* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL   0x8     /* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE        0x10    /* Use memory write and 
invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20  /* Enable palette snooping */
+#define  PCI_COMMAND_PARITY    0x40    /* Enable parity checking */
+#define  PCI_COMMAND_WAIT      0x80    /* Enable address/data stepping */
+#define  PCI_COMMAND_SERR      0x100   /* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK 0x200   /* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS             0x06    /* 16 bits */
+#define  PCI_STATUS_CAP_LIST   0x10    /* Support Capability List */
+#define  PCI_STATUS_66MHZ      0x20    /* Support 66 Mhz PCI 2.1 bus */
+#define  PCI_STATUS_UDF                0x40    /* Support User Definable 
Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK  0x80    /* Accept fast-back to back */
+#define  PCI_STATUS_PARITY     0x100   /* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK        0x600   /* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST                0x000
+#define  PCI_STATUS_DEVSEL_MEDIUM      0x200
+#define  PCI_STATUS_DEVSEL_SLOW                0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT   0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT   0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT   0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR   0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY    0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION     0x08    /* High 24 bits are class, low 8 
revision */
+#define PCI_REVISION_ID                0x08    /* Revision ID */
+#define PCI_CLASS_PROG         0x09    /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE       0x0a    /* Device class */
+
+#define PCI_CACHE_LINE_SIZE    0x0c    /* 8 bits */
+#define PCI_LATENCY_TIMER      0x0d    /* 8 bits */
+#define PCI_HEADER_TYPE                0x0e    /* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL                0
+#define  PCI_HEADER_TYPE_BRIDGE                1
+#define  PCI_HEADER_TYPE_CARDBUS       2
+
+#define PCI_BIST               0x0f    /* 8 bits */
+#define  PCI_BIST_CODE_MASK    0x0f    /* Return result */
+#define  PCI_BIST_START                0x40    /* 1 to start BIST, 2 secs or 
less */
+#define  PCI_BIST_CAPABLE      0x80    /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back.  Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0     0x10    /* 32 bits */
+#define PCI_BASE_ADDRESS_1     0x14    /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2     0x18    /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3     0x1c    /* 32 bits */
+#define PCI_BASE_ADDRESS_4     0x20    /* 32 bits */
+#define PCI_BASE_ADDRESS_5     0x24    /* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE                0x01    /* 0 = memory, 1 = I/O 
*/
+#define  PCI_BASE_ADDRESS_SPACE_IO     0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK        0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32  0x00    /* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M  0x02    /* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64  0x04    /* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH 0x08    /* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK     (~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK      (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS                0x28
+#define PCI_SUBSYSTEM_VENDOR_ID        0x2c
+#define PCI_SUBSYSTEM_ID       0x2e
+#define PCI_ROM_ADDRESS                0x30    /* Bits 31..11 are address, 
10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE        0x01
+#define PCI_ROM_ADDRESS_MASK   (~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST    0x34    /* Offset of first capability list 
entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
+#define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
+#define PCI_MIN_GNT            0x3e    /* 8 bits */
+#define PCI_MAX_LAT            0x3f    /* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS                0x18    /* Primary bus number */
+#define PCI_SECONDARY_BUS      0x19    /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS    0x1a    /* Highest bus number behind the bridge 
*/
+#define PCI_SEC_LATENCY_TIMER  0x1b    /* Latency timer for secondary 
interface */
+#define PCI_IO_BASE            0x1c    /* I/O range behind the bridge */
+#define PCI_IO_LIMIT           0x1d
+#define  PCI_IO_RANGE_TYPE_MASK        0x0fUL  /* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16  0x00
+#define  PCI_IO_RANGE_TYPE_32  0x01
+#define  PCI_IO_RANGE_MASK     (~0x0fUL)
+#define PCI_SEC_STATUS         0x1e    /* Secondary status register, only bit 
14 used */
+#define PCI_MEMORY_BASE                0x20    /* Memory range behind */
+#define PCI_MEMORY_LIMIT       0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_MEMORY_RANGE_MASK (~0x0fUL)
+#define PCI_PREF_MEMORY_BASE   0x24    /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT  0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_PREF_RANGE_TYPE_32        0x00
+#define  PCI_PREF_RANGE_TYPE_64        0x01
+#define  PCI_PREF_RANGE_MASK   (~0x0fUL)
+#define PCI_PREF_BASE_UPPER32  0x28    /* Upper half of prefetchable memory 
range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16    0x30    /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16   0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1       0x38    /* Same as PCI_ROM_ADDRESS, but for 
htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL     0x3e
+#define  PCI_BRIDGE_CTL_PARITY 0x01    /* Enable parity detection on secondary 
interface */
+#define  PCI_BRIDGE_CTL_SERR   0x02    /* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_NO_ISA 0x04    /* Disable bridging of ISA ports */
+#define  PCI_BRIDGE_CTL_VGA    0x08    /* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT   0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET      0x40    /* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK      0x80    /* Fast Back2Back enabled on 
secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST 0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS      0x16    /* Secondary status */
+#define PCI_CB_PRIMARY_BUS     0x18    /* PCI bus number */
+#define PCI_CB_CARD_BUS                0x19    /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a    /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER   0x1b    /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0   0x1c
+#define PCI_CB_MEMORY_LIMIT_0  0x20
+#define PCI_CB_MEMORY_BASE_1   0x24
+#define PCI_CB_MEMORY_LIMIT_1  0x28
+#define PCI_CB_IO_BASE_0       0x2c
+#define PCI_CB_IO_BASE_0_HI    0x2e
+#define PCI_CB_IO_LIMIT_0      0x30
+#define PCI_CB_IO_LIMIT_0_HI   0x32
+#define PCI_CB_IO_BASE_1       0x34
+#define PCI_CB_IO_BASE_1_HI    0x36
+#define PCI_CB_IO_LIMIT_1      0x38
+#define PCI_CB_IO_LIMIT_1_HI   0x3a
+#define  PCI_CB_IO_RANGE_MASK  (~0x03UL)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL  0x3e
+#define  PCI_CB_BRIDGE_CTL_PARITY      0x01    /* Similar to standard bridge 
control register */
+#define  PCI_CB_BRIDGE_CTL_SERR                0x02
+#define  PCI_CB_BRIDGE_CTL_ISA         0x04
+#define  PCI_CB_BRIDGE_CTL_VGA         0x08
+#define  PCI_CB_BRIDGE_CTL_MASTER_ABORT        0x20
+#define  PCI_CB_BRIDGE_CTL_CB_RESET    0x40    /* CardBus reset */
+#define  PCI_CB_BRIDGE_CTL_16BIT_INT   0x80    /* Enable interrupt for 16-bit 
cards */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both 
memory regions */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define  PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID     0x40
+#define PCI_CB_SUBSYSTEM_ID            0x42
+#define PCI_CB_LEGACY_MODE_BASE                0x44    /* 16-bit PC Card 
legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID                0       /* Capability ID */
+#define  PCI_CAP_ID_PM         0x01    /* Power Management */
+#define  PCI_CAP_ID_AGP                0x02    /* Accelerated Graphics Port */
+#define  PCI_CAP_ID_VPD                0x03    /* Vital Product Data */
+#define  PCI_CAP_ID_SLOTID     0x04    /* Slot Identification */
+#define  PCI_CAP_ID_MSI                0x05    /* Message Signalled Interrupts 
*/
+#define  PCI_CAP_ID_CHSWP      0x06    /* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX       0x07    /* PCI-X */
+#define  PCI_CAP_ID_HT         0x08    /* HyperTransport */
+#define  PCI_CAP_ID_VNDR       0x09    /* Vendor specific capability */
+#define  PCI_CAP_ID_SHPC       0x0C    /* PCI Standard Hot-Plug Controller */
+#define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
+#define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
+#define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
+#define PCI_CAP_FLAGS          2       /* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF         4
+
+/* Power Management Registers */
+
+#define PCI_PM_PMC             2       /* PM Capabilities Register */
+#define  PCI_PM_CAP_VER_MASK   0x0007  /* Version */
+#define  PCI_PM_CAP_PME_CLOCK  0x0008  /* PME clock required */
+#define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
+#define  PCI_PM_CAP_DSI                0x0020  /* Device specific 
initialization */
+#define  PCI_PM_CAP_AUX_POWER  0x01C0  /* Auxilliary power support mask */
+#define  PCI_PM_CAP_D1         0x0200  /* D1 power state support */
+#define  PCI_PM_CAP_D2         0x0400  /* D2 power state support */
+#define  PCI_PM_CAP_PME                0x0800  /* PME pin supported */
+#define  PCI_PM_CAP_PME_MASK   0xF800  /* PME Mask of all supported states */
+#define  PCI_PM_CAP_PME_D0     0x0800  /* PME# from D0 */
+#define  PCI_PM_CAP_PME_D1     0x1000  /* PME# from D1 */
+#define  PCI_PM_CAP_PME_D2     0x2000  /* PME# from D2 */
+#define  PCI_PM_CAP_PME_D3     0x4000  /* PME# from D3 (hot) */
+#define  PCI_PM_CAP_PME_D3cold 0x8000  /* PME# from D3 (cold) */
+#define PCI_PM_CTRL            4       /* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK        0x0003  /* Current power state (D0 to 
D3) */
+#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0004  /* No reset for D3hot->D0 */
+#define  PCI_PM_CTRL_PME_ENABLE        0x0100  /* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK     0x1e00  /* Data select (??) */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK   0x6000  /* Data scale (??) */
+#define  PCI_PM_CTRL_PME_STATUS        0x8000  /* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS  6       /* PPB support extensions (??) */
+#define  PCI_PM_PPB_B2_B3      0x40    /* Stop clock when in D3hot (??) */
+#define  PCI_PM_BPCC_ENABLE    0x80    /* Bus power/clock control enable (??) 
*/
+#define PCI_PM_DATA_REGISTER   7       /* (??) */
+#define PCI_PM_SIZEOF          8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION                2       /* BCD version number */
+#define PCI_AGP_RFU            3       /* Rest of capability flags */
+#define PCI_AGP_STATUS         4       /* Status register */
+#define  PCI_AGP_STATUS_RQ_MASK        0xff000000      /* Maximum number of 
requests - 1 */
+#define  PCI_AGP_STATUS_SBA    0x0200  /* Sideband addressing supported */
+#define  PCI_AGP_STATUS_64BIT  0x0020  /* 64-bit addressing supported */
+#define  PCI_AGP_STATUS_FW     0x0010  /* FW transfers supported */
+#define  PCI_AGP_STATUS_RATE4  0x0004  /* 4x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE2  0x0002  /* 2x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE1  0x0001  /* 1x transfer rate supported */
+#define PCI_AGP_COMMAND                8       /* Control register */
+#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of 
requests */
+#define  PCI_AGP_COMMAND_SBA   0x0200  /* Sideband addressing enabled */
+#define  PCI_AGP_COMMAND_AGP   0x0100  /* Allow processing of AGP transactions 
*/
+#define  PCI_AGP_COMMAND_64BIT 0x0020  /* Allow processing of 64-bit addresses 
*/
+#define  PCI_AGP_COMMAND_FW    0x0010  /* Force FW transfers */
+#define  PCI_AGP_COMMAND_RATE4 0x0004  /* Use 4x rate */
+#define  PCI_AGP_COMMAND_RATE2 0x0002  /* Use 2x rate */
+#define  PCI_AGP_COMMAND_RATE1 0x0001  /* Use 1x rate */
+#define PCI_AGP_SIZEOF         12
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR           2       /* Address to access (15 bits!) */
+#define  PCI_VPD_ADDR_MASK     0x7fff  /* Address mask */
+#define  PCI_VPD_ADDR_F                0x8000  /* Write 0, 1 indicates 
completion */
+#define PCI_VPD_DATA           4       /* 32-bits of data returned here */
+
+/* Slot Identification */
+
+#define PCI_SID_ESR            2       /* Expansion Slot Register */
+#define  PCI_SID_ESR_NSLOTS    0x1f    /* Number of expansion slots available 
*/
+#define  PCI_SID_ESR_FIC       0x20    /* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR     3       /* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS          2       /* Various flags */
+#define  PCI_MSI_FLAGS_64BIT   0x80    /* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_QSIZE   0x70    /* Message queue size configured */
+#define  PCI_MSI_FLAGS_QMASK   0x0e    /* Maximum queue size available */
+#define  PCI_MSI_FLAGS_ENABLE  0x01    /* MSI feature enabled */
+#define  PCI_MSI_FLAGS_MASKBIT 0x100   /* 64-bit mask bits allowed */
+#define PCI_MSI_RFU            3       /* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO     4       /* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI     8       /* Upper 32 bits (if 
PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32                8       /* 16 bits of data for 32-bit 
devices */
+#define PCI_MSI_DATA_64                12      /* 16 bits of data for 64-bit 
devices */
+#define PCI_MSI_MASK_BIT       16      /* Mask bits register */
+
+/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+#define PCI_MSIX_FLAGS         2
+#define  PCI_MSIX_FLAGS_QSIZE  0x7FF
+#define  PCI_MSIX_FLAGS_ENABLE (1 << 15)
+#define  PCI_MSIX_FLAGS_MASKALL        (1 << 14)
+#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
+
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR          2       /* Control and Status Register */
+#define  PCI_CHSWP_DHA         0x01    /* Device Hiding Arm */
+#define  PCI_CHSWP_EIM         0x02    /* ENUM# Signal Mask */
+#define  PCI_CHSWP_PIE         0x04    /* Pending Insert or Extract */
+#define  PCI_CHSWP_LOO         0x08    /* LED On / Off */
+#define  PCI_CHSWP_PI          0x30    /* Programming Interface */
+#define  PCI_CHSWP_EXT         0x40    /* ENUM# status - extraction */
+#define  PCI_CHSWP_INS         0x80    /* ENUM# status - insertion */
+
+/* PCI-X registers */
+
+#define PCI_X_CMD              2       /* Modes & Features */
+#define  PCI_X_CMD_DPERR_E     0x0001  /* Data Parity Error Recovery Enable */
+#define  PCI_X_CMD_ERO         0x0002  /* Enable Relaxed Ordering */
+#define  PCI_X_CMD_MAX_READ    0x000c  /* Max Memory Read Byte Count */
+#define  PCI_X_CMD_MAX_SPLIT   0x0070  /* Max Outstanding Split Transactions */
+#define  PCI_X_CMD_VERSION(x)  (((x) >> 12) & 3) /* Version */
+#define PCI_X_STATUS           4       /* PCI-X capabilities */
+#define  PCI_X_STATUS_DEVFN    0x000000ff      /* A copy of devfn */
+#define  PCI_X_STATUS_BUS      0x0000ff00      /* A copy of bus nr */
+#define  PCI_X_STATUS_64BIT    0x00010000      /* 64-bit device */
+#define  PCI_X_STATUS_133MHZ   0x00020000      /* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC 0x00040000      /* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL  0x00080000      /* Unexpected Split Completion 
*/
+#define  PCI_X_STATUS_COMPLEX  0x00100000      /* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ 0x00600000      /* Designed Max Memory Read 
Count */
+#define  PCI_X_STATUS_MAX_SPLIT        0x03800000      /* Designed Max 
Outstanding Split Transactions */
+#define  PCI_X_STATUS_MAX_CUM  0x1c000000      /* Designed Max Cumulative Read 
Size */
+#define  PCI_X_STATUS_SPL_ERR  0x20000000      /* Rcvd Split Completion Error 
Msg */
+#define  PCI_X_STATUS_266MHZ   0x40000000      /* 266 MHz capable */
+#define  PCI_X_STATUS_533MHZ   0x80000000      /* 533 MHz capable */
+
+/* PCI Express capability registers */
+
+#define PCI_EXP_FLAGS          2       /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS     0x000f  /* Capability version */
+#define PCI_EXP_FLAGS_TYPE     0x00f0  /* Device/Port type */
+#define  PCI_EXP_TYPE_ENDPOINT 0x0     /* Express Endpoint */
+#define  PCI_EXP_TYPE_LEG_END  0x1     /* Legacy Endpoint */
+#define  PCI_EXP_TYPE_ROOT_PORT 0x4    /* Root Port */
+#define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
+#define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
+#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
+#define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
+#define PCI_EXP_DEVCAP         4       /* Device capabilities */
+#define  PCI_EXP_DEVCAP_PAYLOAD        0x07    /* Max_Payload_Size */
+#define  PCI_EXP_DEVCAP_PHANTOM        0x18    /* Phantom functions */
+#define  PCI_EXP_DEVCAP_EXT_TAG        0x20    /* Extended tags */
+#define  PCI_EXP_DEVCAP_L0S    0x1c0   /* L0s Acceptable Latency */
+#define  PCI_EXP_DEVCAP_L1     0xe00   /* L1 Acceptable Latency */
+#define  PCI_EXP_DEVCAP_ATN_BUT        0x1000  /* Attention Button Present */
+#define  PCI_EXP_DEVCAP_ATN_IND        0x2000  /* Attention Indicator Present 
*/
+#define  PCI_EXP_DEVCAP_PWR_IND        0x4000  /* Power Indicator Present */
+#define  PCI_EXP_DEVCAP_PWR_VAL        0x3fc0000 /* Slot Power Limit Value */
+#define  PCI_EXP_DEVCAP_PWR_SCL        0xc000000 /* Slot Power Limit Scale */
+#define PCI_EXP_DEVCTL         8       /* Device Control */
+#define  PCI_EXP_DEVCTL_CERE   0x0001  /* Correctable Error Reporting En. */
+#define  PCI_EXP_DEVCTL_NFERE  0x0002  /* Non-Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_FERE   0x0004  /* Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_URRE   0x0008  /* Unsupported Request Reporting En. */
+#define  PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define  PCI_EXP_DEVCTL_PAYLOAD        0x00e0  /* Max_Payload_Size */
+#define  PCI_EXP_DEVCTL_EXT_TAG        0x0100  /* Extended Tag Field Enable */
+#define  PCI_EXP_DEVCTL_PHANTOM        0x0200  /* Phantom Functions Enable */
+#define  PCI_EXP_DEVCTL_AUX_PME        0x0400  /* Auxiliary Power PM Enable */
+#define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
+#define  PCI_EXP_DEVCTL_READRQ 0x7000  /* Max_Read_Request_Size */
+#define PCI_EXP_DEVSTA         10      /* Device Status */
+#define  PCI_EXP_DEVSTA_CED    0x01    /* Correctable Error Detected */
+#define  PCI_EXP_DEVSTA_NFED   0x02    /* Non-Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_FED    0x04    /* Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_URD    0x08    /* Unsupported Request Detected */
+#define  PCI_EXP_DEVSTA_AUXPD  0x10    /* AUX Power Detected */
+#define  PCI_EXP_DEVSTA_TRPND  0x20    /* Transactions Pending */
+#define PCI_EXP_LNKCAP         12      /* Link Capabilities */
+#define PCI_EXP_LNKCTL         16      /* Link Control */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100        /* Enable clkreq */
+#define PCI_EXP_LNKSTA         18      /* Link Status */
+#define PCI_EXP_SLTCAP         20      /* Slot Capabilities */
+#define PCI_EXP_SLTCTL         24      /* Slot Control */
+#define PCI_EXP_SLTSTA         26      /* Slot Status */
+#define PCI_EXP_RTCTL          28      /* Root Control */
+#define  PCI_EXP_RTCTL_SECEE   0x01    /* System Error on Correctable Error */
+#define  PCI_EXP_RTCTL_SENFEE  0x02    /* System Error on Non-Fatal Error */
+#define  PCI_EXP_RTCTL_SEFEE   0x04    /* System Error on Fatal Error */
+#define  PCI_EXP_RTCTL_PMEIE   0x08    /* PME Interrupt Enable */
+#define  PCI_EXP_RTCTL_CRSSVE  0x10    /* CRS Software Visibility Enable */
+#define PCI_EXP_RTCAP          30      /* Root Capabilities */
+#define PCI_EXP_RTSTA          32      /* Root Status */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID(header)         (header & 0x0000ffff)
+#define PCI_EXT_CAP_VER(header)                ((header >> 16) & 0xf)
+#define PCI_EXT_CAP_NEXT(header)       ((header >> 20) & 0xffc)
+
+#define PCI_EXT_CAP_ID_ERR     1
+#define PCI_EXT_CAP_ID_VC      2
+#define PCI_EXT_CAP_ID_DSN     3
+#define PCI_EXT_CAP_ID_PWR     4
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
+#define  PCI_ERR_UNC_TRAIN     0x00000001      /* Training */
+#define  PCI_ERR_UNC_DLP       0x00000010      /* Data Link Protocol */
+#define  PCI_ERR_UNC_POISON_TLP        0x00001000      /* Poisoned TLP */
+#define  PCI_ERR_UNC_FCP       0x00002000      /* Flow Control Protocol */
+#define  PCI_ERR_UNC_COMP_TIME 0x00004000      /* Completion Timeout */
+#define  PCI_ERR_UNC_COMP_ABORT        0x00008000      /* Completer Abort */
+#define  PCI_ERR_UNC_UNX_COMP  0x00010000      /* Unexpected Completion */
+#define  PCI_ERR_UNC_RX_OVER   0x00020000      /* Receiver Overflow */
+#define  PCI_ERR_UNC_MALF_TLP  0x00040000      /* Malformed TLP */
+#define  PCI_ERR_UNC_ECRC      0x00080000      /* ECRC Error Status */
+#define  PCI_ERR_UNC_UNSUP     0x00100000      /* Unsupported Request */
+#define PCI_ERR_UNCOR_MASK     8       /* Uncorrectable Error Mask */
+       /* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER    12      /* Uncorrectable Error Severity */
+       /* Same bits as above */
+#define PCI_ERR_COR_STATUS     16      /* Correctable Error Status */
+#define  PCI_ERR_COR_RCVR      0x00000001      /* Receiver Error Status */
+#define  PCI_ERR_COR_BAD_TLP   0x00000040      /* Bad TLP Status */
+#define  PCI_ERR_COR_BAD_DLLP  0x00000080      /* Bad DLLP Status */
+#define  PCI_ERR_COR_REP_ROLL  0x00000100      /* REPLAY_NUM Rollover */
+#define  PCI_ERR_COR_REP_TIMER 0x00001000      /* Replay Timer Timeout */
+#define PCI_ERR_COR_MASK       20      /* Correctable Error Mask */
+       /* Same bits as above */
+#define PCI_ERR_CAP            24      /* Advanced Error Capabilities */
+#define  PCI_ERR_CAP_FEP(x)    ((x) & 31)      /* First Error Pointer */
+#define  PCI_ERR_CAP_ECRC_GENC 0x00000020      /* ECRC Generation Capable */
+#define  PCI_ERR_CAP_ECRC_GENE 0x00000040      /* ECRC Generation Enable */
+#define  PCI_ERR_CAP_ECRC_CHKC 0x00000080      /* ECRC Check Capable */
+#define  PCI_ERR_CAP_ECRC_CHKE 0x00000100      /* ECRC Check Enable */
+#define PCI_ERR_HEADER_LOG     28      /* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND   44      /* Root Error Command */
+/* Correctable Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_COR_EN                0x00000001
+/* Non-fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN   0x00000002
+/* Fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_FATAL_EN      0x00000004
+#define PCI_ERR_ROOT_STATUS    48
+#define PCI_ERR_ROOT_COR_RCV           0x00000001      /* ERR_COR Received */
+/* Multi ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV     0x00000002
+/* ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_UNCOR_RCV         0x00000004
+/* Multi ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV   0x00000008
+#define PCI_ERR_ROOT_FIRST_FATAL       0x00000010      /* First Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020      /* Non-Fatal Received */
+#define PCI_ERR_ROOT_FATAL_RCV         0x00000040      /* Fatal Received */
+#define PCI_ERR_ROOT_COR_SRC   52
+#define PCI_ERR_ROOT_SRC       54
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1       4
+#define PCI_VC_PORT_REG2       8
+#define PCI_VC_PORT_CTRL       12
+#define PCI_VC_PORT_STATUS     14
+#define PCI_VC_RES_CAP         16
+#define PCI_VC_RES_CTRL                20
+#define PCI_VC_RES_STATUS      26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR            4       /* Data Select Register */
+#define PCI_PWR_DATA           8       /* Data Register */
+#define  PCI_PWR_DATA_BASE(x)  ((x) & 0xff)        /* Base Power */
+#define  PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3)    /* Data Scale */
+#define  PCI_PWR_DATA_PM_SUB(x)        (((x) >> 10) & 7)   /* PM Sub State */
+#define  PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define  PCI_PWR_DATA_TYPE(x)  (((x) >> 15) & 7)   /* Type */
+#define  PCI_PWR_DATA_RAIL(x)  (((x) >> 18) & 7)   /* Power Rail */
+#define PCI_PWR_CAP            12      /* Capability */
+#define  PCI_PWR_CAP_BUDGET(x) ((x) & 1)       /* Included in system budget */
+
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK       0xE0
+#define HT_CAPTYPE_SLAVE       0x00    /* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST                0x20    /* Host/Secondary link 
configuration */
+
+#define HT_5BIT_CAP_MASK       0xF8
+#define HT_CAPTYPE_IRQ         0x80    /* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40        0xA0    /* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2   /* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP        0x90    /* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF     0x98    /* Extended Configuration Space Access 
*/
+#define HT_CAPTYPE_MSI_MAPPING 0xA8    /* MSI Mapping Capability */
+#define  HT_MSI_FLAGS          0x02            /* Offset to flags */
+#define  HT_MSI_FLAGS_ENABLE   0x1             /* Mapping enable */
+#define  HT_MSI_FLAGS_FIXED    0x2             /* Fixed mapping only */
+#define  HT_MSI_FIXED_ADDR     0x00000000FEE00000ULL   /* Fixed addr */
+#define  HT_MSI_ADDR_LO                0x04            /* Offset to low addr 
bits */
+#define  HT_MSI_ADDR_LO_MASK   0xFFF00000      /* Low address bit mask */
+#define  HT_MSI_ADDR_HI                0x08            /* Offset to high addr 
bits */
+#define HT_CAPTYPE_DIRECT_ROUTE        0xB0    /* Direct routing configuration 
*/
+#define HT_CAPTYPE_VCSET       0xB8    /* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY 0xC0    /* Retry on error configuration */
+#define HT_CAPTYPE_GEN3                0xD0    /* Generation 3 hypertransport 
configuration */
+#define HT_CAPTYPE_PM          0xE0    /* Hypertransport powermanagement 
configuration */
+
+
+#endif /* LINUX_PCI_REGS_H */
diff -r a956ef58b012 -r 844e507d56b8 xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c      Fri Sep 21 17:10:00 2007 +0100
+++ b/xen/arch/x86/setup.c      Fri Sep 21 17:15:47 2007 +0100
@@ -1040,6 +1040,8 @@ void __init __start_xen(unsigned long mb
 
     iommu_setup();
 
+    amd_iommu_detect();
+
     /*
      * We're going to setup domain0 using the module(s) that we stashed safely
      * above our heap. The second module, if present, is an initrd ramdisk.
diff -r a956ef58b012 -r 844e507d56b8 xen/include/asm-x86/amd-iommu.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-x86/amd-iommu.h   Fri Sep 21 17:15:47 2007 +0100
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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
+ */
+#ifndef _ASM_X86_64_AMD_IOMMU_H
+#define _ASM_X86_64_AMD_IOMMU_H
+
+#include <xen/init.h>
+#include <xen/types.h>
+#include <xen/spinlock.h>
+#include <xen/mm.h>
+#include <asm/hvm/svm/amd-iommu-defs.h>
+
+#define iommu_found()           (!list_empty(&amd_iommu_head))
+
+extern int amd_iommu_enabled;
+extern struct list_head amd_iommu_head;
+
+extern int __init amd_iommu_detect(void);
+
+struct table_struct {
+    void *buffer;
+    unsigned long entries;
+    unsigned long alloc_size;
+};
+
+struct amd_iommu {
+    struct list_head list;
+    spinlock_t lock; /* protect iommu */
+
+    int iotlb_support;
+    int ht_tunnel_support;
+    int not_present_cached;
+    u8  revision;
+
+    u8  root_bus;
+    u8  first_devfn;
+    u8  last_devfn;
+
+    int last_downstream_bus;
+    int downstream_bus_present[PCI_MAX_BUS_COUNT];
+
+    void *mmio_base;
+    unsigned long mmio_base_phys;
+
+    struct table_struct dev_table;
+    struct table_struct cmd_buffer;
+    u32 cmd_buffer_tail;
+
+    int exclusion_enabled;
+    unsigned long exclusion_base;
+    unsigned long exclusion_limit;
+};
+
+#endif /* _ASM_X86_64_AMD_IOMMU_H */
diff -r a956ef58b012 -r 844e507d56b8 xen/include/asm-x86/fixmap.h
--- a/xen/include/asm-x86/fixmap.h      Fri Sep 21 17:10:00 2007 +0100
+++ b/xen/include/asm-x86/fixmap.h      Fri Sep 21 17:15:47 2007 +0100
@@ -18,6 +18,7 @@
 #include <asm/page.h>
 #include <xen/kexec.h>
 #include <asm/iommu.h>
+#include <asm/amd-iommu.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
@@ -43,6 +44,8 @@ enum fixed_addresses {
       + ((KEXEC_XEN_NO_PAGES >> 1) * KEXEC_IMAGE_NR) - 1,
     FIX_IOMMU_REGS_BASE_0,
     FIX_IOMMU_REGS_END = FIX_IOMMU_REGS_BASE_0 + MAX_IOMMUS-1,
+    FIX_IOMMU_MMIO_BASE_0,
+    FIX_IOMMU_MMIO_END = FIX_IOMMU_MMIO_BASE_0 + IOMMU_PAGES -1,
     __end_of_fixed_addresses
 };
 
diff -r a956ef58b012 -r 844e507d56b8 xen/include/asm-x86/hvm/iommu.h
--- a/xen/include/asm-x86/hvm/iommu.h   Fri Sep 21 17:10:00 2007 +0100
+++ b/xen/include/asm-x86/hvm/iommu.h   Fri Sep 21 17:15:47 2007 +0100
@@ -42,6 +42,11 @@ struct hvm_iommu {
     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 */
+
+    /* amd iommu support */
+    int domain_id;
+    int paging_mode;
+    void *root_table;
 };
 
 #endif // __ASM_X86_HVM_IOMMU_H__
diff -r a956ef58b012 -r 844e507d56b8 
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h      Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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
+ */
+
+#ifndef _ASM_X86_64_AMD_IOMMU_DEFS_H
+#define _ASM_X86_64_AMD_IOMMU_DEFS_H
+
+/* Reserve some non-mapped pages to handle error conditions.
+ * 'bad_dma_address' will point to these reserved pages, and
+ * the mapping funtions will return 'bad_dma_address' if there
+ * are not enough page table entries available.
+ */
+#define IOMMU_RESERVED_BASE_ADDR       0
+#define IOMMU_RESERVED_PAGES           32
+
+/* IOMMU ComWaitInt polling after issuing a COMPLETION_WAIT command */
+#define COMPLETION_WAIT_DEFAULT_POLLING_COUNT  10
+
+/* IOMMU Command Buffer entries: in power of 2 increments, minimum of 256 */
+#define IOMMU_CMD_BUFFER_DEFAULT_ENTRIES       512
+
+#define BITMAP_ENTRIES_PER_BYTE                8
+
+#define PTE_PER_TABLE_SHIFT            9
+#define PTE_PER_TABLE_SIZE             (1 << PTE_PER_TABLE_SHIFT)
+#define PTE_PER_TABLE_MASK             (~(PTE_PER_TABLE_SIZE - 1))
+#define PTE_PER_TABLE_ALIGN(entries)   \
+       (((entries) + PTE_PER_TABLE_SIZE - 1) & PTE_PER_TABLE_MASK)
+#define PTE_PER_TABLE_ALLOC(entries)   \
+       PAGE_SIZE * (PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT)
+
+/* 0-based aperture order (represents virtual address space for DMA mappings */
+#define APERTURE_ORDER_FOR_32B_APERTURE                0
+#define APERTURE_ORDER_FOR_64MB_APERTURE       1
+#define APERTURE_ORDER_FOR_128MB_APERTURE      2
+#define APERTURE_ORDER_FOR_256MB_APERTURE      3
+#define APERTURE_ORDER_FOR_512MB_APERTURE      4
+#define APERTURE_ORDER_FOR_1GB_APERTURE                5
+#define APERTURE_ORDER_FOR_MAX_APERTURE                
APERTURE_ORDER_FOR_1GB_APERTURE
+
+/* The minimum 32MB aperture requires 2**13 level-1 page table entries */
+#define SHIFT_FOR_MIN_APERTURE         13
+#define PAGES_FROM_APERTURE_ORDER(order)       \
+       ((1 << (order)) << SHIFT_FOR_MIN_APERTURE)
+#define ORDER_FROM_APERTURE_PAGES(pages)       \
+       get_order(((pages) * PAGE_SIZE) >> SHIFT_FOR_MIN_APERTURE)
+
+/*
+ * PCI config-space
+ */
+#define VALID_PCI_VENDOR_ID(id)                (((id) != 0) && ((id) != 
0xFFFF))
+#define IS_PCI_MULTI_FUNCTION(hdr)     ((hdr) & 0x80)
+#define IS_PCI_TYPE0_HEADER(hdr)       (((hdr) & 0x7f) == 0)
+#define IS_PCI_TYPE1_HEADER(hdr)       (((hdr) & 0x7f) == 1)
+
+#define PCI_MAX_BUS_COUNT      256
+#define PCI_MAX_DEV_COUNT      32
+#define PCI_MAX_FUNC_COUNT     8
+#define PCI_MIN_DEVFN          0
+#define PCI_MAX_DEVFN          0xFF
+
+/*
+ * Capability blocks are 4-byte aligned, and must start at >= offset 0x40,
+ * for a max of 48 possible cap_blocks (256 - 0x40 = 192; 192 / 4 = 48)
+ * The lower 2 bits of each pointer are reserved, and must be masked off.
+ */
+#define PCI_MIN_CAP_OFFSET     0x40
+#define PCI_MAX_CAP_BLOCKS     48
+#define PCI_CAP_PTR_MASK       0xFC
+
+/* IOMMU Capability */
+#define PCI_CAP_ID_MASK                0x000000FF
+#define PCI_CAP_ID_SHIFT       0
+#define PCI_CAP_NEXT_PTR_MASK  0x0000FF00
+#define PCI_CAP_NEXT_PTR_SHIFT 8
+#define PCI_CAP_TYPE_MASK      0x00070000
+#define PCI_CAP_TYPE_SHIFT     16
+#define PCI_CAP_REV_MASK       0x00F80000
+#define PCI_CAP_REV_SHIFT      19
+#define PCI_CAP_IOTLB_MASK     0x01000000
+#define PCI_CAP_IOTLB_SHIFT    24
+#define PCI_CAP_HT_TUNNEL_MASK 0x02000000
+#define PCI_CAP_HT_TUNNEL_SHIFT        25
+#define PCI_CAP_NP_CACHE_MASK  0x04000000
+#define PCI_CAP_NP_CACHE_SHIFT 26
+#define PCI_CAP_RESET_MASK     0x80000000
+#define PCI_CAP_RESET_SHIFT    31
+
+#define PCI_CAP_ID_SECURE_DEVICE       0x0F
+#define PCI_CAP_TYPE_IOMMU             0x3
+
+#define PCI_CAP_MMIO_BAR_LOW_OFFSET    0x04
+#define PCI_CAP_MMIO_BAR_HIGH_OFFSET   0x08
+#define PCI_CAP_MMIO_BAR_LOW_MASK      0xFFFFC000
+#define IOMMU_MMIO_REGION_LENGTH       0x4000
+
+#define PCI_CAP_RANGE_OFFSET           0x0C
+#define PCI_CAP_BUS_NUMBER_MASK                0x0000FF00
+#define PCI_CAP_BUS_NUMBER_SHIFT       8
+#define PCI_CAP_FIRST_DEVICE_MASK      0x00FF0000
+#define PCI_CAP_FIRST_DEVICE_SHIFT     16
+#define PCI_CAP_LAST_DEVICE_MASK       0xFF000000
+#define PCI_CAP_LAST_DEVICE_SHIFT      24
+
+/* Device Table */
+#define IOMMU_DEV_TABLE_BASE_LOW_OFFSET                0x00
+#define IOMMU_DEV_TABLE_BASE_HIGH_OFFSET       0x04
+#define IOMMU_DEV_TABLE_BASE_LOW_MASK          0xFFFFF000
+#define IOMMU_DEV_TABLE_BASE_LOW_SHIFT         12
+#define IOMMU_DEV_TABLE_BASE_HIGH_MASK         0x000FFFFF
+#define IOMMU_DEV_TABLE_BASE_HIGH_SHIFT                0
+#define IOMMU_DEV_TABLE_SIZE_MASK              0x000001FF
+#define IOMMU_DEV_TABLE_SIZE_SHIFT             0
+
+#define IOMMU_DEV_TABLE_ENTRIES_PER_BUS                256
+#define IOMMU_DEV_TABLE_ENTRY_SIZE             32
+#define IOMMU_DEV_TABLE_U32_PER_ENTRY          (IOMMU_DEV_TABLE_ENTRY_SIZE / 4)
+
+#define IOMMU_DEV_TABLE_SYS_MGT_DMA_ABORTED    0x0
+#define IOMMU_DEV_TABLE_SYS_MGT_MSG_FORWARDED  0x1
+#define IOMMU_DEV_TABLE_SYS_MGT_INT_FORWARDED  0x2
+#define IOMMU_DEV_TABLE_SYS_MGT_DMA_FORWARDED  0x3
+
+#define IOMMU_DEV_TABLE_IO_CONTROL_ABORTED     0x0
+#define IOMMU_DEV_TABLE_IO_CONTROL_FORWARDED   0x1
+#define IOMMU_DEV_TABLE_IO_CONTROL_TRANSLATED  0x2
+
+#define IOMMU_DEV_TABLE_INT_CONTROL_ABORTED    0x0
+#define IOMMU_DEV_TABLE_INT_CONTROL_FORWARDED  0x1
+#define IOMMU_DEV_TABLE_INT_CONTROL_TRANSLATED 0x2
+
+/* DeviceTable Entry[31:0] */
+#define IOMMU_DEV_TABLE_VALID_MASK                     0x00000001
+#define IOMMU_DEV_TABLE_VALID_SHIFT                    0
+#define IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK         0x00000002
+#define IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT                1
+#define IOMMU_DEV_TABLE_PAGING_MODE_MASK               0x00000E00
+#define IOMMU_DEV_TABLE_PAGING_MODE_SHIFT              9
+#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK                0xFFFFF000
+#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT       12
+
+/* DeviceTable Entry[63:32] */
+#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK       0x000FFFFF
+#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT      0
+#define IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK                0x20000000
+#define IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT       29
+#define IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_MASK       0x40000000
+#define IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_SHIFT      30
+
+/* DeviceTable Entry[95:64] */
+#define IOMMU_DEV_TABLE_DOMAIN_ID_MASK 0x0000FFFF
+#define IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT        0
+
+/* DeviceTable Entry[127:96] */
+#define IOMMU_DEV_TABLE_IOTLB_SUPPORT_MASK             0x00000001
+#define IOMMU_DEV_TABLE_IOTLB_SUPPORT_SHIFT            0
+#define IOMMU_DEV_TABLE_SUPRESS_LOGGED_PAGES_MASK      0x00000002
+#define IOMMU_DEV_TABLE_SUPRESS_LOGGED_PAGES_SHIFT     1
+#define IOMMU_DEV_TABLE_SUPRESS_ALL_PAGES_MASK         0x00000004
+#define IOMMU_DEV_TABLE_SUPRESS_ALL_PAGES_SHIFT                2
+#define IOMMU_DEV_TABLE_IO_CONTROL_MASK                        0x00000018
+#define IOMMU_DEV_TABLE_IO_CONTROL_SHIFT               3
+#define IOMMU_DEV_TABLE_IOTLB_CACHE_HINT_MASK          0x00000020
+#define IOMMU_DEV_TABLE_IOTLB_CACHE_HINT_SHIFT         5
+#define IOMMU_DEV_TABLE_SNOOP_DISABLE_MASK             0x00000040
+#define IOMMU_DEV_TABLE_SNOOP_DISABLE_SHIFT            6
+#define IOMMU_DEV_TABLE_ALLOW_EXCLUSION_MASK           0x00000080
+#define IOMMU_DEV_TABLE_ALLOW_EXCLUSION_SHIFT          7
+#define IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK                0x00000300
+#define IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT       8
+
+/* DeviceTable Entry[159:128] */
+#define IOMMU_DEV_TABLE_INT_VALID_MASK                 0x00000001
+#define IOMMU_DEV_TABLE_INT_VALID_SHIFT                        0
+#define IOMMU_DEV_TABLE_INT_TABLE_LENGTH_MASK          0x0000001E
+#define IOMMU_DEV_TABLE_INT_TABLE_LENGTH_SHIFT         1
+#define IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_MASK         0xFFFFFFC0
+#define IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_SHIFT                6
+
+/* DeviceTable Entry[191:160] */
+#define IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_MASK                0x000FFFFF
+#define IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_SHIFT       0
+#define IOMMU_DEV_TABLE_INIT_PASSTHRU_MASK             0x01000000
+#define IOMMU_DEV_TABLE_INIT_PASSTHRU_SHIFT            24
+#define IOMMU_DEV_TABLE_EINT_PASSTHRU_MASK             0x02000000
+#define IOMMU_DEV_TABLE_EINT_PASSTHRU_SHIFT            25
+#define IOMMU_DEV_TABLE_NMI_PASSTHRU_MASK              0x04000000
+#define IOMMU_DEV_TABLE_NMI_PASSTHRU_SHIFT             26
+#define IOMMU_DEV_TABLE_INT_CONTROL_MASK               0x30000000
+#define IOMMU_DEV_TABLE_INT_CONTROL_SHIFT              28
+#define IOMMU_DEV_TABLE_LINT0_ENABLE_MASK              0x40000000
+#define IOMMU_DEV_TABLE_LINT0_ENABLE_SHIFT             30
+#define IOMMU_DEV_TABLE_LINT1_ENABLE_MASK              0x80000000
+#define IOMMU_DEV_TABLE_LINT1_ENABLE_SHIFT             31
+
+/* Command Buffer */
+#define IOMMU_CMD_BUFFER_BASE_LOW_OFFSET       0x08
+#define IOMMU_CMD_BUFFER_BASE_HIGH_OFFSET      0x0C
+#define IOMMU_CMD_BUFFER_HEAD_OFFSET           0x2000
+#define IOMMU_CMD_BUFFER_TAIL_OFFSET           0x2008
+#define IOMMU_CMD_BUFFER_BASE_LOW_MASK         0xFFFFF000
+#define IOMMU_CMD_BUFFER_BASE_LOW_SHIFT                12
+#define IOMMU_CMD_BUFFER_BASE_HIGH_MASK                0x000FFFFF
+#define IOMMU_CMD_BUFFER_BASE_HIGH_SHIFT       0
+#define IOMMU_CMD_BUFFER_LENGTH_MASK           0x0F000000
+#define IOMMU_CMD_BUFFER_LENGTH_SHIFT          24
+#define IOMMU_CMD_BUFFER_HEAD_MASK             0x0007FFF0
+#define IOMMU_CMD_BUFFER_HEAD_SHIFT            4
+#define IOMMU_CMD_BUFFER_TAIL_MASK             0x0007FFF0
+#define IOMMU_CMD_BUFFER_TAIL_SHIFT            4
+
+#define IOMMU_CMD_BUFFER_ENTRY_SIZE                    16
+#define IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE    8
+#define IOMMU_CMD_BUFFER_U32_PER_ENTRY         (IOMMU_CMD_BUFFER_ENTRY_SIZE / 
4)
+
+#define IOMMU_CMD_OPCODE_MASK                  0xF0000000
+#define IOMMU_CMD_OPCODE_SHIFT                 28
+#define IOMMU_CMD_COMPLETION_WAIT              0x1
+#define IOMMU_CMD_INVALIDATE_DEVTAB_ENTRY      0x2
+#define IOMMU_CMD_INVALIDATE_IOMMU_PAGES       0x3
+#define IOMMU_CMD_INVALIDATE_IOTLB_PAGES       0x4
+#define IOMMU_CMD_INVALIDATE_INT_TABLE         0x5
+
+/* COMPLETION_WAIT command */
+#define IOMMU_COMP_WAIT_DATA_BUFFER_SIZE       8
+#define IOMMU_COMP_WAIT_DATA_BUFFER_ALIGNMENT  8
+#define IOMMU_COMP_WAIT_S_FLAG_MASK            0x00000001
+#define IOMMU_COMP_WAIT_S_FLAG_SHIFT           0
+#define IOMMU_COMP_WAIT_I_FLAG_MASK            0x00000002
+#define IOMMU_COMP_WAIT_I_FLAG_SHIFT           1
+#define IOMMU_COMP_WAIT_F_FLAG_MASK            0x00000004
+#define IOMMU_COMP_WAIT_F_FLAG_SHIFT           2
+#define IOMMU_COMP_WAIT_ADDR_LOW_MASK          0xFFFFFFF8
+#define IOMMU_COMP_WAIT_ADDR_LOW_SHIFT         3
+#define IOMMU_COMP_WAIT_ADDR_HIGH_MASK         0x000FFFFF
+#define IOMMU_COMP_WAIT_ADDR_HIGH_SHIFT                0
+
+/* INVALIDATE_IOMMU_PAGES command */
+#define IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_MASK   0x0000FFFF
+#define IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_SHIFT  0
+#define IOMMU_INV_IOMMU_PAGES_S_FLAG_MASK      0x00000001
+#define IOMMU_INV_IOMMU_PAGES_S_FLAG_SHIFT     0
+#define IOMMU_INV_IOMMU_PAGES_PDE_FLAG_MASK    0x00000002
+#define IOMMU_INV_IOMMU_PAGES_PDE_FLAG_SHIFT   1
+#define IOMMU_INV_IOMMU_PAGES_ADDR_LOW_MASK    0xFFFFF000
+#define IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT   12
+#define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK   0xFFFFFFFF
+#define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT  0
+
+/* Event Log */
+#define IOMMU_EVENT_LOG_BASE_LOW_OFFSET                0x10
+#define IOMMU_EVENT_LOG_BASE_HIGH_OFFSET       0x14
+#define IOMMU_EVENT_LOG_HEAD_OFFSET            0x2010
+#define IOMMU_EVENT_LOG_TAIL_OFFSET            0x2018
+#define IOMMU_EVENT_LOG_BASE_LOW_MASK          0xFFFFF000
+#define IOMMU_EVENT_LOG_BASE_LOW_SHIFT         12
+#define IOMMU_EVENT_LOG_BASE_HIGH_MASK         0x000FFFFF
+#define IOMMU_EVENT_LOG_BASE_HIGH_SHIFT                0
+#define IOMMU_EVENT_LOG_LENGTH_MASK            0x0F000000
+#define IOMMU_EVENT_LOG_LENGTH_SHIFT           24
+#define IOMMU_EVENT_LOG_HEAD_MASK              0x0007FFF0
+#define IOMMU_EVENT_LOG_HEAD_SHIFT             4
+#define IOMMU_EVENT_LOG_TAIL_MASK              0x0007FFF0
+#define IOMMU_EVENT_LOG_TAIL_SHIFT             4
+
+#define IOMMU_EVENT_LOG_ENTRY_SIZE                     16
+#define IOMMU_EVENT_LOG_POWER_OF2_ENTRIES_PER_PAGE     8
+#define IOMMU_EVENT_LOG_U32_PER_ENTRY  (IOMMU_EVENT_LOG_ENTRY_SIZE / 4)
+
+#define IOMMU_EVENT_CODE_MASK                  0xF0000000
+#define IOMMU_EVENT_CODE_SHIFT                 28
+#define IOMMU_EVENT_ILLEGAL_DEV_TABLE_ENTRY    0x1
+#define IOMMU_EVENT_IO_PAGE_FALT               0x2
+#define IOMMU_EVENT_DEV_TABLE_HW_ERROR         0x3
+#define IOMMU_EVENT_PAGE_TABLE_HW_ERROR                0x4
+#define IOMMU_EVENT_ILLEGAL_COMMAND_ERROR      0x5
+#define IOMMU_EVENT_COMMAND_HW_ERROR           0x6
+#define IOMMU_EVENT_IOTLB_INV_TIMEOUT          0x7
+#define IOMMU_EVENT_INVALID_DEV_REQUEST                0x8
+
+/* Control Register */
+#define IOMMU_CONTROL_MMIO_OFFSET                      0x18
+#define IOMMU_CONTROL_TRANSLATION_ENABLE_MASK          0x00000001
+#define IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT         0
+#define IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_MASK       0x00000002
+#define IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT      1
+#define IOMMU_CONTROL_EVENT_LOG_ENABLE_MASK            0x00000004
+#define IOMMU_CONTROL_EVENT_LOG_ENABLE_SHIFT           2
+#define IOMMU_CONTROL_EVENT_LOG_INT_MASK               0x00000008
+#define IOMMU_CONTROL_EVENT_LOG_INT_SHIFT              3
+#define IOMMU_CONTROL_COMP_WAIT_INT_MASK               0x00000010
+#define IOMMU_CONTROL_COMP_WAIT_INT_SHIFT              4
+#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_MASK   0x00000020
+#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_SHIFT  5
+#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_MASK                0x000000C0
+#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_SHIFT       6
+#define IOMMU_CONTROL_PASS_POSTED_WRITE_MASK           0x00000100
+#define IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT          8
+#define IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_MASK      0x00000200
+#define IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_SHIFT     9
+#define IOMMU_CONTROL_COHERENT_MASK                    0x00000400
+#define IOMMU_CONTROL_COHERENT_SHIFT                   10
+#define IOMMU_CONTROL_ISOCHRONOUS_MASK                 0x00000800
+#define IOMMU_CONTROL_ISOCHRONOUS_SHIFT                        11
+#define IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_MASK       0x00001000
+#define IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT      12
+#define IOMMU_CONTROL_RESTART_MASK                     0x80000000
+#define IOMMU_CONTROL_RESTART_SHIFT                    31
+
+/* Exclusion Register */
+#define IOMMU_EXCLUSION_BASE_LOW_OFFSET                0x20
+#define IOMMU_EXCLUSION_BASE_HIGH_OFFSET       0x24
+#define IOMMU_EXCLUSION_LIMIT_LOW_OFFSET       0x28
+#define IOMMU_EXCLUSION_LIMIT_HIGH_OFFSET      0x2C
+#define IOMMU_EXCLUSION_BASE_LOW_MASK          0xFFFFF000
+#define IOMMU_EXCLUSION_BASE_LOW_SHIFT         12
+#define IOMMU_EXCLUSION_BASE_HIGH_MASK         0xFFFFFFFF
+#define IOMMU_EXCLUSION_BASE_HIGH_SHIFT                0
+#define IOMMU_EXCLUSION_RANGE_ENABLE_MASK      0x00000001
+#define IOMMU_EXCLUSION_RANGE_ENABLE_SHIFT     0
+#define IOMMU_EXCLUSION_ALLOW_ALL_MASK         0x00000002
+#define IOMMU_EXCLUSION_ALLOW_ALL_SHIFT                1
+#define IOMMU_EXCLUSION_LIMIT_LOW_MASK         0xFFFFF000
+#define IOMMU_EXCLUSION_LIMIT_LOW_SHIFT                12
+#define IOMMU_EXCLUSION_LIMIT_HIGH_MASK                0xFFFFFFFF
+#define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT       0
+
+/* Status Register*/
+#define IOMMU_STATUS_MMIO_OFFSET               0x2020
+#define IOMMU_STATUS_EVENT_OVERFLOW_MASK       0x00000001
+#define IOMMU_STATUS_EVENT_OVERFLOW_SHIFT      0
+#define IOMMU_STATUS_EVENT_LOG_INT_MASK                0x00000002
+#define IOMMU_STATUS_EVENT_LOG_INT_SHIFT       1
+#define IOMMU_STATUS_COMP_WAIT_INT_MASK                0x00000004
+#define IOMMU_STATUS_COMP_WAIT_INT_SHIFT       2
+#define IOMMU_STATUS_EVENT_LOG_RUN_MASK                0x00000008
+#define IOMMU_STATUS_EVENT_LOG_RUN_SHIFT       3
+#define IOMMU_STATUS_CMD_BUFFER_RUN_MASK       0x00000010
+#define IOMMU_STATUS_CMD_BUFFER_RUN_SHIFT      4
+
+/* I/O Page Table */
+#define IOMMU_PAGE_TABLE_ENTRY_SIZE    8
+#define IOMMU_PAGE_TABLE_U32_PER_ENTRY (IOMMU_PAGE_TABLE_ENTRY_SIZE / 4)
+#define IOMMU_PAGE_TABLE_ALIGNMENT     4096
+
+#define IOMMU_PTE_PRESENT_MASK                 0x00000001
+#define IOMMU_PTE_PRESENT_SHIFT                        0
+#define IOMMU_PTE_NEXT_LEVEL_MASK              0x00000E00
+#define IOMMU_PTE_NEXT_LEVEL_SHIFT             9
+#define IOMMU_PTE_ADDR_LOW_MASK                        0xFFFFF000
+#define IOMMU_PTE_ADDR_LOW_SHIFT               12
+#define IOMMU_PTE_ADDR_HIGH_MASK               0x000FFFFF
+#define IOMMU_PTE_ADDR_HIGH_SHIFT              0
+#define IOMMU_PTE_U_MASK                       0x08000000
+#define IOMMU_PTE_U_SHIFT                      7
+#define IOMMU_PTE_FC_MASK                      0x10000000
+#define IOMMU_PTE_FC_SHIFT                     28
+#define IOMMU_PTE_IO_READ_PERMISSION_MASK      0x20000000
+#define IOMMU_PTE_IO_READ_PERMISSION_SHIFT     29
+#define IOMMU_PTE_IO_WRITE_PERMISSION_MASK     0x40000000
+#define IOMMU_PTE_IO_WRITE_PERMISSION_SHIFT    30
+
+/* I/O Page Directory */
+#define IOMMU_PAGE_DIRECTORY_ENTRY_SIZE                8
+#define IOMMU_PAGE_DIRECTORY_ALIGNMENT         4096
+#define IOMMU_PDE_PRESENT_MASK                 0x00000001
+#define IOMMU_PDE_PRESENT_SHIFT                        0
+#define IOMMU_PDE_NEXT_LEVEL_MASK              0x00000E00
+#define IOMMU_PDE_NEXT_LEVEL_SHIFT             9
+#define IOMMU_PDE_ADDR_LOW_MASK                        0xFFFFF000
+#define IOMMU_PDE_ADDR_LOW_SHIFT               12
+#define IOMMU_PDE_ADDR_HIGH_MASK               0x000FFFFF
+#define IOMMU_PDE_ADDR_HIGH_SHIFT              0
+#define IOMMU_PDE_IO_READ_PERMISSION_MASK      0x20000000
+#define IOMMU_PDE_IO_READ_PERMISSION_SHIFT     29
+#define IOMMU_PDE_IO_WRITE_PERMISSION_MASK     0x40000000
+#define IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT    30
+
+/* Paging modes */
+#define IOMMU_PAGING_MODE_DISABLED     0x0
+#define IOMMU_PAGING_MODE_LEVEL_0      0x0
+#define IOMMU_PAGING_MODE_LEVEL_1      0x1
+#define IOMMU_PAGING_MODE_LEVEL_2      0x2
+#define IOMMU_PAGING_MODE_LEVEL_3      0x3
+#define IOMMU_PAGING_MODE_LEVEL_4      0x4
+#define IOMMU_PAGING_MODE_LEVEL_5      0x5
+#define IOMMU_PAGING_MODE_LEVEL_6      0x6
+#define IOMMU_PAGING_MODE_LEVEL_7      0x7
+
+/* Flags */
+#define IOMMU_CONTROL_DISABLED 0
+#define IOMMU_CONTROL_ENABLED  1
+
+#define MMIO_PAGES_PER_IOMMU        (IOMMU_MMIO_REGION_LENGTH / PAGE_SIZE_4K)
+#define IOMMU_PAGES                 (MMIO_PAGES_PER_IOMMU * MAX_AMD_IOMMUS)
+#define DEFAULT_DOMAIN_ADDRESS_WIDTH    48
+#define MAX_AMD_IOMMUS                  32
+#define IOMMU_PAGE_TABLE_LEVEL_3        3
+#define IOMMU_PAGE_TABLE_LEVEL_4        4
+#define IOMMU_IO_WRITE_ENABLED          1
+#define IOMMU_IO_READ_ENABLED           1
+
+#endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
diff -r a956ef58b012 -r 844e507d56b8 
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h     Fri Sep 21 17:15:47 
2007 +0100
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Author: Leo Duran <leo.duran@xxxxxxx>
+ * Author: Wei Wang <wei.wang2@xxxxxxx> - adapted to xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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
+ */
+
+#ifndef _ASM_X86_64_AMD_IOMMU_PROTO_H
+#define _ASM_X86_64_AMD_IOMMU_PROTO_H
+
+#include <asm/amd-iommu.h>
+
+#define for_each_amd_iommu(amd_iommu) \
+    list_for_each_entry(amd_iommu, \
+        &amd_iommu_head, list)
+
+#define DMA_32BIT_MASK  0x00000000ffffffffULL
+#define PAGE_ALIGN(addr)    (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
+#define PAGE_SHIFT_4K                   (12)
+#define PAGE_SIZE_4K                    (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K                    (((u64)-1) << PAGE_SHIFT_4K)
+
+typedef int (*iommu_detect_callback_ptr_t)(u8 bus, u8 dev, u8 func, u8 
cap_ptr);
+
+/* amd-iommu-detect functions */
+int __init scan_for_iommu(iommu_detect_callback_ptr_t iommu_detect_callback);
+int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
+           struct amd_iommu *iommu);
+int __init get_iommu_last_downstream_bus(struct amd_iommu *iommu);
+
+/* amd-iommu-init functions */
+int __init map_iommu_mmio_region(struct amd_iommu *iommu);
+void __init unmap_iommu_mmio_region(struct amd_iommu *iommu);
+void __init register_iommu_dev_table_in_mmio_space(struct amd_iommu *iommu);
+void __init register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu);
+void __init enable_iommu(struct amd_iommu *iommu);
+
+/* mapping functions */
+int amd_iommu_map_page(struct domain *d, unsigned long gfn,
+        unsigned long mfn);
+int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
+
+/* device table functions */
+void amd_iommu_set_dev_table_entry(u32 *dte,
+        u64 root_ptr, u16 domain_id, u8 paging_mode);
+
+/* send cmd to iommu */
+int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]);
+
+/* iommu domain funtions */
+int amd_iommu_domain_init(struct domain *domain);
+void amd_iommu_setup_domain_device(struct domain *domain,
+    struct amd_iommu *iommu, int requestor_id);
+
+/* find iommu for bdf */
+struct amd_iommu *find_iommu_for_device(int bus, int devfn);
+
+static inline u32 get_field_from_reg_u32(u32 reg_value, u32 mask, u32 shift)
+{
+    u32 field;
+    field = (reg_value & mask) >> shift;
+    return field;
+}
+
+static inline u32 set_field_in_reg_u32(u32 field, u32 reg_value,
+        u32 mask, u32 shift, u32 *reg)
+{
+    reg_value &= ~mask;
+    reg_value |= (field << shift) & mask;
+    if (reg)
+        *reg = reg_value;
+    return reg_value;
+}
+
+#endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.