{
acpi_physical_address dmar_addr;
acpi_native_uint dmar_len;
+ const struct acpi_drhd_unit *drhd;
int ret;
if ( ACPI_SUCCESS(acpi_get_table_phys(ACPI_SIG_DMAR, 0,
ret = parse_dmar_table(acpi_parse_dmar);
+ for_each_drhd_unit ( drhd )
+ {
+ const struct acpi_rhsa_unit *rhsa = drhd_to_rhsa(drhd);
+ struct iommu *iommu = drhd->iommu;
+
+ if ( ret )
+ break;
+
+ if ( rhsa )
+ iommu->node = pxm_to_node(rhsa->proximity_domain);
+
+ if ( !(iommu->root_maddr = alloc_pgtable_maddr(1, iommu->node)) )
+ ret = -ENOMEM;
+ }
+
if ( !ret )
{
iommu_init_ops = &intel_iommu_init_ops;
}
/* Allocate page table, return its machine address */
-u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages)
+uint64_t alloc_pgtable_maddr(unsigned long npages, nodeid_t node)
{
- struct acpi_rhsa_unit *rhsa;
struct page_info *pg, *cur_pg;
u64 *vaddr;
- nodeid_t node = NUMA_NO_NODE;
unsigned int i;
- rhsa = drhd_to_rhsa(drhd);
- if ( rhsa )
- node = pxm_to_node(rhsa->proximity_domain);
-
pg = alloc_domheap_pages(NULL, get_order_from_pages(npages),
(node == NUMA_NO_NODE) ? 0 : MEMF_node(node));
if ( !pg )
root = &root_entries[bus];
if ( !root_present(*root) )
{
- maddr = alloc_pgtable_maddr(iommu->intel->drhd, 1);
+ maddr = alloc_pgtable_maddr(1, iommu->node);
if ( maddr == 0 )
{
unmap_vtd_domain_page(root_entries);
static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr, int alloc)
{
- struct acpi_drhd_unit *drhd;
- struct pci_dev *pdev;
struct domain_iommu *hd = dom_iommu(domain);
int addr_width = agaw_to_width(hd->arch.agaw);
struct dma_pte *parent, *pte = NULL;
addr &= (((u64)1) << addr_width) - 1;
ASSERT(spin_is_locked(&hd->arch.mapping_lock));
- if ( hd->arch.pgd_maddr == 0 )
- {
- /*
- * just get any passthrough device in the domainr - assume user
- * assigns only devices from same node to a given guest.
- */
- pdev = pci_get_pdev_by_domain(domain, -1, -1, -1);
- drhd = acpi_find_matched_drhd_unit(pdev);
- if ( !alloc || ((hd->arch.pgd_maddr = alloc_pgtable_maddr(drhd, 1)) == 0) )
- goto out;
- }
+ if ( !hd->arch.pgd_maddr &&
+ (!alloc ||
+ ((hd->arch.pgd_maddr = alloc_pgtable_maddr(1, hd->node)) == 0)) )
+ goto out;
parent = (struct dma_pte *)map_vtd_domain_page(hd->arch.pgd_maddr);
while ( level > 1 )
if ( !alloc )
break;
- pdev = pci_get_pdev_by_domain(domain, -1, -1, -1);
- drhd = acpi_find_matched_drhd_unit(pdev);
- pte_maddr = alloc_pgtable_maddr(drhd, 1);
+ pte_maddr = alloc_pgtable_maddr(1, hd->node);
if ( !pte_maddr )
break;
return -ENOMEM;
iommu->msi.irq = -1; /* No irq assigned yet. */
+ iommu->node = NUMA_NO_NODE;
INIT_LIST_HEAD(&iommu->ats_devices);
iommu->intel = alloc_intel_iommu();
iommu->intel->drhd = drhd;
drhd->iommu = iommu;
- if ( !(iommu->root_maddr = alloc_pgtable_maddr(drhd, 1)) )
- return -ENOMEM;
-
iommu->reg = ioremap(drhd->address, PAGE_SIZE);
if ( !iommu->reg )
return -ENOMEM;
if ( !drhd )
return -ENODEV;
+ /*
+ * Generally we assume only devices from one node to get assigned to a
+ * given guest. But even if not, by replacing the prior value here we
+ * guarantee that at least some basic allocations for the device being
+ * added will get done against its node. Any further allocations for
+ * this or other devices may be penalized then, but some would also be
+ * if we left other than NUMA_NO_NODE untouched here.
+ */
+ if ( drhd->iommu->node != NUMA_NO_NODE )
+ dom_iommu(domain)->node = drhd->iommu->node;
+
ASSERT(pcidevs_locked());
switch ( pdev->type )