# 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->context(iommu, did, 0, 0, DMA_CCMD_DOMAIN_INVL,
- non_present_entry_flush);
-}
-
-static int inline iommu_flush_context_device(
- struct iommu *iommu, u16 did, u16 source_id,
- u8 function_mask, int non_present_entry_flush)
-{
- struct iommu_flush *flush = iommu_get_flush(iommu);
- return flush->context(iommu, did, source_id, function_mask,
- DMA_CCMD_DEVICE_INVL,
- non_present_entry_flush);
-}
-
-/* return value determine if we need a write buffer flush */
-static int flush_iotlb_reg(void *_iommu, u16 did,
- u64 addr, unsigned int size_order, u64 type,
- int non_present_entry_flush)
-{
- struct iommu *iommu = (struct iommu *) _iommu;
- int tlb_offset = ecap_iotlb_offset(iommu->ecap);
- u64 val = 0, val_iva = 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_TLB_GLOBAL_FLUSH:
- /* global flush doesn't need set IVA_REG */
- val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
- break;
- case DMA_TLB_DSI_FLUSH:
- val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
- break;
- case DMA_TLB_PSI_FLUSH:
- val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
- /* Note: always flush non-leaf currently */
- val_iva = size_order | addr;
- break;
- default:
- BUG();
- }
- /* Note: set drain read/write */
- if ( cap_read_drain(iommu->cap) )
- val |= DMA_TLB_READ_DRAIN;
- if ( cap_write_drain(iommu->cap) )
- val |= DMA_TLB_WRITE_DRAIN;
-
- spin_lock_irqsave(&iommu->register_lock, flag);
- /* Note: Only uses first TLB reg currently */
- if ( val_iva )
- dmar_writeq(iommu->reg, tlb_offset, val_iva);
- dmar_writeq(iommu->reg, tlb_offset + 8, val);
-
- /* Make sure hardware complete it */
- start_time = jiffies;
- for ( ; ; )
- {
- val = dmar_readq(iommu->reg, tlb_offset + 8);
- if ( !(val & DMA_TLB_IVT) )
- 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);
-
- /* check IOTLB invalidation granularity */
- if ( DMA_TLB_IAIG(val) == 0 )
- printk(KERN_ERR VTDPREFIX "IOMMU: flush IOTLB failed\n");
- if ( DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type) )
- printk(KERN_ERR VTDPREFIX "IOMMU: tlb flush request %x, actual %x\n",
- (u32)DMA_TLB_IIRG(type), (u32)DMA_TLB_IAIG(val));
- /* flush context entry will implictly flush write buffer */
- return 0;
-}
-
-static int inline iommu_flush_iotlb_global(struct iommu *iommu,
- int non_present_entry_flush)
-{
- struct iommu_flush *flush = iommu_get_flush(iommu);
- return flush->iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
- non_present_entry_flush);
-}
-
-static int inline iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did,
- int non_present_entry_flush)
-{
- struct iommu_flush *flush = iommu_get_flush(iommu);
- return flush->iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH,
- non_present_entry_flush);
-}
-
-static int inline get_alignment(u64 base, unsigned int size)
-{
- int t = 0;
- u64 end;
-
- end = base + size - 1;
- while ( base != end )
- {
- t++;
- base >>= 1;
- end >>= 1;
- }
- return t;
-}
-
-static int inline iommu_flush_iotlb_psi(
- struct iommu *iommu, u16 did,
- u64 addr, unsigned int pages, int non_present_entry_flush)
-{
- unsigned int align;
- struct iommu_flush *flush = iommu_get_flush(iommu);
-
- BUG_ON(addr & (~PAGE_MASK_4K));
- BUG_ON(pages == 0);
-
- /* Fallback to domain selective flush if no PSI support */
- if ( !cap_pgsel_inv(iommu->cap) )
- return iommu_flush_iotlb_dsi(iommu, did,
- non_present_entry_flush);
-
- /*
- * PSI requires page size is 2 ^ x, and the base address is naturally
- * aligned to the size
- */
- align = get_alignment(addr >> PAGE_SHIFT_4K, pages);
- /* Fallback to domain selective flush if size is too big */
- if ( align > cap_max_amask_val(iommu->cap) )
- return iommu_flush_iotlb_dsi(iommu, did,
- non_present_entry_flush);
-
- addr >>= PAGE_SHIFT_4K + align;
- addr <<= PAGE_SHIFT_4K + align;
-
- return flush->iotlb(iommu, did, addr, align,
- DMA_TLB_PSI_FLUSH, non_present_entry_flush);
-}
-
-void iommu_flush_all(void)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
-
- wbinvd();
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- iommu_flush_context_global(iommu, 0);
- iommu_flush_iotlb_global(iommu, 0);
- }
-}
-
-/* clear one page's page table */
-static void dma_pte_clear_one(struct domain *domain, u64 addr)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- struct dma_pte *pte = NULL;
- struct page_info *pg = NULL;
-
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
-
- /* get last level pte */
- pg = dma_addr_level_page(domain, addr, 1);
- if ( !pg )
- return;
- pte = (struct dma_pte *)map_domain_page(page_to_mfn(pg));
- pte += address_level_offset(addr, 1);
- if ( pte )
- {
- dma_clear_pte(*pte);
- iommu_flush_cache_entry(drhd->iommu, pte);
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( cap_caching_mode(iommu->cap) )
- iommu_flush_iotlb_psi(iommu, domain_iommu_domid(domain),
- addr, 1, 0);
- else if (cap_rwbf(iommu->cap))
- iommu_flush_write_buffer(iommu);
- }
- }
- unmap_domain_page(pte);
-}
-
-/* clear last level pte, a tlb flush should be followed */
-static void dma_pte_clear_range(struct domain *domain, u64 start, u64 end)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
- int addr_width = agaw_to_width(hd->agaw);
-
- start &= (((u64)1) << addr_width) - 1;
- end &= (((u64)1) << addr_width) - 1;
- /* in case it's partial page */
- start = PAGE_ALIGN_4K(start);
- end &= PAGE_MASK_4K;
-
- /* we don't need lock here, nobody else touches the iova range */
- while ( start < end )
- {
- dma_pte_clear_one(domain, start);
- start += PAGE_SIZE_4K;
- }
-}
-
-/* free page table pages. last level pte should already be cleared */
-void dma_pte_free_pagetable(struct domain *domain, u64 start, u64 end)
-{
- struct acpi_drhd_unit *drhd;
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
- struct iommu *iommu;
- int addr_width = agaw_to_width(hd->agaw);
- struct dma_pte *pte;
- int total = agaw_to_level(hd->agaw);
- int level;
- u32 tmp;
- struct page_info *pg = NULL;
-
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
- iommu = drhd->iommu;
-
- start &= (((u64)1) << addr_width) - 1;
- end &= (((u64)1) << addr_width) - 1;
-
- /* we don't need lock here, nobody else touches the iova range */
- level = 2;
- while ( level <= total )
- {
- tmp = align_to_level(start, level);
- if ( (tmp >= end) || ((tmp + level_size(level)) > end) )
- return;
-
- while ( tmp < end )
- {
- pg = dma_addr_level_page(domain, tmp, level);
- if ( !pg )
- return;
- pte = (struct dma_pte *)map_domain_page(page_to_mfn(pg));
- pte += address_level_offset(tmp, level);
- dma_clear_pte(*pte);
- iommu_flush_cache_entry(iommu, pte);
- unmap_domain_page(pte);
- free_domheap_page(pg);
-
- tmp += level_size(level);
- }
- level++;
- }
-
- /* free pgd */
- if ( start == 0 && end == ((((u64)1) << addr_width) - 1) )
- {
- free_xenheap_page((void *)hd->pgd);
- hd->pgd = NULL;
- }
-}
-
-/* iommu handling */
-static int iommu_set_root_entry(struct iommu *iommu)
-{
- void *addr;
- u32 cmd, sts;
- struct root_entry *root;
- unsigned long flags;
-
- if ( iommu == NULL )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "iommu_set_root_entry: iommu == NULL\n");
- return -EINVAL;
- }
-
- if ( unlikely(!iommu->root_entry) )
- {
- root = (struct root_entry *)alloc_xenheap_page();
- if ( root == NULL )
- return -ENOMEM;
-
- memset((u8*)root, 0, PAGE_SIZE);
- iommu_flush_cache_page(iommu, root);
-
- if ( cmpxchg((unsigned long *)&iommu->root_entry,
- 0, (unsigned long)root) != 0 )
- free_xenheap_page((void *)root);
- }
-
- addr = iommu->root_entry;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
-
- dmar_writeq(iommu->reg, DMAR_RTADDR_REG, virt_to_maddr(addr));
- cmd = iommu->gcmd | DMA_GCMD_SRTP;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, cmd);
-
- /* Make sure hardware complete it */
- for ( ; ; )
- {
- sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
- if ( sts & DMA_GSTS_RTPS )
- break;
- cpu_relax();
- }
-
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-
- return 0;
-}
-
-static int iommu_enable_translation(struct iommu *iommu)
-{
- u32 sts;
- unsigned long flags;
-
- dprintk(XENLOG_INFO VTDPREFIX,
- "iommu_enable_translation: iommu->reg = %p\n", iommu->reg);
- spin_lock_irqsave(&iommu->register_lock, flags);
- iommu->gcmd |= DMA_GCMD_TE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
- /* Make sure hardware complete it */
- for ( ; ; )
- {
- sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
- if ( sts & DMA_GSTS_TES )
- break;
- cpu_relax();
- }
-
- /* Disable PMRs when VT-d engine takes effect per spec definition */
- disable_pmr(iommu);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- return 0;
-}
-
-int iommu_disable_translation(struct iommu *iommu)
-{
- u32 sts;
- unsigned long flags;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- iommu->gcmd &= ~ DMA_GCMD_TE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
-
- /* Make sure hardware complete it */
- for ( ; ; )
- {
- sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
- if ( !(sts & DMA_GSTS_TES) )
- break;
- cpu_relax();
- }
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- return 0;
-}
-
-static struct iommu *vector_to_iommu[NR_VECTORS];
-static int iommu_page_fault_do_one(struct iommu *iommu, int type,
- u8 fault_reason, u16 source_id, u32 addr)
-{
- dprintk(XENLOG_WARNING VTDPREFIX,
- "iommu_fault:%s: %x:%x.%x addr %x REASON %x iommu->reg = %p\n",
- (type ? "DMA Read" : "DMA Write"), (source_id >> 8),
- PCI_SLOT(source_id & 0xFF), PCI_FUNC(source_id & 0xFF), addr,
- fault_reason, iommu->reg);
-
- if (fault_reason < 0x20)
- print_vtd_entries(current->domain, iommu, (source_id >> 8),
- (source_id & 0xff), (addr >> PAGE_SHIFT));
-
- return 0;
-}
-
-static void iommu_fault_status(u32 fault_status)
-{
- if (fault_status & DMA_FSTS_PFO)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Fault Overflow\n");
- else
- if (fault_status & DMA_FSTS_PPF)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Primary Pending Fault\n");
- else
- if (fault_status & DMA_FSTS_AFO)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Advanced Fault Overflow\n");
- else
- if (fault_status & DMA_FSTS_APF)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Advanced Pending Fault\n");
- else
- if (fault_status & DMA_FSTS_IQE)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Invalidation Queue Error\n");
- else
- if (fault_status & DMA_FSTS_ICE)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Invalidation Completion Error\n");
- else
- if (fault_status & DMA_FSTS_ITE)
- dprintk(XENLOG_ERR VTDPREFIX,
- "iommu_fault_status: Invalidation Time-out Error\n");
-}
-
-#define PRIMARY_FAULT_REG_LEN (16)
-static void iommu_page_fault(int vector, void *dev_id,
- struct cpu_user_regs *regs)
-{
- struct iommu *iommu = dev_id;
- int reg, fault_index;
- u32 fault_status;
- unsigned long flags;
-
- dprintk(XENLOG_WARNING VTDPREFIX,
- "iommu_page_fault: iommu->reg = %p\n", iommu->reg);
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- fault_status = dmar_readl(iommu->reg, DMAR_FSTS_REG);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-
- iommu_fault_status(fault_status);
-
- /* FIXME: ignore advanced fault log */
- if ( !(fault_status & DMA_FSTS_PPF) )
- return;
- fault_index = dma_fsts_fault_record_index(fault_status);
- reg = cap_fault_reg_offset(iommu->cap);
- for ( ; ; )
- {
- u8 fault_reason;
- u16 source_id;
- u32 guest_addr, data;
- int type;
-
- /* highest 32 bits */
- spin_lock_irqsave(&iommu->register_lock, flags);
- data = dmar_readl(iommu->reg, reg +
- fault_index * PRIMARY_FAULT_REG_LEN + 12);
- if ( !(data & DMA_FRCD_F) )
- {
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- break;
- }
-
- fault_reason = dma_frcd_fault_reason(data);
- type = dma_frcd_type(data);
-
- data = dmar_readl(iommu->reg, reg +
- fault_index * PRIMARY_FAULT_REG_LEN + 8);
- source_id = dma_frcd_source_id(data);
-
- guest_addr = dmar_readq(iommu->reg, reg +
- fault_index * PRIMARY_FAULT_REG_LEN);
- guest_addr = dma_frcd_page_addr(guest_addr);
- /* clear the fault */
- dmar_writel(iommu->reg, reg +
- fault_index * PRIMARY_FAULT_REG_LEN + 12, DMA_FRCD_F);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-
- iommu_page_fault_do_one(iommu, type, fault_reason,
- source_id, guest_addr);
-
- fault_index++;
- if ( fault_index > cap_num_fault_regs(iommu->cap) )
- fault_index = 0;
- }
-
- /* clear primary fault overflow */
- if ( fault_status & DMA_FSTS_PFO )
- {
- spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_PFO);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- }
-}
-
-static void dma_msi_unmask(unsigned int vector)
-{
- struct iommu *iommu = vector_to_iommu[vector];
- unsigned long flags;
-
- /* unmask it */
- spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writel(iommu->reg, DMAR_FECTL_REG, 0);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-}
-
-static void dma_msi_mask(unsigned int vector)
-{
- unsigned long flags;
- struct iommu *iommu = vector_to_iommu[vector];
-
- /* mask it */
- spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writel(iommu->reg, DMAR_FECTL_REG, DMA_FECTL_IM);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-}
-
-static unsigned int dma_msi_startup(unsigned int vector)
-{
- dma_msi_unmask(vector);
- return 0;
-}
-
-static void dma_msi_end(unsigned int vector)
-{
- dma_msi_unmask(vector);
- ack_APIC_irq();
-}
-
-static void dma_msi_data_init(struct iommu *iommu, int vector)
-{
- u32 msi_data = 0;
- unsigned long flags;
-
- /* Fixed, edge, assert mode. Follow MSI setting */
- msi_data |= vector & 0xff;
- msi_data |= 1 << 14;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writel(iommu->reg, DMAR_FEDATA_REG, msi_data);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-}
-
-static void dma_msi_addr_init(struct iommu *iommu, int phy_cpu)
-{
- u64 msi_address;
- unsigned long flags;
-
- /* Physical, dedicated cpu. Follow MSI setting */
- msi_address = (MSI_ADDRESS_HEADER << (MSI_ADDRESS_HEADER_SHIFT + 8));
- msi_address |= MSI_PHYSICAL_MODE << 2;
- msi_address |= MSI_REDIRECTION_HINT_MODE << 3;
- msi_address |= phy_cpu << MSI_TARGET_CPU_SHIFT;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writel(iommu->reg, DMAR_FEADDR_REG, (u32)msi_address);
- dmar_writel(iommu->reg, DMAR_FEUADDR_REG, (u32)(msi_address >> 32));
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-}
-
-static void dma_msi_set_affinity(unsigned int vector, cpumask_t dest)
-{
- struct iommu *iommu = vector_to_iommu[vector];
- dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(dest)));
-}
-
-static struct hw_interrupt_type dma_msi_type = {
- .typename = "DMA_MSI",
- .startup = dma_msi_startup,
- .shutdown = dma_msi_mask,
- .enable = dma_msi_unmask,
- .disable = dma_msi_mask,
- .ack = dma_msi_mask,
- .end = dma_msi_end,
- .set_affinity = dma_msi_set_affinity,
-};
-
-int iommu_set_interrupt(struct iommu *iommu)
-{
- int vector, ret;
-
- vector = assign_irq_vector(AUTO_ASSIGN);
- vector_to_iommu[vector] = iommu;
-
- /* VT-d fault is a MSI, make irq == vector */
- irq_vector[vector] = vector;
- vector_irq[vector] = vector;
-
- if ( !vector )
- {
- gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: no vectors\n");
- return -EINVAL;
- }
-
- irq_desc[vector].handler = &dma_msi_type;
- ret = request_irq(vector, iommu_page_fault, 0, "dmar", iommu);
- if ( ret )
- gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: can't request irq\n");
- return vector;
-}
-
-struct iommu *iommu_alloc(void *hw_data)
-{
- struct acpi_drhd_unit *drhd = (struct acpi_drhd_unit *) hw_data;
- struct iommu *iommu;
- struct qi_ctrl *qi_ctrl;
- struct ir_ctrl *ir_ctrl;
-
- if ( nr_iommus > MAX_IOMMUS )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "IOMMU: nr_iommus %d > MAX_IOMMUS\n", nr_iommus);
- return NULL;
- }
-
- iommu = xmalloc(struct iommu);
- if ( !iommu )
- return NULL;
- memset(iommu, 0, sizeof(struct iommu));
-
- set_fixmap_nocache(FIX_IOMMU_REGS_BASE_0 + nr_iommus, drhd->address);
- iommu->reg = (void *) fix_to_virt(FIX_IOMMU_REGS_BASE_0 + nr_iommus);
-
- printk("iommu_alloc: iommu->reg = %p drhd->address = %lx\n",
- iommu->reg, drhd->address);
-
- nr_iommus++;
-
- if ( !iommu->reg )
- {
- printk(KERN_ERR VTDPREFIX "IOMMU: can't mapping the region\n");
- goto error;
- }
-
- iommu->cap = dmar_readq(iommu->reg, DMAR_CAP_REG);
- iommu->ecap = dmar_readq(iommu->reg, DMAR_ECAP_REG);
-
- printk("iommu_alloc: cap = %"PRIx64"\n",iommu->cap);
- printk("iommu_alloc: ecap = %"PRIx64"\n", iommu->ecap);
-
- spin_lock_init(&iommu->lock);
- spin_lock_init(&iommu->register_lock);
-
- qi_ctrl = iommu_qi_ctrl(iommu);
- spin_lock_init(&qi_ctrl->qinval_lock);
- spin_lock_init(&qi_ctrl->qinval_poll_lock);
-
- ir_ctrl = iommu_ir_ctrl(iommu);
- spin_lock_init(&ir_ctrl->iremap_lock);
-
- drhd->iommu = iommu;
- return iommu;
- error:
- xfree(iommu);
- return NULL;
-}
-
-static void free_iommu(struct iommu *iommu)
-{
- if ( !iommu )
- return;
- if ( iommu->root_entry )
- free_xenheap_page((void *)iommu->root_entry);
- if ( iommu->reg )
- iounmap(iommu->reg);
- free_irq(iommu->vector);
- xfree(iommu);
-}
-
-#define guestwidth_to_adjustwidth(gaw) ({ \
- int agaw, r = (gaw - 12) % 9; \
- agaw = (r == 0) ? gaw : (gaw + 9 - r); \
- if ( agaw > 64 ) \
- agaw = 64; \
- agaw; })
-
-int intel_iommu_domain_init(struct domain *domain)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
- struct iommu *iommu = NULL;
- int guest_width = DEFAULT_DOMAIN_ADDRESS_WIDTH;
- int adjust_width, agaw;
- unsigned long sagaw;
- struct acpi_drhd_unit *drhd;
-
- if ( !vtd_enabled || list_empty(&acpi_drhd_units) )
- return 0;
-
- for_each_drhd_unit ( drhd )
- iommu = drhd->iommu ? : iommu_alloc(drhd);
-
- /* calculate AGAW */
- if (guest_width > cap_mgaw(iommu->cap))
- guest_width = cap_mgaw(iommu->cap);
- adjust_width = guestwidth_to_adjustwidth(guest_width);
- agaw = width_to_agaw(adjust_width);
- /* FIXME: hardware doesn't support it, choose a bigger one? */
- sagaw = cap_sagaw(iommu->cap);
- if ( !test_bit(agaw, &sagaw) )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "IOMMU: hardware doesn't support the agaw\n");
- agaw = find_next_bit(&sagaw, 5, agaw);
- if ( agaw >= 5 )
- return -ENODEV;
- }
- hd->agaw = agaw;
- return 0;
-}
-
-static int domain_context_mapping_one(
- struct domain *domain,
- struct iommu *iommu,
- u8 bus, u8 devfn)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(domain);
- struct context_entry *context;
- unsigned long flags;
- int ret = 0;
-
- context = device_to_context_entry(iommu, bus, devfn);
- if ( !context )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "domain_context_mapping_one:context == NULL:"
- "bdf = %x:%x:%x\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
- return -ENOMEM;
- }
-
- if ( context_present(*context) )
- {
- gdprintk(XENLOG_WARNING VTDPREFIX,
- "domain_context_mapping_one:context present:bdf=%x:%x:%x\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
- return 0;
- }
-
- spin_lock_irqsave(&iommu->lock, flags);
- /*
- * domain_id 0 is not valid on Intel's IOMMU, force domain_id to
- * be 1 based as required by intel's iommu hw.
- */
- context_set_domain_id(context, domain);
- context_set_address_width(*context, hd->agaw);
-
- if ( ecap_pass_thru(iommu->ecap) )
- context_set_translation_type(*context, CONTEXT_TT_PASS_THRU);
-#ifdef CONTEXT_PASSTHRU
- else
- {
-#endif
- if ( !hd->pgd )
- {
- struct dma_pte *pgd = (struct dma_pte *)alloc_xenheap_page();
- if ( !pgd )
- {
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- return -ENOMEM;
- }
- memset(pgd, 0, PAGE_SIZE);
- hd->pgd = pgd;
- }
-
- context_set_address_root(*context, virt_to_maddr(hd->pgd));
- context_set_translation_type(*context, CONTEXT_TT_MULTI_LEVEL);
-#ifdef CONTEXT_PASSTHRU
- }
-#endif
-
- context_set_fault_enable(*context);
- context_set_present(*context);
- iommu_flush_cache_entry(iommu, context);
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_mapping_one-%x:%x:%x-*context=%"PRIx64":%"PRIx64
- " hd->pgd=%p\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
- context->hi, context->lo, hd->pgd);
-
- if ( iommu_flush_context_device(iommu, domain_iommu_domid(domain),
- (((u16)bus) << 8) | devfn,
- DMA_CCMD_MASK_NOBIT, 1) )
- iommu_flush_write_buffer(iommu);
- else
- iommu_flush_iotlb_dsi(iommu, domain_iommu_domid(domain), 0);
- spin_unlock_irqrestore(&iommu->lock, flags);
- return ret;
-}
-
-static int __pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap)
-{
- u8 id;
- int ttl = 48;
-
- while ( ttl-- )
- {
- pos = read_pci_config_byte(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
- if ( pos < 0x40 )
- break;
-
- pos &= ~3;
- id = read_pci_config_byte(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
- pos + PCI_CAP_LIST_ID);
-
- if ( id == 0xff )
- break;
- if ( id == cap )
- return pos;
-
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
-}
-
-#define PCI_BASE_CLASS_BRIDGE 0x06
-#define PCI_CLASS_BRIDGE_PCI 0x0604
-
-#define DEV_TYPE_PCIe_ENDPOINT 1
-#define DEV_TYPE_PCI_BRIDGE 2
-#define DEV_TYPE_PCI 3
-
-int pdev_type(struct pci_dev *dev)
-{
- u16 class_device;
- u16 status;
-
- class_device = read_pci_config_16(dev->bus, PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn), PCI_CLASS_DEVICE);
- if ( class_device == PCI_CLASS_BRIDGE_PCI )
- return DEV_TYPE_PCI_BRIDGE;
-
- status = read_pci_config_16(dev->bus, PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn), PCI_STATUS);
-
- if ( !(status & PCI_STATUS_CAP_LIST) )
- return DEV_TYPE_PCI;
-
- if ( __pci_find_next_cap(dev->bus, dev->devfn,
- PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP) )
- return DEV_TYPE_PCIe_ENDPOINT;
-
- return DEV_TYPE_PCI;
-}
-
-#define MAX_BUSES 256
-struct pci_dev bus2bridge[MAX_BUSES];
-
-static int domain_context_mapping(
- struct domain *domain,
- struct iommu *iommu,
- struct pci_dev *pdev)
-{
- int ret = 0;
- int dev, func, sec_bus, sub_bus;
- u32 type;
-
- type = pdev_type(pdev);
- switch ( type )
- {
- case DEV_TYPE_PCI_BRIDGE:
- sec_bus = read_pci_config_byte(
- pdev->bus, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), PCI_SECONDARY_BUS);
-
- if ( bus2bridge[sec_bus].bus == 0 )
- {
- bus2bridge[sec_bus].bus = pdev->bus;
- bus2bridge[sec_bus].devfn = pdev->devfn;
- }
-
- sub_bus = read_pci_config_byte(
- pdev->bus, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
-
- if ( sec_bus != sub_bus )
- gdprintk(XENLOG_WARNING VTDPREFIX,
- "context_context_mapping: nested PCI bridge not "
- "supported: bdf = %x:%x:%x sec_bus = %x sub_bus = %x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
- sec_bus, sub_bus);
- break;
- case DEV_TYPE_PCIe_ENDPOINT:
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_mapping:PCIe : bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- ret = domain_context_mapping_one(domain, iommu,
- (u8)(pdev->bus), (u8)(pdev->devfn));
- break;
- case DEV_TYPE_PCI:
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_mapping:PCI: bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-
- if ( pdev->bus == 0 )
- ret = domain_context_mapping_one(
- domain, iommu, (u8)(pdev->bus), (u8)(pdev->devfn));
- else
- {
- if ( bus2bridge[pdev->bus].bus != 0 )
- gdprintk(XENLOG_WARNING VTDPREFIX,
- "domain_context_mapping:bus2bridge"
- "[%d].bus != 0\n", pdev->bus);
-
- ret = domain_context_mapping_one(
- domain, iommu,
- (u8)(bus2bridge[pdev->bus].bus),
- (u8)(bus2bridge[pdev->bus].devfn));
-
- /* now map everything behind the PCI bridge */
- for ( dev = 0; dev < 32; dev++ )
- {
- for ( func = 0; func < 8; func++ )
- {
- ret = domain_context_mapping_one(
- domain, iommu,
- pdev->bus, (u8)PCI_DEVFN(dev, func));
- if ( ret )
- return ret;
- }
- }
- }
- break;
- default:
- gdprintk(XENLOG_ERR VTDPREFIX,
- "domain_context_mapping:unknown type : bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int domain_context_unmap_one(
- struct domain *domain,
- struct iommu *iommu,
- u8 bus, u8 devfn)
-{
- struct context_entry *context;
- unsigned long flags;
-
- context = device_to_context_entry(iommu, bus, devfn);
- if ( !context )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "domain_context_unmap_one-%x:%x:%x- context == NULL:return\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
- return -ENOMEM;
- }
-
- if ( !context_present(*context) )
- {
- gdprintk(XENLOG_WARNING VTDPREFIX,
- "domain_context_unmap_one-%x:%x:%x- "
- "context NOT present:return\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
- return 0;
- }
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_unmap_one: bdf = %x:%x:%x\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
- spin_lock_irqsave(&iommu->lock, flags);
- context_clear_present(*context);
- context_clear_entry(*context);
- iommu_flush_cache_entry(iommu, context);
- iommu_flush_context_global(iommu, 0);
- iommu_flush_iotlb_global(iommu, 0);
- spin_unlock_irqrestore(&iommu->lock, flags);
-
- return 0;
-}
-
-static int domain_context_unmap(
- struct domain *domain,
- struct iommu *iommu,
- struct pci_dev *pdev)
-{
- int ret = 0;
- int dev, func, sec_bus, sub_bus;
- u32 type;
-
- type = pdev_type(pdev);
- switch ( type )
- {
- case DEV_TYPE_PCI_BRIDGE:
- sec_bus = read_pci_config_byte(
- pdev->bus, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), PCI_SECONDARY_BUS);
- sub_bus = read_pci_config_byte(
- pdev->bus, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_unmap:BRIDGE:%x:%x:%x "
- "sec_bus=%x sub_bus=%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), sec_bus, sub_bus);
- break;
- case DEV_TYPE_PCIe_ENDPOINT:
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_unmap:PCIe : bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- ret = domain_context_unmap_one(domain, iommu,
- (u8)(pdev->bus), (u8)(pdev->devfn));
- break;
- case DEV_TYPE_PCI:
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_unmap:PCI: bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- if ( pdev->bus == 0 )
- ret = domain_context_unmap_one(
- domain, iommu,
- (u8)(pdev->bus), (u8)(pdev->devfn));
- else
- {
- if ( bus2bridge[pdev->bus].bus != 0 )
- gdprintk(XENLOG_WARNING VTDPREFIX,
- "domain_context_unmap:"
- "bus2bridge[%d].bus != 0\n", pdev->bus);
-
- ret = domain_context_unmap_one(domain, iommu,
- (u8)(bus2bridge[pdev->bus].bus),
- (u8)(bus2bridge[pdev->bus].devfn));
-
- /* Unmap everything behind the PCI bridge */
- for ( dev = 0; dev < 32; dev++ )
- {
- for ( func = 0; func < 8; func++ )
- {
- ret = domain_context_unmap_one(
- domain, iommu,
- pdev->bus, (u8)PCI_DEVFN(dev, func));
- if ( ret )
- return ret;
- }
- }
- }
- break;
- default:
- gdprintk(XENLOG_ERR VTDPREFIX,
- "domain_context_unmap:unknown type: bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-void reassign_device_ownership(
- 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 acpi_drhd_unit *drhd;
- struct iommu *iommu;
- int status;
- unsigned long flags;
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "reassign_device-%x:%x:%x- source = %d target = %d\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
- source->domain_id, target->domain_id);
-
- pdev_flr(bus, devfn);
-
- for_each_pdev( source, pdev )
- {
- if ( (pdev->bus != bus) || (pdev->devfn != devfn) )
- continue;
-
- drhd = acpi_find_matched_drhd_unit(pdev);
- iommu = drhd->iommu;
- domain_context_unmap(source, iommu, pdev);
-
- /* 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);
-
- status = domain_context_mapping(target, iommu, pdev);
- if ( status != 0 )
- gdprintk(XENLOG_ERR VTDPREFIX, "domain_context_mapping failed\n");
-
- break;
- }
-}
-
-void return_devices_to_dom0(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);
- dprintk(XENLOG_INFO VTDPREFIX,
- "return_devices_to_dom0: bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
- reassign_device_ownership(d, dom0, pdev->bus, pdev->devfn);
- }
-
-#ifdef VTD_DEBUG
- for_each_pdev ( dom0, pdev )
- dprintk(XENLOG_INFO VTDPREFIX,
- "return_devices_to_dom0:%x: bdf = %x:%x:%x\n",
- dom0->domain_id, pdev->bus,
- PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-#endif
-}
-
-void iommu_domain_teardown(struct domain *d)
-{
- if ( list_empty(&acpi_drhd_units) )
- return;
-
- iommu_domid_release(d);
-
-#if CONFIG_PAGING_LEVELS == 3
- {
- struct hvm_iommu *hd = domain_hvm_iommu(d);
- int level = agaw_to_level(hd->agaw);
- struct dma_pte *pgd = NULL;
-
- switch ( level )
- {
- case VTD_PAGE_TABLE_LEVEL_3:
- if ( hd->pgd )
- free_xenheap_page((void *)hd->pgd);
- break;
- case VTD_PAGE_TABLE_LEVEL_4:
- if ( hd->pgd )
- {
- pgd = hd->pgd;
- if ( pgd[0].val != 0 )
- free_xenheap_page((void*)maddr_to_virt(
- dma_pte_addr(pgd[0])));
- free_xenheap_page((void *)hd->pgd);
- }
- break;
- default:
- gdprintk(XENLOG_ERR VTDPREFIX,
- "Unsupported p2m table sharing level!\n");
- break;
- }
- }
-#endif
- return_devices_to_dom0(d);
-}
-
-static int domain_context_mapped(struct pci_dev *pdev)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- int ret;
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- ret = device_context_mapped(iommu, pdev->bus, pdev->devfn);
- if ( ret )
- return ret;
- }
-
- return 0;
-}
-
-int intel_iommu_map_page(
- struct domain *d, unsigned long gfn, unsigned long mfn)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- struct dma_pte *pte = NULL;
- struct page_info *pg = NULL;
-
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
- iommu = drhd->iommu;
-
-#ifdef CONTEXT_PASSTHRU
- /* do nothing if dom0 and iommu supports pass thru */
- if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
- return 0;
-#endif
-
- pg = addr_to_dma_page(d, (paddr_t)gfn << PAGE_SHIFT_4K);
- if ( !pg )
- return -ENOMEM;
- pte = (struct dma_pte *)map_domain_page(page_to_mfn(pg));
- pte += gfn & LEVEL_MASK;
- dma_set_pte_addr(*pte, (paddr_t)mfn << PAGE_SHIFT_4K);
- dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE);
- iommu_flush_cache_entry(iommu, pte);
- unmap_domain_page(pte);
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( cap_caching_mode(iommu->cap) )
- iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
- (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0);
- else if ( cap_rwbf(iommu->cap) )
- iommu_flush_write_buffer(iommu);
- }
-
- return 0;
-}
-
-int intel_iommu_unmap_page(struct domain *d, unsigned long gfn)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
-
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
- iommu = drhd->iommu;
-
-#ifdef CONTEXT_PASSTHRU
- /* do nothing if dom0 and iommu supports pass thru */
- if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
- return 0;
-#endif
-
- dma_pte_clear_one(d, (paddr_t)gfn << PAGE_SHIFT_4K);
-
- return 0;
-}
-
-int iommu_page_mapping(struct domain *domain, paddr_t iova,
- void *hpa, size_t size, int prot)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- unsigned long start_pfn, end_pfn;
- struct dma_pte *pte = NULL;
- int index;
- struct page_info *pg = NULL;
-
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
- iommu = drhd->iommu;
- if ( (prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0 )
- return -EINVAL;
- iova = (iova >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K;
- start_pfn = (unsigned long)(((unsigned long) hpa) >> PAGE_SHIFT_4K);
- end_pfn = (unsigned long)
- ((PAGE_ALIGN_4K(((unsigned long)hpa) + size)) >> PAGE_SHIFT_4K);
- index = 0;
- while ( start_pfn < end_pfn )
- {
- pg = addr_to_dma_page(domain, iova + PAGE_SIZE_4K * index);
- if ( !pg )
- return -ENOMEM;
- pte = (struct dma_pte *)map_domain_page(page_to_mfn(pg));
- pte += start_pfn & LEVEL_MASK;
- dma_set_pte_addr(*pte, start_pfn << PAGE_SHIFT_4K);
- dma_set_pte_prot(*pte, prot);
- iommu_flush_cache_entry(iommu, pte);
- unmap_domain_page(pte);
- start_pfn++;
- index++;
- }
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( cap_caching_mode(iommu->cap) )
- iommu_flush_iotlb_psi(iommu, domain_iommu_domid(domain),
- iova, index, 0);
- else if ( cap_rwbf(iommu->cap) )
- iommu_flush_write_buffer(iommu);
- }
-
- return 0;
-}
-
-int iommu_page_unmapping(struct domain *domain, paddr_t addr, size_t size)
-{
- dma_pte_clear_range(domain, addr, addr + size);
-
- return 0;
-}
-
-void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu = NULL;
- struct dma_pte *pte = (struct dma_pte *) p2m_entry;
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( cap_caching_mode(iommu->cap) )
- iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
- (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0);
- else if ( cap_rwbf(iommu->cap) )
- iommu_flush_write_buffer(iommu);
- }
-
- iommu_flush_cache_entry(iommu, pte);
-}
-
-static int iommu_prepare_rmrr_dev(
- struct domain *d,
- struct acpi_rmrr_unit *rmrr,
- struct pci_dev *pdev)
-{
- struct acpi_drhd_unit *drhd;
- unsigned long size;
- int ret;
-
- /* page table init */
- size = rmrr->end_address - rmrr->base_address + 1;
- ret = iommu_page_mapping(d, rmrr->base_address,
- (void *)rmrr->base_address, size,
- DMA_PTE_READ|DMA_PTE_WRITE);
- if ( ret )
- return ret;
-
- if ( domain_context_mapped(pdev) == 0 )
- {
- drhd = acpi_find_matched_drhd_unit(pdev);
- ret = domain_context_mapping(d, drhd->iommu, pdev);
- if ( !ret )
- return 0;
- }
-
- return ret;
-}
-
-void __init setup_dom0_devices(void)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(dom0);
- struct acpi_drhd_unit *drhd;
- struct pci_dev *pdev;
- int bus, dev, func, ret;
- u32 l;
-
-#ifdef DEBUG_VTD_CONTEXT_ENTRY
- for ( bus = 0; bus < 256; bus++ )
- {
- for ( dev = 0; dev < 32; dev++ )
- {
- for ( func = 0; func < 8; func++ )
- {
- struct context_entry *context;
- struct pci_dev device;
-
- device.bus = bus;
- device.devfn = PCI_DEVFN(dev, func);
- drhd = acpi_find_matched_drhd_unit(&device);
- context = device_to_context_entry(drhd->iommu,
- bus, PCI_DEVFN(dev, func));
- if ( (context->lo != 0) || (context->hi != 0) )
- dprintk(XENLOG_INFO VTDPREFIX,
- "setup_dom0_devices-%x:%x:%x- context not 0\n",
- bus, dev, func);
- }
- }
- }
-#endif
-
- 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);
-
- drhd = acpi_find_matched_drhd_unit(pdev);
- ret = domain_context_mapping(dom0, drhd->iommu, pdev);
- if ( ret != 0 )
- gdprintk(XENLOG_ERR VTDPREFIX,
- "domain_context_mapping failed\n");
- }
- }
- }
-
- for_each_pdev ( dom0, pdev )
- dprintk(XENLOG_INFO VTDPREFIX,
- "setup_dom0_devices: bdf = %x:%x:%x\n",
- pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-}
-
-void clear_fault_bits(struct iommu *iommu)
-{
- u64 val;
-
- val = dmar_readq(
- iommu->reg,
- cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+0x8);
- dmar_writeq(
- iommu->reg,
- cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+8,
- val);
- dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_FAULTS);
-}
-
-static int init_vtd_hw(void)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- struct iommu_flush *flush = NULL;
- int vector;
- int ret;
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- ret = iommu_set_root_entry(iommu);
- if ( ret )
- {
- gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: set root entry failed\n");
- return -EIO;
- }
-
- vector = iommu_set_interrupt(iommu);
- dma_msi_data_init(iommu, vector);
- dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(cpu_online_map)));
- iommu->vector = vector;
- clear_fault_bits(iommu);
- dmar_writel(iommu->reg, DMAR_FECTL_REG, 0);
-
- /* initialize flush functions */
- flush = iommu_get_flush(iommu);
- flush->context = flush_context_reg;
- flush->iotlb = flush_iotlb_reg;
- }
- return 0;
-}
-
-static int init_vtd2_hw(void)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( qinval_setup(iommu) != 0 )
- dprintk(XENLOG_ERR VTDPREFIX,
- "Queued Invalidation hardware not found\n");
-
- if ( intremap_setup(iommu) != 0 )
- dprintk(XENLOG_ERR VTDPREFIX,
- "Interrupt Remapping hardware not found\n");
- }
- return 0;
-}
-
-static int enable_vtd_translation(void)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- if ( iommu_enable_translation(iommu) )
- return -EIO;
- }
- return 0;
-}
-
-static void setup_dom0_rmrr(void)
-{
- struct acpi_rmrr_unit *rmrr;
- struct pci_dev *pdev;
- int ret;
-
- for_each_rmrr_device ( rmrr, pdev )
- ret = iommu_prepare_rmrr_dev(dom0, rmrr, pdev);
- if ( ret )
- gdprintk(XENLOG_ERR VTDPREFIX,
- "IOMMU: mapping reserved region failed\n");
- end_for_each_rmrr_device ( rmrr, pdev )
-}
-
-int iommu_setup(void)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(dom0);
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- unsigned long i;
-
- if ( !vtd_enabled )
- return 0;
-
- spin_lock_init(&domid_bitmap_lock);
- INIT_LIST_HEAD(&hd->pdev_list);
-
- /* setup clflush size */
- x86_clflush_size = ((cpuid_ebx(1) >> 8) & 0xff) * 8;
-
- /* Allocate IO page directory page for the domain. */
- drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
- iommu = drhd->iommu;
-
- /* Allocate domain id bitmap, and set bit 0 as reserved */
- domid_bitmap_size = cap_ndoms(iommu->cap);
- domid_bitmap = xmalloc_bytes(domid_bitmap_size / 8);
- if ( domid_bitmap == NULL )
- goto error;
- memset(domid_bitmap, 0, domid_bitmap_size / 8);
- set_bit(0, domid_bitmap);
-
- /* setup 1:1 page table for dom0 */
- for ( i = 0; i < max_page; i++ )
- iommu_map_page(dom0, i, i);
-
- init_vtd_hw();
- setup_dom0_devices();
- setup_dom0_rmrr();
- iommu_flush_all();
- enable_vtd_translation();
- init_vtd2_hw();
-
- return 0;
-
- error:
- printk("iommu_setup() failed\n");
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- free_iommu(iommu);
- }
- return -EIO;
-}
-
-/*
- * If the device isn't owned by dom0, it means it already
- * has been assigned to other domain, or it's not exist.
- */
-int device_assigned(u8 bus, u8 devfn)
-{
- struct pci_dev *pdev;
-
- for_each_pdev( dom0, pdev )
- if ( (pdev->bus == bus ) && (pdev->devfn == devfn) )
- return 0;
-
- return 1;
-}
-
-int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
-{
- struct acpi_rmrr_unit *rmrr;
- struct pci_dev *pdev;
- int ret = 0;
-
- if ( list_empty(&acpi_drhd_units) )
- return ret;
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "assign_device: bus = %x dev = %x func = %x\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
- reassign_device_ownership(dom0, d, bus, devfn);
-
- /* Setup rmrr identify mapping */
- for_each_rmrr_device( rmrr, pdev )
- if ( pdev->bus == bus && pdev->devfn == devfn )
- {
- ret = iommu_prepare_rmrr_dev(d, rmrr, pdev);
- if ( ret )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "IOMMU: mapping reserved region failed\n");
- return ret;
- }
- }
- end_for_each_rmrr_device(rmrr, pdev)
-
- return ret;
-}
-
-void iommu_set_pgd(struct domain *d)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
- unsigned long p2m_table;
-
- if ( hd->pgd )
- {
- gdprintk(XENLOG_INFO VTDPREFIX,
- "iommu_set_pgd_1: hd->pgd = %p\n", hd->pgd);
- hd->pgd = NULL;
- }
- p2m_table = mfn_x(pagetable_get_mfn(d->arch.phys_table));
-
-#if CONFIG_PAGING_LEVELS == 3
- if ( !hd->pgd )
- {
- int level = agaw_to_level(hd->agaw);
- struct dma_pte *pmd = NULL;
- struct dma_pte *pgd = NULL;
- struct dma_pte *pte = NULL;
- l3_pgentry_t *l3e;
- unsigned long flags;
- int i;
-
- 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);
- gdprintk(XENLOG_ERR VTDPREFIX,
- "Allocate pgd memory failed!\n");
- return;
- }
- memset(pgd, 0, PAGE_SIZE);
- hd->pgd = pgd;
- }
-
- l3e = map_domain_page(p2m_table);
- switch ( level )
- {
- case VTD_PAGE_TABLE_LEVEL_3: /* Weybridge */
- /* We only support 8 entries for the PAE L3 p2m table */
- for ( i = 0; i < 8 ; i++ )
- {
- /* Don't create new L2 entry, use ones from p2m table */
- pgd[i].val = l3e[i].l3 | _PAGE_PRESENT | _PAGE_RW;
- }
- break;
-
- case VTD_PAGE_TABLE_LEVEL_4: /* Stoakley */
- /* We allocate one more page for the top vtd page table. */
- pmd = (struct dma_pte *)alloc_xenheap_page();
- if ( !pmd )
- {
- unmap_domain_page(l3e);
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- gdprintk(XENLOG_ERR VTDPREFIX,
- "Allocate pmd memory failed!\n");
- return;
- }
- memset((u8*)pmd, 0, PAGE_SIZE);
- pte = &pgd[0];
- dma_set_pte_addr(*pte, virt_to_maddr(pmd));
- dma_set_pte_readable(*pte);
- dma_set_pte_writable(*pte);
-
- for ( i = 0; i < 8; i++ )
- {
- /* Don't create new L2 entry, use ones from p2m table */
- pmd[i].val = l3e[i].l3 | _PAGE_PRESENT | _PAGE_RW;
- }
- break;
- default:
- gdprintk(XENLOG_ERR VTDPREFIX,
- "iommu_set_pgd:Unsupported p2m table sharing level!\n");
- break;
- }
- unmap_domain_page(l3e);
- spin_unlock_irqrestore(&hd->mapping_lock, flags);
- }
-#elif CONFIG_PAGING_LEVELS == 4
- if ( !hd->pgd )
- {
- int level = agaw_to_level(hd->agaw);
- l3_pgentry_t *l3e;
- mfn_t pgd_mfn;
-
- switch ( level )
- {
- case VTD_PAGE_TABLE_LEVEL_3:
- l3e = map_domain_page(p2m_table);
- if ( (l3e_get_flags(*l3e) & _PAGE_PRESENT) == 0 )
- {
- gdprintk(XENLOG_ERR VTDPREFIX,
- "iommu_set_pgd: second level wasn't there\n");
- unmap_domain_page(l3e);
- return;
- }
- pgd_mfn = _mfn(l3e_get_pfn(*l3e));
- unmap_domain_page(l3e);
- hd->pgd = maddr_to_virt(pagetable_get_paddr(
- pagetable_from_mfn(pgd_mfn)));
- break;
-
- case VTD_PAGE_TABLE_LEVEL_4:
- pgd_mfn = _mfn(p2m_table);
- hd->pgd = maddr_to_virt(pagetable_get_paddr(
- pagetable_from_mfn(pgd_mfn)));
- break;
- default:
- gdprintk(XENLOG_ERR VTDPREFIX,
- "iommu_set_pgd:Unsupported p2m table sharing level!\n");
- break;
- }
- }
-#endif
- gdprintk(XENLOG_INFO VTDPREFIX,
- "iommu_set_pgd: hd->pgd = %p\n", hd->pgd);
-}
-
-
-u8 iommu_state[MAX_IOMMU_REGS * MAX_IOMMUS];
-int iommu_suspend(void)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- int i = 0;
-
- iommu_flush_all();
-
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- iommu_state[DMAR_RTADDR_REG * i] =
- (u64) dmar_readq(iommu->reg, DMAR_RTADDR_REG);
- iommu_state[DMAR_FECTL_REG * i] =
- (u32) dmar_readl(iommu->reg, DMAR_FECTL_REG);
- iommu_state[DMAR_FEDATA_REG * i] =
- (u32) dmar_readl(iommu->reg, DMAR_FEDATA_REG);
- iommu_state[DMAR_FEADDR_REG * i] =
- (u32) dmar_readl(iommu->reg, DMAR_FEADDR_REG);
- iommu_state[DMAR_FEUADDR_REG * i] =
- (u32) dmar_readl(iommu->reg, DMAR_FEUADDR_REG);
- iommu_state[DMAR_PLMBASE_REG * i] =
- (u32) dmar_readl(iommu->reg, DMAR_PLMBASE_REG);
- iommu_state[DMAR_PLMLIMIT_REG * i] =
- (u32) dmar_readl(iommu->reg, DMAR_PLMLIMIT_REG);
- iommu_state[DMAR_PHMBASE_REG * i] =
- (u64) dmar_readq(iommu->reg, DMAR_PHMBASE_REG);
- iommu_state[DMAR_PHMLIMIT_REG * i] =
- (u64) dmar_readq(iommu->reg, DMAR_PHMLIMIT_REG);
- i++;
- }
-
- return 0;
-}
-
-int iommu_resume(void)
-{
- struct acpi_drhd_unit *drhd;
- struct iommu *iommu;
- int i = 0;
-
- iommu_flush_all();
-
- init_vtd_hw();
- for_each_drhd_unit ( drhd )
- {
- iommu = drhd->iommu;
- dmar_writeq( iommu->reg, DMAR_RTADDR_REG,
- (u64) iommu_state[DMAR_RTADDR_REG * i]);
- dmar_writel(iommu->reg, DMAR_FECTL_REG,
- (u32) iommu_state[DMAR_FECTL_REG * i]);
- dmar_writel(iommu->reg, DMAR_FEDATA_REG,
- (u32) iommu_state[DMAR_FEDATA_REG * i]);
- dmar_writel(iommu->reg, DMAR_FEADDR_REG,
- (u32) iommu_state[DMAR_FEADDR_REG * i]);
- dmar_writel(iommu->reg, DMAR_FEUADDR_REG,
- (u32) iommu_state[DMAR_FEUADDR_REG * i]);
- dmar_writel(iommu->reg, DMAR_PLMBASE_REG,
- (u32) iommu_state[DMAR_PLMBASE_REG * i]);
- dmar_writel(iommu->reg, DMAR_PLMLIMIT_REG,
- (u32) iommu_state[DMAR_PLMLIMIT_REG * i]);
- dmar_writeq(iommu->reg, DMAR_PHMBASE_REG,
- (u64) iommu_state[DMAR_PHMBASE_REG * i]);
- dmar_writeq(iommu->reg, DMAR_PHMLIMIT_REG,
- (u64) iommu_state[DMAR_PHMLIMIT_REG * i]);
-
- if ( iommu_enable_translation(iommu) )
- return -EIO;
- i++;
- }
- return 0;
-}
-
-struct iommu_ops intel_iommu_ops = {
- .init = intel_iommu_domain_init,
- .assign_device = intel_iommu_assign_device,
- .teardown = iommu_domain_teardown,
- .map_page = intel_iommu_map_page,
- .unmap_page = intel_iommu_unmap_page,
- .reassign_device = reassign_device_ownership,
-};
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/intremap.c
--- a/xen/arch/x86/hvm/vmx/vtd/intremap.c Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- * Copyright (C) Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
- */
-
-#include <xen/config.h>
-#include <xen/lib.h>
-#include <xen/init.h>
-#include <xen/irq.h>
-#include <xen/delay.h>
-#include <xen/sched.h>
-#include <xen/acpi.h>
-#include <xen/keyhandler.h>
-#include <xen/spinlock.h>
-#include <asm/io.h>
-#include <asm/mc146818rtc.h>
-#include <asm/smp.h>
-#include <asm/desc.h>
-#include <mach_apic.h>
-#include <io_ports.h>
-
-#include <xen/spinlock.h>
-#include <xen/xmalloc.h>
-#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/iommu.h>
-#include <asm/hvm/vmx/intel-iommu.h>
-#include "dmar.h"
-#include "vtd.h"
-#include "pci-direct.h"
-#include "pci_regs.h"
-#include "msi.h"
-#include "extern.h"
-
-u16 apicid_to_bdf(int apic_id)
-{
- struct acpi_drhd_unit *drhd = ioapic_to_drhd(apic_id);
- struct acpi_ioapic_unit *acpi_ioapic_unit;
-
- list_for_each_entry ( acpi_ioapic_unit, &drhd->ioapic_list, list )
- if ( acpi_ioapic_unit->apic_id == apic_id )
- return acpi_ioapic_unit->ioapic.info;
-
- dprintk(XENLOG_ERR VTDPREFIX, "Didn't find the bdf for the apic_id!\n");
- return 0;
-}
-
-static void remap_entry_to_ioapic_rte(
- struct iommu *iommu, struct IO_APIC_route_entry *old_rte)
-{
- struct iremap_entry *iremap_entry = NULL;
- struct IO_APIC_route_remap_entry *remap_rte;
- unsigned int index;
- unsigned long flags;
- struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
-
- if ( ir_ctrl == NULL )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "remap_entry_to_ioapic_rte: ir_ctl == NULL");
- return;
- }
-
- remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
- index = (remap_rte->index_15 << 15) + remap_rte->index_0_14;
-
- if ( index > ir_ctrl->iremap_index )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "Index is larger than remap table entry size. Error!\n");
- return;
- }
-
- spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
-
- iremap_entry = &ir_ctrl->iremap[index];
-
- old_rte->vector = iremap_entry->lo.vector;
- old_rte->delivery_mode = iremap_entry->lo.dlm;
- old_rte->dest_mode = iremap_entry->lo.dm;
- old_rte->trigger = iremap_entry->lo.tm;
- old_rte->__reserved_2 = 0;
- old_rte->dest.logical.__reserved_1 = 0;
- old_rte->dest.logical.logical_dest = iremap_entry->lo.dst;
-
- spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
-}
-
-static void ioapic_rte_to_remap_entry(struct iommu *iommu,
- int apic_id, struct IO_APIC_route_entry *old_rte)
-{
- struct iremap_entry *iremap_entry = NULL;
- struct IO_APIC_route_remap_entry *remap_rte;
- unsigned int index;
- unsigned long flags;
- int ret = 0;
- struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
-
- remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
- spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
- index = ir_ctrl->iremap_index;
- if ( index > IREMAP_ENTRY_NR - 1 )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "The interrupt number is more than 256!\n");
- goto out;
- }
-
- iremap_entry = &(ir_ctrl->iremap[index]);
- if ( *(u64 *)iremap_entry != 0 )
- dprintk(XENLOG_WARNING VTDPREFIX,
- "Interrupt remapping entry is in use already!\n");
- iremap_entry->lo.fpd = 0;
- iremap_entry->lo.dm = old_rte->dest_mode;
- iremap_entry->lo.rh = 0;
- iremap_entry->lo.tm = old_rte->trigger;
- iremap_entry->lo.dlm = old_rte->delivery_mode;
- iremap_entry->lo.avail = 0;
- iremap_entry->lo.res_1 = 0;
- iremap_entry->lo.vector = old_rte->vector;
- iremap_entry->lo.res_2 = 0;
- iremap_entry->lo.dst = (old_rte->dest.logical.logical_dest << 8);
- iremap_entry->hi.sid = apicid_to_bdf(apic_id);
- iremap_entry->hi.sq = 0; /* comparing all 16-bit of SID */
- iremap_entry->hi.svt = 1; /* turn on requestor ID verification SID/SQ */
- iremap_entry->hi.res_1 = 0;
- iremap_entry->lo.p = 1; /* finally, set present bit */
- ir_ctrl->iremap_index++;
-
- iommu_flush_iec_index(iommu, 0, index);
- ret = invalidate_sync(iommu);
-
- /* now construct new ioapic rte entry */
- remap_rte->vector = old_rte->vector;
- remap_rte->delivery_mode = 0; /* has to be 0 for remap format */
- remap_rte->index_15 = index & 0x8000;
- remap_rte->index_0_14 = index & 0x7fff;
- remap_rte->delivery_status = old_rte->delivery_status;
- remap_rte->polarity = old_rte->polarity;
- remap_rte->irr = old_rte->irr;
- remap_rte->trigger = old_rte->trigger;
- remap_rte->mask = 1;
- remap_rte->reserved = 0;
- remap_rte->format = 1; /* indicate remap format */
-out:
- spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
- return;
-}
-
-unsigned int
-io_apic_read_remap_rte(
- unsigned int apic, unsigned int reg)
-{
- struct IO_APIC_route_entry old_rte = { 0 };
- struct IO_APIC_route_remap_entry *remap_rte;
- int rte_upper = (reg & 1) ? 1 : 0;
- struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
- struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
-
- if ( !iommu || !(ir_ctrl->iremap) )
- {
- *IO_APIC_BASE(apic) = reg;
- return *(IO_APIC_BASE(apic)+4);
- }
-
- if ( rte_upper )
- reg--;
-
- /* read lower and upper 32-bits of rte entry */
- *IO_APIC_BASE(apic) = reg;
- *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4);
- *IO_APIC_BASE(apic) = reg + 1;
- *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4);
-
- remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
-
- if ( remap_rte->mask || (remap_rte->format == 0) )
- {
- *IO_APIC_BASE(apic) = reg;
- return *(IO_APIC_BASE(apic)+4);
- }
-
- remap_entry_to_ioapic_rte(iommu, &old_rte);
- if ( rte_upper )
- {
- *IO_APIC_BASE(apic) = reg + 1;
- return (*(((u32 *)&old_rte) + 1));
- }
- else
- {
- *IO_APIC_BASE(apic) = reg;
- return (*(((u32 *)&old_rte) + 0));
- }
-}
-
-void
-io_apic_write_remap_rte(
- unsigned int apic, unsigned int reg, unsigned int value)
-{
- struct IO_APIC_route_entry old_rte = { 0 };
- struct IO_APIC_route_remap_entry *remap_rte;
- int rte_upper = (reg & 1) ? 1 : 0;
- struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
- struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
-
- if ( !iommu || !(ir_ctrl->iremap) )
- {
- *IO_APIC_BASE(apic) = reg;
- *(IO_APIC_BASE(apic)+4) = value;
- return;
- }
-
- if ( rte_upper )
- reg--;
-
- /* read both lower and upper 32-bits of rte entry */
- *IO_APIC_BASE(apic) = reg;
- *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4);
- *IO_APIC_BASE(apic) = reg + 1;
- *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4);
-
- remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
- if ( remap_rte->mask || (remap_rte->format == 0) )
- {
- *IO_APIC_BASE(apic) = rte_upper ? ++reg : reg;
- *(IO_APIC_BASE(apic)+4) = value;
- return;
- }
-
- *(((u32 *)&old_rte) + rte_upper) = value;
- ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid, &old_rte);
-
- /* write new entry to ioapic */
- *IO_APIC_BASE(apic) = reg;
- *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0);
- *IO_APIC_BASE(apic) = reg + 1;
- *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+1);
-}
-
-int intremap_setup(struct iommu *iommu)
-{
- struct ir_ctrl *ir_ctrl;
- unsigned long start_time;
- u64 paddr;
-
- if ( !ecap_intr_remap(iommu->ecap) )
- return -ENODEV;
-
- ir_ctrl = iommu_ir_ctrl(iommu);
- if ( ir_ctrl->iremap == NULL )
- {
- ir_ctrl->iremap = alloc_xenheap_page();
- if ( ir_ctrl->iremap == NULL )
- {
- dprintk(XENLOG_WARNING VTDPREFIX,
- "Cannot allocate memory for ir_ctrl->iremap\n");
- return -ENODEV;
- }
- memset(ir_ctrl->iremap, 0, PAGE_SIZE);
- }
-
- paddr = virt_to_maddr(ir_ctrl->iremap);
-#if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT)
- /* set extended interrupt mode bit */
- paddr |= ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIMI_SHIFT) : 0;
-#endif
- /* size field = 256 entries per 4K page = 8 - 1 */
- paddr |= 7;
- dmar_writeq(iommu->reg, DMAR_IRTA_REG, paddr);
-
- /* set SIRTP */
- iommu->gcmd |= DMA_GCMD_SIRTP;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
-
- /* Make sure hardware complete it */
- start_time = jiffies;
- while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) )
- {
- if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "Cannot set SIRTP field for interrupt remapping\n");
- return -ENODEV;
- }
- cpu_relax();
- }
-
- /* enable comaptiblity format interrupt pass through */
- iommu->gcmd |= DMA_GCMD_CFI;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
-
- start_time = jiffies;
- while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) )
- {
- if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "Cannot set CFI field for interrupt remapping\n");
- return -ENODEV;
- }
- cpu_relax();
- }
-
- /* enable interrupt remapping hardware */
- iommu->gcmd |= DMA_GCMD_IRE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
-
- start_time = jiffies;
- while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) )
- {
- if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "Cannot set IRE field for interrupt remapping\n");
- return -ENODEV;
- }
- cpu_relax();
- }
-
- /* After set SIRTP, we should do globally invalidate the IEC */
- iommu_flush_iec_global(iommu);
-
- return 0;
-}
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/io.c
--- a/xen/arch/x86/hvm/vmx/vtd/io.c Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- * Copyright (C) Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
- */
-
-#include <xen/init.h>
-#include <xen/config.h>
-#include <xen/init.h>
-#include <xen/mm.h>
-#include <xen/lib.h>
-#include <xen/errno.h>
-#include <xen/trace.h>
-#include <xen/event.h>
-#include <xen/hypercall.h>
-#include <asm/current.h>
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/apic.h>
-#include <asm/paging.h>
-#include <asm/shadow.h>
-#include <asm/p2m.h>
-#include <asm/hvm/hvm.h>
-#include <asm/hvm/support.h>
-#include <asm/hvm/vpt.h>
-#include <asm/hvm/vpic.h>
-#include <asm/hvm/vlapic.h>
-#include <public/sched.h>
-#include <xen/iocap.h>
-#include <public/hvm/ioreq.h>
-#include <public/domctl.h>
-
-static void pt_irq_time_out(void *data)
-{
- struct hvm_mirq_dpci_mapping *irq_map = data;
- unsigned int guest_gsi, machine_gsi = 0;
- struct hvm_irq_dpci *dpci = irq_map->dom->arch.hvm_domain.irq.dpci;
- struct dev_intx_gsi_link *digl;
- uint32_t device, intx;
-
- list_for_each_entry ( digl, &irq_map->digl_list, list )
- {
- guest_gsi = digl->gsi;
- machine_gsi = dpci->girq[guest_gsi].machine_gsi;
- device = digl->device;
- intx = digl->intx;
- hvm_pci_intx_deassert(irq_map->dom, device, intx);
- }
-
- clear_bit(machine_gsi, dpci->dirq_mask);
- stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]);
- spin_lock(&dpci->dirq_lock);
- dpci->mirq[machine_gsi].pending = 0;
- spin_unlock(&dpci->dirq_lock);
- pirq_guest_eoi(irq_map->dom, machine_gsi);
-}
-
-int pt_irq_create_bind_vtd(
- struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t machine_gsi, guest_gsi;
- uint32_t device, intx, link;
- struct dev_intx_gsi_link *digl;
-
- if ( hvm_irq_dpci == NULL )
- {
- hvm_irq_dpci = xmalloc(struct hvm_irq_dpci);
- if ( hvm_irq_dpci == NULL )
- return -ENOMEM;
-
- memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
- spin_lock_init(&hvm_irq_dpci->dirq_lock);
- for ( int i = 0; i < NR_IRQS; i++ )
- INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
-
- if ( cmpxchg((unsigned long *)&d->arch.hvm_domain.irq.dpci,
- 0, (unsigned long)hvm_irq_dpci) != 0 )
- xfree(hvm_irq_dpci);
-
- hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- }
-
- machine_gsi = pt_irq_bind->machine_irq;
- device = pt_irq_bind->u.pci.device;
- intx = pt_irq_bind->u.pci.intx;
- guest_gsi = hvm_pci_intx_gsi(device, intx);
- link = hvm_pci_intx_link(device, intx);
- hvm_irq_dpci->link_cnt[link]++;
-
- digl = xmalloc(struct dev_intx_gsi_link);
- if ( !digl )
- return -ENOMEM;
-
- digl->device = device;
- digl->intx = intx;
- digl->gsi = guest_gsi;
- digl->link = link;
- list_add_tail(&digl->list,
- &hvm_irq_dpci->mirq[machine_gsi].digl_list);
-
- hvm_irq_dpci->girq[guest_gsi].valid = 1;
- hvm_irq_dpci->girq[guest_gsi].device = device;
- hvm_irq_dpci->girq[guest_gsi].intx = intx;
- hvm_irq_dpci->girq[guest_gsi].machine_gsi = machine_gsi;
-
- /* Bind the same mirq once in the same domain */
- if ( !hvm_irq_dpci->mirq[machine_gsi].valid )
- {
- hvm_irq_dpci->mirq[machine_gsi].valid = 1;
- hvm_irq_dpci->mirq[machine_gsi].dom = d;
-
- init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
- pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
- /* Deal with gsi for legacy devices */
- pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
- }
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "VT-d irq bind: m_irq = %x device = %x intx = %x\n",
- machine_gsi, device, intx);
- return 0;
-}
-
-int pt_irq_destroy_bind_vtd(
- struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t machine_gsi, guest_gsi;
- uint32_t device, intx, link;
- struct list_head *digl_list, *tmp;
- struct dev_intx_gsi_link *digl;
-
- if ( hvm_irq_dpci == NULL )
- return 0;
-
- machine_gsi = pt_irq_bind->machine_irq;
- device = pt_irq_bind->u.pci.device;
- intx = pt_irq_bind->u.pci.intx;
- guest_gsi = hvm_pci_intx_gsi(device, intx);
- link = hvm_pci_intx_link(device, intx);
- hvm_irq_dpci->link_cnt[link]--;
-
- gdprintk(XENLOG_INFO,
- "pt_irq_destroy_bind_vtd: machine_gsi=%d, guest_gsi=%d, device=%d,
intx=%d.\n",
- machine_gsi, guest_gsi, device, intx);
- memset(&hvm_irq_dpci->girq[guest_gsi], 0, sizeof(struct
hvm_girq_dpci_mapping));
-
- /* clear the mirq info */
- if ( hvm_irq_dpci->mirq[machine_gsi].valid )
- {
-
- list_for_each_safe ( digl_list, tmp,
- &hvm_irq_dpci->mirq[machine_gsi].digl_list )
- {
- digl = list_entry(digl_list,
- struct dev_intx_gsi_link, list);
- if ( digl->device == device &&
- digl->intx == intx &&
- digl->link == link &&
- digl->gsi == guest_gsi )
- {
- list_del(&digl->list);
- xfree(digl);
- }
- }
-
- if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
- {
- pirq_guest_unbind(d, machine_gsi);
- kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
- hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
- hvm_irq_dpci->mirq[machine_gsi].valid = 0;
- }
- }
-
- gdprintk(XENLOG_INFO,
- "XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n",
- machine_gsi, device, intx);
-
- return 0;
-}
-
-int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
-{
- struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
-
- if ( !iommu_enabled || (d == dom0) || (hvm_irq->dpci == NULL) ||
- !hvm_irq->dpci->mirq[mirq].valid )
- return 0;
-
- /*
- * Set a timer here to avoid situations where the IRQ line is shared, and
- * the device belonging to the pass-through guest is not yet active. In
- * this case the guest may not pick up the interrupt (e.g., masked at the
- * PIC) and we need to detect that.
- */
- set_bit(mirq, hvm_irq->dpci->dirq_mask);
- set_timer(&hvm_irq->dpci->hvm_timer[irq_to_vector(mirq)],
- NOW() + PT_IRQ_TIME_OUT);
- vcpu_kick(d->vcpu[0]);
-
- return 1;
-}
-
-static void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
-{
- struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
- struct hvm_irq_dpci *dpci = hvm_irq->dpci;
- struct dev_intx_gsi_link *digl, *tmp;
- int i;
-
- ASSERT(isairq < NR_ISAIRQS);
- if ( !iommu_enabled || !dpci ||
- !test_bit(isairq, dpci->isairq_map) )
- return;
-
- /* Multiple mirq may be mapped to one isa irq */
- for ( i = 0; i < NR_IRQS; i++ )
- {
- if ( !dpci->mirq[i].valid )
- continue;
-
- list_for_each_entry_safe ( digl, tmp,
- &dpci->mirq[i].digl_list, list )
- {
- if ( hvm_irq->pci_link.route[digl->link] == isairq )
- {
- hvm_pci_intx_deassert(d, digl->device, digl->intx);
- spin_lock(&dpci->dirq_lock);
- if ( --dpci->mirq[i].pending == 0 )
- {
- spin_unlock(&dpci->dirq_lock);
- gdprintk(XENLOG_INFO VTDPREFIX,
- "hvm_dpci_isairq_eoi:: mirq = %x\n", i);
- stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
- pirq_guest_eoi(d, i);
- }
- else
- spin_unlock(&dpci->dirq_lock);
- }
- }
- }
-}
-
-void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
- union vioapic_redir_entry *ent)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t device, intx, machine_gsi;
-
- if ( !iommu_enabled || (hvm_irq_dpci == NULL) ||
- (guest_gsi >= NR_ISAIRQS &&
- !hvm_irq_dpci->girq[guest_gsi].valid) )
- return;
-
- if ( guest_gsi < NR_ISAIRQS )
- {
- hvm_dpci_isairq_eoi(d, guest_gsi);
- return;
- }
-
- machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
- device = hvm_irq_dpci->girq[guest_gsi].device;
- intx = hvm_irq_dpci->girq[guest_gsi].intx;
- hvm_pci_intx_deassert(d, device, intx);
-
- spin_lock(&hvm_irq_dpci->dirq_lock);
- if ( --hvm_irq_dpci->mirq[machine_gsi].pending == 0 )
- {
- spin_unlock(&hvm_irq_dpci->dirq_lock);
-
- gdprintk(XENLOG_INFO VTDPREFIX,
- "hvm_dpci_eoi:: mirq = %x\n", machine_gsi);
- stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
- if ( (ent == NULL) || !ent->fields.mask )
- pirq_guest_eoi(d, machine_gsi);
- }
- else
- spin_unlock(&hvm_irq_dpci->dirq_lock);
-}
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/msi.h
--- a/xen/arch/x86/hvm/vmx/vtd/msi.h Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@xxxxxxxxx)
- */
-
-#ifndef MSI_H
-#define MSI_H
-
-/*
- * Assume the maximum number of hot plug slots supported by the system is about
- * ten. The worstcase is that each of these slots is hot-added with a device,
- * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
- * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
- * as below to ensure at least one message is assigned to each detected MSI/
- * MSI-X device function.
- */
-#define NR_HP_RESERVED_VECTORS 20
-
-extern int vector_irq[NR_VECTORS];
-extern int pci_vector_resources(int last, int nr_released);
-
-/*
- * MSI-X Address Register
- */
-#define PCI_MSIX_FLAGS_QSIZE 0x7FF
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
-#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
-
-#define PCI_MSIX_ENTRY_SIZE 16
-#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4
-#define PCI_MSIX_ENTRY_DATA_OFFSET 8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12
-
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
-#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
-#define msi_data_reg(base, is64bit) \
- ( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 )
-#define msi_mask_bits_reg(base, is64bit) \
- ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
-#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE
-#define multi_msi_capable(control) \
- (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
-#define multi_msi_enable(control, num) \
- control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
-#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT)
-#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT)
-#define msi_enable(control, num) multi_msi_enable(control, num); \
- control |= PCI_MSI_FLAGS_ENABLE
-
-#define msix_table_offset_reg(base) (base + 0x04)
-#define msix_pba_offset_reg(base) (base + 0x08)
-#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE
-#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE
-#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
-#define multi_msix_capable msix_table_size
-#define msix_unmask(address) (address & ~PCI_MSIX_FLAGS_BITMASK)
-#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
-#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
-
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER 0xfee
-#define MSI_ADDRESS_HEADER_SHIFT 12
-#define MSI_ADDRESS_HEADER_MASK 0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f
-#define MSI_TARGET_CPU_MASK 0xff
-#define MSI_TARGET_CPU_SHIFT 12
-#define MSI_DELIVERY_MODE 0
-#define MSI_LEVEL_MODE 1 /* Edge always assert */
-#define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE 0
-#define MSI_LOGICAL_MODE 1
-#define MSI_REDIRECTION_HINT_MODE 0
-
-#define __LITTLE_ENDIAN_BITFIELD 1
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u32 vector : 8;
- __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */
- __u32 reserved_1 : 3;
- __u32 level : 1; /* 0: deassert | 1: assert */
- __u32 trigger : 1; /* 0: edge | 1: level */
- __u32 reserved_2 : 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u32 reserved_2 : 16;
- __u32 trigger : 1; /* 0: edge | 1: level */
- __u32 level : 1; /* 0: deassert | 1: assert */
- __u32 reserved_1 : 3;
- __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */
- __u32 vector : 8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
- union {
- struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u32 reserved_1 : 2;
- __u32 dest_mode : 1; /*0:physic | 1:logic */
- __u32 redirection_hint: 1; /*0: dedicated CPU
- 1: lowest priority */
- __u32 reserved_2 : 4;
- __u32 dest_id : 24; /* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u32 dest_id : 24; /* Destination ID */
- __u32 reserved_2 : 4;
- __u32 redirection_hint: 1; /*0: dedicated CPU
- 1: lowest priority */
- __u32 dest_mode : 1; /*0:physic | 1:logic */
- __u32 reserved_1 : 2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- }u;
- __u32 value;
- }lo_address;
- __u32 hi_address;
-} __attribute__ ((packed));
-
-#endif /* MSI_H */
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/pci-direct.h
--- a/xen/arch/x86/hvm/vmx/vtd/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/vmx/vtd/pci_regs.h
--- a/xen/arch/x86/hvm/vmx/vtd/pci_regs.h Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,449 +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
- */
-
-#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_IRQCONF 0x08 /* HyperTransport IRQ Configuration */
-#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 */
-
-/* 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_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 */
-#define PCI_ERR_ROOT_STATUS 48
-#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 */
-
-#endif /* LINUX_PCI_REGS_H */
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/qinval.c
--- a/xen/arch/x86/hvm/vmx/vtd/qinval.c Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,456 +0,0 @@
-/*
- * Copyright (c) 2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) Allen Kay <allen.m.kay@xxxxxxxxx>
- * Copyright (C) Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
- */
-
-
-#include <xen/init.h>
-#include <xen/irq.h>
-#include <xen/spinlock.h>
-#include <xen/sched.h>
-#include <xen/xmalloc.h>
-#include <xen/domain_page.h>
-#include <asm/delay.h>
-#include <asm/string.h>
-#include <asm/iommu.h>
-#include <asm/hvm/vmx/intel-iommu.h>
-#include "dmar.h"
-#include "vtd.h"
-#include "pci-direct.h"
-#include "pci_regs.h"
-#include "msi.h"
-#include "extern.h"
-
-static void print_qi_regs(struct iommu *iommu)
-{
- u64 val;
-
- val = dmar_readq(iommu->reg, DMAR_IQA_REG);
- printk("DMAR_IAQ_REG = %"PRIx64"\n", val);
-
- val = dmar_readq(iommu->reg, DMAR_IQH_REG);
- printk("DMAR_IAH_REG = %"PRIx64"\n", val);
-
- val = dmar_readq(iommu->reg, DMAR_IQT_REG);
- printk("DMAR_IAT_REG = %"PRIx64"\n", val);
-}
-
-static int qinval_next_index(struct iommu *iommu)
-{
- u64 val;
- val = dmar_readq(iommu->reg, DMAR_IQT_REG);
- return (val >> 4);
-}
-
-static int qinval_update_qtail(struct iommu *iommu, int index)
-{
- u64 val;
-
- /* Need an ASSERT to insure that we have got register lock */
- val = (index < (QINVAL_ENTRY_NR-1)) ? (index + 1) : 0;
- dmar_writeq(iommu->reg, DMAR_IQT_REG, (val << 4));
- return 0;
-}
-
-static int gen_cc_inv_dsc(struct iommu *iommu, int index,
- u16 did, u16 source_id, u8 function_mask, u8 granu)
-{
- u64 *ptr64;
- unsigned long flags;
- struct qinval_entry * qinval_entry = NULL;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- spin_lock_irqsave(&qi_ctrl->qinval_lock, flags);
- qinval_entry = &qi_ctrl->qinval[index];
- qinval_entry->q.cc_inv_dsc.lo.type = TYPE_INVAL_CONTEXT;
- qinval_entry->q.cc_inv_dsc.lo.granu = granu;
- qinval_entry->q.cc_inv_dsc.lo.res_1 = 0;
- qinval_entry->q.cc_inv_dsc.lo.did = did;
- qinval_entry->q.cc_inv_dsc.lo.sid = source_id;
- qinval_entry->q.cc_inv_dsc.lo.fm = function_mask;
- qinval_entry->q.cc_inv_dsc.lo.res_2 = 0;
- qinval_entry->q.cc_inv_dsc.hi.res = 0;
- spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags);
-
- ptr64 = (u64 *)qinval_entry;
- return 0;
-}
-
-int queue_invalidate_context(struct iommu *iommu,
- u16 did, u16 source_id, u8 function_mask, u8 granu)
-{
- int ret = -1;
- unsigned long flags;
- int index = -1;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- index = qinval_next_index(iommu);
- if (index == -1)
- return -EBUSY;
- ret = gen_cc_inv_dsc(iommu, index, did, source_id,
- function_mask, granu);
- ret |= qinval_update_qtail(iommu, index);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- return ret;
-}
-
-static int gen_iotlb_inv_dsc(struct iommu *iommu, int index,
- u8 granu, u8 dr, u8 dw, u16 did, u8 am, u8 ih, u64 addr)
-{
- unsigned long flags;
- struct qinval_entry * qinval_entry = NULL;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- if ( index == -1 )
- return -1;
- spin_lock_irqsave(&qi_ctrl->qinval_lock, flags);
-
- qinval_entry = &qi_ctrl->qinval[index];
- qinval_entry->q.iotlb_inv_dsc.lo.type = TYPE_INVAL_IOTLB;
- qinval_entry->q.iotlb_inv_dsc.lo.granu = granu;
- qinval_entry->q.iotlb_inv_dsc.lo.dr = 0;
- qinval_entry->q.iotlb_inv_dsc.lo.dw = 0;
- qinval_entry->q.iotlb_inv_dsc.lo.res_1 = 0;
- qinval_entry->q.iotlb_inv_dsc.lo.did = did;
- qinval_entry->q.iotlb_inv_dsc.lo.res_2 = 0;
-
- qinval_entry->q.iotlb_inv_dsc.hi.am = am;
- qinval_entry->q.iotlb_inv_dsc.hi.ih = ih;
- qinval_entry->q.iotlb_inv_dsc.hi.res_1 = 0;
- qinval_entry->q.iotlb_inv_dsc.hi.addr = addr;
-
- spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags);
- return 0;
-}
-
-int queue_invalidate_iotlb(struct iommu *iommu,
- u8 granu, u8 dr, u8 dw, u16 did, u8 am, u8 ih, u64 addr)
-{
- int ret = -1;
- unsigned long flags;
- int index = -1;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
-
- index = qinval_next_index(iommu);
- ret = gen_iotlb_inv_dsc(iommu, index, granu, dr, dw, did,
- am, ih, addr);
- ret |= qinval_update_qtail(iommu, index);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- return ret;
-}
-
-static int gen_wait_dsc(struct iommu *iommu, int index,
- u8 iflag, u8 sw, u8 fn, u32 sdata, volatile u32 *saddr)
-{
- u64 *ptr64;
- unsigned long flags;
- struct qinval_entry * qinval_entry = NULL;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- if ( index == -1 )
- return -1;
- spin_lock_irqsave(&qi_ctrl->qinval_lock, flags);
- qinval_entry = &qi_ctrl->qinval[index];
- qinval_entry->q.inv_wait_dsc.lo.type = TYPE_INVAL_WAIT;
- qinval_entry->q.inv_wait_dsc.lo.iflag = iflag;
- qinval_entry->q.inv_wait_dsc.lo.sw = sw;
- qinval_entry->q.inv_wait_dsc.lo.fn = fn;
- qinval_entry->q.inv_wait_dsc.lo.res_1 = 0;
- qinval_entry->q.inv_wait_dsc.lo.sdata = sdata;
- qinval_entry->q.inv_wait_dsc.hi.res_1 = 0;
- qinval_entry->q.inv_wait_dsc.hi.saddr = virt_to_maddr(saddr) >> 2;
- spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags);
- ptr64 = (u64 *)qinval_entry;
- return 0;
-}
-
-static int queue_invalidate_wait(struct iommu *iommu,
- u8 iflag, u8 sw, u8 fn, u32 sdata, volatile u32 *saddr)
-{
- unsigned long flags;
- unsigned long start_time;
- int index = -1;
- int ret = -1;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- spin_lock_irqsave(&qi_ctrl->qinval_poll_lock, flags);
- spin_lock_irqsave(&iommu->register_lock, flags);
- index = qinval_next_index(iommu);
- if (*saddr == 1)
- *saddr = 0;
- ret = gen_wait_dsc(iommu, index, iflag, sw, fn, sdata, saddr);
- ret |= qinval_update_qtail(iommu, index);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
-
- /* Now we don't support interrupt method */
- if ( sw )
- {
- /* In case all wait descriptor writes to same addr with same data */
- start_time = jiffies;
- while ( *saddr != 1 ) {
- if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT)) {
- print_qi_regs(iommu);
- panic("queue invalidate wait descriptor was not executed\n");
- }
- cpu_relax();
- }
- }
- spin_unlock_irqrestore(&qi_ctrl->qinval_poll_lock, flags);
- return ret;
-}
-
-int invalidate_sync(struct iommu *iommu)
-{
- int ret = -1;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- if (qi_ctrl->qinval)
- {
- ret = queue_invalidate_wait(iommu,
- 0, 1, 1, 1, &qi_ctrl->qinval_poll_status);
- return ret;
- }
- return 0;
-}
-
-static int gen_dev_iotlb_inv_dsc(struct iommu *iommu, int index,
- u32 max_invs_pend, u16 sid, u16 size, u64 addr)
-{
- unsigned long flags;
- struct qinval_entry * qinval_entry = NULL;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- if ( index == -1 )
- return -1;
- spin_lock_irqsave(&qi_ctrl->qinval_lock, flags);
-
- qinval_entry = &qi_ctrl->qinval[index];
- qinval_entry->q.dev_iotlb_inv_dsc.lo.type = TYPE_INVAL_DEVICE_IOTLB;
- qinval_entry->q.dev_iotlb_inv_dsc.lo.res_1 = 0;
- qinval_entry->q.dev_iotlb_inv_dsc.lo.max_invs_pend = max_invs_pend;
- qinval_entry->q.dev_iotlb_inv_dsc.lo.res_2 = 0;
- qinval_entry->q.dev_iotlb_inv_dsc.lo.sid = sid;
- qinval_entry->q.dev_iotlb_inv_dsc.lo.res_3 = 0;
-
- qinval_entry->q.dev_iotlb_inv_dsc.hi.size = size;
- qinval_entry->q.dev_iotlb_inv_dsc.hi.addr = addr;
-
- spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags);
- return 0;
-}
-
-int queue_invalidate_device_iotlb(struct iommu *iommu,
- u32 max_invs_pend, u16 sid, u16 size, u64 addr)
-{
- int ret = -1;
- unsigned long flags;
- int index = -1;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- index = qinval_next_index(iommu);
- ret = gen_dev_iotlb_inv_dsc(iommu, index, max_invs_pend,
- sid, size, addr);
- ret |= qinval_update_qtail(iommu, index);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- return ret;
-}
-
-static int gen_iec_inv_dsc(struct iommu *iommu, int index,
- u8 granu, u8 im, u16 iidx)
-{
- unsigned long flags;
- struct qinval_entry * qinval_entry = NULL;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- if ( index == -1 )
- return -1;
- spin_lock_irqsave(&qi_ctrl->qinval_lock, flags);
-
- qinval_entry = &qi_ctrl->qinval[index];
- qinval_entry->q.iec_inv_dsc.lo.type = TYPE_INVAL_IEC;
- qinval_entry->q.iec_inv_dsc.lo.granu = granu;
- qinval_entry->q.iec_inv_dsc.lo.res_1 = 0;
- qinval_entry->q.iec_inv_dsc.lo.im = im;
- qinval_entry->q.iec_inv_dsc.lo.iidx = iidx;
- qinval_entry->q.iec_inv_dsc.lo.res_2 = 0;
- qinval_entry->q.iec_inv_dsc.hi.res = 0;
-
- spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags);
- return 0;
-}
-
-int queue_invalidate_iec(struct iommu *iommu, u8 granu, u8 im, u16 iidx)
-{
- int ret;
- unsigned long flags;
- int index = -1;
-
- spin_lock_irqsave(&iommu->register_lock, flags);
- index = qinval_next_index(iommu);
- ret = gen_iec_inv_dsc(iommu, index, granu, im, iidx);
- ret |= qinval_update_qtail(iommu, index);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- return ret;
-}
-
-u64 iec_cap;
-int __iommu_flush_iec(struct iommu *iommu, u8 granu, u8 im, u16 iidx)
-{
- int ret;
- ret = queue_invalidate_iec(iommu, granu, im, iidx);
- ret |= invalidate_sync(iommu);
-
- /*
- * reading vt-d architecture register will ensure
- * draining happens in implementation independent way.
- */
- iec_cap = dmar_readq(iommu->reg, DMAR_CAP_REG);
- return ret;
-}
-
-int iommu_flush_iec_global(struct iommu *iommu)
-{
- return __iommu_flush_iec(iommu, IEC_GLOBAL_INVL, 0, 0);
-}
-
-int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx)
-{
- return __iommu_flush_iec(iommu, IEC_INDEX_INVL, im, iidx);
-}
-
-static int flush_context_qi(
- void *_iommu, u16 did, u16 sid, u8 fm, u64 type,
- int non_present_entry_flush)
-{
- int ret = 0;
- struct iommu *iommu = (struct iommu *)_iommu;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- /*
- * 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;
- }
-
- if (qi_ctrl->qinval)
- {
- ret = queue_invalidate_context(iommu, did, sid, fm,
- type >> DMA_CCMD_INVL_GRANU_OFFSET);
- ret |= invalidate_sync(iommu);
- }
- return ret;
-}
-
-static int flush_iotlb_qi(
- void *_iommu, u16 did,
- u64 addr, unsigned int size_order, u64 type,
- int non_present_entry_flush)
-{
- u8 dr = 0, dw = 0;
- int ret = 0;
- struct iommu *iommu = (struct iommu *)_iommu;
- struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu);
-
- /*
- * 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;
- }
-
- if (qi_ctrl->qinval) {
- /* use queued invalidation */
- if (cap_write_drain(iommu->cap))
- dw = 1;
- if (cap_read_drain(iommu->cap))
- dr = 1;
- /* Need to conside the ih bit later */
- ret = queue_invalidate_iotlb(iommu,
- (type >> DMA_TLB_FLUSH_GRANU_OFFSET), dr,
- dw, did, (u8)size_order, 0, addr);
- ret |= invalidate_sync(iommu);
- }
- return ret;
-}
-
-int qinval_setup(struct iommu *iommu)
-{
- unsigned long start_time;
- u64 paddr;
- u32 status = 0;
- struct qi_ctrl *qi_ctrl;
- struct iommu_flush *flush;
-
- qi_ctrl = iommu_qi_ctrl(iommu);
- flush = iommu_get_flush(iommu);
-
- if ( !ecap_queued_inval(iommu->ecap) )
- return -ENODEV;
-
- if (qi_ctrl->qinval == NULL) {
- qi_ctrl->qinval = alloc_xenheap_page();
- if (qi_ctrl->qinval == NULL)
- panic("Cannot allocate memory for qi_ctrl->qinval\n");
- memset((u8*)qi_ctrl->qinval, 0, PAGE_SIZE_4K);
- flush->context = flush_context_qi;
- flush->iotlb = flush_iotlb_qi;
- }
- paddr = virt_to_maddr(qi_ctrl->qinval);
-
- /* Setup Invalidation Queue Address(IQA) register with the
- * address of the page we just allocated. QS field at
- * bits[2:0] to indicate size of queue is one 4KB page.
- * That's 256 entries. Queued Head (IQH) and Queue Tail (IQT)
- * registers are automatically reset to 0 with write
- * to IQA register.
- */
- dmar_writeq(iommu->reg, DMAR_IQA_REG, paddr);
-
- /* enable queued invalidation hardware */
- iommu->gcmd |= DMA_GCMD_QIE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
-
- /* Make sure hardware complete it */
- start_time = jiffies;
- while (1) {
- status = dmar_readl(iommu->reg, DMAR_GSTS_REG);
- if (status & DMA_GSTS_QIES)
- break;
- if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT))
- panic("Cannot set QIE field for queue invalidation\n");
- cpu_relax();
- }
- status = 0;
- return status;
-}
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/utils.c
--- a/xen/arch/x86/hvm/vmx/vtd/utils.c Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,338 +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>
- */
-
-#include <xen/init.h>
-#include <xen/bitmap.h>
-#include <xen/irq.h>
-#include <xen/spinlock.h>
-#include <xen/sched.h>
-#include <xen/delay.h>
-#include <asm/iommu.h>
-#include <asm/hvm/vmx/intel-iommu.h>
-#include "dmar.h"
-#include "pci-direct.h"
-#include "pci_regs.h"
-#include "msi.h"
-
-#include <xen/mm.h>
-#include <xen/xmalloc.h>
-#include <xen/inttypes.h>
-
-#define INTEL 0x8086
-#define SEABURG 0x4000
-#define C_STEP 2
-
-int vtd_hw_check(void)
-{
- u16 vendor, device;
- u8 revision, stepping;
-
- vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);
- device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
- revision = read_pci_config_byte(0, 0, 0, PCI_REVISION_ID);
- stepping = revision & 0xf;
-
- if ( (vendor == INTEL) && (device == SEABURG) )
- {
- if ( stepping < C_STEP )
- {
- dprintk(XENLOG_WARNING VTDPREFIX,
- "*** VT-d disabled - pre C0-step Seaburg found\n");
- dprintk(XENLOG_WARNING VTDPREFIX,
- "*** vendor = %x device = %x revision = %x\n",
- vendor, device, revision);
- vtd_enabled = 0;
- return -ENODEV;
- }
- }
- return 0;
-}
-
-/* Disable vt-d protected memory registers. */
-void disable_pmr(struct iommu *iommu)
-{
- unsigned long start_time;
- unsigned int val;
-
- val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
- if ( !(val & DMA_PMEN_PRS) )
- return;
-
- dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);
- start_time = jiffies;
-
- for ( ; ; )
- {
- val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
- if ( (val & DMA_PMEN_PRS) == 0 )
- break;
-
- if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
- panic("Disable PMRs timeout\n");
-
- cpu_relax();
- }
-
- dprintk(XENLOG_INFO VTDPREFIX,
- "Disabled protected memory registers\n");
-}
-
-static u8 find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap)
-{
- u8 id;
- int max_cap = 48;
- u8 pos = PCI_CAPABILITY_LIST;
- u16 status;
-
- status = read_pci_config_16(bus, dev, func, PCI_STATUS);
- if ( (status & PCI_STATUS_CAP_LIST) == 0 )
- return 0;
-
- while ( max_cap-- )
- {
- pos = read_pci_config_byte(bus, dev, func, pos);
- if ( pos < 0x40 )
- break;
-
- pos &= ~3;
- id = read_pci_config_byte(bus, dev, func, pos + PCI_CAP_LIST_ID);
-
- if ( id == 0xff )
- break;
- else if ( id == cap )
- return pos;
-
- pos += PCI_CAP_LIST_NEXT;
- }
-
- return 0;
-}
-
-#define PCI_D3hot (3)
-#define PCI_CONFIG_DWORD_SIZE (64)
-#define PCI_EXP_DEVCAP_FLR (1 << 28)
-#define PCI_EXP_DEVCTL_FLR (1 << 15)
-
-void pdev_flr(u8 bus, u8 devfn)
-{
- u8 pos;
- u32 dev_cap, dev_status, pm_ctl;
- int flr = 0;
- u8 dev = PCI_SLOT(devfn);
- u8 func = PCI_FUNC(devfn);
-
- pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_EXP);
- if ( pos != 0 )
- {
- dev_cap = read_pci_config(bus, dev, func, pos + PCI_EXP_DEVCAP);
- if ( dev_cap & PCI_EXP_DEVCAP_FLR )
- {
- write_pci_config(bus, dev, func,
- pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
- do {
- dev_status = read_pci_config(bus, dev, func,
- pos + PCI_EXP_DEVSTA);
- } while ( dev_status & PCI_EXP_DEVSTA_TRPND );
-
- flr = 1;
- }
- }
-
- /* If this device doesn't support function level reset,
- * program device from D0 t0 D3hot, and then return to D0
- * to implement function level reset
- */
- if ( flr == 0 )
- {
- pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_PM);
- if ( pos != 0 )
- {
- int i;
- u32 config[PCI_CONFIG_DWORD_SIZE];
- for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
- config[i] = read_pci_config(bus, dev, func, i*4);
-
- /* Enter D3hot without soft reset */
- pm_ctl = read_pci_config(bus, dev, func, pos + PCI_PM_CTRL);
- pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET;
- pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;
- pm_ctl |= PCI_D3hot;
- write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, pm_ctl);
- mdelay(10);
-
- /* From D3hot to D0 */
- write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, 0);
- mdelay(10);
-
- /* Write saved configurations to device */
- for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
- write_pci_config(bus, dev, func, i*4, config[i]);
-
- flr = 1;
- }
- }
-}
-
-void print_iommu_regs(struct acpi_drhd_unit *drhd)
-{
- struct iommu *iommu = drhd->iommu;
-
- printk("---- print_iommu_regs ----\n");
- printk("print_iommu_regs: drhd->address = %lx\n", drhd->address);
- printk("print_iommu_regs: DMAR_VER_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_VER_REG));
- printk("print_iommu_regs: DMAR_CAP_REG = %"PRIx64"\n",
- dmar_readq(iommu->reg,DMAR_CAP_REG));
- printk("print_iommu_regs: n_fault_reg = %"PRIx64"\n",
- cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
- printk("print_iommu_regs: fault_recording_offset_l = %"PRIx64"\n",
- cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
- printk("print_iommu_regs: fault_recording_offset_h = %"PRIx64"\n",
- cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
- printk("print_iommu_regs: fault_recording_reg_l = %"PRIx64"\n",
- dmar_readq(iommu->reg,
- cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
- printk("print_iommu_regs: fault_recording_reg_h = %"PRIx64"\n",
- dmar_readq(iommu->reg,
- cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) +
8));
- printk("print_iommu_regs: DMAR_ECAP_REG = %"PRIx64"\n",
- dmar_readq(iommu->reg,DMAR_ECAP_REG));
- printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_GCMD_REG));
- printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_GSTS_REG));
- printk("print_iommu_regs: DMAR_RTADDR_REG = %"PRIx64"\n",
- dmar_readq(iommu->reg,DMAR_RTADDR_REG));
- printk("print_iommu_regs: DMAR_CCMD_REG = %"PRIx64"\n",
- dmar_readq(iommu->reg,DMAR_CCMD_REG));
- printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_FSTS_REG));
- printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_FECTL_REG));
- printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_FEDATA_REG));
- printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_FEADDR_REG));
- printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",
- dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
-}
-
-u32 get_level_index(unsigned long gmfn, int level)
-{
- while ( --level )
- gmfn = gmfn >> LEVEL_STRIDE;
-
- return gmfn & LEVEL_MASK;
-}
-
-void print_vtd_entries(
- struct domain *d,
- struct iommu *iommu,
- int bus, int devfn,
- unsigned long gmfn)
-{
- struct hvm_iommu *hd = domain_hvm_iommu(d);
- struct acpi_drhd_unit *drhd;
- struct context_entry *ctxt_entry;
- struct root_entry *root_entry;
- struct dma_pte pte;
- u64 *l;
- u32 l_index;
- u32 i = 0;
- int level = agaw_to_level(hd->agaw);
-
- printk("print_vtd_entries: domain_id = %x bdf = %x:%x:%x gmfn = %lx\n",
- d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);
-
- if ( hd->pgd == NULL )
- {
- printk(" hg->pgd == NULL\n");
- return;
- }
- printk(" d->pgd = %p virt_to_maddr(hd->pgd) = %lx\n",
- hd->pgd, virt_to_maddr(hd->pgd));
-
- for_each_drhd_unit ( drhd )
- {
- printk("---- print_vtd_entries %d ----\n", i++);
-
- root_entry = iommu->root_entry;
- if ( root_entry == NULL )
- {
- printk(" root_entry == NULL\n");
- continue;
- }
-
- printk(" root_entry = %p\n", root_entry);
- printk(" root_entry[%x] = %"PRIx64"\n", bus, root_entry[bus].val);
- if ( !root_present(root_entry[bus]) )
- {
- printk(" root_entry[%x] not present\n", bus);
- continue;
- }
-
- ctxt_entry =
- maddr_to_virt((root_entry[bus].val >> PAGE_SHIFT) << PAGE_SHIFT);
- if ( ctxt_entry == NULL )
- {
- printk(" ctxt_entry == NULL\n");
- continue;
- }
-
- printk(" context = %p\n", ctxt_entry);
- printk(" context[%x] = %"PRIx64" %"PRIx64"\n",
- devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);
- if ( !context_present(ctxt_entry[devfn]) )
- {
- printk(" ctxt_entry[%x] not present\n", devfn);
- continue;
- }
-
- if ( level != VTD_PAGE_TABLE_LEVEL_3 &&
- level != VTD_PAGE_TABLE_LEVEL_4)
- {
- printk("Unsupported VTD page table level (%d)!\n", level);
- continue;
- }
-
- l = maddr_to_virt(ctxt_entry[devfn].lo);
- do
- {
- l = (u64*)(((unsigned long)l >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
- printk(" l%d = %p\n", level, l);
- if ( l == NULL )
- {
- printk(" l%d == NULL\n", level);
- break;
- }
- l_index = get_level_index(gmfn, level);
- printk(" l%d_index = %x\n", level, l_index);
- printk(" l%d[%x] = %"PRIx64"\n", level, l_index, l[l_index]);
-
- pte.val = l[l_index];
- if ( !dma_pte_present(pte) )
- {
- printk(" l%d[%x] not present\n", level, l_index);
- break;
- }
-
- l = maddr_to_virt(l[l_index]);
- } while ( --level );
- }
-}
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/arch/x86/hvm/vmx/vtd/vtd.h
--- a/xen/arch/x86/hvm/vmx/vtd/vtd.h Thu Feb 21 14:50:27 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +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_H_
-#define _VTD_H_
-
-#include <xen/list.h>
-#include <asm/iommu.h>
-
-#define VTDPREFIX "[VT-D]"
-
-#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
-#define time_after(a,b) \
- (typecheck(unsigned long, a) && \
- typecheck(unsigned long, b) && \
- ((long)(b) - (long)(a) < 0))
-
-struct IO_APIC_route_remap_entry {
- union {
- u64 val;
- struct {
- u64 vector:8,
- delivery_mode:3,
- index_15:1,
- delivery_status:1,
- polarity:1,
- irr:1,
- trigger:1,
- mask:1,
- reserved:31,
- format:1,
- index_0_14:15;
- };
- };
-};
-
-#endif // _VTD_H_
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/drivers/Makefile
--- a/xen/drivers/Makefile Thu Feb 21 14:50:27 2008 +0000
+++ b/xen/drivers/Makefile Thu Feb 21 15:06:37 2008 +0000
@@ -1,3 +1,4 @@ subdir-y += char
subdir-y += char
+subdir-$(x86) += passthrough
subdir-$(HAS_ACPI) += acpi
subdir-$(HAS_VGA) += video
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/drivers/passthrough/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/Makefile Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,2 @@
+subdir-$(x86) += vtd
+subdir-$(x86) += amd
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/drivers/passthrough/amd/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/amd/Makefile Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,4 @@
+obj-y += iommu_detect.o
+obj-y += iommu_init.o
+obj-y += iommu_map.o
+obj-y += pci_amd_iommu.o
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/drivers/passthrough/amd/iommu_detect.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/amd/iommu_detect.c Thu Feb 21 15:06:37
2008 +0000
@@ -0,0 +1,215 @@
+/*
+ * 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/drivers/passthrough/amd/iommu_init.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/amd/iommu_init.c Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,147 @@
+/*
+ * 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/drivers/passthrough/amd/iommu_map.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/amd/iommu_map.c Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,450 @@
+/*
+ * 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/drivers/passthrough/amd/pci_amd_iommu.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c Thu Feb 21 15:06:37
2008 +0000
@@ -0,0 +1,578 @@
+/*
+ * 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/drivers/passthrough/pci-direct.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/pci-direct.h Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,48 @@
+#ifndef ASM_PCI_DIRECT_H
+#define ASM_PCI_DIRECT_H 1
+
+#include <xen/types.h>
+#include <asm/io.h>
+
+/* Direct PCI access. This is used for PCI accesses in early boot before
+ the PCI subsystem works. */
+
+#define PDprintk(x...)
+
+static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
+{
+ u32 v;
+ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+ v = inl(0xcfc);
+ if (v != 0xffffffff)
+ PDprintk("%x reading 4 from %x: %x\n", slot, offset, v);
+ return v;
+}
+
+static inline u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
+{
+ u8 v;
+ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+ v = inb(0xcfc + (offset&3));
+ PDprintk("%x reading 1 from %x: %x\n", slot, offset, v);
+ return v;
+}
+
+static inline u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
+{
+ u16 v;
+ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+ v = inw(0xcfc + (offset&2));
+ PDprintk("%x reading 2 from %x: %x\n", slot, offset, v);
+ return v;
+}
+
+static inline void write_pci_config(
+ u8 bus, u8 slot, u8 func, u8 offset, u32 val)
+{
+ PDprintk("%x writing to %x: %x\n", slot, offset, val);
+ outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+ outl(val, 0xcfc);
+}
+
+#endif
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/drivers/passthrough/pci_regs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/pci_regs.h Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,530 @@
+/*
+ * 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_ISA 0x04 /* Enable ISA mode */
+#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 */
+#define PCI_CAP_ID_DBG 0x0A /* Debug port */
+#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control
*/
+#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
+#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
+#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
+#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_READ_512 0x0000 /* 512 byte maximum read byte count */
+#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */
+#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */
+#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */
+#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */
+ /* Max # of outstanding split transactions */
+#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */
+#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */
+#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */
+#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */
+#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */
+#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */
+#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */
+#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */
+#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/drivers/passthrough/vtd/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/Makefile Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,6 @@
+obj-y += iommu.o
+obj-y += dmar.o
+obj-y += utils.o
+obj-y += io.o
+obj-y += qinval.o
+obj-y += intremap.o
diff -r f1a107ec62b6 -r 591cfd37bd54 xen/drivers/passthrough/vtd/dmar.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/dmar.c Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,625 @@
+/*
+ * 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/drivers/passthrough/vtd/dmar.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/dmar.h Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,104 @@
+/*
+ * 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/drivers/passthrough/vtd/extern.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/extern.h Thu Feb 21 15:06:37 2008 +0000
@@ -0,0 +1,51 @@
+/*
+ * 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);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|