# 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
|