# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1203606397 0
# Node ID 591cfd37bd5409d534034c64a3356a9b492b23bb
# Parent f1a107ec62b6e8829981ff05fb988047174de479
Move vtd and amd iommu code to arch-generic location.
Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
---
xen/arch/x86/hvm/svm/amd_iommu/Makefile | 4
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c | 215 --
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c | 147 -
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c | 450 ----
xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c | 578 -----
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/hvm/vmx/vtd/Makefile | 6
xen/arch/x86/hvm/vmx/vtd/dmar.c | 625 ------
xen/arch/x86/hvm/vmx/vtd/dmar.h | 104 -
xen/arch/x86/hvm/vmx/vtd/extern.h | 51
xen/arch/x86/hvm/vmx/vtd/intel-iommu.c | 2178 ----------------------
xen/arch/x86/hvm/vmx/vtd/intremap.c | 340 ---
xen/arch/x86/hvm/vmx/vtd/io.c | 296 --
xen/arch/x86/hvm/vmx/vtd/msi.h | 127 -
xen/arch/x86/hvm/vmx/vtd/pci-direct.h | 48
xen/arch/x86/hvm/vmx/vtd/pci_regs.h | 449 ----
xen/arch/x86/hvm/vmx/vtd/qinval.c | 456 ----
xen/arch/x86/hvm/vmx/vtd/utils.c | 338 ---
xen/arch/x86/hvm/vmx/vtd/vtd.h | 54
xen/arch/x86/Rules.mk | 4
xen/arch/x86/hvm/svm/Makefile | 2
xen/arch/x86/hvm/vmx/Makefile | 2
xen/drivers/Makefile | 1
xen/drivers/passthrough/Makefile | 2
xen/drivers/passthrough/amd/Makefile | 4
xen/drivers/passthrough/amd/iommu_detect.c | 215 ++
xen/drivers/passthrough/amd/iommu_init.c | 147 +
xen/drivers/passthrough/amd/iommu_map.c | 450 ++++
xen/drivers/passthrough/amd/pci_amd_iommu.c | 578 +++++
xen/drivers/passthrough/pci-direct.h | 48
xen/drivers/passthrough/pci_regs.h | 530 +++++
xen/drivers/passthrough/vtd/Makefile | 6
xen/drivers/passthrough/vtd/dmar.c | 625 ++++++
xen/drivers/passthrough/vtd/dmar.h | 104 +
xen/drivers/passthrough/vtd/extern.h | 51
xen/drivers/passthrough/vtd/intremap.c | 339 +++
xen/drivers/passthrough/vtd/io.c | 296 ++
xen/drivers/passthrough/vtd/iommu.c | 2178 ++++++++++++++++++++++
xen/drivers/passthrough/vtd/msi.h | 127 +
xen/drivers/passthrough/vtd/qinval.c | 455 ++++
xen/drivers/passthrough/vtd/utils.c | 337 +++
xen/drivers/passthrough/vtd/vtd.h | 54
43 files changed, 6550 insertions(+), 7032 deletions(-)
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/Rules.mk
--- a/xen/arch/x86/Rules.mk Thu Feb 21 14:50:27 2008 +0000
+++ b/xen/arch/x86/Rules.mk Thu Feb 21 15:06:37 2008 +0000
@@ -39,7 +39,9 @@ CFLAGS += -DCONFIG_X86_SUPERVISOR_MODE_K
CFLAGS += -DCONFIG_X86_SUPERVISOR_MODE_KERNEL=1
endif
-ifeq ($(XEN_TARGET_ARCH),x86_32)
+x86 := y
+
+ifeq ($(TARGET_SUBARCH),x86_32)
x86_32 := y
x86_64 := n
endif
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/svm/Makefile
--- a/xen/arch/x86/hvm/svm/Makefile Thu Feb 21 14:50:27 2008 +0000
+++ b/xen/arch/x86/hvm/svm/Makefile Thu Feb 21 15:06:37 2008 +0000
@@ -1,7 +1,5 @@ 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 f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/svm/amd_iommu/Makefile
--- a/xen/arch/x86/hvm/svm/amd_iommu/Makefile Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-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 f1a107ec62b6 -r 591cfd37bd54
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c
--- a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c Thu Feb 21 14:50:27
2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,215 +0,0 @@
-/*
- * 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 <xen/config.h>
-#include <xen/errno.h>
-#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;
-
-#if HACK_BIOS_SETTINGS
- /* 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 */
-#endif
-
- 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%"PRIx64"\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 f1a107ec62b6 -r 591cfd37bd54
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c
--- a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c Thu Feb 21 14:50:27
2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-/*
- * 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 <xen/config.h>
-#include <xen/errno.h>
-#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 f1a107ec62b6 -r 591cfd37bd54
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c
--- a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c Thu Feb 21 14:50:27
2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,450 +0,0 @@
-/*
- * 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 <xen/sched.h>
-#include <asm/hvm/iommu.h>
-#include <asm/amd-iommu.h>
-#include <asm/hvm/svm/amd-iommu-proto.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;
-
- 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;
-
- 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[])
-{
- 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);
-}
-
-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: Warning:"
- " ComWaitInt bit did not assert!\n");
- }
-}
-
-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;
-}
-
-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));
-}
-
-void invalidate_dev_table_entry(struct amd_iommu *iommu,
- u16 device_id)
-{
- u32 cmd[4], entry;
-
- cmd[3] = cmd[2] = 0;
- set_field_in_reg_u32(device_id, 0,
- IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_MASK,
- IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_SHIFT, &entry);
- cmd[0] = entry;
-
- set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_DEVTAB_ENTRY, 0,
- IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT,
- &entry);
- cmd[1] = entry;
-
- send_iommu_command(iommu, cmd);
-}
-
-int amd_iommu_is_dte_page_translation_valid(u32 *entry)
-{
- return (get_field_from_reg_u32(entry[0],
- IOMMU_DEV_TABLE_VALID_MASK,
- IOMMU_DEV_TABLE_VALID_SHIFT) &&
- get_field_from_reg_u32(entry[0],
- IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
- IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT));
-}
-
-static void *get_pte_from_page_tables(void *table, int level,
- unsigned long io_pfn)
-{
- unsigned long offset;
- void *pde = NULL;
-
- BUG_ON(table == NULL);
-
- while ( level > 0 )
- {
- 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) )
- {
- void *next_table = alloc_xenheap_page();
- if ( next_table == NULL )
- return NULL;
- memset(next_table, 0, PAGE_SIZE);
- if ( *(u64 *)pde == 0 )
- {
- unsigned long 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 )
- {
- dprintk(XENLOG_ERR,
- "AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", gfn);
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return -EIO;
- }
-
- set_page_table_entry_present((u32 *)pte, maddr, iw, ir);
-
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return 0;
-}
-
-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 )
- {
- dprintk(XENLOG_ERR,
- "AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", gfn);
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return -EIO;
- }
-
- /* 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;
-}
diff -r f1a107ec62b6 -r 591cfd37bd54
xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c
--- a/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c Thu Feb 21 14:50:27
2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,578 +0,0 @@
-/*
- * 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;
-
- 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, *next;
-
- list_for_each_entry_safe ( iommu, next, &amd_iommu_head, list )
- {
- 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);
-
- if ( !amd_iommu_is_dte_page_translation_valid((u32 *)dte) )
- {
- spin_lock_irqsave(&iommu->lock, flags);
-
- amd_iommu_set_dev_table_entry(
- (u32 *)dte,
- root_ptr, hd->domain_id, hd->paging_mode);
- invalidate_dev_table_entry(iommu, requestor_id);
- flush_command_buffer(iommu);
- dprintk(XENLOG_INFO, "AMD IOMMU: Set DTE req_id:%x, "
- "root_ptr:%"PRIx64", 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 ( 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 */
- unsigned long flags;
-
- spin_lock_irqsave(&hd->mapping_lock, flags);
- if ( !hd->root_table )
- {
- hd->root_table = (void *)alloc_xenheap_page();
- if ( !hd->root_table )
- goto error_out;
- memset((u8*)hd->root_table, 0, PAGE_SIZE);
- }
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
-
- return 0;
- error_out:
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return -ENOMEM;
-}
-
-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);
-
- /* allocate page directroy */
- if ( allocate_domain_resources(hd) != 0 )
- {
- deallocate_domain_resources(hd);
- return -ENOMEM;
- }
-
- 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;
-}
-
-static void amd_iommu_disable_domain_device(
- struct domain *domain, struct amd_iommu *iommu, u16 requestor_id)
-{
- void *dte;
- unsigned long flags;
-
- dte = iommu->dev_table.buffer +
- (requestor_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
-
- if ( amd_iommu_is_dte_page_translation_valid((u32 *)dte) )
- {
- spin_lock_irqsave(&iommu->lock, flags);
- memset (dte, 0, IOMMU_DEV_TABLE_ENTRY_SIZE);
- invalidate_dev_table_entry(iommu, requestor_id);
- flush_command_buffer(iommu);
- dprintk(XENLOG_INFO , "AMD IOMMU: disable DTE 0x%x,"
- " domain_id:%d, paging_mode:%d\n",
- requestor_id, domain_hvm_iommu(domain)->domain_id,
- domain_hvm_iommu(domain)->paging_mode);
- spin_unlock_irqrestore(&iommu->lock, flags);
- }
-}
-
-extern void pdev_flr(u8 bus, u8 devfn);
-
-static int reassign_device( struct domain *source, struct domain *target,
- u8 bus, u8 devfn)
-{
- struct hvm_iommu *source_hd = domain_hvm_iommu(source);
- struct hvm_iommu *target_hd = domain_hvm_iommu(target);
- struct pci_dev *pdev;
- struct amd_iommu *iommu;
- int req_id, bdf;
- unsigned long flags;
-
- for_each_pdev( source, pdev )
- {
- if ( (pdev->bus != bus) || (pdev->devfn != devfn) )
- continue;
-
- pdev->bus = bus;
- pdev->devfn = devfn;
-
- bdf = (bus << 8) | devfn;
- req_id = requestor_id_from_bdf(bdf);
- iommu = find_iommu_for_device(bus, devfn);
-
- if ( iommu )
- {
- amd_iommu_disable_domain_device(source, iommu, req_id);
- /* Move pci device from the source domain to target domain. */
- spin_lock_irqsave(&source_hd->iommu_list_lock, flags);
- spin_lock_irqsave(&target_hd->iommu_list_lock, flags);
- list_move(&pdev->list, &target_hd->pdev_list);
- spin_unlock_irqrestore(&target_hd->iommu_list_lock, flags);
- spin_unlock_irqrestore(&source_hd->iommu_list_lock, flags);
-
- amd_iommu_setup_domain_device(target, iommu, req_id);
- gdprintk(XENLOG_INFO ,
- "AMD IOMMU: reassign %x:%x.%x domain %d -> domain %d\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
- source->domain_id, target->domain_id);
- }
- else
- {
- gdprintk(XENLOG_ERR , "AMD IOMMU: fail to find iommu."
- " %x:%x.%x cannot be assigned to domain %d\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn), target->domain_id);
- return -ENODEV;
- }
-
- break;
- }
- return 0;
-}
-
-int amd_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
-{
- pdev_flr(bus, devfn);
- return reassign_device(dom0, d, bus, devfn);
-}
-
-static void release_domain_devices(struct domain *d)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
- struct pci_dev *pdev;
-
- while ( !list_empty(&hd->pdev_list) )
- {
- pdev = list_entry(hd->pdev_list.next, typeof(*pdev), list);
- pdev_flr(pdev->bus, pdev->devfn);
- gdprintk(XENLOG_INFO ,
- "AMD IOMMU: release devices %x:%x.%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- reassign_device(d, dom0, pdev->bus, pdev->devfn);
- }
-}
-
-static void deallocate_next_page_table(void *table, unsigned long index,
- int level)
-{
- unsigned long next_index;
- void *next_table, *pde;
- int next_level;
-
- pde = table + (index * IOMMU_PAGE_TABLE_ENTRY_SIZE);
- next_table = amd_iommu_get_vptr_from_page_table_entry((u32 *)pde);
-
- if ( next_table )
- {
- next_level = level - 1;
- if ( next_level > 1 )
- {
- next_index = 0;
- do
- {
- deallocate_next_page_table(next_table,
- next_index, next_level);
- ++next_index;
- } while (next_index < PTE_PER_TABLE_SIZE);
- }
-
- free_xenheap_page(next_table);
- }
-}
-
-static void deallocate_iommu_page_tables(struct domain *d)
-{
- unsigned long index;
- struct hvm_iommu *hd = domain_hvm_iommu(d);
-
- if ( hd ->root_table )
- {
- index = 0;
- do
- {
- deallocate_next_page_table(hd->root_table,
- index, hd->paging_mode);
- ++index;
- } while ( index < PTE_PER_TABLE_SIZE );
-
- free_xenheap_page(hd ->root_table);
- }
-
- hd ->root_table = NULL;
-}
-
-void amd_iommu_domain_destroy(struct domain *d)
-{
- if ( !amd_iommu_enabled )
- return;
-
- deallocate_iommu_page_tables(d);
- release_domain_devices(d);
-}
-
-void amd_iommu_return_device(struct domain *s, struct domain *t, u8 bus, u8
devfn)
-{
- pdev_flr(bus, devfn);
- reassign_device(s, t, bus, devfn);
-}
-
-struct iommu_ops amd_iommu_ops = {
- .init = amd_iommu_domain_init,
- .assign_device = amd_iommu_assign_device,
- .teardown = amd_iommu_domain_destroy,
- .map_page = amd_iommu_map_page,
- .unmap_page = amd_iommu_unmap_page,
- .reassign_device = amd_iommu_return_device,
-};
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/svm/amd_iommu/pci-direct.h
--- a/xen/arch/x86/hvm/svm/amd_iommu/pci-direct.h Thu Feb 21 14:50:27
2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#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 f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/svm/amd_iommu/pci_regs.h
--- a/xen/arch/x86/hvm/svm/amd_iommu/pci_regs.h Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,513 +0,0 @@
-/*
- * 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 f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/Makefile
--- a/xen/arch/x86/hvm/vmx/Makefile Thu Feb 21 14:50:27 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/Makefile Thu Feb 21 15:06:37 2008 +0000
@@ -1,5 +1,3 @@ subdir-y += vtd
-subdir-y += vtd
-
subdir-$(x86_32) += x86_32
subdir-$(x86_64) += x86_64
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/Makefile
--- a/xen/arch/x86/hvm/vmx/vtd/Makefile Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-obj-y += intel-iommu.o
-obj-y += dmar.o
-obj-y += utils.o
-obj-y += io.o
-obj-y += qinval.o
-obj-y += intremap.o
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/dmar.c
--- a/xen/arch/x86/hvm/vmx/vtd/dmar.c Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,625 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Ashok Raj <ashok.raj@xxxxxxxxx>
- * Copyright (C) Shaohua Li <shaohua.li@xxxxxxxxx>
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx> - adapted to xen
- */
-
-#include <xen/init.h>
-#include <xen/bitmap.h>
-#include <xen/kernel.h>
-#include <xen/acpi.h>
-#include <xen/mm.h>
-#include <xen/xmalloc.h>
-#include <asm/string.h>
-#include "dmar.h"
-#include "pci-direct.h"
-#include "pci_regs.h"
-
-int vtd_enabled;
-boolean_param("vtd", vtd_enabled);
-
-#undef PREFIX
-#define PREFIX VTDPREFIX "ACPI DMAR:"
-#define DEBUG
-
-#define MIN_SCOPE_LEN (sizeof(struct acpi_pci_path) + \
- sizeof(struct acpi_dev_scope))
-
-LIST_HEAD(acpi_drhd_units);
-LIST_HEAD(acpi_rmrr_units);
-LIST_HEAD(acpi_atsr_units);
-
-u8 dmar_host_address_width;
-
-static int __init acpi_register_drhd_unit(struct acpi_drhd_unit *drhd)
-{
- /*
- * add INCLUDE_ALL at the tail, so scan the list will find it at
- * the very end.
- */
- if ( drhd->include_all )
- list_add_tail(&drhd->list, &acpi_drhd_units);
- else
- list_add(&drhd->list, &acpi_drhd_units);
- return 0;
-}
-
-static int __init acpi_register_rmrr_unit(struct acpi_rmrr_unit *rmrr)
-{
- list_add(&rmrr->list, &acpi_rmrr_units);
- return 0;
-}
-
-static int acpi_ioapic_device_match(
- struct list_head *ioapic_list, unsigned int apic_id)
-{
- struct acpi_ioapic_unit *ioapic;
- list_for_each_entry( ioapic, ioapic_list, list ) {
- if (ioapic->apic_id == apic_id)
- return 1;
- }
- return 0;
-}
-
-struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id)
-{
- struct acpi_drhd_unit *drhd;
- list_for_each_entry( drhd, &acpi_drhd_units, list ) {
- if ( acpi_ioapic_device_match(&drhd->ioapic_list, apic_id) ) {
- dprintk(XENLOG_INFO VTDPREFIX,
- "ioapic_to_drhd: drhd->address = %lx\n",
- drhd->address);
- return drhd;
- }
- }
- return NULL;
-}
-
-struct iommu * ioapic_to_iommu(unsigned int apic_id)
-{
- struct acpi_drhd_unit *drhd;
-
- list_for_each_entry( drhd, &acpi_drhd_units, list ) {
- if ( acpi_ioapic_device_match(&drhd->ioapic_list, apic_id) ) {
- dprintk(XENLOG_INFO VTDPREFIX,
- "ioapic_to_iommu: drhd->address = %lx\n",
- drhd->address);
- return drhd->iommu;
- }
- }
- dprintk(XENLOG_INFO VTDPREFIX, "returning NULL\n");
- return NULL;
-}
-
-static int acpi_pci_device_match(struct pci_dev *devices, int cnt,
- struct pci_dev *dev)
-{
- int i;
-
- for ( i = 0; i < cnt; i++ )
- {
- if ( (dev->bus == devices->bus) &&
- (dev->devfn == devices->devfn) )
- return 1;
- devices++;
- }
- return 0;
-}
-
-static int __init acpi_register_atsr_unit(struct acpi_atsr_unit *atsr)
-{
- /*
- * add ALL_PORTS at the tail, so scan the list will find it at
- * the very end.
- */
- if ( atsr->all_ports )
- list_add_tail(&atsr->list, &acpi_atsr_units);
- else
- list_add(&atsr->list, &acpi_atsr_units);
- return 0;
-}
-
-struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *dev)
-{
- struct acpi_drhd_unit *drhd;
- struct acpi_drhd_unit *include_all_drhd;
-
- include_all_drhd = NULL;
- list_for_each_entry ( drhd, &acpi_drhd_units, list )
- {
- if ( drhd->include_all )
- {
- include_all_drhd = drhd;
- continue;
- }
-
- if ( acpi_pci_device_match(drhd->devices,
- drhd->devices_cnt, dev) )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "acpi_find_matched_drhd_unit: drhd->address = %lx\n",
- drhd->address);
- return drhd;
- }
- }
-
- if ( include_all_drhd )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "acpi_find_matched_drhd_unit:include_all_drhd->addr = %lx\n",
- include_all_drhd->address);
- return include_all_drhd;
- }
-
- return NULL;
-}
-
-struct acpi_rmrr_unit * acpi_find_matched_rmrr_unit(struct pci_dev *dev)
-{
- struct acpi_rmrr_unit *rmrr;
-
- list_for_each_entry ( rmrr, &acpi_rmrr_units, list )
- {
- if ( acpi_pci_device_match(rmrr->devices,
- rmrr->devices_cnt, dev) )
- return rmrr;
- }
-
- return NULL;
-}
-
-struct acpi_atsr_unit * acpi_find_matched_atsr_unit(struct pci_dev *dev)
-{
- struct acpi_atsr_unit *atsru;
- struct acpi_atsr_unit *all_ports_atsru;
-
- all_ports_atsru = NULL;
- list_for_each_entry ( atsru, &acpi_atsr_units, list )
- {
- if ( atsru->all_ports )
- all_ports_atsru = atsru;
- if ( acpi_pci_device_match(atsru->devices,
- atsru->devices_cnt, dev) )
- return atsru;
- }
-
- if ( all_ports_atsru )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "acpi_find_matched_atsr_unit: all_ports_atsru\n");
- return all_ports_atsru;;
- }
-
- return NULL;
-}
-
-static int scope_device_count(void *start, void *end)
-{
- struct acpi_dev_scope *scope;
- u8 bus, sub_bus, sec_bus;
- struct acpi_pci_path *path;
- int depth, count = 0;
- u8 dev, func;
- u32 l;
-
- while ( start < end )
- {
- scope = start;
- if ( (scope->length < MIN_SCOPE_LEN) ||
- (scope->dev_type >= ACPI_DEV_ENTRY_COUNT) )
- {
- dprintk(XENLOG_WARNING VTDPREFIX, "Invalid device scope\n");
- return -EINVAL;
- }
-
- path = (struct acpi_pci_path *)(scope + 1);
- bus = scope->start_bus;
- depth = (scope->length - sizeof(struct acpi_dev_scope))
- / sizeof(struct acpi_pci_path);
- while ( --depth )
- {
- bus = read_pci_config_byte(
- bus, path->dev, path->fn, PCI_SECONDARY_BUS);
- path++;
- }
-
- if ( scope->dev_type == ACPI_DEV_ENDPOINT )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "found endpoint: bdf = %x:%x:%x\n",
- bus, path->dev, path->fn);
- count++;
- }
- else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "found bridge: bdf = %x:%x:%x\n",
- bus, path->dev, path->fn);
- sec_bus = read_pci_config_byte(
- bus, path->dev, path->fn, PCI_SECONDARY_BUS);
- sub_bus = read_pci_config_byte(
- bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
-
- while ( sec_bus <= sub_bus )
- {
- for ( dev = 0; dev < 32; dev++ )
- {
- for ( func = 0; func < 8; func++ )
- {
- l = read_pci_config(
- sec_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 )
- break;
- count++;
- }
- }
- sec_bus++;
- }
- }
- else if ( scope->dev_type == ACPI_DEV_IOAPIC )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "found IOAPIC: bdf = %x:%x:%x\n",
- bus, path->dev, path->fn);
- count++;
- }
- else
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "found MSI HPET: bdf = %x:%x:%x\n",
- bus, path->dev, path->fn);
- count++;
- }
-
- start += scope->length;
- }
-
- return count;
-}
-
-static int __init acpi_parse_dev_scope(
- void *start, void *end, void *acpi_entry, int type)
-{
- struct acpi_dev_scope *scope;
- u8 bus, sub_bus, sec_bus;
- struct acpi_pci_path *path;
- struct acpi_ioapic_unit *acpi_ioapic_unit = NULL;
- int depth;
- struct pci_dev *pdev;
- u8 dev, func;
- u32 l;
-
- int *cnt = NULL;
- struct pci_dev **devices = NULL;
- struct acpi_drhd_unit *dmaru = (struct acpi_drhd_unit *) acpi_entry;
- struct acpi_rmrr_unit *rmrru = (struct acpi_rmrr_unit *) acpi_entry;
- struct acpi_atsr_unit *atsru = (struct acpi_atsr_unit *) acpi_entry;
-
- switch (type) {
- case DMAR_TYPE:
- cnt = &(dmaru->devices_cnt);
- devices = &(dmaru->devices);
- break;
- case RMRR_TYPE:
- cnt = &(rmrru->devices_cnt);
- devices = &(rmrru->devices);
- break;
- case ATSR_TYPE:
- cnt = &(atsru->devices_cnt);
- devices = &(atsru->devices);
- break;
- default:
- dprintk(XENLOG_ERR VTDPREFIX, "invalid vt-d acpi entry type\n");
- }
-
- *cnt = scope_device_count(start, end);
- if ( *cnt == 0 )
- {
- dprintk(XENLOG_INFO VTDPREFIX, "acpi_parse_dev_scope: no device\n");
- return 0;
- }
-
- *devices = xmalloc_array(struct pci_dev, *cnt);
- if ( !*devices )
- return -ENOMEM;
- memset(*devices, 0, sizeof(struct pci_dev) * (*cnt));
-
- pdev = *devices;
- while ( start < end )
- {
- scope = start;
- path = (struct acpi_pci_path *)(scope + 1);
- depth = (scope->length - sizeof(struct acpi_dev_scope))
- / sizeof(struct acpi_pci_path);
- bus = scope->start_bus;
-
- while ( --depth )
- {
- bus = read_pci_config_byte(
- bus, path->dev, path->fn, PCI_SECONDARY_BUS);
- path++;
- }
-
- if ( scope->dev_type == ACPI_DEV_ENDPOINT )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "found endpoint: bdf = %x:%x:%x\n",
- bus, path->dev, path->fn);
- pdev->bus = bus;
- pdev->devfn = PCI_DEVFN(path->dev, path->fn);
- pdev++;
- }
- else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
- {
- dprintk(XENLOG_INFO VTDPREFIX,
- "found bridge: bus = %x dev = %x func = %x\n",
- bus, path->dev, path->fn);
- sec_bus = read_pci_config_byte(
- bus, path->dev, path->fn, PCI_SECONDARY_BUS);
- sub_bus = read_pci_config_byte(
- bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
-
- while ( sec_bus <= sub_bus )
- {
- for ( dev = 0; dev < 32; dev++ )
- {
- for ( func = 0; func < 8; func++ )
- {
- l = read_pci_config(
- sec_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 )
- break;
-
- pdev->bus = sec_bus;
- pdev->devfn = PCI_DEVFN(dev, func);
- pdev++;
- }
- }
- sec_bus++;
- }
- }
- else if ( scope->dev_type == ACPI_DEV_IOAPIC )
- {
- acpi_ioapic_unit = xmalloc(struct acpi_ioapic_unit);
- if ( !acpi_ioapic_unit )
- return -ENOMEM;
- acpi_ioapic_unit->apic_id = scope->enum_id;
- acpi_ioapic_unit->ioapic.bdf.bus = bus;
- acpi_ioapic_unit->ioapic.bdf.dev = path->dev;
- acpi_ioapic_unit->ioapic.bdf.func = path->fn;
- list_add(&acpi_ioapic_unit->list, &dmaru->ioapic_list);
- dprintk(XENLOG_INFO VTDPREFIX,
- "found IOAPIC: bus = %x dev = %x func = %x\n",
- bus, path->dev, path->fn);
- }
- else
- dprintk(XENLOG_INFO VTDPREFIX,
- "found MSI HPET: bus = %x dev = %x func = %x\n",
- bus, path->dev, path->fn);
- start += scope->length;
- }
-
- return 0;
-}
-
-static int __init
-acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
-{
- struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
- struct acpi_drhd_unit *dmaru;
- int ret = 0;
- static int include_all;
- void *dev_scope_start, *dev_scope_end;
-
- dmaru = xmalloc(struct acpi_drhd_unit);
- if ( !dmaru )
- return -ENOMEM;
- memset(dmaru, 0, sizeof(struct acpi_drhd_unit));
-
- dmaru->address = drhd->address;
- dmaru->include_all = drhd->flags & 1; /* BIT0: INCLUDE_ALL */
- INIT_LIST_HEAD(&dmaru->ioapic_list);
- dprintk(XENLOG_INFO VTDPREFIX, "dmaru->address = %lx\n", dmaru->address);
-
- dev_scope_start = (void *)(drhd + 1);
- dev_scope_end = ((void *)drhd) + header->length;
- ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
- dmaru, DMAR_TYPE);
-
- if ( dmaru->include_all )
- {
- dprintk(XENLOG_INFO VTDPREFIX, "found INCLUDE_ALL\n");
- /* Only allow one INCLUDE_ALL */
- if ( include_all )
- {
- dprintk(XENLOG_WARNING VTDPREFIX,
- "Only one INCLUDE_ALL device scope is allowed\n");
- ret = -EINVAL;
- }
- include_all = 1;
- }
-
- if ( ret )
- xfree(dmaru);
- else
- acpi_register_drhd_unit(dmaru);
- return ret;
-}
-
-static int __init
-acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
-{
- struct acpi_table_rmrr *rmrr = (struct acpi_table_rmrr *)header;
- struct acpi_rmrr_unit *rmrru;
- void *dev_scope_start, *dev_scope_end;
- int ret = 0;
-
- rmrru = xmalloc(struct acpi_rmrr_unit);
- if ( !rmrru )
- return -ENOMEM;
- memset(rmrru, 0, sizeof(struct acpi_rmrr_unit));
-
- rmrru->base_address = rmrr->base_address;
- rmrru->end_address = rmrr->end_address;
- dev_scope_start = (void *)(rmrr + 1);
- dev_scope_end = ((void *)rmrr) + header->length;
- ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
- rmrru, RMRR_TYPE);
- if ( ret || (rmrru->devices_cnt == 0) )
- xfree(rmrru);
- else
- acpi_register_rmrr_unit(rmrru);
- return ret;
-}
-
-static int __init
-acpi_parse_one_atsr(struct acpi_dmar_entry_header *header)
-{
- struct acpi_table_atsr *atsr = (struct acpi_table_atsr *)header;
- struct acpi_atsr_unit *atsru;
- int ret = 0;
- static int all_ports;
- void *dev_scope_start, *dev_scope_end;
-
- atsru = xmalloc(struct acpi_atsr_unit);
- if ( !atsru )
- return -ENOMEM;
- memset(atsru, 0, sizeof(struct acpi_atsr_unit));
-
- atsru->all_ports = atsr->flags & 1; /* BIT0: ALL_PORTS */
- if ( !atsru->all_ports )
- {
- dev_scope_start = (void *)(atsr + 1);
- dev_scope_end = ((void *)atsr) + header->length;
- ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
- atsru, ATSR_TYPE);
- }
- else {
- dprintk(XENLOG_INFO VTDPREFIX, "found ALL_PORTS\n");
- /* Only allow one ALL_PORTS */
- if ( all_ports )
- {
- dprintk(XENLOG_WARNING VTDPREFIX,
- "Only one ALL_PORTS device scope is allowed\n");
- ret = -EINVAL;
- }
- all_ports = 1;
- }
-
- if ( ret )
- xfree(atsr);
- else
- acpi_register_atsr_unit(atsru);
- return ret;
-}
-
-static int __init acpi_parse_dmar(unsigned long phys_addr,
- unsigned long size)
-{
- struct acpi_table_dmar *dmar = NULL;
- struct acpi_dmar_entry_header *entry_header;
- int ret = 0;
-
- if ( !phys_addr || !size )
- return -EINVAL;
-
- dmar = (struct acpi_table_dmar *)__acpi_map_table(phys_addr, size);
- if ( !dmar )
- {
- dprintk(XENLOG_WARNING VTDPREFIX, "Unable to map DMAR\n");
- return -ENODEV;
- }
-
- if ( !dmar->haw )
- {
- dprintk(XENLOG_WARNING VTDPREFIX, "Zero: Invalid DMAR haw\n");
- return -EINVAL;
- }
-
- dmar_host_address_width = dmar->haw;
- dprintk(XENLOG_INFO VTDPREFIX, "Host address width %d\n",
- dmar_host_address_width);
-
- entry_header = (struct acpi_dmar_entry_header *)(dmar + 1);
- while ( ((unsigned long)entry_header) <
- (((unsigned long)dmar) + size) )
- {
- switch ( entry_header->type )
- {
- case ACPI_DMAR_DRHD:
- dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_DRHD\n");
- ret = acpi_parse_one_drhd(entry_header);
- break;
- case ACPI_DMAR_RMRR:
- dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_RMRR\n");
- ret = acpi_parse_one_rmrr(entry_header);
- break;
- case ACPI_DMAR_ATSR:
- dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_ATSR\n");
- ret = acpi_parse_one_atsr(entry_header);
- break;
- default:
- dprintk(XENLOG_WARNING VTDPREFIX, "Unknown DMAR structure type\n");
- ret = -EINVAL;
- break;
- }
- if ( ret )
- break;
-
- entry_header = ((void *)entry_header + entry_header->length);
- }
-
- /* Zap APCI DMAR signature to prevent dom0 using vt-d HW. */
- dmar->header.signature[0] = '\0';
-
- return ret;
-}
-
-int acpi_dmar_init(void)
-{
- int rc;
-
- if ( !vtd_enabled )
- return -ENODEV;
-
- if ( (rc = vtd_hw_check()) != 0 )
- return rc;
-
- acpi_table_parse(ACPI_DMAR, acpi_parse_dmar);
-
- if ( list_empty(&acpi_drhd_units) )
- {
- dprintk(XENLOG_ERR VTDPREFIX, "No DMAR devices found\n");
- vtd_enabled = 0;
- return -ENODEV;
- }
-
- printk("Intel VT-d has been enabled\n");
-
- return 0;
-}
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/dmar.h
--- a/xen/arch/x86/hvm/vmx/vtd/dmar.h Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Ashok Raj <ashok.raj@xxxxxxxxx>
- * Copyright (C) Shaohua Li <shaohua.li@xxxxxxxxx>
- */
-
-#ifndef _DMAR_H_
-#define _DMAR_H_
-
-#include <xen/list.h>
-#include <asm/iommu.h>
-
-extern u8 dmar_host_address_width;
-
-/* This one is for interrupt remapping */
-struct acpi_ioapic_unit {
- struct list_head list;
- int apic_id;
- union {
- u16 info;
- struct {
- u16 func: 3,
- dev: 5,
- bus: 8;
- }bdf;
- }ioapic;
-};
-
-struct acpi_drhd_unit {
- struct list_head list;
- unsigned long address; /* register base address of the unit */
- struct pci_dev *devices; /* target devices */
- int devices_cnt;
- u8 include_all:1;
- struct iommu *iommu;
- struct list_head ioapic_list;
-};
-
-struct acpi_rmrr_unit {
- struct list_head list;
- unsigned long base_address;
- unsigned long end_address;
- struct pci_dev *devices; /* target devices */
- int devices_cnt;
- u8 allow_all:1;
-};
-
-struct acpi_atsr_unit {
- struct list_head list;
- struct pci_dev *devices; /* target devices */
- int devices_cnt;
- u8 all_ports:1;
-};
-
-#define for_each_iommu(domain, iommu) \
- list_for_each_entry(iommu, \
- &(domain->arch.hvm_domain.hvm_iommu.iommu_list), list)
-
-#define for_each_pdev(domain, pdev) \
- list_for_each_entry(pdev, \
- &(domain->arch.hvm_domain.hvm_iommu.pdev_list), list)
-
-#define for_each_drhd_unit(drhd) \
- list_for_each_entry(drhd, &acpi_drhd_units, list)
-#define for_each_rmrr_device(rmrr, pdev) \
- list_for_each_entry(rmrr, &acpi_rmrr_units, list) { \
- int _i; \
- for (_i = 0; _i < rmrr->devices_cnt; _i++) { \
- pdev = &(rmrr->devices[_i]);
-#define end_for_each_rmrr_device(rmrr, pdev) \
- } \
- }
-
-struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *dev);
-struct acpi_rmrr_unit * acpi_find_matched_rmrr_unit(struct pci_dev *dev);
-
-#define DMAR_TYPE 1
-#define RMRR_TYPE 2
-#define ATSR_TYPE 3
-
-#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
-#define time_after(a,b) \
- (typecheck(unsigned long, a) && \
- typecheck(unsigned long, b) && \
- ((long)(b) - (long)(a) < 0))
-
-int vtd_hw_check(void);
-void disable_pmr(struct iommu *iommu);
-
-#endif // _DMAR_H_
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/extern.h
--- a/xen/arch/x86/hvm/vmx/vtd/extern.h Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- * Copyright (C) Weidong Han <weidong.han@xxxxxxxxx>
- */
-
-#ifndef _VTD_EXTERN_H_
-#define _VTD_EXTERN_H_
-
-#include "dmar.h"
-
-extern struct qi_ctrl *qi_ctrl;
-extern struct ir_ctrl *ir_ctrl;
-
-void print_iommu_regs(struct acpi_drhd_unit *drhd);
-void print_vtd_entries(struct domain *d, struct iommu *iommu,
- int bus, int devfn, unsigned long gmfn);
-void pdev_flr(u8 bus, u8 devfn);
-
-int qinval_setup(struct iommu *iommu);
-int intremap_setup(struct iommu *iommu);
-int queue_invalidate_context(struct iommu *iommu,
- u16 did, u16 source_id, u8 function_mask, u8 granu);
-int queue_invalidate_iotlb(struct iommu *iommu,
- u8 granu, u8 dr, u8 dw, u16 did, u8 am, u8 ih, u64 addr);
-int queue_invalidate_iec(struct iommu *iommu,
- u8 granu, u8 im, u16 iidx);
-int invalidate_sync(struct iommu *iommu);
-int iommu_flush_iec_global(struct iommu *iommu);
-int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx);
-void print_iommu_regs(struct acpi_drhd_unit *drhd);
-int vtd_hw_check(void);
-struct iommu * ioapic_to_iommu(unsigned int apic_id);
-struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id);
-void clear_fault_bits(struct iommu *iommu);
-
-#endif // _VTD_EXTERN_H_
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c
--- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2178 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Ashok Raj <ashok.raj@xxxxxxxxx>
- * Copyright (C) Shaohua Li <shaohua.li@xxxxxxxxx>
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx> - adapted to xen
- */
-
-#include <xen/init.h>
-#include <xen/irq.h>
-#include <xen/spinlock.h>
-#include <xen/sched.h>
-#include <xen/xmalloc.h>
-#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/mm.h>
-#include <asm/iommu.h>
-#include <asm/hvm/vmx/intel-iommu.h>
-#include "dmar.h"
-#include "pci-direct.h"
-#include "pci_regs.h"
-#include "msi.h"
-#include "extern.h"
-
-#define domain_iommu_domid(d) ((d)->arch.hvm_domain.hvm_iommu.iommu_domid)
-
-static spinlock_t domid_bitmap_lock; /* protect domain id bitmap */
-static int domid_bitmap_size; /* domain id bitmap size in bit */
-static void *domid_bitmap; /* iommu domain id bitmap */
-
-#define DID_FIELD_WIDTH 16
-#define DID_HIGH_OFFSET 8
-static void context_set_domain_id(struct context_entry *context,
- struct domain *d)
-{
- unsigned long flags;
- domid_t iommu_domid = domain_iommu_domid(d);
-
- if ( iommu_domid == 0 )
- {
- spin_lock_irqsave(&domid_bitmap_lock, flags);
- iommu_domid = find_first_zero_bit(domid_bitmap, domid_bitmap_size);
- set_bit(iommu_domid, domid_bitmap);
- spin_unlock_irqrestore(&domid_bitmap_lock, flags);
- d->arch.hvm_domain.hvm_iommu.iommu_domid = iommu_domid;
- }
-
- context->hi &= (1 << DID_HIGH_OFFSET) - 1;
- context->hi |= iommu_domid << DID_HIGH_OFFSET;
-}
-
-static void iommu_domid_release(struct domain *d)
-{
- domid_t iommu_domid = domain_iommu_domid(d);
-
- if ( iommu_domid != 0 )
- {
- d->arch.hvm_domain.hvm_iommu.iommu_domid = 0;
- clear_bit(iommu_domid, domid_bitmap);
- }
-}
-
-unsigned int x86_clflush_size;
-void clflush_cache_range(void *adr, int size)
-{
- int i;
- for ( i = 0; i < size; i += x86_clflush_size )
- clflush(adr + i);
-}
-
-static void __iommu_flush_cache(struct iommu *iommu, void *addr, int size)
-{
- if ( !ecap_coherent(iommu->ecap) )
- clflush_cache_range(addr, size);
-}
-
-#define iommu_flush_cache_entry(iommu, addr) \
- __iommu_flush_cache(iommu, addr, 8)
-#define iommu_flush_cache_page(iommu, addr) \
- __iommu_flush_cache(iommu, addr, PAGE_SIZE_4K)
-
-int nr_iommus;
-/* context entry handling */
-static struct context_entry * device_to_context_entry(struct iommu *iommu,
- u8 bus, u8 devfn)
-{
- struct root_entry *root;
- struct context_entry *context;
- unsigned long phy_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&iommu->lock, flags);
- root = &iommu->root_entry[bus];
- if ( !root_present(*root) )
- {
- phy_addr = (unsigned long) alloc_xenheap_page();
- if ( !phy_addr )
- {
- spin_unlock_irqrestore(&iommu->lock, flags);
- return NULL;
- }
- memset((void *) phy_addr, 0, PAGE_SIZE);
- iommu_flush_cache_page(iommu, (void *)phy_addr);
- phy_addr = virt_to_maddr((void *)phy_addr);
- set_root_value(*root, phy_addr);
- set_root_present(*root);
- iommu_flush_cache_entry(iommu, root);
- }
- phy_addr = (unsigned long) get_context_addr(*root);
- context = (struct context_entry *)maddr_to_virt(phy_addr);
- spin_unlock_irqrestore(&iommu->lock, flags);
- return &context[devfn];
-}
-
-static int device_context_mapped(struct iommu *iommu, u8 bus, u8 devfn)
-{
- struct root_entry *root;
- struct context_entry *context;
- unsigned long phy_addr;
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&iommu->lock, flags);
- root = &iommu->root_entry[bus];
- if ( !root_present(*root) )
- {
- ret = 0;
- goto out;
- }
- phy_addr = get_context_addr(*root);
- context = (struct context_entry *)maddr_to_virt(phy_addr);
- ret = context_present(context[devfn]);
- out:
- spin_unlock_irqrestore(&iommu->lock, flags);
- return ret;
-}
-
-static struct page_info *addr_to_dma_page(struct domain *domain, u64 addr)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- int addr_width = agaw_to_width(hd->agaw);
- struct dma_pte *parent, *pte = NULL, *pgd;
- int level = agaw_to_level(hd->agaw);
- int offset;
- unsigned long flags;
- struct page_info *pg = NULL;
- u64 *vaddr = NULL;
-
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
- iommu = drhd->iommu;
-
- addr &= (((u64)1) << addr_width) - 1;
- spin_lock_irqsave(&hd->mapping_lock, flags);
- if ( !hd->pgd )
- {
- pgd = (struct dma_pte *)alloc_xenheap_page();
- if ( !pgd )
- {
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return NULL;
- }
- memset(pgd, 0, PAGE_SIZE);
- hd->pgd = pgd;
- }
-
- parent = hd->pgd;
- while ( level > 1 )
- {
- offset = address_level_offset(addr, level);
- pte = &parent[offset];
-
- if ( dma_pte_addr(*pte) == 0 )
- {
- pg = alloc_domheap_page(NULL);
- vaddr = map_domain_page(page_to_mfn(pg));
- if ( !vaddr )
- {
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return NULL;
- }
- memset(vaddr, 0, PAGE_SIZE);
- iommu_flush_cache_page(iommu, vaddr);
-
- dma_set_pte_addr(*pte, page_to_maddr(pg));
-
- /*
- * high level table always sets r/w, last level
- * page table control read/write
- */
- dma_set_pte_readable(*pte);
- dma_set_pte_writable(*pte);
- iommu_flush_cache_entry(iommu, pte);
- }
- else
- {
- pg = maddr_to_page(pte->val);
- vaddr = map_domain_page(page_to_mfn(pg));
- if ( !vaddr )
- {
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return NULL;
- }
- }
-
- if ( parent != hd->pgd )
- unmap_domain_page(parent);
-
- if ( level == 2 && vaddr )
- {
- unmap_domain_page(vaddr);
- break;
- }
-
- parent = (struct dma_pte *)vaddr;
- vaddr = NULL;
- level--;
- }
-
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return pg;
-}
-
-/* return address's page at specific level */
-static struct page_info *dma_addr_level_page(struct domain *domain,
- u64 addr, int level)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
- struct dma_pte *parent, *pte = NULL;
- int total = agaw_to_level(hd->agaw);
- int offset;
- struct page_info *pg = NULL;
-
- parent = hd->pgd;
- while ( level <= total )
- {
- offset = address_level_offset(addr, total);
- pte = &parent[offset];
- if ( dma_pte_addr(*pte) == 0 )
- {
- if ( parent != hd->pgd )
- unmap_domain_page(parent);
- break;
- }
-
- pg = maddr_to_page(pte->val);
- if ( parent != hd->pgd )
- unmap_domain_page(parent);
-
- if ( level == total )
- return pg;
-
- parent = map_domain_page(page_to_mfn(pg));
- total--;
- }
-
- return NULL;
-}
-
-static void iommu_flush_write_buffer(struct iommu *iommu)
-{
- u32 val;
- unsigned long flag;
- unsigned long start_time;
-
- if ( !cap_rwbf(iommu->cap) )
- return;
- val = iommu->gcmd | DMA_GCMD_WBF;
-
- spin_lock_irqsave(&iommu->register_lock, flag);
- dmar_writel(iommu->reg, DMAR_GCMD_REG, val);
-
- /* Make sure hardware complete it */
- start_time = jiffies;
- for ( ; ; )
- {
- val = dmar_readl(iommu->reg, DMAR_GSTS_REG);
- if ( !(val & DMA_GSTS_WBFS) )
- break;
- if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
- panic("DMAR hardware is malfunctional,"
- " please disable IOMMU\n");
- cpu_relax();
- }
- spin_unlock_irqrestore(&iommu->register_lock, flag);
-}
-
-/* return value determine if we need a write buffer flush */
-static int flush_context_reg(
- void *_iommu,
- u16 did, u16 source_id, u8 function_mask, u64 type,
- int non_present_entry_flush)
-{
- struct iommu *iommu = (struct iommu *) _iommu;
- u64 val = 0;
- unsigned long flag;
- unsigned long start_time;
-
- /*
- * In the non-present entry flush case, if hardware doesn't cache
- * non-present entry we do nothing and if hardware cache non-present
- * entry, we flush entries of domain 0 (the domain id is used to cache
- * any non-present entries)
- */
- if ( non_present_entry_flush )
- {
- if ( !cap_caching_mode(iommu->cap) )
- return 1;
- else
- did = 0;
- }
-
- /* use register invalidation */
- switch ( type )
- {
- case DMA_CCMD_GLOBAL_INVL:
- val = DMA_CCMD_GLOBAL_INVL;
- break;
- case DMA_CCMD_DOMAIN_INVL:
- val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
- break;
- case DMA_CCMD_DEVICE_INVL:
- val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
- |DMA_CCMD_SID(source_id)|DMA_CCMD_FM(function_mask);
- break;
- default:
- BUG();
- }
- val |= DMA_CCMD_ICC;
-
- spin_lock_irqsave(&iommu->register_lock, flag);
- dmar_writeq(iommu->reg, DMAR_CCMD_REG, val);
-
- /* Make sure hardware complete it */
- start_time = jiffies;
- for ( ; ; )
- {
- val = dmar_readq(iommu->reg, DMAR_CCMD_REG);
- if ( !(val & DMA_CCMD_ICC) )
- break;
- if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
- panic("DMAR hardware is malfunctional, please disable IOMMU\n");
- cpu_relax();
- }
- spin_unlock_irqrestore(&iommu->register_lock, flag);
- /* flush context entry will implictly flush write buffer */
- return 0;
-}
-
-static int inline iommu_flush_context_global(
- struct iommu *iommu, int non_present_entry_flush)
-{
- struct iommu_flush *flush = iommu_get_flush(iommu);
- return flush->context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
- non_present_entry_flush);
-}
-
-static int inline iommu_flush_context_domain(
- struct iommu *iommu, u16 did, int non_present_entry_flush)
-{
- struct iommu_flush *flush = iommu_get_flush(iommu);
- return flush->co |