aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2014-05-15 06:40:46 -0400
committerJoerg Roedel <jroedel@suse.de>2014-05-26 05:22:24 -0400
commit4ee3cc9c4a62659bc5f5ed59ea49a0b98b5ac670 (patch)
treef439de08f59f9f9b70de278c301217ae8b71c115 /drivers/iommu
parentbc28191b165bb07f2817219da1b8c20246d022f6 (diff)
iommu/ipmmu-vmsa: Set the PTE contiguous hint bit when possible
The contiguous hint bit signals to the IOMMU that a range of 16 PTEs refer to physically contiguous memory. It improves performances by dividing the number of TLB lookups by 16, effectively implementing 64kB page sizes. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/ipmmu-vmsa.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index f8f5b194a360..e64c616208e2 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -209,6 +209,9 @@ static LIST_HEAD(ipmmu_devices);
209#define ARM_VMSA_PTE_MEMATTR_NC (((pteval_t)0x5) << 2) 209#define ARM_VMSA_PTE_MEMATTR_NC (((pteval_t)0x5) << 2)
210#define ARM_VMSA_PTE_MEMATTR_DEV (((pteval_t)0x1) << 2) 210#define ARM_VMSA_PTE_MEMATTR_DEV (((pteval_t)0x1) << 2)
211 211
212#define ARM_VMSA_PTE_CONT_ENTRIES 16
213#define ARM_VMSA_PTE_CONT_SIZE (PAGE_SIZE * ARM_VMSA_PTE_CONT_ENTRIES)
214
212#define IPMMU_PTRS_PER_PTE 512 215#define IPMMU_PTRS_PER_PTE 512
213#define IPMMU_PTRS_PER_PMD 512 216#define IPMMU_PTRS_PER_PMD 512
214#define IPMMU_PTRS_PER_PGD 4 217#define IPMMU_PTRS_PER_PGD 4
@@ -569,10 +572,44 @@ static int ipmmu_alloc_init_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd,
569 pteval |= ARM_VMSA_PTE_SH_IS; 572 pteval |= ARM_VMSA_PTE_SH_IS;
570 start = pte; 573 start = pte;
571 574
572 /* Install the page table entries. */ 575 /*
576 * Install the page table entries.
577 *
578 * Set the contiguous hint in the PTEs where possible. The hint
579 * indicates a series of ARM_VMSA_PTE_CONT_ENTRIES PTEs mapping a
580 * physically contiguous region with the following constraints:
581 *
582 * - The region start is aligned to ARM_VMSA_PTE_CONT_SIZE
583 * - Each PTE in the region has the contiguous hint bit set
584 *
585 * We don't support partial unmapping so there's no need to care about
586 * clearing the contiguous hint from neighbour PTEs.
587 */
573 do { 588 do {
574 *pte++ = pfn_pte(pfn++, __pgprot(pteval)); 589 unsigned long chunk_end;
575 addr += PAGE_SIZE; 590
591 /*
592 * If the address is aligned to a contiguous region size and the
593 * mapping size is large enough, process the largest possible
594 * number of PTEs multiple of ARM_VMSA_PTE_CONT_ENTRIES.
595 * Otherwise process the smallest number of PTEs to align the
596 * address to a contiguous region size or to complete the
597 * mapping.
598 */
599 if (IS_ALIGNED(addr, ARM_VMSA_PTE_CONT_SIZE) &&
600 end - addr >= ARM_VMSA_PTE_CONT_SIZE) {
601 chunk_end = round_down(end, ARM_VMSA_PTE_CONT_SIZE);
602 pteval |= ARM_VMSA_PTE_CONT;
603 } else {
604 chunk_end = min(ALIGN(addr, ARM_VMSA_PTE_CONT_SIZE),
605 end);
606 pteval &= ~ARM_VMSA_PTE_CONT;
607 }
608
609 do {
610 *pte++ = pfn_pte(pfn++, __pgprot(pteval));
611 addr += PAGE_SIZE;
612 } while (addr != chunk_end);
576 } while (addr != end); 613 } while (addr != end);
577 614
578 ipmmu_flush_pgtable(mmu, start, sizeof(*pte) * (pte - start)); 615 ipmmu_flush_pgtable(mmu, start, sizeof(*pte) * (pte - start));