#define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops
domain for an IOMMU */
+#define APERTURE_RANGE_SIZE (128 * 1024 * 1024)
+
/*
* This structure contains generic data for IOMMU protection domains
* independent of their use.
};
/*
+ * For dynamic growth the aperture size is split into ranges of 128MB of
+ * DMA address space each. This struct represents one such range.
+ */
+struct aperture_range {
+
+ /* address allocation bitmap */
+ unsigned long *bitmap;
+
+ /*
+ * Array of PTE pages for the aperture. In this array we save all the
+ * leaf pages of the domain page table used for the aperture. This way
+ * we don't need to walk the page table to find a specific PTE. We can
+ * just calculate its address in constant time.
+ */
+ u64 *pte_pages[64];
+};
+
+/*
* Data container for a dma_ops specific protection domain
*/
struct dma_ops_domain {
/* address we start to search for free addresses */
unsigned long next_bit;
- /* address allocation bitmap */
- unsigned long *bitmap;
-
- /*
- * Array of PTE pages for the aperture. In this array we save all the
- * leaf pages of the domain page table used for the aperture. This way
- * we don't need to walk the page table to find a specific PTE. We can
- * just calculate its address in constant time.
- */
- u64 **pte_pages;
+ /* address space relevant data */
+ struct aperture_range aperture;
/* This will be set to true when TLB needs to be flushed */
bool need_flush;
* as allocated in the aperture
*/
if (addr < dma_dom->aperture_size)
- __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap);
+ __set_bit(addr >> PAGE_SHIFT,
+ dma_dom->aperture.bitmap);
}
return 0;
dom->need_flush = true;
}
- address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
- 0 , boundary_size, align_mask);
+ address = iommu_area_alloc(dom->aperture.bitmap, limit, dom->next_bit,
+ pages, 0 , boundary_size, align_mask);
if (address == -1) {
- address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
- 0, boundary_size, align_mask);
+ address = iommu_area_alloc(dom->aperture.bitmap, limit, 0,
+ pages, 0, boundary_size,
+ align_mask);
dom->need_flush = true;
}
unsigned int pages)
{
address >>= PAGE_SHIFT;
- iommu_area_free(dom->bitmap, address, pages);
+ iommu_area_free(dom->aperture.bitmap, address, pages);
if (address >= dom->next_bit)
dom->need_flush = true;
if (start_page + pages > last_page)
pages = last_page - start_page;
- iommu_area_reserve(dom->bitmap, start_page, pages);
+ iommu_area_reserve(dom->aperture.bitmap, start_page, pages);
}
static void free_pagetable(struct protection_domain *domain)
free_pagetable(&dom->domain);
- kfree(dom->pte_pages);
-
- kfree(dom->bitmap);
+ free_page((unsigned long)dom->aperture.bitmap);
kfree(dom);
}
dma_dom->domain.priv = dma_dom;
if (!dma_dom->domain.pt_root)
goto free_dma_dom;
- dma_dom->aperture_size = (1ULL << order);
- dma_dom->bitmap = kzalloc(dma_dom->aperture_size / (PAGE_SIZE * 8),
- GFP_KERNEL);
- if (!dma_dom->bitmap)
+ dma_dom->aperture_size = APERTURE_RANGE_SIZE;
+ dma_dom->aperture.bitmap = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!dma_dom->aperture.bitmap)
goto free_dma_dom;
/*
* mark the first page as allocated so we never return 0 as
* a valid dma-address. So we can use 0 as error value
*/
- dma_dom->bitmap[0] = 1;
+ dma_dom->aperture.bitmap[0] = 1;
dma_dom->next_bit = 0;
dma_dom->need_flush = false;
/*
* At the last step, build the page tables so we don't need to
* allocate page table pages in the dma_ops mapping/unmapping
- * path.
+ * path for the first 128MB of dma address space.
*/
num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512);
- dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *),
- GFP_KERNEL);
- if (!dma_dom->pte_pages)
- goto free_dma_dom;
l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL);
if (l2_pde == NULL)
dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
for (i = 0; i < num_pte_pages; ++i) {
- dma_dom->pte_pages[i] = (u64 *)get_zeroed_page(GFP_KERNEL);
- if (!dma_dom->pte_pages[i])
+ u64 **pte_page = &dma_dom->aperture.pte_pages[i];
+ *pte_page = (u64 *)get_zeroed_page(GFP_KERNEL);
+ if (!*pte_page)
goto free_dma_dom;
- address = virt_to_phys(dma_dom->pte_pages[i]);
+ address = virt_to_phys(*pte_page);
l2_pde[i] = IOMMU_L1_PDE(address);
}
paddr &= PAGE_MASK;
- pte = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+ pte = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
pte += IOMMU_PTE_L0_INDEX(address);
__pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
WARN_ON(address & ~PAGE_MASK || address >= dom->aperture_size);
- pte = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+ pte = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
pte += IOMMU_PTE_L0_INDEX(address);
WARN_ON(!*pte);