Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 125581
b: refs/heads/master
c: fe40f1e
h: refs/heads/master
i:
  125579: 329adfb
v: v3
  • Loading branch information
Weidong Han authored and Joerg Roedel committed Jan 3, 2009
1 parent 9265c9a commit e41efb6
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: faa3d6f5ffe7bf60ebfd0d36513fbcda0eb0ea1a
refs/heads/master: fe40f1e020d0923f5f35ca15f02a206c75a28053
61 changes: 61 additions & 0 deletions trunk/drivers/pci/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ struct dmar_domain {
int iommu_coherency;/* indicate coherency of iommu access */
int iommu_count; /* reference count of iommu */
spinlock_t iommu_lock; /* protect iommu set in domain */
u64 max_addr; /* maximum mapped address */
};

/* PCI domain-device relationship */
Expand Down Expand Up @@ -2849,6 +2850,22 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
/* domain id for virtual machine, it won't be set in context */
static unsigned long vm_domid;

static int vm_domain_min_agaw(struct dmar_domain *domain)
{
int i;
int min_agaw = domain->agaw;

i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
for (; i < g_num_of_iommus; ) {
if (min_agaw > g_iommus[i]->agaw)
min_agaw = g_iommus[i]->agaw;

i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
}

return min_agaw;
}

static struct dmar_domain *iommu_alloc_vm_domain(void)
{
struct dmar_domain *domain;
Expand Down Expand Up @@ -2883,6 +2900,7 @@ static int vm_domain_init(struct dmar_domain *domain, int guest_width)

domain->iommu_count = 0;
domain->iommu_coherency = 0;
domain->max_addr = 0;

/* always allocate the top pgd */
domain->pgd = (struct dma_pte *)alloc_pgtable_page();
Expand Down Expand Up @@ -2974,6 +2992,9 @@ EXPORT_SYMBOL_GPL(intel_iommu_free_domain);
int intel_iommu_attach_device(struct dmar_domain *domain,
struct pci_dev *pdev)
{
struct intel_iommu *iommu;
int addr_width;
u64 end;
int ret;

/* normally pdev is not mapped */
Expand All @@ -2989,6 +3010,21 @@ int intel_iommu_attach_device(struct dmar_domain *domain,
}
}

iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
if (!iommu)
return -ENODEV;

/* check if this iommu agaw is sufficient for max mapped address */
addr_width = agaw_to_width(iommu->agaw);
end = DOMAIN_MAX_ADDR(addr_width);
end = end & VTD_PAGE_MASK;
if (end < domain->max_addr) {
printk(KERN_ERR "%s: iommu agaw (%d) is not "
"sufficient for the mapped address (%llx)\n",
__func__, iommu->agaw, domain->max_addr);
return -EFAULT;
}

ret = domain_context_mapping(domain, pdev);
if (ret)
return ret;
Expand All @@ -3008,7 +3044,29 @@ EXPORT_SYMBOL_GPL(intel_iommu_detach_device);
int intel_iommu_map_address(struct dmar_domain *domain, dma_addr_t iova,
u64 hpa, size_t size, int prot)
{
u64 max_addr;
int addr_width;
int ret;

max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
if (domain->max_addr < max_addr) {
int min_agaw;
u64 end;

/* check if minimum agaw is sufficient for mapped address */
min_agaw = vm_domain_min_agaw(domain);
addr_width = agaw_to_width(min_agaw);
end = DOMAIN_MAX_ADDR(addr_width);
end = end & VTD_PAGE_MASK;
if (end < max_addr) {
printk(KERN_ERR "%s: iommu agaw (%d) is not "
"sufficient for the mapped address (%llx)\n",
__func__, min_agaw, max_addr);
return -EFAULT;
}
domain->max_addr = max_addr;
}

ret = domain_page_mapping(domain, iova, hpa, size, prot);
return ret;
}
Expand All @@ -3023,6 +3081,9 @@ void intel_iommu_unmap_address(struct dmar_domain *domain,
base = iova & VTD_PAGE_MASK;
size = VTD_PAGE_ALIGN(size);
dma_pte_clear_range(domain, base, base + size);

if (domain->max_addr == base + size)
domain->max_addr = base;
}
EXPORT_SYMBOL_GPL(intel_iommu_unmap_address);

Expand Down

0 comments on commit e41efb6

Please sign in to comment.