# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1202987657 0
# Node ID 72f52dd2dba8e0a7ac616c75520e5b168ec1eb9e
# Parent c9d9bbf1204c66fe4a067b4a61b551d5999a9315
x86 iommu: Define vendor-neutral interface for access to IOMMU.
Signed-off-by: Wei Wang <wei.wang2@xxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/domctl.c | 8
xen/arch/x86/hvm/Makefile | 1
xen/arch/x86/hvm/iommu.c | 135 ++++++++
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c | 2
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c | 371 +++++++++++-----------
xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c | 346 +++++++++++++++-----
xen/arch/x86/hvm/svm/intr.c | 41 ++
xen/arch/x86/hvm/vioapic.c | 2
xen/arch/x86/hvm/vmx/vtd/intel-iommu.c | 38 +-
xen/arch/x86/hvm/vmx/vtd/io.c | 53 ---
xen/arch/x86/mm/p2m.c | 17 -
xen/include/asm-x86/hvm/iommu.h | 3
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h | 5
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h | 18 -
xen/include/asm-x86/hvm/vmx/intel-iommu.h | 8
xen/include/asm-x86/iommu.h | 16
16 files changed, 725 insertions(+), 339 deletions(-)
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/domctl.c Thu Feb 14 11:14:17 2008 +0000
@@ -530,7 +530,7 @@ long arch_do_domctl(
u8 bus, devfn;
ret = -EINVAL;
- if ( !vtd_enabled )
+ if ( !iommu_enabled )
break;
bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff;
@@ -553,7 +553,7 @@ long arch_do_domctl(
u8 bus, devfn;
ret = -EINVAL;
- if ( !vtd_enabled )
+ if ( !iommu_enabled )
break;
if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
@@ -589,9 +589,9 @@ long arch_do_domctl(
if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL )
break;
bind = &(domctl->u.bind_pt_irq);
- if (vtd_enabled)
+ if ( iommu_enabled )
ret = pt_irq_create_bind_vtd(d, bind);
- if (ret < 0)
+ if ( ret < 0 )
gdprintk(XENLOG_ERR, "pt_irq_create_bind failed!\n");
rcu_unlock_domain(d);
}
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/hvm/Makefile Thu Feb 14 11:14:17 2008 +0000
@@ -6,6 +6,7 @@ obj-y += instrlen.o
obj-y += instrlen.o
obj-y += intercept.o
obj-y += io.o
+obj-y += iommu.o
obj-y += irq.o
obj-y += mtrr.o
obj-y += platform.o
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/hvm/iommu.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/iommu.c Thu Feb 14 11:14:17 2008 +0000
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#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>
+
+extern struct iommu_ops intel_iommu_ops;
+extern struct iommu_ops amd_iommu_ops;
+
+int 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);
+ INIT_LIST_HEAD(&hd->g2m_ioport_list);
+
+ if ( !iommu_enabled )
+ return 0;
+
+ switch ( boot_cpu_data.x86_vendor )
+ {
+ case X86_VENDOR_INTEL:
+ hd->platform_ops = &intel_iommu_ops;
+ break;
+ case X86_VENDOR_AMD:
+ hd->platform_ops = &amd_iommu_ops;
+ break;
+ default:
+ BUG();
+ }
+
+ return hd->platform_ops->init(domain);
+}
+
+int assign_device(struct domain *d, u8 bus, u8 devfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return 0;
+
+ return hd->platform_ops->assign_device(d, bus, devfn);
+}
+
+void iommu_domain_destroy(struct domain *d)
+{
+ struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ uint32_t i;
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+ struct list_head *ioport_list, *digl_list, *tmp;
+ struct g2m_ioport *ioport;
+ struct dev_intx_gsi_link *digl;
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return;
+
+ if ( hvm_irq_dpci != NULL )
+ {
+ for ( i = 0; i < NR_IRQS; i++ )
+ {
+ if ( !hvm_irq_dpci->mirq[i].valid )
+ continue;
+
+ pirq_guest_unbind(d, i);
+ kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]);
+
+ list_for_each_safe ( digl_list, tmp,
+ &hvm_irq_dpci->mirq[i].digl_list )
+ {
+ digl = list_entry(digl_list,
+ struct dev_intx_gsi_link, list);
+ list_del(&digl->list);
+ xfree(digl);
+ }
+ }
+
+ d->arch.hvm_domain.irq.dpci = NULL;
+ xfree(hvm_irq_dpci);
+ }
+
+ if ( hd )
+ {
+ list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list )
+ {
+ ioport = list_entry(ioport_list, struct g2m_ioport, list);
+ list_del(&ioport->list);
+ xfree(ioport);
+ }
+ }
+
+ return hd->platform_ops->teardown(d);
+}
+
+int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return 0;
+
+ return hd->platform_ops->map_page(d, gfn, mfn);
+}
+
+int iommu_unmap_page(struct domain *d, unsigned long gfn)
+{
+ struct hvm_iommu *hd = domain_hvm_iommu(d);
+
+ if ( !iommu_enabled || !hd->platform_ops)
+ return 0;
+
+ return hd->platform_ops->unmap_page(d, gfn);
+}
diff -r c9d9bbf1204c -r 72f52dd2dba8
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 14 10:36:47
2008 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c Thu Feb 14 11:14:17
2008 +0000
@@ -89,12 +89,14 @@ int __init get_iommu_capabilities(u8 bus
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;
diff -r c9d9bbf1204c -r 72f52dd2dba8
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 14 10:36:47
2008 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c Thu Feb 14 11:14:17
2008 +0000
@@ -30,22 +30,20 @@ static int queue_iommu_command(struct am
u32 tail, head, *cmd_buffer;
int i;
- BUG_ON( !iommu || !cmd );
-
tail = iommu->cmd_buffer_tail;
- if ( ++tail == iommu->cmd_buffer.entries ) {
+ 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 ) {
+ 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 ) {
+ (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;
@@ -58,27 +56,25 @@ static void commit_iommu_command_buffer(
{
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);
+ 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) ) {
+ 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 io_addr, u16 domain_id)
{
u64 addr_lo, addr_hi;
u32 cmd[4], entry;
@@ -87,51 +83,52 @@ static void invalidate_iommu_page(struct
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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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)
+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);
+ 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]);
+ 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]);
+ 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? */
@@ -139,34 +136,36 @@ static void flush_command_buffer(struct
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);
+ 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 ) {
+ 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__);
+ 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]);
+ 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)
+ int iw, int ir)
{
u64 addr_lo, addr_hi;
u32 entry;
@@ -175,33 +174,33 @@ static void set_page_table_entry_present
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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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 next_ptr, u8 next_level)
{
u64 addr_lo, addr_hi;
u32 entry;
@@ -211,29 +210,31 @@ static void amd_iommu_set_page_directory
/* 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);
+ 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);
+ 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);
+ 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)
+ u8 paging_mode)
{
u64 addr_hi, addr_lo;
u32 entry;
@@ -241,54 +242,56 @@ void amd_iommu_set_dev_table_entry(u32 *
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);
+ 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);
+ 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, &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);
+ 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;
@@ -297,42 +300,74 @@ static int amd_iommu_is_pte_present(u32
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));
+ 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 io_pfn)
{
unsigned long offset;
- void *pde = 0;
-
- BUG_ON( !table );
+ void *pde = NULL;
+
+ BUG_ON(table == NULL);
while ( level > 0 )
{
- void *next_table = 0;
- unsigned long next_ptr;
offset = io_pfn >> ((PTE_PER_TABLE_SHIFT *
- (level - IOMMU_PAGING_MODE_LEVEL_1)));
+ (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();
+ 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 ) {
- next_ptr = (u64)virt_to_maddr(next_table);
- amd_iommu_set_page_directory_entry((u32 *)pde,
- next_ptr, level - 1);
- } else
+ 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--;
@@ -341,8 +376,7 @@ static void *get_pte_from_page_tables(vo
return pde;
}
-int amd_iommu_map_page(struct domain *d, unsigned long gfn,
- unsigned long mfn)
+int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
{
void *pte;
unsigned long flags;
@@ -352,7 +386,7 @@ int amd_iommu_map_page(struct domain *d,
BUG_ON( !hd->root_table );
- maddr = (u64)(mfn << PAGE_SHIFT);
+ maddr = (u64)mfn << PAGE_SHIFT;
iw = IOMMU_IO_WRITE_ENABLED;
ir = IOMMU_IO_READ_ENABLED;
@@ -360,18 +394,18 @@ int amd_iommu_map_page(struct domain *d,
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 {
+ if ( pte == 0 )
+ {
dprintk(XENLOG_ERR,
- "%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n",
- __FUNCTION__, gfn);
+ "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)
@@ -386,34 +420,31 @@ int amd_iommu_unmap_page(struct domain *
BUG_ON( !hd->root_table );
requestor_id = hd->domain_id;
- io_addr = (u64)(gfn << PAGE_SHIFT);
+ 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 {
+ if ( pte == 0 )
+ {
dprintk(XENLOG_ERR,
- "%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n",
- __FUNCTION__, gfn);
+ "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 c9d9bbf1204c -r 72f52dd2dba8
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 14 10:36:47
2008 +0000
+++ b/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c Thu Feb 14 11:14:17
2008 +0000
@@ -51,19 +51,17 @@ static void __init init_cleanup(void)
{
struct amd_iommu *iommu;
- dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
-
- for_each_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) {
+ struct table_struct *table)
+{
+ if ( table->buffer )
+ {
free_xenheap_pages(table->buffer,
- get_order_from_bytes(table->alloc_size));
+ get_order_from_bytes(table->alloc_size));
table->buffer = NULL;
}
}
@@ -76,11 +74,10 @@ static void __init deallocate_iommu_reso
static void __init detect_cleanup(void)
{
- struct amd_iommu *iommu;
-
- dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__);
-
- for_each_amd_iommu(iommu) {
+ 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);
@@ -91,19 +88,21 @@ static int requestor_id_from_bdf(int bdf
{
/* HACK - HACK */
/* account for possible 'aliasing' by parent device */
- return bdf;
+ return bdf;
}
static int __init allocate_iommu_table_struct(struct table_struct *table,
- const char *name)
+ const char *name)
{
table->buffer = (void *) alloc_xenheap_pages(
get_order_from_bytes(table->alloc_size));
- if ( !table->buffer ) {
+ if ( !table->buffer )
+ {
dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating %s\n", name);
return -ENOMEM;
}
+
memset(table->buffer, 0, table->alloc_size);
return 0;
@@ -114,32 +113,32 @@ static int __init allocate_iommu_resourc
/* 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_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)
+ 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 =
+ 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:
+ "Command Buffer") != 0 )
+ goto error_out;
+
+ return 0;
+
+ error_out:
deallocate_iommu_resources(iommu);
return -ENOMEM;
}
@@ -149,7 +148,8 @@ int iommu_detect_callback(u8 bus, u8 dev
struct amd_iommu *iommu;
iommu = (struct amd_iommu *) xmalloc(struct amd_iommu);
- if ( !iommu ) {
+ if ( !iommu )
+ {
dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating amd_iommu\n");
return -ENOMEM;
}
@@ -170,7 +170,7 @@ int iommu_detect_callback(u8 bus, u8 dev
return 0;
-error_out:
+ error_out:
xfree(iommu);
return -ENODEV;
}
@@ -180,11 +180,12 @@ static int __init amd_iommu_init(void)
struct amd_iommu *iommu;
unsigned long flags;
- for_each_amd_iommu(iommu) {
+ 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)
+ 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);
@@ -200,7 +201,7 @@ static int __init amd_iommu_init(void)
return 0;
-error_out:
+ error_out:
init_cleanup();
return -ENODEV;
}
@@ -209,13 +210,16 @@ struct amd_iommu *find_iommu_for_device(
{
struct amd_iommu *iommu;
- for_each_amd_iommu(iommu) {
- if ( bus == iommu->root_bus ) {
- if ( devfn >= iommu->first_devfn &&
- devfn <= iommu->last_devfn )
+ 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 ) {
+ else if ( bus <= iommu->last_downstream_bus )
+ {
if ( iommu->downstream_bus_present[bus] )
return iommu;
}
@@ -238,16 +242,21 @@ void amd_iommu_setup_domain_device(
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:%"PRIx64", domain_id:%d, paging_mode:%d\n",
- requestor_id, root_ptr, hd->domain_id, hd->paging_mode);
-
- spin_unlock_irqrestore(&iommu->lock, flags);
+ 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)
@@ -259,13 +268,16 @@ void __init amd_iommu_setup_dom0_devices
u32 l;
int req_id, bdf;
- for ( bus = 0; bus < 256; bus++ ) {
- for ( dev = 0; dev < 32; dev++ ) {
- for ( func = 0; func < 8; func++ ) {
+ 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 )
+ l == 0x0000ffff || l == 0xffff0000 )
continue;
pdev = xmalloc(struct pci_dev);
@@ -288,29 +300,33 @@ int amd_iommu_detect(void)
{
unsigned long i;
- if ( !enable_amd_iommu ) {
+ 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 ) {
+ if ( scan_for_iommu(iommu_detect_callback) != 0 )
+ {
dprintk(XENLOG_ERR, "AMD IOMMU: Error detection\n");
goto error_out;
}
- if ( !iommu_found() ) {
+ if ( !iommu_found() )
+ {
printk("AMD IOMMU: Not found!\n");
return 0;
}
- if ( amd_iommu_init() != 0 ) {
+ if ( amd_iommu_init() != 0 )
+ {
dprintk(XENLOG_ERR, "AMD IOMMU: Error initialization\n");
goto error_out;
}
- if ( amd_iommu_domain_init(dom0) != 0 )
+ if ( iommu_domain_init(dom0) != 0 )
goto error_out;
/* setup 1:1 page table for dom0 */
@@ -320,21 +336,31 @@ int amd_iommu_detect(void)
amd_iommu_setup_dom0_devices();
return 0;
-error_out:
- detect_cleanup();
- return -ENODEV;
+ 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();
+ unsigned long flags;
+
+ spin_lock_irqsave(&hd->mapping_lock, flags);
if ( !hd->root_table )
- return -ENOMEM;
- memset((u8*)hd->root_table, 0, PAGE_SIZE);
-
- return 0;
+ {
+ 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)
@@ -346,7 +372,8 @@ static int get_paging_mode(unsigned long
if ( entries > max_page )
entries = max_page;
- while ( entries > PTE_PER_TABLE_SIZE ) {
+ while ( entries > PTE_PER_TABLE_SIZE )
+ {
entries = PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT;
++level;
if ( level > 6 )
@@ -362,14 +389,11 @@ int amd_iommu_domain_init(struct 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 ( allocate_domain_resources(hd) != 0 )
+ {
+ deallocate_domain_resources(hd);
+ return -ENOMEM;
}
if ( is_hvm_domain(domain) )
@@ -380,10 +404,168 @@ int amd_iommu_domain_init(struct domain
hd->domain_id = domain->domain_id;
return 0;
-
-error_out:
- deallocate_domain_resources(hd);
- return -ENOMEM;
-}
-
-
+}
+
+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);
+}
+
+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,
+};
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/hvm/svm/intr.c Thu Feb 14 11:14:17 2008 +0000
@@ -94,6 +94,46 @@ static void enable_intr_window(struct vc
vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
}
+static void svm_dirq_assist(struct vcpu *v)
+{
+ unsigned int irq;
+ uint32_t device, intx;
+ struct domain *d = v->domain;
+ struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+ struct dev_intx_gsi_link *digl;
+
+ if ( !amd_iommu_enabled || (v->vcpu_id != 0) || (hvm_irq_dpci == NULL) )
+ return;
+
+ for ( irq = find_first_bit(hvm_irq_dpci->dirq_mask, NR_IRQS);
+ irq < NR_IRQS;
+ irq = find_next_bit(hvm_irq_dpci->dirq_mask, NR_IRQS, irq + 1) )
+ {
+ stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]);
+ clear_bit(irq, &hvm_irq_dpci->dirq_mask);
+
+ list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list )
+ {
+ device = digl->device;
+ intx = digl->intx;
+ hvm_pci_intx_assert(d, device, intx);
+ spin_lock(&hvm_irq_dpci->dirq_lock);
+ hvm_irq_dpci->mirq[irq].pending++;
+ spin_unlock(&hvm_irq_dpci->dirq_lock);
+ }
+
+ /*
+ * Set a timer to see if the guest can finish the interrupt or not. For
+ * example, the guest OS may unmask the PIC during boot, before the
+ * guest driver is loaded. hvm_pci_intx_assert() may succeed, but the
+ * guest will never deal with the irq, then the physical interrupt line
+ * will never be deasserted.
+ */
+ set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)],
+ NOW() + PT_IRQ_TIME_OUT);
+ }
+}
+
asmlinkage void svm_intr_assist(void)
{
struct vcpu *v = current;
@@ -102,6 +142,7 @@ asmlinkage void svm_intr_assist(void)
/* Crank the handle on interrupt state. */
pt_update_irq(v);
+ svm_dirq_assist(v);
do {
intack = hvm_vcpu_has_pending_irq(v);
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/hvm/vioapic.c
--- a/xen/arch/x86/hvm/vioapic.c Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/hvm/vioapic.c Thu Feb 14 11:14:17 2008 +0000
@@ -458,7 +458,7 @@ void vioapic_update_EOI(struct domain *d
ent->fields.remote_irr = 0;
- if ( vtd_enabled )
+ if ( iommu_enabled )
{
spin_unlock(&d->arch.hvm_domain.irq_lock);
hvm_dpci_eoi(current->domain, gsi, ent);
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c
--- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Thu Feb 14 11:14:17 2008 +0000
@@ -1047,7 +1047,7 @@ static void free_iommu(struct iommu *iom
agaw = 64; \
agaw; })
-int iommu_domain_init(struct domain *domain)
+int intel_iommu_domain_init(struct domain *domain)
{
struct hvm_iommu *hd = domain_hvm_iommu(domain);
struct iommu *iommu = NULL;
@@ -1055,11 +1055,6 @@ int iommu_domain_init(struct domain *dom
int adjust_width, agaw;
unsigned long sagaw;
struct acpi_drhd_unit *drhd;
-
- spin_lock_init(&hd->mapping_lock);
- spin_lock_init(&hd->iommu_list_lock);
- INIT_LIST_HEAD(&hd->pdev_list);
- INIT_LIST_HEAD(&hd->g2m_ioport_list);
if ( !vtd_enabled || list_empty(&acpi_drhd_units) )
return 0;
@@ -1550,7 +1545,8 @@ static int domain_context_mapped(struct
return 0;
}
-int iommu_map_page(struct domain *d, paddr_t gfn, paddr_t mfn)
+int intel_iommu_map_page(
+ struct domain *d, unsigned long gfn, unsigned long mfn)
{
struct acpi_drhd_unit *drhd;
struct iommu *iommu;
@@ -1566,12 +1562,12 @@ int iommu_map_page(struct domain *d, pad
return 0;
#endif
- pg = addr_to_dma_page(d, gfn << PAGE_SHIFT_4K);
+ 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, mfn << PAGE_SHIFT_4K);
+ 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);
@@ -1581,7 +1577,7 @@ int iommu_map_page(struct domain *d, pad
iommu = drhd->iommu;
if ( cap_caching_mode(iommu->cap) )
iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
- gfn << PAGE_SHIFT_4K, 1, 0);
+ (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0);
else if ( cap_rwbf(iommu->cap) )
iommu_flush_write_buffer(iommu);
}
@@ -1589,7 +1585,7 @@ int iommu_map_page(struct domain *d, pad
return 0;
}
-int iommu_unmap_page(struct domain *d, dma_addr_t gfn)
+int intel_iommu_unmap_page(struct domain *d, unsigned long gfn)
{
struct acpi_drhd_unit *drhd;
struct iommu *iommu;
@@ -1603,12 +1599,12 @@ int iommu_unmap_page(struct domain *d, d
return 0;
#endif
- dma_pte_clear_one(d, gfn << PAGE_SHIFT_4K);
+ dma_pte_clear_one(d, (paddr_t)gfn << PAGE_SHIFT_4K);
return 0;
}
-int iommu_page_mapping(struct domain *domain, dma_addr_t iova,
+int iommu_page_mapping(struct domain *domain, paddr_t iova,
void *hpa, size_t size, int prot)
{
struct acpi_drhd_unit *drhd;
@@ -1655,14 +1651,14 @@ int iommu_page_mapping(struct domain *do
return 0;
}
-int iommu_page_unmapping(struct domain *domain, dma_addr_t addr, size_t size)
+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, dma_addr_t gfn, u64 *p2m_entry)
+void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry)
{
struct acpi_drhd_unit *drhd;
struct iommu *iommu = NULL;
@@ -1673,7 +1669,7 @@ void iommu_flush(struct domain *d, dma_a
iommu = drhd->iommu;
if ( cap_caching_mode(iommu->cap) )
iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),
- gfn << PAGE_SHIFT_4K, 1, 0);
+ (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0);
else if ( cap_rwbf(iommu->cap) )
iommu_flush_write_buffer(iommu);
}
@@ -1921,7 +1917,7 @@ int device_assigned(u8 bus, u8 devfn)
return 1;
}
-int assign_device(struct domain *d, u8 bus, u8 devfn)
+int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
{
struct acpi_rmrr_unit *rmrr;
struct pci_dev *pdev;
@@ -2151,6 +2147,14 @@ int iommu_resume(void)
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,
+};
+
/*
* Local variables:
* mode: C
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/hvm/vmx/vtd/io.c
--- a/xen/arch/x86/hvm/vmx/vtd/io.c Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/vtd/io.c Thu Feb 14 11:14:17 2008 +0000
@@ -141,7 +141,7 @@ int hvm_do_IRQ_dpci(struct domain *d, un
{
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
- if ( !vtd_enabled || (d == dom0) || (hvm_irq->dpci == NULL) ||
+ if ( !iommu_enabled || (d == dom0) || (hvm_irq->dpci == NULL) ||
!hvm_irq->dpci->mirq[mirq].valid )
return 0;
@@ -167,7 +167,7 @@ static void hvm_dpci_isairq_eoi(struct d
int i;
ASSERT(isairq < NR_ISAIRQS);
- if ( !vtd_enabled || !dpci ||
+ if ( !iommu_enabled || !dpci ||
!test_bit(isairq, dpci->isairq_map) )
return;
@@ -205,7 +205,7 @@ void hvm_dpci_eoi(struct domain *d, unsi
struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
uint32_t device, intx, machine_gsi;
- if ( !vtd_enabled || (hvm_irq_dpci == NULL) ||
+ if ( !iommu_enabled || (hvm_irq_dpci == NULL) ||
(guest_gsi >= NR_ISAIRQS &&
!hvm_irq_dpci->girq[guest_gsi].valid) )
return;
@@ -235,50 +235,3 @@ void hvm_dpci_eoi(struct domain *d, unsi
else
spin_unlock(&hvm_irq_dpci->dirq_lock);
}
-
-void iommu_domain_destroy(struct domain *d)
-{
- struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- uint32_t i;
- struct hvm_iommu *hd = domain_hvm_iommu(d);
- struct list_head *ioport_list, *digl_list, *tmp;
- struct g2m_ioport *ioport;
- struct dev_intx_gsi_link *digl;
-
- if ( !vtd_enabled )
- return;
-
- if ( hvm_irq_dpci != NULL )
- {
- for ( i = 0; i < NR_IRQS; i++ )
- if ( hvm_irq_dpci->mirq[i].valid )
- {
- pirq_guest_unbind(d, i);
- kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]);
-
- list_for_each_safe ( digl_list, tmp,
- &hvm_irq_dpci->mirq[i].digl_list )
- {
- digl = list_entry(digl_list,
- struct dev_intx_gsi_link, list);
- list_del(&digl->list);
- xfree(digl);
- }
- }
-
- d->arch.hvm_domain.irq.dpci = NULL;
- xfree(hvm_irq_dpci);
- }
-
- if ( hd )
- {
- list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list )
- {
- ioport = list_entry(ioport_list, struct g2m_ioport, list);
- list_del(&ioport->list);
- xfree(ioport);
- }
- }
-
- iommu_domain_teardown(d);
-}
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/arch/x86/mm/p2m.c Thu Feb 14 11:14:17 2008 +0000
@@ -255,8 +255,21 @@ set_p2m_entry(struct domain *d, unsigned
/* level 1 entry */
paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1);
- if ( vtd_enabled && (p2mt == p2m_mmio_direct) && is_hvm_domain(d) )
- iommu_flush(d, gfn, (u64*)p2m_entry);
+ if ( iommu_enabled && is_hvm_domain(d) )
+ {
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
+ {
+ if ( (p2mt == p2m_mmio_direct) )
+ iommu_flush(d, gfn, (u64*)p2m_entry);
+ }
+ else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
+ {
+ if ( p2mt == p2m_ram_rw )
+ iommu_map_page(d, gfn, mfn_x(mfn));
+ else
+ iommu_unmap_page(d, gfn);
+ }
+ }
/* Success */
rv = 1;
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/include/asm-x86/hvm/iommu.h
--- a/xen/include/asm-x86/hvm/iommu.h Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/include/asm-x86/hvm/iommu.h Thu Feb 14 11:14:17 2008 +0000
@@ -48,6 +48,9 @@ struct hvm_iommu {
int domain_id;
int paging_mode;
void *root_table;
+
+ /* iommu_ops */
+ struct iommu_ops *platform_ops;
};
#endif // __ASM_X86_HVM_IOMMU_H__
diff -r c9d9bbf1204c -r 72f52dd2dba8
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Feb 14 10:36:47
2008 +0000
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Feb 14 11:14:17
2008 +0000
@@ -262,6 +262,10 @@
#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
+
+/* INVALIDATE_DEVTAB_ENTRY command */
+#define IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_MASK 0x0000FFFF
+#define IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_SHIFT 0
/* Event Log */
#define IOMMU_EVENT_LOG_BASE_LOW_OFFSET 0x10
@@ -415,5 +419,6 @@
#define IOMMU_PAGE_TABLE_LEVEL_4 4
#define IOMMU_IO_WRITE_ENABLED 1
#define IOMMU_IO_READ_ENABLED 1
+#define HACK_BIOS_SETTINGS 0
#endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
diff -r c9d9bbf1204c -r 72f52dd2dba8
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Thu Feb 14 10:36:47
2008 +0000
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Thu Feb 14 11:14:17
2008 +0000
@@ -27,13 +27,15 @@
list_for_each_entry(amd_iommu, \
&amd_iommu_head, list)
+#define for_each_pdev(domain, pdev) \
+ list_for_each_entry(pdev, \
+ &(domain->arch.hvm_domain.hvm_iommu.pdev_list), 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);
+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);
@@ -49,16 +51,20 @@ void __init enable_iommu(struct amd_iomm
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_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
+void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry);
/* device table functions */
void amd_iommu_set_dev_table_entry(u32 *dte,
u64 root_ptr, u16 domain_id, u8 paging_mode);
+int amd_iommu_is_dte_page_translation_valid(u32 *entry);
+void invalidate_dev_table_entry(struct amd_iommu *iommu,
+ u16 devic_id);
/* send cmd to iommu */
int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]);
+void flush_command_buffer(struct amd_iommu *iommu);
/* iommu domain funtions */
int amd_iommu_domain_init(struct domain *domain);
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/include/asm-x86/hvm/vmx/intel-iommu.h
--- a/xen/include/asm-x86/hvm/vmx/intel-iommu.h Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/include/asm-x86/hvm/vmx/intel-iommu.h Thu Feb 14 11:14:17 2008 +0000
@@ -422,8 +422,6 @@ struct poll_info {
#define VTD_PAGE_TABLE_LEVEL_3 3
#define VTD_PAGE_TABLE_LEVEL_4 4
-typedef paddr_t dma_addr_t;
-
#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
#define MAX_IOMMUS 32
#define MAX_IOMMU_REGS 0xc0
@@ -447,8 +445,10 @@ struct ir_ctrl {
};
struct iommu_flush {
- int (*context)(void *iommu, u16 did, u16 source_id, u8 function_mask, u64
type, int non_present_entry_flush);
- int (*iotlb)(void *iommu, u16 did, u64 addr, unsigned int size_order, u64
type, int non_present_entry_flush);
+ int (*context)(void *iommu, u16 did, u16 source_id,
+ u8 function_mask, u64 type, int non_present_entry_flush);
+ int (*iotlb)(void *iommu, u16 did, u64 addr, unsigned int size_order,
+ u64 type, int non_present_entry_flush);
};
struct intel_iommu {
diff -r c9d9bbf1204c -r 72f52dd2dba8 xen/include/asm-x86/iommu.h
--- a/xen/include/asm-x86/iommu.h Thu Feb 14 10:36:47 2008 +0000
+++ b/xen/include/asm-x86/iommu.h Thu Feb 14 11:14:17 2008 +0000
@@ -28,7 +28,9 @@
#include <public/domctl.h>
extern int vtd_enabled;
+extern int amd_iommu_enabled;
+#define iommu_enabled ( amd_iommu_enabled || vtd_enabled )
#define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu)
#define domain_vmx_iommu(d) (&d->arch.hvm_domain.hvm_iommu.vmx_iommu)
#define iommu_qi_ctrl(iommu) (&(iommu->intel.qi_ctrl));
@@ -72,9 +74,9 @@ void iommu_domain_destroy(struct domain
void iommu_domain_destroy(struct domain *d);
int device_assigned(u8 bus, u8 devfn);
int assign_device(struct domain *d, u8 bus, u8 devfn);
-int iommu_map_page(struct domain *d, dma_addr_t gfn, dma_addr_t mfn);
-int iommu_unmap_page(struct domain *d, dma_addr_t gfn);
-void iommu_flush(struct domain *d, dma_addr_t gfn, u64 *p2m_entry);
+int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
+int iommu_unmap_page(struct domain *d, unsigned long gfn);
+void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry);
void iommu_set_pgd(struct domain *d);
void iommu_domain_teardown(struct domain *d);
int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);
@@ -89,4 +91,12 @@ void io_apic_write_remap_rte(unsigned in
#define PT_IRQ_TIME_OUT MILLISECS(8)
#define VTDPREFIX "[VT-D]"
+struct iommu_ops {
+ int (*init)(struct domain *d);
+ int (*assign_device)(struct domain *d, u8 bus, u8 devfn);
+ void (*teardown)(struct domain *d);
+ int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn);
+ int (*unmap_page)(struct domain *d, unsigned long gfn);
+};
+
#endif /* _IOMMU_H_ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|