diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/intel-iommu.c | 55 |
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); |
