diff options
| author | Will Deacon <will.deacon@arm.com> | 2014-11-14 12:18:23 -0500 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2015-01-19 09:46:44 -0500 |
| commit | e1d3c0fd701df831169b116cd5c5d6203ac07f70 (patch) | |
| tree | eb2537042682bf45a36148d06bb0bfb10ce3da74 | |
| parent | fdb1d7be7c4d452e9735aeb2b60ae8a2fcf0a514 (diff) | |
iommu: add ARM LPAE page table allocator
A number of IOMMUs found in ARM SoCs can walk architecture-compatible
page tables.
This patch adds a generic allocator for Stage-1 and Stage-2 v7/v8
long-descriptor page tables. 4k, 16k and 64k pages are supported, with
up to 4-levels of walk to cover a 48-bit address space.
Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | drivers/iommu/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/iommu/Makefile | 1 | ||||
| -rw-r--r-- | drivers/iommu/io-pgtable-arm.c | 781 | ||||
| -rw-r--r-- | drivers/iommu/io-pgtable.c | 11 | ||||
| -rw-r--r-- | drivers/iommu/io-pgtable.h | 14 |
6 files changed, 817 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 3589d67437f8..00b27863384e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -1589,6 +1589,7 @@ M: Will Deacon <will.deacon@arm.com> | |||
| 1589 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | 1589 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) |
| 1590 | S: Maintained | 1590 | S: Maintained |
| 1591 | F: drivers/iommu/arm-smmu.c | 1591 | F: drivers/iommu/arm-smmu.c |
| 1592 | F: drivers/iommu/io-pgtable-arm.c | ||
| 1592 | 1593 | ||
| 1593 | ARM64 PORT (AARCH64 ARCHITECTURE) | 1594 | ARM64 PORT (AARCH64 ARCHITECTURE) |
| 1594 | M: Catalin Marinas <catalin.marinas@arm.com> | 1595 | M: Catalin Marinas <catalin.marinas@arm.com> |
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 3faaa41db8ff..306454fbc52d 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig | |||
| @@ -19,6 +19,15 @@ menu "Generic IOMMU Pagetable Support" | |||
| 19 | config IOMMU_IO_PGTABLE | 19 | config IOMMU_IO_PGTABLE |
| 20 | bool | 20 | bool |
| 21 | 21 | ||
| 22 | config IOMMU_IO_PGTABLE_LPAE | ||
| 23 | bool "ARMv7/v8 Long Descriptor Format" | ||
| 24 | select IOMMU_IO_PGTABLE | ||
| 25 | help | ||
| 26 | Enable support for the ARM long descriptor pagetable format. | ||
| 27 | This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page | ||
| 28 | sizes at both stage-1 and stage-2, as well as address spaces | ||
| 29 | up to 48-bits in size. | ||
| 30 | |||
| 22 | endmenu | 31 | endmenu |
| 23 | 32 | ||
| 24 | config OF_IOMMU | 33 | config OF_IOMMU |
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 701c9516e2ae..d6889b487d55 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile | |||
| @@ -2,6 +2,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o | |||
| 2 | obj-$(CONFIG_IOMMU_API) += iommu-traces.o | 2 | obj-$(CONFIG_IOMMU_API) += iommu-traces.o |
| 3 | obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o | 3 | obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o |
| 4 | obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o | 4 | obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o |
| 5 | obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o | ||
| 5 | obj-$(CONFIG_OF_IOMMU) += of_iommu.o | 6 | obj-$(CONFIG_OF_IOMMU) += of_iommu.o |
| 6 | obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o | 7 | obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o |
| 7 | obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o | 8 | obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o |
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c new file mode 100644 index 000000000000..dbe6178a53e9 --- /dev/null +++ b/drivers/iommu/io-pgtable-arm.c | |||
| @@ -0,0 +1,781 @@ | |||
| 1 | /* | ||
| 2 | * CPU-agnostic ARM page table allocator. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | * Copyright (C) 2014 ARM Limited | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define pr_fmt(fmt) "arm-lpae io-pgtable: " fmt | ||
| 22 | |||
| 23 | #include <linux/iommu.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/sizes.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/types.h> | ||
| 28 | |||
| 29 | #include "io-pgtable.h" | ||
| 30 | |||
| 31 | #define ARM_LPAE_MAX_ADDR_BITS 48 | ||
| 32 | #define ARM_LPAE_S2_MAX_CONCAT_PAGES 16 | ||
| 33 | #define ARM_LPAE_MAX_LEVELS 4 | ||
| 34 | |||
| 35 | /* Struct accessors */ | ||
| 36 | #define io_pgtable_to_data(x) \ | ||
| 37 | container_of((x), struct arm_lpae_io_pgtable, iop) | ||
| 38 | |||
| 39 | #define io_pgtable_ops_to_pgtable(x) \ | ||
| 40 | container_of((x), struct io_pgtable, ops) | ||
| 41 | |||
| 42 | #define io_pgtable_ops_to_data(x) \ | ||
| 43 | io_pgtable_to_data(io_pgtable_ops_to_pgtable(x)) | ||
| 44 | |||
| 45 | /* | ||
| 46 | * For consistency with the architecture, we always consider | ||
| 47 | * ARM_LPAE_MAX_LEVELS levels, with the walk starting at level n >=0 | ||
| 48 | */ | ||
| 49 | #define ARM_LPAE_START_LVL(d) (ARM_LPAE_MAX_LEVELS - (d)->levels) | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Calculate the right shift amount to get to the portion describing level l | ||
| 53 | * in a virtual address mapped by the pagetable in d. | ||
| 54 | */ | ||
| 55 | #define ARM_LPAE_LVL_SHIFT(l,d) \ | ||
| 56 | ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1)) \ | ||
| 57 | * (d)->bits_per_level) + (d)->pg_shift) | ||
| 58 | |||
| 59 | #define ARM_LPAE_PAGES_PER_PGD(d) ((d)->pgd_size >> (d)->pg_shift) | ||
| 60 | |||
| 61 | /* | ||
| 62 | * Calculate the index at level l used to map virtual address a using the | ||
| 63 | * pagetable in d. | ||
| 64 | */ | ||
| 65 | #define ARM_LPAE_PGD_IDX(l,d) \ | ||
| 66 | ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0) | ||
| 67 | |||
| 68 | #define ARM_LPAE_LVL_IDX(a,l,d) \ | ||
| 69 | (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) & \ | ||
| 70 | ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1)) | ||
| 71 | |||
| 72 | /* Calculate the block/page mapping size at level l for pagetable in d. */ | ||
| 73 | #define ARM_LPAE_BLOCK_SIZE(l,d) \ | ||
| 74 | (1 << (ilog2(sizeof(arm_lpae_iopte)) + \ | ||
| 75 | ((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level))) | ||
| 76 | |||
| 77 | /* Page table bits */ | ||
| 78 | #define ARM_LPAE_PTE_TYPE_SHIFT 0 | ||
| 79 | #define ARM_LPAE_PTE_TYPE_MASK 0x3 | ||
| 80 | |||
| 81 | #define ARM_LPAE_PTE_TYPE_BLOCK 1 | ||
| 82 | #define ARM_LPAE_PTE_TYPE_TABLE 3 | ||
| 83 | #define ARM_LPAE_PTE_TYPE_PAGE 3 | ||
| 84 | |||
| 85 | #define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53) | ||
| 86 | #define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10) | ||
| 87 | #define ARM_LPAE_PTE_SH_NS (((arm_lpae_iopte)0) << 8) | ||
| 88 | #define ARM_LPAE_PTE_SH_OS (((arm_lpae_iopte)2) << 8) | ||
| 89 | #define ARM_LPAE_PTE_SH_IS (((arm_lpae_iopte)3) << 8) | ||
| 90 | #define ARM_LPAE_PTE_VALID (((arm_lpae_iopte)1) << 0) | ||
| 91 | |||
| 92 | #define ARM_LPAE_PTE_ATTR_LO_MASK (((arm_lpae_iopte)0x3ff) << 2) | ||
| 93 | /* Ignore the contiguous bit for block splitting */ | ||
| 94 | #define ARM_LPAE_PTE_ATTR_HI_MASK (((arm_lpae_iopte)6) << 52) | ||
| 95 | #define ARM_LPAE_PTE_ATTR_MASK (ARM_LPAE_PTE_ATTR_LO_MASK | \ | ||
| 96 | ARM_LPAE_PTE_ATTR_HI_MASK) | ||
| 97 | |||
| 98 | /* Stage-1 PTE */ | ||
| 99 | #define ARM_LPAE_PTE_AP_UNPRIV (((arm_lpae_iopte)1) << 6) | ||
| 100 | #define ARM_LPAE_PTE_AP_RDONLY (((arm_lpae_iopte)2) << 6) | ||
| 101 | #define ARM_LPAE_PTE_ATTRINDX_SHIFT 2 | ||
| 102 | #define ARM_LPAE_PTE_nG (((arm_lpae_iopte)1) << 11) | ||
| 103 | |||
| 104 | /* Stage-2 PTE */ | ||
| 105 | #define ARM_LPAE_PTE_HAP_FAULT (((arm_lpae_iopte)0) << 6) | ||
| 106 | #define ARM_LPAE_PTE_HAP_READ (((arm_lpae_iopte)1) << 6) | ||
| 107 | #define ARM_LPAE_PTE_HAP_WRITE (((arm_lpae_iopte)2) << 6) | ||
| 108 | #define ARM_LPAE_PTE_MEMATTR_OIWB (((arm_lpae_iopte)0xf) << 2) | ||
| 109 | #define ARM_LPAE_PTE_MEMATTR_NC (((arm_lpae_iopte)0x5) << 2) | ||
| 110 | #define ARM_LPAE_PTE_MEMATTR_DEV (((arm_lpae_iopte)0x1) << 2) | ||
| 111 | |||
| 112 | /* Register bits */ | ||
| 113 | #define ARM_32_LPAE_TCR_EAE (1 << 31) | ||
| 114 | #define ARM_64_LPAE_S2_TCR_RES1 (1 << 31) | ||
| 115 | |||
| 116 | #define ARM_LPAE_TCR_TG0_4K (0 << 14) | ||
| 117 | #define ARM_LPAE_TCR_TG0_64K (1 << 14) | ||
| 118 | #define ARM_LPAE_TCR_TG0_16K (2 << 14) | ||
| 119 | |||
| 120 | #define ARM_LPAE_TCR_SH0_SHIFT 12 | ||
| 121 | #define ARM_LPAE_TCR_SH0_MASK 0x3 | ||
| 122 | #define ARM_LPAE_TCR_SH_NS 0 | ||
| 123 | #define ARM_LPAE_TCR_SH_OS 2 | ||
| 124 | #define ARM_LPAE_TCR_SH_IS 3 | ||
| 125 | |||
| 126 | #define ARM_LPAE_TCR_ORGN0_SHIFT 10 | ||
| 127 | #define ARM_LPAE_TCR_IRGN0_SHIFT 8 | ||
| 128 | #define ARM_LPAE_TCR_RGN_MASK 0x3 | ||
| 129 | #define ARM_LPAE_TCR_RGN_NC 0 | ||
| 130 | #define ARM_LPAE_TCR_RGN_WBWA 1 | ||
| 131 | #define ARM_LPAE_TCR_RGN_WT 2 | ||
| 132 | #define ARM_LPAE_TCR_RGN_WB 3 | ||
| 133 | |||
| 134 | #define ARM_LPAE_TCR_SL0_SHIFT 6 | ||
| 135 | #define ARM_LPAE_TCR_SL0_MASK 0x3 | ||
| 136 | |||
| 137 | #define ARM_LPAE_TCR_T0SZ_SHIFT 0 | ||
| 138 | #define ARM_LPAE_TCR_SZ_MASK 0xf | ||
| 139 | |||
| 140 | #define ARM_LPAE_TCR_PS_SHIFT 16 | ||
| 141 | #define ARM_LPAE_TCR_PS_MASK 0x7 | ||
| 142 | |||
| 143 | #define ARM_LPAE_TCR_IPS_SHIFT 32 | ||
| 144 | #define ARM_LPAE_TCR_IPS_MASK 0x7 | ||
| 145 | |||
| 146 | #define ARM_LPAE_TCR_PS_32_BIT 0x0ULL | ||
| 147 | #define ARM_LPAE_TCR_PS_36_BIT 0x1ULL | ||
| 148 | #define ARM_LPAE_TCR_PS_40_BIT 0x2ULL | ||
| 149 | #define ARM_LPAE_TCR_PS_42_BIT 0x3ULL | ||
| 150 | #define ARM_LPAE_TCR_PS_44_BIT 0x4ULL | ||
| 151 | #define ARM_LPAE_TCR_PS_48_BIT 0x5ULL | ||
| 152 | |||
| 153 | #define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) | ||
| 154 | #define ARM_LPAE_MAIR_ATTR_MASK 0xff | ||
| 155 | #define ARM_LPAE_MAIR_ATTR_DEVICE | ||
