aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/intel-iommu.c
diff options
context:
space:
mode:
authorWeidong Han <weidong.han@intel.com>2008-12-08 10:08:15 -0500
committerJoerg Roedel <joerg.roedel@amd.com>2009-01-03 08:02:18 -0500
commitea6606b02fc3192f2edab2db669fa0b9756b4e67 (patch)
tree821832b7880301dca6def43eae3b39138e220c64 /drivers/pci/intel-iommu.c
parent5e98c4b1d6e89676193c355e430eddf369bcf195 (diff)
Change domain_context_mapping_one for virtual machine domain
vm_domid won't be set in context, find available domain id for a device from its iommu. For a virtual machine domain, a default agaw will be set, and skip top levels of page tables for iommu which has less agaw than default. Signed-off-by: Weidong Han <weidong.han@intel.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r--drivers/pci/intel-iommu.c55
1 files changed, 52 insertions, 3 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 171f6c61fa1d..8a204d5bb427 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1454,6 +1454,11 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
1454 struct context_entry *context; 1454 struct context_entry *context;
1455 unsigned long flags; 1455 unsigned long flags;
1456 struct intel_iommu *iommu; 1456 struct intel_iommu *iommu;
1457 struct dma_pte *pgd;
1458 unsigned long num;
1459 unsigned long ndomains;
1460 int id;
1461 int agaw;
1457 1462
1458 pr_debug("Set context mapping for %02x:%02x.%d\n", 1463 pr_debug("Set context mapping for %02x:%02x.%d\n",
1459 bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); 1464 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
@@ -1472,9 +1477,53 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
1472 return 0; 1477 return 0;
1473 } 1478 }
1474 1479
1475 context_set_domain_id(context, domain->id); 1480 id = domain->id;
1476 context_set_address_width(context, domain->agaw); 1481 pgd = domain->pgd;
1477 context_set_address_root(context, virt_to_phys(domain->pgd)); 1482
1483 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1484 int found = 0;
1485
1486 /* find an available domain id for this device in iommu */
1487 ndomains = cap_ndoms(iommu->cap);
1488 num = find_first_bit(iommu->domain_ids, ndomains);
1489 for (; num < ndomains; ) {
1490 if (iommu->domains[num] == domain) {
1491 id = num;
1492 found = 1;
1493 break;
1494 }
1495 num = find_next_bit(iommu->domain_ids,
1496 cap_ndoms(iommu->cap), num+1);
1497 }
1498
1499 if (found == 0) {
1500 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1501 if (num >= ndomains) {
1502 spin_unlock_irqrestore(&iommu->lock, flags);
1503 printk(KERN_ERR "IOMMU: no free domain ids\n");
1504 return -EFAULT;
1505 }
1506
1507 set_bit(num, iommu->domain_ids);
1508 iommu->domains[num] = domain;
1509 id = num;
1510 }
1511
1512 /* Skip top levels of page tables for
1513 * iommu which has less agaw than default.
1514 */
1515 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1516 pgd = phys_to_virt(dma_pte_addr(pgd));
1517 if (!dma_pte_present(pgd)) {
1518 spin_unlock_irqrestore(&iommu->lock, flags);
1519 return -ENOMEM;
1520 }
1521 }
1522 }
1523
1524 context_set_domain_id(context, id);
1525 context_set_address_width(context, iommu->agaw);
1526 context_set_address_root(context, virt_to_phys(pgd));
1478 context_set_translation_type(context, CONTEXT_TT_MULTI_LEVEL); 1527 context_set_translation_type(context, CONTEXT_TT_MULTI_LEVEL);
1479 context_set_fault_enable(context); 1528 context_set_fault_enable(context);
1480 context_set_present(context); 1529 context_set_present(context);