diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2014-05-15 06:40:46 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2014-05-26 05:22:24 -0400 |
commit | 4ee3cc9c4a62659bc5f5ed59ea49a0b98b5ac670 (patch) | |
tree | f439de08f59f9f9b70de278c301217ae8b71c115 /drivers/iommu | |
parent | bc28191b165bb07f2817219da1b8c20246d022f6 (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.c | 43 |
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)); |