aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2014-11-14 12:18:23 -0500
committerWill Deacon <will.deacon@arm.com>2015-01-19 09:46:44 -0500
commite1d3c0fd701df831169b116cd5c5d6203ac07f70 (patch)
treeeb2537042682bf45a36148d06bb0bfb10ce3da74
parentfdb1d7be7c4d452e9735aeb2b60ae8a2fcf0a514 (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--MAINTAINERS1
-rw-r--r--drivers/iommu/Kconfig9
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/io-pgtable-arm.c781
-rw-r--r--drivers/iommu/io-pgtable.c11
-rw-r--r--drivers/iommu/io-pgtable.h14
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>
1589L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 1589L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
1590S: Maintained 1590S: Maintained
1591F: drivers/iommu/arm-smmu.c 1591F: drivers/iommu/arm-smmu.c
1592F: drivers/iommu/io-pgtable-arm.c
1592 1593
1593ARM64 PORT (AARCH64 ARCHITECTURE) 1594ARM64 PORT (AARCH64 ARCHITECTURE)
1594M: Catalin Marinas <catalin.marinas@arm.com> 1595M: 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"
19config IOMMU_IO_PGTABLE 19config IOMMU_IO_PGTABLE
20 bool 20 bool
21 21
22config 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
22endmenu 31endmenu
23 32
24config OF_IOMMU 33config 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
2obj-$(CONFIG_IOMMU_API) += iommu-traces.o 2obj-$(CONFIG_IOMMU_API) += iommu-traces.o
3obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o 3obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
4obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o 4obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o
5obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
5obj-$(CONFIG_OF_IOMMU) += of_iommu.o 6obj-$(CONFIG_OF_IOMMU) += of_iommu.o
6obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o 7obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
7obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o 8obj-$(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