Add AMD IOMMU support into hypervisor

Signed-off-by: Wei Wang <wei.wang2@amd.com>
This commit is contained in:
Keir Fraser committed 2007-09-21 17:15:47 +01:00
1 parent ed20abc6f0
commit 0700c962ac
14 files changed
+2318

No files matched your search

+2
View File
@@ -1,6 +1,8 @@
subdir-$(x86_32) += x86_32
subdir-$(x86_64) += x86_64
subdir-y += amd_iommu
obj-y += asid.o
obj-y += emulate.o
obj-y += intr.o
+4
View File
@@ -0,0 +1,4 @@
obj-y += amd-iommu-detect.o
obj-y += amd-iommu-init.o
obj-y += amd-iommu-map.o
obj-y += pci-amd-iommu.o
@@ -0,0 +1,211 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/iommu.h>
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include "pci-direct.h"
#include "pci_regs.h"
static int __init valid_bridge_bus_config(int bus, int dev, int func,
int *sec_bus, int *sub_bus)
{
int pri_bus;
pri_bus = read_pci_config_byte(bus, dev, func, PCI_PRIMARY_BUS);
*sec_bus = read_pci_config_byte(bus, dev, func, PCI_SECONDARY_BUS);
*sub_bus = read_pci_config_byte(bus, dev, func, PCI_SUBORDINATE_BUS);
return ( pri_bus == bus && *sec_bus > bus && *sub_bus >= *sec_bus );
}
int __init get_iommu_last_downstream_bus(struct amd_iommu *iommu)
{
int bus, dev, func;
int devfn, hdr_type;
int sec_bus, sub_bus;
int multi_func;
bus = iommu->last_downstream_bus = iommu->root_bus;
iommu->downstream_bus_present[bus] = 1;
dev = PCI_SLOT(iommu->first_devfn);
multi_func = PCI_FUNC(iommu->first_devfn) > 0;
for ( devfn = iommu->first_devfn; devfn <= iommu->last_devfn; ++devfn ) {
/* skipping to next device#? */
if ( dev != PCI_SLOT(devfn) ) {
dev = PCI_SLOT(devfn);
multi_func = 0;
}
func = PCI_FUNC(devfn);
if ( !VALID_PCI_VENDOR_ID(
read_pci_config_16(bus, dev, func, PCI_VENDOR_ID)) )
continue;
hdr_type = read_pci_config_byte(bus, dev, func,
PCI_HEADER_TYPE);
if ( func == 0 )
multi_func = IS_PCI_MULTI_FUNCTION(hdr_type);
if ( (func == 0 || multi_func) &&
IS_PCI_TYPE1_HEADER(hdr_type) ) {
if (!valid_bridge_bus_config(bus, dev, func,
&sec_bus, &sub_bus))
return -ENODEV;
if ( sub_bus > iommu->last_downstream_bus )
iommu->last_downstream_bus = sub_bus;
do {
iommu->downstream_bus_present[sec_bus] = 1;
} while ( sec_bus++ < sub_bus );
}
}
return 0;
}
int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
struct amd_iommu *iommu)
{
u32 cap_header, cap_range;
u64 mmio_bar;
/* remove it when BIOS available */
write_pci_config(bus, dev, func,
cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET, 0x00000000);
write_pci_config(bus, dev, func,
cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET, 0x40000001);
/* remove it when BIOS available */
mmio_bar = (u64)read_pci_config(bus, dev, func,
cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32;
mmio_bar |= read_pci_config(bus, dev, func,
cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET) &
PCI_CAP_MMIO_BAR_LOW_MASK;
iommu->mmio_base_phys = (unsigned long)mmio_bar;
if ( (mmio_bar == 0) || ( (mmio_bar & 0x3FFF) != 0 ) ) {
dprintk(XENLOG_ERR ,
"AMD IOMMU: Invalid MMIO_BAR = 0x%lx\n", mmio_bar);
return -ENODEV;
}
cap_header = read_pci_config(bus, dev, func, cap_ptr);
iommu->revision = get_field_from_reg_u32(cap_header,
PCI_CAP_REV_MASK, PCI_CAP_REV_SHIFT);
iommu->iotlb_support = get_field_from_reg_u32(cap_header,
PCI_CAP_IOTLB_MASK, PCI_CAP_IOTLB_SHIFT);
iommu->ht_tunnel_support = get_field_from_reg_u32(cap_header,
PCI_CAP_HT_TUNNEL_MASK,
PCI_CAP_HT_TUNNEL_SHIFT);
iommu->not_present_cached = get_field_from_reg_u32(cap_header,
PCI_CAP_NP_CACHE_MASK,
PCI_CAP_NP_CACHE_SHIFT);
cap_range = read_pci_config(bus, dev, func,
cap_ptr + PCI_CAP_RANGE_OFFSET);
iommu->root_bus = get_field_from_reg_u32(cap_range,
PCI_CAP_BUS_NUMBER_MASK,
PCI_CAP_BUS_NUMBER_SHIFT);
iommu->first_devfn = get_field_from_reg_u32(cap_range,
PCI_CAP_FIRST_DEVICE_MASK,
PCI_CAP_FIRST_DEVICE_SHIFT);
iommu->last_devfn = get_field_from_reg_u32(cap_range,
PCI_CAP_LAST_DEVICE_MASK,
PCI_CAP_LAST_DEVICE_SHIFT);
return 0;
}
static int __init scan_caps_for_iommu(int bus, int dev, int func,
iommu_detect_callback_ptr_t iommu_detect_callback)
{
int cap_ptr, cap_id, cap_type;
u32 cap_header;
int count, error = 0;
count = 0;
cap_ptr = read_pci_config_byte(bus, dev, func,
PCI_CAPABILITY_LIST);
while ( cap_ptr >= PCI_MIN_CAP_OFFSET &&
count < PCI_MAX_CAP_BLOCKS && !error ) {
cap_ptr &= PCI_CAP_PTR_MASK;
cap_header = read_pci_config(bus, dev, func, cap_ptr);
cap_id = get_field_from_reg_u32(cap_header,
PCI_CAP_ID_MASK, PCI_CAP_ID_SHIFT);
if ( cap_id == PCI_CAP_ID_SECURE_DEVICE ) {
cap_type = get_field_from_reg_u32(cap_header,
PCI_CAP_TYPE_MASK, PCI_CAP_TYPE_SHIFT);
if ( cap_type == PCI_CAP_TYPE_IOMMU ) {
error = iommu_detect_callback(
bus, dev, func, cap_ptr);
}
}
cap_ptr = get_field_from_reg_u32(cap_header,
PCI_CAP_NEXT_PTR_MASK, PCI_CAP_NEXT_PTR_SHIFT);
++count; }
return error;
}
static int __init scan_functions_for_iommu(int bus, int dev,
iommu_detect_callback_ptr_t iommu_detect_callback)
{
int func, hdr_type;
int count, error = 0;
func = 0;
count = 1;
while ( VALID_PCI_VENDOR_ID(read_pci_config_16(bus, dev, func,
PCI_VENDOR_ID)) && !error && func < count ) {
hdr_type = read_pci_config_byte(bus, dev, func,
PCI_HEADER_TYPE);
if ( func == 0 && IS_PCI_MULTI_FUNCTION(hdr_type) )
count = PCI_MAX_FUNC_COUNT;
if ( IS_PCI_TYPE0_HEADER(hdr_type) ||
IS_PCI_TYPE1_HEADER(hdr_type) ) {
error = scan_caps_for_iommu(bus, dev, func,
iommu_detect_callback);
}
++func;
}
return error;
}
int __init scan_for_iommu(iommu_detect_callback_ptr_t iommu_detect_callback)
{
int bus, dev, error = 0;
for ( bus = 0; bus < PCI_MAX_BUS_COUNT && !error; ++bus ) {
for ( dev = 0; dev < PCI_MAX_DEV_COUNT && !error; ++dev ) {
error = scan_functions_for_iommu(bus, dev,
iommu_detect_callback);
}
}
return error;
}
@@ -0,0 +1,145 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include <asm-x86/fixmap.h>
#include "pci-direct.h"
#include "pci_regs.h"
extern int nr_amd_iommus;
int __init map_iommu_mmio_region(struct amd_iommu *iommu)
{
unsigned long mfn;
if ( nr_amd_iommus > MAX_AMD_IOMMUS ) {
gdprintk(XENLOG_ERR,
"IOMMU: nr_amd_iommus %d > MAX_IOMMUS\n", nr_amd_iommus);
return -ENOMEM;
}
iommu->mmio_base = (void *) fix_to_virt(FIX_IOMMU_MMIO_BASE_0 +
nr_amd_iommus * MMIO_PAGES_PER_IOMMU);
mfn = (unsigned long)iommu->mmio_base_phys >> PAGE_SHIFT;
map_pages_to_xen((unsigned long)iommu->mmio_base, mfn,
MMIO_PAGES_PER_IOMMU, PAGE_HYPERVISOR_NOCACHE);
memset((u8*)iommu->mmio_base, 0, IOMMU_MMIO_REGION_LENGTH);
return 0;
}
void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
{
if ( iommu->mmio_base ) {
iounmap(iommu->mmio_base);
iommu->mmio_base = NULL;
}
}
void __init register_iommu_dev_table_in_mmio_space(struct amd_iommu *iommu)
{
u64 addr_64, addr_lo, addr_hi;
u32 entry;
addr_64 = (u64)virt_to_maddr(iommu->dev_table.buffer);
addr_lo = addr_64 & DMA_32BIT_MASK;
addr_hi = addr_64 >> 32;
set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
IOMMU_DEV_TABLE_BASE_LOW_MASK,
IOMMU_DEV_TABLE_BASE_LOW_SHIFT, &entry);
set_field_in_reg_u32((iommu->dev_table.alloc_size / PAGE_SIZE) - 1,
entry, IOMMU_DEV_TABLE_SIZE_MASK,
IOMMU_DEV_TABLE_SIZE_SHIFT, &entry);
writel(entry, iommu->mmio_base + IOMMU_DEV_TABLE_BASE_LOW_OFFSET);
set_field_in_reg_u32((u32)addr_hi, 0,
IOMMU_DEV_TABLE_BASE_HIGH_MASK,
IOMMU_DEV_TABLE_BASE_HIGH_SHIFT, &entry);
writel(entry, iommu->mmio_base + IOMMU_DEV_TABLE_BASE_HIGH_OFFSET);
}
void __init register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu)
{
u64 addr_64, addr_lo, addr_hi;
u32 power_of2_entries;
u32 entry;
addr_64 = (u64)virt_to_maddr(iommu->cmd_buffer.buffer);
addr_lo = addr_64 & DMA_32BIT_MASK;
addr_hi = addr_64 >> 32;
set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
IOMMU_CMD_BUFFER_BASE_LOW_MASK,
IOMMU_CMD_BUFFER_BASE_LOW_SHIFT, &entry);
writel(entry, iommu->mmio_base + IOMMU_CMD_BUFFER_BASE_LOW_OFFSET);
power_of2_entries = get_order_from_bytes(iommu->cmd_buffer.alloc_size) +
IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE;
set_field_in_reg_u32((u32)addr_hi, 0,
IOMMU_CMD_BUFFER_BASE_HIGH_MASK,
IOMMU_CMD_BUFFER_BASE_HIGH_SHIFT, &entry);
set_field_in_reg_u32(power_of2_entries, entry,
IOMMU_CMD_BUFFER_LENGTH_MASK,
IOMMU_CMD_BUFFER_LENGTH_SHIFT, &entry);
writel(entry, iommu->mmio_base+IOMMU_CMD_BUFFER_BASE_HIGH_OFFSET);
}
static void __init set_iommu_translation_control(struct amd_iommu *iommu,
int enable)
{
u32 entry;
entry = readl(iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
set_field_in_reg_u32(iommu->ht_tunnel_support ? IOMMU_CONTROL_ENABLED :
IOMMU_CONTROL_ENABLED, entry,
IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_MASK,
IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT, &entry);
set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
IOMMU_CONTROL_ENABLED, entry,
IOMMU_CONTROL_TRANSLATION_ENABLE_MASK,
IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT, &entry);
writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
}
static void __init set_iommu_command_buffer_control(struct amd_iommu *iommu,
int enable)
{
u32 entry;
entry = readl(iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
IOMMU_CONTROL_ENABLED, entry,
IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_MASK,
IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT, &entry);
writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
}
void __init enable_iommu(struct amd_iommu *iommu)
{
set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_ENABLED);
set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
printk("AMD IOMMU %d: Enabled\n", nr_amd_iommus);
}
@@ -0,0 +1,419 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/hvm/iommu.h>
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include <xen/sched.h>
extern long amd_iommu_poll_comp_wait;
static int queue_iommu_command(struct amd_iommu *iommu, u32 cmd[])
{
u32 tail, head, *cmd_buffer;
int i;
BUG_ON( !iommu || !cmd );
tail = iommu->cmd_buffer_tail;
if ( ++tail == iommu->cmd_buffer.entries ) {
tail = 0;
}
head = get_field_from_reg_u32(
readl(iommu->mmio_base+IOMMU_CMD_BUFFER_HEAD_OFFSET),
IOMMU_CMD_BUFFER_HEAD_MASK,
IOMMU_CMD_BUFFER_HEAD_SHIFT);
if ( head != tail ) {
cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +
(iommu->cmd_buffer_tail * IOMMU_CMD_BUFFER_ENTRY_SIZE));
for ( i = 0; i < IOMMU_CMD_BUFFER_U32_PER_ENTRY; ++i ) {
cmd_buffer[i] = cmd[i];
}
iommu->cmd_buffer_tail = tail;
return 1;
}
return 0;
}
static void commit_iommu_command_buffer(struct amd_iommu *iommu)
{
u32 tail;
BUG_ON( !iommu );
set_field_in_reg_u32(iommu->cmd_buffer_tail, 0,
IOMMU_CMD_BUFFER_TAIL_MASK,
IOMMU_CMD_BUFFER_TAIL_SHIFT, &tail);
writel(tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET);
}
int send_iommu_command(struct amd_iommu *iommu, u32 cmd[])
{
BUG_ON( !iommu || !cmd );
if ( queue_iommu_command(iommu, cmd) ) {
commit_iommu_command_buffer(iommu);
return 1;
}
return 0;
}
static void invalidate_iommu_page(struct amd_iommu *iommu,
u64 io_addr, u16 domain_id)
{
u64 addr_lo, addr_hi;
u32 cmd[4], entry;
addr_lo = io_addr & DMA_32BIT_MASK;
addr_hi = io_addr >> 32;
set_field_in_reg_u32(domain_id, 0,
IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_MASK,
IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_IOMMU_PAGES, entry,
IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT, &entry);
cmd[1] = entry;
set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, 0,
IOMMU_INV_IOMMU_PAGES_S_FLAG_MASK,
IOMMU_INV_IOMMU_PAGES_S_FLAG_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
IOMMU_INV_IOMMU_PAGES_PDE_FLAG_MASK,
IOMMU_INV_IOMMU_PAGES_PDE_FLAG_SHIFT, &entry);
set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, entry,
IOMMU_INV_IOMMU_PAGES_ADDR_LOW_MASK,
IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT, &entry);
cmd[2] = entry;
set_field_in_reg_u32((u32)addr_hi, 0,
IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK,
IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT, &entry);
cmd[3] = entry;
cmd[0] = 0;
send_iommu_command(iommu, cmd);
}
static void flush_command_buffer(struct amd_iommu *iommu)
{
u32 cmd[4], status;
int loop_count, comp_wait;
/* clear 'ComWaitInt' in status register (WIC) */
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,
IOMMU_STATUS_COMP_WAIT_INT_MASK,
IOMMU_STATUS_COMP_WAIT_INT_SHIFT, &status);
writel(status, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
/* send an empty COMPLETION_WAIT command to flush command buffer */
cmd[3] = cmd[2] = 0;
set_field_in_reg_u32(IOMMU_CMD_COMPLETION_WAIT, 0,
IOMMU_CMD_OPCODE_MASK,
IOMMU_CMD_OPCODE_SHIFT, &cmd[1]);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,
IOMMU_COMP_WAIT_I_FLAG_MASK,
IOMMU_COMP_WAIT_I_FLAG_SHIFT, &cmd[0]);
send_iommu_command(iommu, cmd);
/* wait for 'ComWaitInt' to signal comp#endifletion? */
if ( amd_iommu_poll_comp_wait ) {
loop_count = amd_iommu_poll_comp_wait;
do {
status = readl(iommu->mmio_base +
IOMMU_STATUS_MMIO_OFFSET);
comp_wait = get_field_from_reg_u32(status,
IOMMU_STATUS_COMP_WAIT_INT_MASK,
IOMMU_STATUS_COMP_WAIT_INT_SHIFT);
--loop_count;
} while ( loop_count && !comp_wait );
if ( comp_wait ) {
/* clear 'ComWaitInt' in status register (WIC) */
status &= IOMMU_STATUS_COMP_WAIT_INT_MASK;
writel(status, iommu->mmio_base +
IOMMU_STATUS_MMIO_OFFSET);
} else
dprintk(XENLOG_WARNING, "AMD IOMMU: %s(): Warning:"
" ComWaitInt bit did not assert!\n",
__FUNCTION__);
}
}
static void clear_page_table_entry_present(u32 *pte)
{
set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, pte[0],
IOMMU_PTE_PRESENT_MASK,
IOMMU_PTE_PRESENT_SHIFT, &pte[0]);
}
static void set_page_table_entry_present(u32 *pte, u64 page_addr,
int iw, int ir)
{
u64 addr_lo, addr_hi;
u32 entry;
addr_lo = page_addr & DMA_32BIT_MASK;
addr_hi = page_addr >> 32;
set_field_in_reg_u32((u32)addr_hi, 0,
IOMMU_PTE_ADDR_HIGH_MASK,
IOMMU_PTE_ADDR_HIGH_SHIFT, &entry);
set_field_in_reg_u32(iw ? IOMMU_CONTROL_ENABLED :
IOMMU_CONTROL_DISABLED, entry,
IOMMU_PTE_IO_WRITE_PERMISSION_MASK,
IOMMU_PTE_IO_WRITE_PERMISSION_SHIFT, &entry);
set_field_in_reg_u32(ir ? IOMMU_CONTROL_ENABLED :
IOMMU_CONTROL_DISABLED, entry,
IOMMU_PTE_IO_READ_PERMISSION_MASK,
IOMMU_PTE_IO_READ_PERMISSION_SHIFT, &entry);
pte[1] = entry;
set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
IOMMU_PTE_ADDR_LOW_MASK,
IOMMU_PTE_ADDR_LOW_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_PAGING_MODE_LEVEL_0, entry,
IOMMU_PTE_NEXT_LEVEL_MASK,
IOMMU_PTE_NEXT_LEVEL_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_PTE_PRESENT_MASK,
IOMMU_PTE_PRESENT_SHIFT, &entry);
pte[0] = entry;
}
static void amd_iommu_set_page_directory_entry(u32 *pde,
u64 next_ptr, u8 next_level)
{
u64 addr_lo, addr_hi;
u32 entry;
addr_lo = next_ptr & DMA_32BIT_MASK;
addr_hi = next_ptr >> 32;
/* enable read/write permissions,which will be enforced at the PTE */
set_field_in_reg_u32((u32)addr_hi, 0,
IOMMU_PDE_ADDR_HIGH_MASK, IOMMU_PDE_ADDR_HIGH_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_PDE_IO_WRITE_PERMISSION_MASK,
IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_PDE_IO_READ_PERMISSION_MASK,
IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);
pde[1] = entry;
/* mark next level as 'present' */
set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
IOMMU_PDE_ADDR_LOW_MASK, IOMMU_PDE_ADDR_LOW_SHIFT, &entry);
set_field_in_reg_u32(next_level, entry,
IOMMU_PDE_NEXT_LEVEL_MASK,
IOMMU_PDE_NEXT_LEVEL_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_PDE_PRESENT_MASK,
IOMMU_PDE_PRESENT_SHIFT, &entry);
pde[0] = entry;
}
void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u16 domain_id,
u8 paging_mode)
{
u64 addr_hi, addr_lo;
u32 entry;
dte[6] = dte[5] = dte[4] = 0;
set_field_in_reg_u32(IOMMU_DEV_TABLE_SYS_MGT_MSG_FORWARDED, 0,
IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK,
IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT, &entry);
dte[3] = entry;
set_field_in_reg_u32(domain_id, 0,
IOMMU_DEV_TABLE_DOMAIN_ID_MASK,
IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT, &entry);
dte[2] = entry;
addr_lo = root_ptr & DMA_32BIT_MASK;
addr_hi = root_ptr >> 32;
set_field_in_reg_u32((u32)addr_hi, 0,
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK,
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_MASK,
IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK,
IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT, &entry);
dte[1] = entry;
set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0,
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK,
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT, &entry);
set_field_in_reg_u32(paging_mode, entry,
IOMMU_DEV_TABLE_PAGING_MODE_MASK,
IOMMU_DEV_TABLE_PAGING_MODE_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &entry);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
IOMMU_DEV_TABLE_VALID_MASK,
IOMMU_DEV_TABLE_VALID_SHIFT, &entry);
dte[0] = entry;
}
static void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry)
{
u64 addr_lo, addr_hi, ptr;
addr_lo = get_field_from_reg_u32(entry[0],
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK,
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT);
addr_hi = get_field_from_reg_u32(entry[1],
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK,
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT);
ptr = (addr_hi << 32) | (addr_lo << PAGE_SHIFT);
return ptr ? maddr_to_virt((unsigned long)ptr) : NULL;
}
static int amd_iommu_is_pte_present(u32 *entry)
{
return (get_field_from_reg_u32(entry[0],
IOMMU_PDE_PRESENT_MASK,
IOMMU_PDE_PRESENT_SHIFT));
}
static void *get_pte_from_page_tables(void *table, int level,
unsigned long io_pfn)
{
unsigned long offset;
void *pde = 0;
BUG_ON( !table );
while ( level > 0 )
{
void *next_table = 0;
unsigned long next_ptr;
offset = io_pfn >> ((PTE_PER_TABLE_SHIFT *
(level - IOMMU_PAGING_MODE_LEVEL_1)));
offset &= ~PTE_PER_TABLE_MASK;
pde = table + (offset * IOMMU_PAGE_TABLE_ENTRY_SIZE);
if ( level == 1 )
break;
if ( !pde )
return NULL;
if ( !amd_iommu_is_pte_present(pde) ) {
next_table = alloc_xenheap_page();
if ( next_table == NULL )
return NULL;
memset(next_table, 0, PAGE_SIZE);
if ( *(u64*)(pde) == 0 ) {
next_ptr = (u64)virt_to_maddr(next_table);
amd_iommu_set_page_directory_entry((u32 *)pde,
next_ptr, level - 1);
} else
free_xenheap_page(next_table);
}
table = amd_iommu_get_vptr_from_page_table_entry(pde);
level--;
}
return pde;
}
int amd_iommu_map_page(struct domain *d, unsigned long gfn,
unsigned long mfn)
{
void *pte;
unsigned long flags;
u64 maddr;
struct hvm_iommu *hd = domain_hvm_iommu(d);
int iw, ir;
BUG_ON( !hd->root_table );
maddr = (u64)(mfn << PAGE_SHIFT);
iw = IOMMU_IO_WRITE_ENABLED;
ir = IOMMU_IO_READ_ENABLED;
spin_lock_irqsave(&hd->mapping_lock, flags);
pte = get_pte_from_page_tables(hd->root_table, hd->paging_mode, gfn);
if ( pte != 0 ) {
set_page_table_entry_present((u32 *)pte, maddr, iw, ir);
spin_unlock_irqrestore(&hd->mapping_lock, flags);
return 0;
} else {
dprintk(XENLOG_ERR,
"%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n",
__FUNCTION__, gfn);
spin_unlock_irqrestore(&hd->mapping_lock, flags);
return -EIO;
}
}
int amd_iommu_unmap_page(struct domain *d, unsigned long gfn)
{
void *pte;
unsigned long flags;
u64 io_addr = gfn;
int requestor_id;
struct amd_iommu *iommu;
struct hvm_iommu *hd = domain_hvm_iommu(d);
BUG_ON( !hd->root_table );
requestor_id = hd->domain_id;
io_addr = (u64)(gfn << PAGE_SHIFT);
spin_lock_irqsave(&hd->mapping_lock, flags);
pte = get_pte_from_page_tables(hd->root_table, hd->paging_mode, gfn);
if ( pte != 0 ) {
/* mark PTE as 'page not present' */
clear_page_table_entry_present((u32 *)pte);
spin_unlock_irqrestore(&hd->mapping_lock, flags);
/* send INVALIDATE_IOMMU_PAGES command */
for_each_amd_iommu(iommu) {
spin_lock_irqsave(&iommu->lock, flags);
invalidate_iommu_page(iommu, io_addr, requestor_id);
flush_command_buffer(iommu);
spin_unlock_irqrestore(&iommu->lock, flags);
}
return 0;
} else {
dprintk(XENLOG_ERR,
"%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n",
__FUNCTION__, gfn);
spin_unlock_irqrestore(&hd->mapping_lock, flags);
return -EIO;
}
}
@@ -0,0 +1,389 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include <xen/sched.h>
#include <asm/mm.h>
#include "pci-direct.h"
#include "pci_regs.h"
struct list_head amd_iommu_head;
long amd_iommu_poll_comp_wait = COMPLETION_WAIT_DEFAULT_POLLING_COUNT;
static long amd_iommu_cmd_buffer_entries = IOMMU_CMD_BUFFER_DEFAULT_ENTRIES;
int nr_amd_iommus = 0;
/* will set if amd-iommu HW is found */
int amd_iommu_enabled = 0;
static int enable_amd_iommu = 0;
boolean_param("enable_amd_iommu", enable_amd_iommu);
static void deallocate_domain_page_tables(struct hvm_iommu *hd)
{
if ( hd->root_table )
free_xenheap_page(hd->root_table);
}
static void deallocate_domain_resources(struct hvm_iommu *hd)
{
deallocate_domain_page_tables(hd);
}
static void __init init_cleanup(void)
{
struct amd_iommu *iommu;
dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
for_each_amd_iommu(iommu) {
unmap_iommu_mmio_region(iommu);
}
}
static void __init deallocate_iommu_table_struct(
struct table_struct *table)
{
if (table->buffer) {
free_xenheap_pages(table->buffer,
get_order_from_bytes(table->alloc_size));
table->buffer = NULL;
}
}
static void __init deallocate_iommu_resources(struct amd_iommu *iommu)
{
deallocate_iommu_table_struct(&iommu->dev_table);
deallocate_iommu_table_struct(&iommu->cmd_buffer);;
}
static void __init detect_cleanup(void)
{
struct amd_iommu *iommu;
dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
for_each_amd_iommu(iommu) {
list_del(&iommu->list);
deallocate_iommu_resources(iommu);
xfree(iommu);
}
}
static int requestor_id_from_bdf(int bdf)
{
/* HACK - HACK */
/* account for possible 'aliasing' by parent device */
return bdf;
}
static int __init allocate_iommu_table_struct(struct table_struct *table,
const char *name)
{
table->buffer = (void *) alloc_xenheap_pages(
get_order_from_bytes(table->alloc_size));
if ( !table->buffer ) {
dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating %s\n", name);
return -ENOMEM;
}
memset(table->buffer, 0, table->alloc_size);
return 0;
}
static int __init allocate_iommu_resources(struct amd_iommu *iommu)
{
/* allocate 'device table' on a 4K boundary */
iommu->dev_table.alloc_size =
PAGE_ALIGN(((iommu->last_downstream_bus + 1) *
IOMMU_DEV_TABLE_ENTRIES_PER_BUS) *
IOMMU_DEV_TABLE_ENTRY_SIZE);
iommu->dev_table.entries =
iommu->dev_table.alloc_size / IOMMU_DEV_TABLE_ENTRY_SIZE;
if (allocate_iommu_table_struct(&iommu->dev_table,
"Device Table") != 0)
goto error_out;
/* allocate 'command buffer' in power of 2 increments of 4K */
iommu->cmd_buffer_tail = 0;
iommu->cmd_buffer.alloc_size =
PAGE_SIZE << get_order_from_bytes(
PAGE_ALIGN(amd_iommu_cmd_buffer_entries *
IOMMU_CMD_BUFFER_ENTRY_SIZE));
iommu->cmd_buffer.entries =
iommu->cmd_buffer.alloc_size / IOMMU_CMD_BUFFER_ENTRY_SIZE;
if ( allocate_iommu_table_struct(&iommu->cmd_buffer,
"Command Buffer") != 0 )
goto error_out;
return 0;
error_out:
deallocate_iommu_resources(iommu);
return -ENOMEM;
}
int iommu_detect_callback(u8 bus, u8 dev, u8 func, u8 cap_ptr)
{
struct amd_iommu *iommu;
iommu = (struct amd_iommu *) xmalloc(struct amd_iommu);
if ( !iommu ) {
dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating amd_iommu\n");
return -ENOMEM;
}
memset(iommu, 0, sizeof(struct amd_iommu));
spin_lock_init(&iommu->lock);
/* get capability and topology information */
if ( get_iommu_capabilities(bus, dev, func, cap_ptr, iommu) != 0 )
goto error_out;
if ( get_iommu_last_downstream_bus(iommu) != 0 )
goto error_out;
list_add_tail(&iommu->list, &amd_iommu_head);
/* allocate resources for this IOMMU */
if (allocate_iommu_resources(iommu) != 0)
goto error_out;
return 0;
error_out:
xfree(iommu);
return -ENODEV;
}
static int __init amd_iommu_init(void)
{
struct amd_iommu *iommu;
unsigned long flags;
for_each_amd_iommu(iommu) {
spin_lock_irqsave(&iommu->lock, flags);
/* register IOMMU data strucures in MMIO space */
if (map_iommu_mmio_region(iommu) != 0)
goto error_out;
register_iommu_dev_table_in_mmio_space(iommu);
register_iommu_cmd_buffer_in_mmio_space(iommu);
/* enable IOMMU translation services */
enable_iommu(iommu);
nr_amd_iommus++;
spin_unlock_irqrestore(&iommu->lock, flags);
}
amd_iommu_enabled = 1;
return 0;
error_out:
init_cleanup();
return -ENODEV;
}
struct amd_iommu *find_iommu_for_device(int bus, int devfn)
{
struct amd_iommu *iommu;
for_each_amd_iommu(iommu) {
if ( bus == iommu->root_bus ) {
if ( devfn >= iommu->first_devfn &&
devfn <= iommu->last_devfn )
return iommu;
}
else if ( bus <= iommu->last_downstream_bus ) {
if ( iommu->downstream_bus_present[bus] )
return iommu;
}
}
return NULL;
}
void amd_iommu_setup_domain_device(struct domain *domain,
struct amd_iommu *iommu, int requestor_id)
{
void *dte;
u64 root_ptr;
unsigned long flags;
struct hvm_iommu *hd = domain_hvm_iommu(domain);
BUG_ON( !hd->root_table||!hd->paging_mode );
root_ptr = (u64)virt_to_maddr(hd->root_table);
dte = iommu->dev_table.buffer +
(requestor_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
spin_lock_irqsave(&iommu->lock, flags);
amd_iommu_set_dev_table_entry((u32 *)dte,
root_ptr, hd->domain_id, hd->paging_mode);
dprintk(XENLOG_INFO, "AMD IOMMU: Set DTE req_id:%x, "
"root_ptr:%lx, domain_id:%d, paging_mode:%d\n",
requestor_id, root_ptr, hd->domain_id, hd->paging_mode);
spin_unlock_irqrestore(&iommu->lock, flags);
}
void __init amd_iommu_setup_dom0_devices(void)
{
struct hvm_iommu *hd = domain_hvm_iommu(dom0);
struct amd_iommu *iommu;
struct pci_dev *pdev;
int bus, dev, func;
u32 l;
int req_id, bdf;
for ( bus = 0; bus < 256; bus++ ) {
for ( dev = 0; dev < 32; dev++ ) {
for ( func = 0; func < 8; func++ ) {
l = read_pci_config(bus, dev, func, PCI_VENDOR_ID);
/* some broken boards return 0 or ~0 if a slot is empty: */
if ( l == 0xffffffff || l == 0x00000000 ||
l == 0x0000ffff || l == 0xffff0000 )
continue;
pdev = xmalloc(struct pci_dev);
pdev->bus = bus;
pdev->devfn = PCI_DEVFN(dev, func);
list_add_tail(&pdev->list, &hd->pdev_list);
bdf = (bus << 8) | pdev->devfn;
req_id = requestor_id_from_bdf(bdf);
iommu = find_iommu_for_device(bus, pdev->devfn);
if ( iommu )
amd_iommu_setup_domain_device(dom0, iommu, req_id);
}
}
}
}
int amd_iommu_detect(void)
{
unsigned long i;
if ( !enable_amd_iommu ) {
printk("AMD IOMMU: Disabled\n");
return 0;
}
INIT_LIST_HEAD(&amd_iommu_head);
if ( scan_for_iommu(iommu_detect_callback) != 0 ) {
dprintk(XENLOG_ERR, "AMD IOMMU: Error detection\n");
goto error_out;
}
if ( !iommu_found() ) {
printk("AMD IOMMU: Not found!\n");
return 0;
}
if ( amd_iommu_init() != 0 ) {
dprintk(XENLOG_ERR, "AMD IOMMU: Error initialization\n");
goto error_out;
}
if ( amd_iommu_domain_init(dom0) != 0 )
goto error_out;
/* setup 1:1 page table for dom0 */
for ( i = 0; i < max_page; i++ )
amd_iommu_map_page(dom0, i, i);
amd_iommu_setup_dom0_devices();
return 0;
error_out:
detect_cleanup();
return -ENODEV;
}
static int allocate_domain_resources(struct hvm_iommu *hd)
{
/* allocate root table */
hd->root_table = (void *)alloc_xenheap_page();
if ( !hd->root_table )
return -ENOMEM;
memset((u8*)hd->root_table, 0, PAGE_SIZE);
return 0;
}
static int get_paging_mode(unsigned long entries)
{
int level = 1;
BUG_ON ( !max_page );
if ( entries > max_page )
entries = max_page;
while ( entries > PTE_PER_TABLE_SIZE ) {
entries = PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT;
++level;
if ( level > 6 )
return -ENOMEM;
}
dprintk(XENLOG_INFO, "AMD IOMMU: paging mode = %d\n", level);
return level;
}
int amd_iommu_domain_init(struct domain *domain)
{
struct hvm_iommu *hd = domain_hvm_iommu(domain);
spin_lock_init(&hd->mapping_lock);
spin_lock_init(&hd->iommu_list_lock);
INIT_LIST_HEAD(&hd->pdev_list);
/* allocate page directroy */
if ( allocate_domain_resources(hd) != 0 ) {
dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
goto error_out;
}
if ( is_hvm_domain(domain) )
hd->paging_mode = IOMMU_PAGE_TABLE_LEVEL_4;
else
hd->paging_mode = get_paging_mode(max_page);
hd->domain_id = domain->domain_id;
return 0;
error_out:
deallocate_domain_resources(hd);
return -ENOMEM;
}
@@ -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
+513
View File
@@ -0,0 +1,513 @@
/*
* pci_regs.h
*
* PCI standard defines
* Copyright 1994, Drew Eckhardt
* Copyright 1997--1999 Martin Mares <mj@ucw.cz>
*
* 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 */
+2
View File
@@ -1040,6 +1040,8 @@ void __init __start_xen(unsigned long mbi_p)
iommu_setup();
amd_iommu_detect();
/*
* We're going to setup domain0 using the module(s) that we stashed safely
* above our heap. The second module, if present, is an initrd ramdisk.
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _ASM_X86_64_AMD_IOMMU_H
#define _ASM_X86_64_AMD_IOMMU_H
#include <xen/init.h>
#include <xen/types.h>
#include <xen/spinlock.h>
#include <xen/mm.h>
#include <asm/hvm/svm/amd-iommu-defs.h>
#define iommu_found() (!list_empty(&amd_iommu_head))
extern int amd_iommu_enabled;
extern struct list_head amd_iommu_head;
extern int __init amd_iommu_detect(void);
struct table_struct {
void *buffer;
unsigned long entries;
unsigned long alloc_size;
};
struct amd_iommu {
struct list_head list;
spinlock_t lock; /* protect iommu */
int iotlb_support;
int ht_tunnel_support;
int not_present_cached;
u8 revision;
u8 root_bus;
u8 first_devfn;
u8 last_devfn;
int last_downstream_bus;
int downstream_bus_present[PCI_MAX_BUS_COUNT];
void *mmio_base;
unsigned long mmio_base_phys;
struct table_struct dev_table;
struct table_struct cmd_buffer;
u32 cmd_buffer_tail;
int exclusion_enabled;
unsigned long exclusion_base;
unsigned long exclusion_limit;
};
#endif /* _ASM_X86_64_AMD_IOMMU_H */
+3
View File
@@ -18,6 +18,7 @@
#include <asm/page.h>
#include <xen/kexec.h>
#include <asm/iommu.h>
#include <asm/amd-iommu.h>
/*
* Here we define all the compile-time 'special' virtual
@@ -43,6 +44,8 @@ enum fixed_addresses {
+ ((KEXEC_XEN_NO_PAGES >> 1) * KEXEC_IMAGE_NR) - 1,
FIX_IOMMU_REGS_BASE_0,
FIX_IOMMU_REGS_END = FIX_IOMMU_REGS_BASE_0 + MAX_IOMMUS-1,
FIX_IOMMU_MMIO_BASE_0,
FIX_IOMMU_MMIO_END = FIX_IOMMU_MMIO_BASE_0 + IOMMU_PAGES -1,
__end_of_fixed_addresses
};
+5
View File
@@ -42,6 +42,11 @@ struct hvm_iommu {
spinlock_t mapping_lock; /* io page table lock */
int agaw; /* adjusted guest address width, 0 is level 2 30-bit */
struct list_head g2m_ioport_list; /* guest to machine ioport mapping */
/* amd iommu support */
int domain_id;
int paging_mode;
void *root_table;
};
#endif // __ASM_X86_HVM_IOMMU_H__
@@ -0,0 +1,419 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _ASM_X86_64_AMD_IOMMU_DEFS_H
#define _ASM_X86_64_AMD_IOMMU_DEFS_H
/* Reserve some non-mapped pages to handle error conditions.
* 'bad_dma_address' will point to these reserved pages, and
* the mapping funtions will return 'bad_dma_address' if there
* are not enough page table entries available.
*/
#define IOMMU_RESERVED_BASE_ADDR 0
#define IOMMU_RESERVED_PAGES 32
/* IOMMU ComWaitInt polling after issuing a COMPLETION_WAIT command */
#define COMPLETION_WAIT_DEFAULT_POLLING_COUNT 10
/* IOMMU Command Buffer entries: in power of 2 increments, minimum of 256 */
#define IOMMU_CMD_BUFFER_DEFAULT_ENTRIES 512
#define BITMAP_ENTRIES_PER_BYTE 8
#define PTE_PER_TABLE_SHIFT 9
#define PTE_PER_TABLE_SIZE (1 << PTE_PER_TABLE_SHIFT)
#define PTE_PER_TABLE_MASK (~(PTE_PER_TABLE_SIZE - 1))
#define PTE_PER_TABLE_ALIGN(entries) \
(((entries) + PTE_PER_TABLE_SIZE - 1) & PTE_PER_TABLE_MASK)
#define PTE_PER_TABLE_ALLOC(entries) \
PAGE_SIZE * (PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT)
/* 0-based aperture order (represents virtual address space for DMA mappings */
#define APERTURE_ORDER_FOR_32B_APERTURE 0
#define APERTURE_ORDER_FOR_64MB_APERTURE 1
#define APERTURE_ORDER_FOR_128MB_APERTURE 2
#define APERTURE_ORDER_FOR_256MB_APERTURE 3
#define APERTURE_ORDER_FOR_512MB_APERTURE 4
#define APERTURE_ORDER_FOR_1GB_APERTURE 5
#define APERTURE_ORDER_FOR_MAX_APERTURE APERTURE_ORDER_FOR_1GB_APERTURE
/* The minimum 32MB aperture requires 2**13 level-1 page table entries */
#define SHIFT_FOR_MIN_APERTURE 13
#define PAGES_FROM_APERTURE_ORDER(order) \
((1 << (order)) << SHIFT_FOR_MIN_APERTURE)
#define ORDER_FROM_APERTURE_PAGES(pages) \
get_order(((pages) * PAGE_SIZE) >> SHIFT_FOR_MIN_APERTURE)
/*
* PCI config-space
*/
#define VALID_PCI_VENDOR_ID(id) (((id) != 0) && ((id) != 0xFFFF))
#define IS_PCI_MULTI_FUNCTION(hdr) ((hdr) & 0x80)
#define IS_PCI_TYPE0_HEADER(hdr) (((hdr) & 0x7f) == 0)
#define IS_PCI_TYPE1_HEADER(hdr) (((hdr) & 0x7f) == 1)
#define PCI_MAX_BUS_COUNT 256
#define PCI_MAX_DEV_COUNT 32
#define PCI_MAX_FUNC_COUNT 8
#define PCI_MIN_DEVFN 0
#define PCI_MAX_DEVFN 0xFF
/*
* Capability blocks are 4-byte aligned, and must start at >= offset 0x40,
* for a max of 48 possible cap_blocks (256 - 0x40 = 192; 192 / 4 = 48)
* The lower 2 bits of each pointer are reserved, and must be masked off.
*/
#define PCI_MIN_CAP_OFFSET 0x40
#define PCI_MAX_CAP_BLOCKS 48
#define PCI_CAP_PTR_MASK 0xFC
/* IOMMU Capability */
#define PCI_CAP_ID_MASK 0x000000FF
#define PCI_CAP_ID_SHIFT 0
#define PCI_CAP_NEXT_PTR_MASK 0x0000FF00
#define PCI_CAP_NEXT_PTR_SHIFT 8
#define PCI_CAP_TYPE_MASK 0x00070000
#define PCI_CAP_TYPE_SHIFT 16
#define PCI_CAP_REV_MASK 0x00F80000
#define PCI_CAP_REV_SHIFT 19
#define PCI_CAP_IOTLB_MASK 0x01000000
#define PCI_CAP_IOTLB_SHIFT 24
#define PCI_CAP_HT_TUNNEL_MASK 0x02000000
#define PCI_CAP_HT_TUNNEL_SHIFT 25
#define PCI_CAP_NP_CACHE_MASK 0x04000000
#define PCI_CAP_NP_CACHE_SHIFT 26
#define PCI_CAP_RESET_MASK 0x80000000
#define PCI_CAP_RESET_SHIFT 31
#define PCI_CAP_ID_SECURE_DEVICE 0x0F
#define PCI_CAP_TYPE_IOMMU 0x3
#define PCI_CAP_MMIO_BAR_LOW_OFFSET 0x04
#define PCI_CAP_MMIO_BAR_HIGH_OFFSET 0x08
#define PCI_CAP_MMIO_BAR_LOW_MASK 0xFFFFC000
#define IOMMU_MMIO_REGION_LENGTH 0x4000
#define PCI_CAP_RANGE_OFFSET 0x0C
#define PCI_CAP_BUS_NUMBER_MASK 0x0000FF00
#define PCI_CAP_BUS_NUMBER_SHIFT 8
#define PCI_CAP_FIRST_DEVICE_MASK 0x00FF0000
#define PCI_CAP_FIRST_DEVICE_SHIFT 16
#define PCI_CAP_LAST_DEVICE_MASK 0xFF000000
#define PCI_CAP_LAST_DEVICE_SHIFT 24
/* Device Table */
#define IOMMU_DEV_TABLE_BASE_LOW_OFFSET 0x00
#define IOMMU_DEV_TABLE_BASE_HIGH_OFFSET 0x04
#define IOMMU_DEV_TABLE_BASE_LOW_MASK 0xFFFFF000
#define IOMMU_DEV_TABLE_BASE_LOW_SHIFT 12
#define IOMMU_DEV_TABLE_BASE_HIGH_MASK 0x000FFFFF
#define IOMMU_DEV_TABLE_BASE_HIGH_SHIFT 0
#define IOMMU_DEV_TABLE_SIZE_MASK 0x000001FF
#define IOMMU_DEV_TABLE_SIZE_SHIFT 0
#define IOMMU_DEV_TABLE_ENTRIES_PER_BUS 256
#define IOMMU_DEV_TABLE_ENTRY_SIZE 32
#define IOMMU_DEV_TABLE_U32_PER_ENTRY (IOMMU_DEV_TABLE_ENTRY_SIZE / 4)
#define IOMMU_DEV_TABLE_SYS_MGT_DMA_ABORTED 0x0
#define IOMMU_DEV_TABLE_SYS_MGT_MSG_FORWARDED 0x1
#define IOMMU_DEV_TABLE_SYS_MGT_INT_FORWARDED 0x2
#define IOMMU_DEV_TABLE_SYS_MGT_DMA_FORWARDED 0x3
#define IOMMU_DEV_TABLE_IO_CONTROL_ABORTED 0x0
#define IOMMU_DEV_TABLE_IO_CONTROL_FORWARDED 0x1
#define IOMMU_DEV_TABLE_IO_CONTROL_TRANSLATED 0x2
#define IOMMU_DEV_TABLE_INT_CONTROL_ABORTED 0x0
#define IOMMU_DEV_TABLE_INT_CONTROL_FORWARDED 0x1
#define IOMMU_DEV_TABLE_INT_CONTROL_TRANSLATED 0x2
/* DeviceTable Entry[31:0] */
#define IOMMU_DEV_TABLE_VALID_MASK 0x00000001
#define IOMMU_DEV_TABLE_VALID_SHIFT 0
#define IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK 0x00000002
#define IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT 1
#define IOMMU_DEV_TABLE_PAGING_MODE_MASK 0x00000E00
#define IOMMU_DEV_TABLE_PAGING_MODE_SHIFT 9
#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK 0xFFFFF000
#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT 12
/* DeviceTable Entry[63:32] */
#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK 0x000FFFFF
#define IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT 0
#define IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK 0x20000000
#define IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT 29
#define IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_MASK 0x40000000
#define IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_SHIFT 30
/* DeviceTable Entry[95:64] */
#define IOMMU_DEV_TABLE_DOMAIN_ID_MASK 0x0000FFFF
#define IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT 0
/* DeviceTable Entry[127:96] */
#define IOMMU_DEV_TABLE_IOTLB_SUPPORT_MASK 0x00000001
#define IOMMU_DEV_TABLE_IOTLB_SUPPORT_SHIFT 0
#define IOMMU_DEV_TABLE_SUPRESS_LOGGED_PAGES_MASK 0x00000002
#define IOMMU_DEV_TABLE_SUPRESS_LOGGED_PAGES_SHIFT 1
#define IOMMU_DEV_TABLE_SUPRESS_ALL_PAGES_MASK 0x00000004
#define IOMMU_DEV_TABLE_SUPRESS_ALL_PAGES_SHIFT 2
#define IOMMU_DEV_TABLE_IO_CONTROL_MASK 0x00000018
#define IOMMU_DEV_TABLE_IO_CONTROL_SHIFT 3
#define IOMMU_DEV_TABLE_IOTLB_CACHE_HINT_MASK 0x00000020
#define IOMMU_DEV_TABLE_IOTLB_CACHE_HINT_SHIFT 5
#define IOMMU_DEV_TABLE_SNOOP_DISABLE_MASK 0x00000040
#define IOMMU_DEV_TABLE_SNOOP_DISABLE_SHIFT 6
#define IOMMU_DEV_TABLE_ALLOW_EXCLUSION_MASK 0x00000080
#define IOMMU_DEV_TABLE_ALLOW_EXCLUSION_SHIFT 7
#define IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK 0x00000300
#define IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT 8
/* DeviceTable Entry[159:128] */
#define IOMMU_DEV_TABLE_INT_VALID_MASK 0x00000001
#define IOMMU_DEV_TABLE_INT_VALID_SHIFT 0
#define IOMMU_DEV_TABLE_INT_TABLE_LENGTH_MASK 0x0000001E
#define IOMMU_DEV_TABLE_INT_TABLE_LENGTH_SHIFT 1
#define IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_MASK 0xFFFFFFC0
#define IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_SHIFT 6
/* DeviceTable Entry[191:160] */
#define IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_MASK 0x000FFFFF
#define IOMMU_DEV_TABLE_INT_TABLE_PTR_HIGH_SHIFT 0
#define IOMMU_DEV_TABLE_INIT_PASSTHRU_MASK 0x01000000
#define IOMMU_DEV_TABLE_INIT_PASSTHRU_SHIFT 24
#define IOMMU_DEV_TABLE_EINT_PASSTHRU_MASK 0x02000000
#define IOMMU_DEV_TABLE_EINT_PASSTHRU_SHIFT 25
#define IOMMU_DEV_TABLE_NMI_PASSTHRU_MASK 0x04000000
#define IOMMU_DEV_TABLE_NMI_PASSTHRU_SHIFT 26
#define IOMMU_DEV_TABLE_INT_CONTROL_MASK 0x30000000
#define IOMMU_DEV_TABLE_INT_CONTROL_SHIFT 28
#define IOMMU_DEV_TABLE_LINT0_ENABLE_MASK 0x40000000
#define IOMMU_DEV_TABLE_LINT0_ENABLE_SHIFT 30
#define IOMMU_DEV_TABLE_LINT1_ENABLE_MASK 0x80000000
#define IOMMU_DEV_TABLE_LINT1_ENABLE_SHIFT 31
/* Command Buffer */
#define IOMMU_CMD_BUFFER_BASE_LOW_OFFSET 0x08
#define IOMMU_CMD_BUFFER_BASE_HIGH_OFFSET 0x0C
#define IOMMU_CMD_BUFFER_HEAD_OFFSET 0x2000
#define IOMMU_CMD_BUFFER_TAIL_OFFSET 0x2008
#define IOMMU_CMD_BUFFER_BASE_LOW_MASK 0xFFFFF000
#define IOMMU_CMD_BUFFER_BASE_LOW_SHIFT 12
#define IOMMU_CMD_BUFFER_BASE_HIGH_MASK 0x000FFFFF
#define IOMMU_CMD_BUFFER_BASE_HIGH_SHIFT 0
#define IOMMU_CMD_BUFFER_LENGTH_MASK 0x0F000000
#define IOMMU_CMD_BUFFER_LENGTH_SHIFT 24
#define IOMMU_CMD_BUFFER_HEAD_MASK 0x0007FFF0
#define IOMMU_CMD_BUFFER_HEAD_SHIFT 4
#define IOMMU_CMD_BUFFER_TAIL_MASK 0x0007FFF0
#define IOMMU_CMD_BUFFER_TAIL_SHIFT 4
#define IOMMU_CMD_BUFFER_ENTRY_SIZE 16
#define IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE 8
#define IOMMU_CMD_BUFFER_U32_PER_ENTRY (IOMMU_CMD_BUFFER_ENTRY_SIZE / 4)
#define IOMMU_CMD_OPCODE_MASK 0xF0000000
#define IOMMU_CMD_OPCODE_SHIFT 28
#define IOMMU_CMD_COMPLETION_WAIT 0x1
#define IOMMU_CMD_INVALIDATE_DEVTAB_ENTRY 0x2
#define IOMMU_CMD_INVALIDATE_IOMMU_PAGES 0x3
#define IOMMU_CMD_INVALIDATE_IOTLB_PAGES 0x4
#define IOMMU_CMD_INVALIDATE_INT_TABLE 0x5
/* COMPLETION_WAIT command */
#define IOMMU_COMP_WAIT_DATA_BUFFER_SIZE 8
#define IOMMU_COMP_WAIT_DATA_BUFFER_ALIGNMENT 8
#define IOMMU_COMP_WAIT_S_FLAG_MASK 0x00000001
#define IOMMU_COMP_WAIT_S_FLAG_SHIFT 0
#define IOMMU_COMP_WAIT_I_FLAG_MASK 0x00000002
#define IOMMU_COMP_WAIT_I_FLAG_SHIFT 1
#define IOMMU_COMP_WAIT_F_FLAG_MASK 0x00000004
#define IOMMU_COMP_WAIT_F_FLAG_SHIFT 2
#define IOMMU_COMP_WAIT_ADDR_LOW_MASK 0xFFFFFFF8
#define IOMMU_COMP_WAIT_ADDR_LOW_SHIFT 3
#define IOMMU_COMP_WAIT_ADDR_HIGH_MASK 0x000FFFFF
#define IOMMU_COMP_WAIT_ADDR_HIGH_SHIFT 0
/* INVALIDATE_IOMMU_PAGES command */
#define IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_MASK 0x0000FFFF
#define IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_SHIFT 0
#define IOMMU_INV_IOMMU_PAGES_S_FLAG_MASK 0x00000001
#define IOMMU_INV_IOMMU_PAGES_S_FLAG_SHIFT 0
#define IOMMU_INV_IOMMU_PAGES_PDE_FLAG_MASK 0x00000002
#define IOMMU_INV_IOMMU_PAGES_PDE_FLAG_SHIFT 1
#define IOMMU_INV_IOMMU_PAGES_ADDR_LOW_MASK 0xFFFFF000
#define IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT 12
#define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK 0xFFFFFFFF
#define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT 0
/* Event Log */
#define IOMMU_EVENT_LOG_BASE_LOW_OFFSET 0x10
#define IOMMU_EVENT_LOG_BASE_HIGH_OFFSET 0x14
#define IOMMU_EVENT_LOG_HEAD_OFFSET 0x2010
#define IOMMU_EVENT_LOG_TAIL_OFFSET 0x2018
#define IOMMU_EVENT_LOG_BASE_LOW_MASK 0xFFFFF000
#define IOMMU_EVENT_LOG_BASE_LOW_SHIFT 12
#define IOMMU_EVENT_LOG_BASE_HIGH_MASK 0x000FFFFF
#define IOMMU_EVENT_LOG_BASE_HIGH_SHIFT 0
#define IOMMU_EVENT_LOG_LENGTH_MASK 0x0F000000
#define IOMMU_EVENT_LOG_LENGTH_SHIFT 24
#define IOMMU_EVENT_LOG_HEAD_MASK 0x0007FFF0
#define IOMMU_EVENT_LOG_HEAD_SHIFT 4
#define IOMMU_EVENT_LOG_TAIL_MASK 0x0007FFF0
#define IOMMU_EVENT_LOG_TAIL_SHIFT 4
#define IOMMU_EVENT_LOG_ENTRY_SIZE 16
#define IOMMU_EVENT_LOG_POWER_OF2_ENTRIES_PER_PAGE 8
#define IOMMU_EVENT_LOG_U32_PER_ENTRY (IOMMU_EVENT_LOG_ENTRY_SIZE / 4)
#define IOMMU_EVENT_CODE_MASK 0xF0000000
#define IOMMU_EVENT_CODE_SHIFT 28
#define IOMMU_EVENT_ILLEGAL_DEV_TABLE_ENTRY 0x1
#define IOMMU_EVENT_IO_PAGE_FALT 0x2
#define IOMMU_EVENT_DEV_TABLE_HW_ERROR 0x3
#define IOMMU_EVENT_PAGE_TABLE_HW_ERROR 0x4
#define IOMMU_EVENT_ILLEGAL_COMMAND_ERROR 0x5
#define IOMMU_EVENT_COMMAND_HW_ERROR 0x6
#define IOMMU_EVENT_IOTLB_INV_TIMEOUT 0x7
#define IOMMU_EVENT_INVALID_DEV_REQUEST 0x8
/* Control Register */
#define IOMMU_CONTROL_MMIO_OFFSET 0x18
#define IOMMU_CONTROL_TRANSLATION_ENABLE_MASK 0x00000001
#define IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT 0
#define IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_MASK 0x00000002
#define IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT 1
#define IOMMU_CONTROL_EVENT_LOG_ENABLE_MASK 0x00000004
#define IOMMU_CONTROL_EVENT_LOG_ENABLE_SHIFT 2
#define IOMMU_CONTROL_EVENT_LOG_INT_MASK 0x00000008
#define IOMMU_CONTROL_EVENT_LOG_INT_SHIFT 3
#define IOMMU_CONTROL_COMP_WAIT_INT_MASK 0x00000010
#define IOMMU_CONTROL_COMP_WAIT_INT_SHIFT 4
#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_MASK 0x00000020
#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_SHIFT 5
#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_MASK 0x000000C0
#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_SHIFT 6
#define IOMMU_CONTROL_PASS_POSTED_WRITE_MASK 0x00000100
#define IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT 8
#define IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_MASK 0x00000200
#define IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_SHIFT 9
#define IOMMU_CONTROL_COHERENT_MASK 0x00000400
#define IOMMU_CONTROL_COHERENT_SHIFT 10
#define IOMMU_CONTROL_ISOCHRONOUS_MASK 0x00000800
#define IOMMU_CONTROL_ISOCHRONOUS_SHIFT 11
#define IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_MASK 0x00001000
#define IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT 12
#define IOMMU_CONTROL_RESTART_MASK 0x80000000
#define IOMMU_CONTROL_RESTART_SHIFT 31
/* Exclusion Register */
#define IOMMU_EXCLUSION_BASE_LOW_OFFSET 0x20
#define IOMMU_EXCLUSION_BASE_HIGH_OFFSET 0x24
#define IOMMU_EXCLUSION_LIMIT_LOW_OFFSET 0x28
#define IOMMU_EXCLUSION_LIMIT_HIGH_OFFSET 0x2C
#define IOMMU_EXCLUSION_BASE_LOW_MASK 0xFFFFF000
#define IOMMU_EXCLUSION_BASE_LOW_SHIFT 12
#define IOMMU_EXCLUSION_BASE_HIGH_MASK 0xFFFFFFFF
#define IOMMU_EXCLUSION_BASE_HIGH_SHIFT 0
#define IOMMU_EXCLUSION_RANGE_ENABLE_MASK 0x00000001
#define IOMMU_EXCLUSION_RANGE_ENABLE_SHIFT 0
#define IOMMU_EXCLUSION_ALLOW_ALL_MASK 0x00000002
#define IOMMU_EXCLUSION_ALLOW_ALL_SHIFT 1
#define IOMMU_EXCLUSION_LIMIT_LOW_MASK 0xFFFFF000
#define IOMMU_EXCLUSION_LIMIT_LOW_SHIFT 12
#define IOMMU_EXCLUSION_LIMIT_HIGH_MASK 0xFFFFFFFF
#define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT 0
/* Status Register*/
#define IOMMU_STATUS_MMIO_OFFSET 0x2020
#define IOMMU_STATUS_EVENT_OVERFLOW_MASK 0x00000001
#define IOMMU_STATUS_EVENT_OVERFLOW_SHIFT 0
#define IOMMU_STATUS_EVENT_LOG_INT_MASK 0x00000002
#define IOMMU_STATUS_EVENT_LOG_INT_SHIFT 1
#define IOMMU_STATUS_COMP_WAIT_INT_MASK 0x00000004
#define IOMMU_STATUS_COMP_WAIT_INT_SHIFT 2
#define IOMMU_STATUS_EVENT_LOG_RUN_MASK 0x00000008
#define IOMMU_STATUS_EVENT_LOG_RUN_SHIFT 3
#define IOMMU_STATUS_CMD_BUFFER_RUN_MASK 0x00000010
#define IOMMU_STATUS_CMD_BUFFER_RUN_SHIFT 4
/* I/O Page Table */
#define IOMMU_PAGE_TABLE_ENTRY_SIZE 8
#define IOMMU_PAGE_TABLE_U32_PER_ENTRY (IOMMU_PAGE_TABLE_ENTRY_SIZE / 4)
#define IOMMU_PAGE_TABLE_ALIGNMENT 4096
#define IOMMU_PTE_PRESENT_MASK 0x00000001
#define IOMMU_PTE_PRESENT_SHIFT 0
#define IOMMU_PTE_NEXT_LEVEL_MASK 0x00000E00
#define IOMMU_PTE_NEXT_LEVEL_SHIFT 9
#define IOMMU_PTE_ADDR_LOW_MASK 0xFFFFF000
#define IOMMU_PTE_ADDR_LOW_SHIFT 12
#define IOMMU_PTE_ADDR_HIGH_MASK 0x000FFFFF
#define IOMMU_PTE_ADDR_HIGH_SHIFT 0
#define IOMMU_PTE_U_MASK 0x08000000
#define IOMMU_PTE_U_SHIFT 7
#define IOMMU_PTE_FC_MASK 0x10000000
#define IOMMU_PTE_FC_SHIFT 28
#define IOMMU_PTE_IO_READ_PERMISSION_MASK 0x20000000
#define IOMMU_PTE_IO_READ_PERMISSION_SHIFT 29
#define IOMMU_PTE_IO_WRITE_PERMISSION_MASK 0x40000000
#define IOMMU_PTE_IO_WRITE_PERMISSION_SHIFT 30
/* I/O Page Directory */
#define IOMMU_PAGE_DIRECTORY_ENTRY_SIZE 8
#define IOMMU_PAGE_DIRECTORY_ALIGNMENT 4096
#define IOMMU_PDE_PRESENT_MASK 0x00000001
#define IOMMU_PDE_PRESENT_SHIFT 0
#define IOMMU_PDE_NEXT_LEVEL_MASK 0x00000E00
#define IOMMU_PDE_NEXT_LEVEL_SHIFT 9
#define IOMMU_PDE_ADDR_LOW_MASK 0xFFFFF000
#define IOMMU_PDE_ADDR_LOW_SHIFT 12
#define IOMMU_PDE_ADDR_HIGH_MASK 0x000FFFFF
#define IOMMU_PDE_ADDR_HIGH_SHIFT 0
#define IOMMU_PDE_IO_READ_PERMISSION_MASK 0x20000000
#define IOMMU_PDE_IO_READ_PERMISSION_SHIFT 29
#define IOMMU_PDE_IO_WRITE_PERMISSION_MASK 0x40000000
#define IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT 30
/* Paging modes */
#define IOMMU_PAGING_MODE_DISABLED 0x0
#define IOMMU_PAGING_MODE_LEVEL_0 0x0
#define IOMMU_PAGING_MODE_LEVEL_1 0x1
#define IOMMU_PAGING_MODE_LEVEL_2 0x2
#define IOMMU_PAGING_MODE_LEVEL_3 0x3
#define IOMMU_PAGING_MODE_LEVEL_4 0x4
#define IOMMU_PAGING_MODE_LEVEL_5 0x5
#define IOMMU_PAGING_MODE_LEVEL_6 0x6
#define IOMMU_PAGING_MODE_LEVEL_7 0x7
/* Flags */
#define IOMMU_CONTROL_DISABLED 0
#define IOMMU_CONTROL_ENABLED 1
#define MMIO_PAGES_PER_IOMMU (IOMMU_MMIO_REGION_LENGTH / PAGE_SIZE_4K)
#define IOMMU_PAGES (MMIO_PAGES_PER_IOMMU * MAX_AMD_IOMMUS)
#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
#define MAX_AMD_IOMMUS 32
#define IOMMU_PAGE_TABLE_LEVEL_3 3
#define IOMMU_PAGE_TABLE_LEVEL_4 4
#define IOMMU_IO_WRITE_ENABLED 1
#define IOMMU_IO_READ_ENABLED 1
#endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
@@ -0,0 +1,88 @@
/*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Author: Leo Duran <leo.duran@amd.com>
* Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _ASM_X86_64_AMD_IOMMU_PROTO_H
#define _ASM_X86_64_AMD_IOMMU_PROTO_H
#include <asm/amd-iommu.h>
#define for_each_amd_iommu(amd_iommu) \
list_for_each_entry(amd_iommu, \
&amd_iommu_head, list)
#define DMA_32BIT_MASK 0x00000000ffffffffULL
#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
#define PAGE_SHIFT_4K (12)
#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
typedef int (*iommu_detect_callback_ptr_t)(u8 bus, u8 dev, u8 func, u8 cap_ptr);
/* amd-iommu-detect functions */
int __init scan_for_iommu(iommu_detect_callback_ptr_t iommu_detect_callback);
int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
struct amd_iommu *iommu);
int __init get_iommu_last_downstream_bus(struct amd_iommu *iommu);
/* amd-iommu-init functions */
int __init map_iommu_mmio_region(struct amd_iommu *iommu);
void __init unmap_iommu_mmio_region(struct amd_iommu *iommu);
void __init register_iommu_dev_table_in_mmio_space(struct amd_iommu *iommu);
void __init register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu);
void __init enable_iommu(struct amd_iommu *iommu);
/* mapping functions */
int amd_iommu_map_page(struct domain *d, unsigned long gfn,
unsigned long mfn);
int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
/* device table functions */
void amd_iommu_set_dev_table_entry(u32 *dte,
u64 root_ptr, u16 domain_id, u8 paging_mode);
/* send cmd to iommu */
int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]);
/* iommu domain funtions */
int amd_iommu_domain_init(struct domain *domain);
void amd_iommu_setup_domain_device(struct domain *domain,
struct amd_iommu *iommu, int requestor_id);
/* find iommu for bdf */
struct amd_iommu *find_iommu_for_device(int bus, int devfn);
static inline u32 get_field_from_reg_u32(u32 reg_value, u32 mask, u32 shift)
{
u32 field;
field = (reg_value & mask) >> shift;
return field;
}
static inline u32 set_field_in_reg_u32(u32 field, u32 reg_value,
u32 mask, u32 shift, u32 *reg)
{
reg_value &= ~mask;
reg_value |= (field << shift) & mask;
if (reg)
*reg = reg_value;
return reg_value;
}
#endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.