# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1245752064 -3600
# Node ID aa472909b39c1228434c4550915ee3cc18c57bfe
# Parent 71c67be96ef68e7f94c78e991e9b8f25a76af658
vtd: IO NUMA support
This patch adds VT-d RHSA processing for IO NUMA support. The basic
idea is to parse ACPI RHSA structure to obtain VT-d HW to proximity
domain mapping. This mapping is then used when allocating pages for
Vt-d HW data structures.
Signed-off-by: Allen Kay <allen.m.kay@xxxxxxxxx>
---
xen/drivers/passthrough/vtd/dmar.c | 56 +++++++++++++++++++++++++++++++++
xen/drivers/passthrough/vtd/dmar.h | 5 ++
xen/drivers/passthrough/vtd/extern.h | 2 +
xen/drivers/passthrough/vtd/ia64/vtd.c | 19 -----------
xen/drivers/passthrough/vtd/intremap.c | 4 +-
xen/drivers/passthrough/vtd/iommu.c | 54 ++++++++++++++++++++++++++++---
xen/drivers/passthrough/vtd/qinval.c | 4 +-
xen/drivers/passthrough/vtd/vtd.h | 2 -
xen/drivers/passthrough/vtd/x86/vtd.c | 21 ------------
xen/include/xen/acpi.h | 7 ++++
10 files changed, 126 insertions(+), 48 deletions(-)
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/dmar.c
--- a/xen/drivers/passthrough/vtd/dmar.c Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.c Tue Jun 23 11:14:24 2009 +0100
@@ -42,6 +42,7 @@ LIST_HEAD(acpi_drhd_units);
LIST_HEAD(acpi_drhd_units);
LIST_HEAD(acpi_rmrr_units);
LIST_HEAD(acpi_atsr_units);
+LIST_HEAD(acpi_rhsa_units);
u8 dmar_host_address_width;
@@ -127,6 +128,20 @@ struct acpi_drhd_unit * ioapic_to_drhd(u
return NULL;
}
+struct acpi_drhd_unit * iommu_to_drhd(struct iommu *iommu)
+{
+ struct acpi_drhd_unit *drhd;
+
+ if ( iommu == NULL )
+ return NULL;
+
+ list_for_each_entry( drhd, &acpi_drhd_units, list )
+ if ( drhd->iommu == iommu )
+ return drhd;
+
+ return NULL;
+}
+
struct iommu * ioapic_to_iommu(unsigned int apic_id)
{
struct acpi_drhd_unit *drhd;
@@ -157,6 +172,9 @@ struct acpi_drhd_unit * acpi_find_matche
struct acpi_drhd_unit *include_all = NULL;
int i;
+ if ( pdev == NULL )
+ return NULL;
+
if (pdev->info.is_extfn) {
bus = pdev->bus;
devfn = 0;
@@ -197,6 +215,21 @@ struct acpi_atsr_unit * acpi_find_matche
all_ports = atsr;
}
return all_ports;
+}
+
+struct acpi_rhsa_unit * drhd_to_rhsa(struct acpi_drhd_unit *drhd)
+{
+ struct acpi_rhsa_unit *rhsa;
+
+ if ( drhd == NULL )
+ return NULL;
+
+ list_for_each_entry ( rhsa, &acpi_rhsa_units, list )
+ {
+ if ( rhsa->address == drhd->address )
+ return rhsa;
+ }
+ return NULL;
}
/*
@@ -453,6 +486,25 @@ acpi_parse_one_atsr(struct acpi_dmar_ent
return ret;
}
+static int __init
+acpi_parse_one_rhsa(struct acpi_dmar_entry_header *header)
+{
+ struct acpi_table_rhsa *rhsa = (struct acpi_table_rhsa *)header;
+ struct acpi_rhsa_unit *rhsau;
+ int ret = 0;
+
+ rhsau = xmalloc(struct acpi_rhsa_unit);
+ if ( !rhsau )
+ return -ENOMEM;
+ memset(rhsau, 0, sizeof(struct acpi_rhsa_unit));
+
+ rhsau->address = rhsa->address;
+ rhsau->domain = rhsa->domain;
+ list_add_tail(&rhsau->list, &acpi_rhsa_units);
+
+ return ret;
+}
+
static int __init acpi_parse_dmar(struct acpi_table_header *table)
{
struct acpi_table_dmar *dmar;
@@ -491,6 +543,10 @@ static int __init acpi_parse_dmar(struct
case ACPI_DMAR_ATSR:
dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_ATSR\n");
ret = acpi_parse_one_atsr(entry_header);
+ break;
+ case ACPI_DMAR_RHSA:
+ dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_RHSA\n");
+ ret = acpi_parse_one_rhsa(entry_header);
break;
default:
dprintk(XENLOG_WARNING VTDPREFIX, "Unknown DMAR structure type\n");
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/dmar.h
--- a/xen/drivers/passthrough/vtd/dmar.h Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.h Tue Jun 23 11:14:24 2009 +0100
@@ -69,6 +69,11 @@ struct acpi_atsr_unit {
u8 all_ports:1;
};
+struct acpi_rhsa_unit {
+ struct list_head list;
+ u64 address;
+ u32 domain;
+};
#define for_each_drhd_unit(drhd) \
list_for_each_entry(drhd, &acpi_drhd_units, list)
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/extern.h
--- a/xen/drivers/passthrough/vtd/extern.h Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/extern.h Tue Jun 23 11:14:24 2009 +0100
@@ -45,6 +45,8 @@ int iommu_flush_iec_index(struct iommu *
int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx);
struct iommu * ioapic_to_iommu(unsigned int apic_id);
struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id);
+struct acpi_drhd_unit * iommu_to_drhd(struct iommu *iommu);
+struct acpi_rhsa_unit * drhd_to_rhsa(struct acpi_drhd_unit *drhd);
void clear_fault_bits(struct iommu *iommu);
int ats_device(int seg, int bus, int devfn);
int enable_ats_device(int seg, int bus, int devfn);
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/ia64/vtd.c
--- a/xen/drivers/passthrough/vtd/ia64/vtd.c Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/ia64/vtd.c Tue Jun 23 11:14:24 2009 +0100
@@ -44,25 +44,6 @@ void unmap_vtd_domain_page(void *va)
void unmap_vtd_domain_page(void *va)
{
unmap_domain_page(va);
-}
-
-/* Allocate page table, return its machine address */
-u64 alloc_pgtable_maddr(struct domain *d, unsigned long npages)
-{
- struct page_info *pg;
- u64 *vaddr;
-
- pg = alloc_domheap_pages(NULL, get_order_from_pages(npages),
- d ? MEMF_node(domain_to_node(d)) : 0);
- vaddr = map_domain_page(page_to_mfn(pg));
- if ( !vaddr )
- return 0;
- memset(vaddr, 0, PAGE_SIZE * npages);
-
- iommu_flush_cache_page(vaddr, npages);
- unmap_domain_page(vaddr);
-
- return page_to_maddr(pg);
}
void free_pgtable_maddr(u64 maddr)
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/intremap.c
--- a/xen/drivers/passthrough/vtd/intremap.c Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/intremap.c Tue Jun 23 11:14:24 2009 +0100
@@ -614,6 +614,7 @@ void msi_msg_write_remap_rte(
int enable_intremap(struct iommu *iommu)
{
+ struct acpi_drhd_unit *drhd;
struct ir_ctrl *ir_ctrl;
u32 sts, gcmd;
unsigned long flags;
@@ -623,7 +624,8 @@ int enable_intremap(struct iommu *iommu)
ir_ctrl = iommu_ir_ctrl(iommu);
if ( ir_ctrl->iremap_maddr == 0 )
{
- ir_ctrl->iremap_maddr = alloc_pgtable_maddr(NULL, 1);
+ drhd = iommu_to_drhd(iommu);
+ ir_ctrl->iremap_maddr = alloc_pgtable_maddr(drhd, 1);
if ( ir_ctrl->iremap_maddr == 0 )
{
dprintk(XENLOG_WARNING VTDPREFIX,
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c Tue Jun 23 11:14:24 2009 +0100
@@ -38,6 +38,7 @@
#define domain_iommu_domid(d) ((d)->arch.hvm_domain.hvm_iommu.iommu_domid)
+int nr_iommus;
static spinlock_t domid_bitmap_lock; /* protect domain id bitmap */
static int domid_bitmap_size; /* domain id bitmap size in bits */
static unsigned long *domid_bitmap; /* iommu domain id bitmap */
@@ -136,10 +137,37 @@ void iommu_flush_cache_page(void *addr,
__iommu_flush_cache(addr, PAGE_SIZE_4K * npages);
}
-int nr_iommus;
+/* Allocate page table, return its machine address */
+u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages)
+{
+ struct acpi_rhsa_unit *rhsa;
+ struct page_info *pg;
+ u64 *vaddr;
+
+ rhsa = drhd_to_rhsa(drhd);
+ if ( !rhsa )
+ dprintk(XENLOG_INFO VTDPREFIX,
+ "IOMMU: RHSA == NULL, IO NUMA memory allocation disabled\n");
+
+ pg = alloc_domheap_pages(NULL, get_order_from_pages(npages),
+ rhsa ? rhsa->domain : 0);
+ if ( !pg )
+ return 0;
+ vaddr = map_domain_page(page_to_mfn(pg));
+ if ( !vaddr )
+ return 0;
+ memset(vaddr, 0, PAGE_SIZE * npages);
+
+ iommu_flush_cache_page(vaddr, npages);
+ unmap_domain_page(vaddr);
+
+ return page_to_maddr(pg);
+}
+
/* context entry handling */
static u64 bus_to_context_maddr(struct iommu *iommu, u8 bus)
{
+ struct acpi_drhd_unit *drhd;
struct root_entry *root, *root_entries;
u64 maddr;
@@ -148,7 +176,8 @@ static u64 bus_to_context_maddr(struct i
root = &root_entries[bus];
if ( !root_present(*root) )
{
- maddr = alloc_pgtable_maddr(NULL, 1);
+ drhd = iommu_to_drhd(iommu);
+ maddr = alloc_pgtable_maddr(drhd, 1);
if ( maddr == 0 )
{
unmap_vtd_domain_page(root_entries);
@@ -165,6 +194,8 @@ static u64 bus_to_context_maddr(struct i
static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr, int alloc)
{
+ struct acpi_drhd_unit *drhd;
+ struct pci_dev *pdev;
struct hvm_iommu *hd = domain_hvm_iommu(domain);
int addr_width = agaw_to_width(hd->agaw);
struct dma_pte *parent, *pte = NULL;
@@ -176,8 +207,12 @@ static u64 addr_to_dma_page_maddr(struct
addr &= (((u64)1) << addr_width) - 1;
ASSERT(spin_is_locked(&hd->mapping_lock));
if ( hd->pgd_maddr == 0 )
- if ( !alloc || ((hd->pgd_maddr = alloc_pgtable_maddr(domain, 1)) == 0)
)
+ {
+ pdev = pci_get_pdev_by_domain(domain, -1, -1);
+ drhd = acpi_find_matched_drhd_unit(pdev);
+ if ( !alloc || ((hd->pgd_maddr = alloc_pgtable_maddr(drhd, 1)) == 0) )
goto out;
+ }
parent = (struct dma_pte *)map_vtd_domain_page(hd->pgd_maddr);
while ( level > 1 )
@@ -189,9 +224,13 @@ static u64 addr_to_dma_page_maddr(struct
{
if ( !alloc )
break;
- maddr = alloc_pgtable_maddr(domain, 1);
+
+ pdev = pci_get_pdev_by_domain(domain, -1, -1);
+ drhd = acpi_find_matched_drhd_unit(pdev);
+ maddr = alloc_pgtable_maddr(drhd, 1);
if ( !maddr )
break;
+
dma_set_pte_addr(*pte, maddr);
vaddr = map_vtd_domain_page(maddr);
@@ -548,13 +587,18 @@ static void iommu_free_pagetable(u64 pt_
static int iommu_set_root_entry(struct iommu *iommu)
{
+ struct acpi_drhd_unit *drhd;
u32 sts;
unsigned long flags;
spin_lock(&iommu->lock);
if ( iommu->root_maddr == 0 )
- iommu->root_maddr = alloc_pgtable_maddr(NULL, 1);
+ {
+ drhd = iommu_to_drhd(iommu);
+ iommu->root_maddr = alloc_pgtable_maddr(drhd, 1);
+ }
+
if ( iommu->root_maddr == 0 )
{
spin_unlock(&iommu->lock);
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/qinval.c
--- a/xen/drivers/passthrough/vtd/qinval.c Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/qinval.c Tue Jun 23 11:14:24 2009 +0100
@@ -416,6 +416,7 @@ static int flush_iotlb_qi(
int enable_qinval(struct iommu *iommu)
{
+ struct acpi_drhd_unit *drhd;
struct qi_ctrl *qi_ctrl;
struct iommu_flush *flush;
u32 sts;
@@ -428,7 +429,8 @@ int enable_qinval(struct iommu *iommu)
if ( qi_ctrl->qinval_maddr == 0 )
{
- qi_ctrl->qinval_maddr = alloc_pgtable_maddr(NULL, NUM_QINVAL_PAGES);
+ drhd = iommu_to_drhd(iommu);
+ qi_ctrl->qinval_maddr = alloc_pgtable_maddr(drhd, NUM_QINVAL_PAGES);
if ( qi_ctrl->qinval_maddr == 0 )
{
dprintk(XENLOG_WARNING VTDPREFIX,
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/vtd.h
--- a/xen/drivers/passthrough/vtd/vtd.h Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/vtd.h Tue Jun 23 11:14:24 2009 +0100
@@ -101,7 +101,7 @@ void cacheline_flush(char *);
void cacheline_flush(char *);
void flush_all_cache(void);
void *map_to_nocache_virt(int nr_iommus, u64 maddr);
-u64 alloc_pgtable_maddr(struct domain *d, unsigned long npages);
+u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages);
void free_pgtable_maddr(u64 maddr);
void *map_vtd_domain_page(u64 maddr);
void unmap_vtd_domain_page(void *va);
diff -r 71c67be96ef6 -r aa472909b39c xen/drivers/passthrough/vtd/x86/vtd.c
--- a/xen/drivers/passthrough/vtd/x86/vtd.c Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/drivers/passthrough/vtd/x86/vtd.c Tue Jun 23 11:14:24 2009 +0100
@@ -42,27 +42,6 @@ void unmap_vtd_domain_page(void *va)
void unmap_vtd_domain_page(void *va)
{
unmap_domain_page(va);
-}
-
-/* Allocate page table, return its machine address */
-u64 alloc_pgtable_maddr(struct domain *d, unsigned long npages)
-{
- struct page_info *pg;
- u64 *vaddr;
- unsigned long mfn;
-
- pg = alloc_domheap_pages(NULL, get_order_from_pages(npages),
- d ? MEMF_node(domain_to_node(d)) : 0);
- if ( !pg )
- return 0;
- mfn = page_to_mfn(pg);
- vaddr = map_domain_page(mfn);
- memset(vaddr, 0, PAGE_SIZE * npages);
-
- iommu_flush_cache_page(vaddr, npages);
- unmap_domain_page(vaddr);
-
- return (u64)mfn << PAGE_SHIFT_4K;
}
void free_pgtable_maddr(u64 maddr)
diff -r 71c67be96ef6 -r aa472909b39c xen/include/xen/acpi.h
--- a/xen/include/xen/acpi.h Tue Jun 23 11:13:29 2009 +0100
+++ b/xen/include/xen/acpi.h Tue Jun 23 11:14:24 2009 +0100
@@ -197,6 +197,7 @@ enum acpi_dmar_entry_type {
ACPI_DMAR_DRHD = 0,
ACPI_DMAR_RMRR,
ACPI_DMAR_ATSR,
+ ACPI_DMAR_RHSA,
ACPI_DMAR_ENTRY_COUNT
};
@@ -222,6 +223,12 @@ struct acpi_table_atsr {
u8 flags;
u8 reserved;
u16 segment;
+} __attribute__ ((packed));
+
+struct acpi_table_rhsa {
+ struct acpi_dmar_entry_header header;
+ u32 domain;
+ u64 address; /* register base address for this drhd */
} __attribute__ ((packed));
enum acpi_dev_scope_type {
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|