aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJoerg Roedel <joro@8bytes.org>2012-12-03 12:40:59 -0500
committerJoerg Roedel <joro@8bytes.org>2012-12-03 12:40:59 -0500
commit18e170d03bcd17f5ccb35b271a95783f63145be7 (patch)
tree5ce68cab628b93119d4c160efc6092e1ba6fa93e /drivers/iommu
parent9489e9dcae718d5fde988e4a684a0f55b5f94d17 (diff)
parent2ab7c84815cffd5fe4946a472fc67fefa8ac3c29 (diff)
Merge branch 'omap-for-v3.8/cleanup-headers-iommu' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into arm/omap
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/omap-iommu-debug.c8
-rw-r--r--drivers/iommu/omap-iommu.c39
-rw-r--r--drivers/iommu/omap-iommu.h228
-rw-r--r--drivers/iommu/omap-iommu2.c370
-rw-r--r--drivers/iommu/omap-iopgtable.h98
-rw-r--r--drivers/iommu/omap-iovmm.c50
7 files changed, 785 insertions, 9 deletions
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 14a4d5fc94fa..f66b816d455c 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_DMAR_TABLE) += dmar.o
7obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o 7obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
8obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o 8obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
9obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o 9obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
10obj-$(CONFIG_OMAP_IOMMU) += omap-iommu2.o
10obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o 11obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
11obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o 12obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
12obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o 13obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index f55fc5dfbadc..d97fbe4fb9b1 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -18,11 +18,11 @@
18#include <linux/uaccess.h> 18#include <linux/uaccess.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/debugfs.h> 20#include <linux/debugfs.h>
21#include <linux/omap-iommu.h>
22#include <linux/platform_data/iommu-omap.h>
21 23
22#include <plat/iommu.h> 24#include "omap-iopgtable.h"
23#include <plat/iovmm.h> 25#include "omap-iommu.h"
24
25#include <plat/iopgtable.h>
26 26
27#define MAXCOLUMN 100 /* for short messages */ 27#define MAXCOLUMN 100 /* for short messages */
28 28
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index d0b1234581be..badc17c2bcb4 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -19,14 +19,17 @@
19#include <linux/clk.h> 19#include <linux/clk.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/iommu.h> 21#include <linux/iommu.h>
22#include <linux/omap-iommu.h>
22#include <linux/mutex.h> 23#include <linux/mutex.h>
23#include <linux/spinlock.h> 24#include <linux/spinlock.h>
25#include <linux/io.h>
24 26
25#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
26 28
27#include <plat/iommu.h> 29#include <linux/platform_data/iommu-omap.h>
28 30
29#include <plat/iopgtable.h> 31#include "omap-iopgtable.h"
32#include "omap-iommu.h"
30 33
31#define for_each_iotlb_cr(obj, n, __i, cr) \ 34#define for_each_iotlb_cr(obj, n, __i, cr) \
32 for (__i = 0; \ 35 for (__i = 0; \
@@ -51,6 +54,21 @@ struct omap_iommu_domain {
51 spinlock_t lock; 54 spinlock_t lock;
52}; 55};
53 56
57#define MMU_LOCK_BASE_SHIFT 10
58#define MMU_LOCK_BASE_MASK (0x1f << MMU_LOCK_BASE_SHIFT)
59#define MMU_LOCK_BASE(x) \
60 ((x & MMU_LOCK_BASE_MASK) >> MMU_LOCK_BASE_SHIFT)
61
62#define MMU_LOCK_VICT_SHIFT 4
63#define MMU_LOCK_VICT_MASK (0x1f << MMU_LOCK_VICT_SHIFT)
64#define MMU_LOCK_VICT(x) \
65 ((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT)
66
67struct iotlb_lock {
68 short base;
69 short vict;
70};
71
54/* accommodate the difference between omap1 and omap2/3 */ 72/* accommodate the difference between omap1 and omap2/3 */
55static const struct iommu_functions *arch_iommu; 73static const struct iommu_functions *arch_iommu;
56 74
@@ -1015,6 +1033,23 @@ static void iopte_cachep_ctor(void *iopte)
1015 clean_dcache_area(iopte, IOPTE_TABLE_SIZE); 1033 clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
1016} 1034}
1017 1035
1036static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
1037 u32 flags)
1038{
1039 memset(e, 0, sizeof(*e));
1040
1041 e->da = da;
1042 e->pa = pa;
1043 e->valid = 1;
1044 /* FIXME: add OMAP1 support */
1045 e->pgsz = flags & MMU_CAM_PGSZ_MASK;
1046 e->endian = flags & MMU_RAM_ENDIAN_MASK;
1047 e->elsz = flags & MMU_RAM_ELSZ_MASK;
1048 e->mixed = flags & MMU_RAM_MIXED_MASK;
1049
1050 return iopgsz_to_bytes(e->pgsz);
1051}
1052
1018static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, 1053static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
1019 phys_addr_t pa, size_t bytes, int prot) 1054 phys_addr_t pa, size_t bytes, int prot)
1020{ 1055{
diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h
new file mode 100644
index 000000000000..2b5f3c04d167
--- /dev/null
+++ b/drivers/iommu/omap-iommu.h
@@ -0,0 +1,228 @@
1/*
2 * omap iommu: main structures
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#if defined(CONFIG_ARCH_OMAP1)
14#error "iommu for this processor not implemented yet"
15#endif
16
17struct iotlb_entry {
18 u32 da;
19 u32 pa;
20 u32 pgsz, prsvd, valid;
21 union {
22 u16 ap;
23 struct {
24 u32 endian, elsz, mixed;
25 };
26 };
27};
28
29struct omap_iommu {
30 const char *name;
31 struct module *owner;
32 struct clk *clk;
33 void __iomem *regbase;
34 struct device *dev;
35 void *isr_priv;
36 struct iommu_domain *domain;
37
38 unsigned int refcount;
39 spinlock_t iommu_lock; /* global for this whole object */
40
41 /*
42 * We don't change iopgd for a situation like pgd for a task,
43 * but share it globally for each iommu.
44 */
45 u32 *iopgd;
46 spinlock_t page_table_lock; /* protect iopgd */
47
48 int nr_tlb_entries;
49
50 struct list_head mmap;
51 struct mutex mmap_lock; /* protect mmap */
52
53 void *ctx; /* iommu context: registres saved area */
54 u32 da_start;
55 u32 da_end;
56};
57
58struct cr_regs {
59 union {
60 struct {
61 u16 cam_l;
62 u16 cam_h;
63 };
64 u32 cam;
65 };
66 union {
67 struct {
68 u16 ram_l;
69 u16 ram_h;
70 };
71 u32 ram;
72 };
73};
74
75/* architecture specific functions */
76struct iommu_functions {
77 unsigned long version;
78
79 int (*enable)(struct omap_iommu *obj);
80 void (*disable)(struct omap_iommu *obj);
81 void (*set_twl)(struct omap_iommu *obj, bool on);
82 u32 (*fault_isr)(struct omap_iommu *obj, u32 *ra);
83
84 void (*tlb_read_cr)(struct omap_iommu *obj, struct cr_regs *cr);
85 void (*tlb_load_cr)(struct omap_iommu *obj, struct cr_regs *cr);
86
87 struct cr_regs *(*alloc_cr)(struct omap_iommu *obj,
88 struct iotlb_entry *e);
89 int (*cr_valid)(struct cr_regs *cr);
90 u32 (*cr_to_virt)(struct cr_regs *cr);
91 void (*cr_to_e)(struct cr_regs *cr, struct iotlb_entry *e);
92 ssize_t (*dump_cr)(struct omap_iommu *obj, struct cr_regs *cr,
93 char *buf);
94
95 u32 (*get_pte_attr)(struct iotlb_entry *e);
96
97 void (*save_ctx)(struct omap_iommu *obj);
98 void (*restore_ctx)(struct omap_iommu *obj);
99 ssize_t (*dump_ctx)(struct omap_iommu *obj, char *buf, ssize_t len);
100};
101
102#ifdef CONFIG_IOMMU_API
103/**
104 * dev_to_omap_iommu() - retrieves an omap iommu object from a user device
105 * @dev: iommu client device
106 */
107static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev)
108{
109 struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
110
111 return arch_data->iommu_dev;
112}
113#endif
114
115/*
116 * MMU Register offsets
117 */
118#define MMU_REVISION 0x00
119#define MMU_SYSCONFIG 0x10
120#define MMU_SYSSTATUS 0x14
121#define MMU_IRQSTATUS 0x18
122#define MMU_IRQENABLE 0x1c
123#define MMU_WALKING_ST 0x40
124#define MMU_CNTL 0x44
125#define MMU_FAULT_AD 0x48
126#define MMU_TTB 0x4c
127#define MMU_LOCK 0x50
128#define MMU_LD_TLB 0x54
129#define MMU_CAM 0x58
130#define MMU_RAM 0x5c
131#define MMU_GFLUSH 0x60
132#define MMU_FLUSH_ENTRY 0x64
133#define MMU_READ_CAM 0x68
134#define MMU_READ_RAM 0x6c
135#define MMU_EMU_FAULT_AD 0x70
136
137#define MMU_REG_SIZE 256
138
139/*
140 * MMU Register bit definitions
141 */
142#define MMU_CAM_VATAG_SHIFT 12
143#define MMU_CAM_VATAG_MASK \
144 ((~0UL >> MMU_CAM_VATAG_SHIFT) << MMU_CAM_VATAG_SHIFT)
145#define MMU_CAM_P (1 << 3)
146#define MMU_CAM_V (1 << 2)
147#define MMU_CAM_PGSZ_MASK 3
148#define MMU_CAM_PGSZ_1M (0 << 0)
149#define MMU_CAM_PGSZ_64K (1 << 0)
150#define MMU_CAM_PGSZ_4K (2 << 0)
151#define MMU_CAM_PGSZ_16M (3 << 0)
152
153#define MMU_RAM_PADDR_SHIFT 12
154#define MMU_RAM_PADDR_MASK \
155 ((~0UL >> MMU_RAM_PADDR_SHIFT) << MMU_RAM_PADDR_SHIFT)
156
157#define MMU_RAM_ENDIAN_MASK (1 << MMU_RAM_ENDIAN_SHIFT)
158#define MMU_RAM_ENDIAN_BIG (1 << MMU_RAM_ENDIAN_SHIFT)
159
160#define MMU_RAM_ELSZ_MASK (3 << MMU_RAM_ELSZ_SHIFT)
161#define MMU_RAM_ELSZ_8 (0 << MMU_RAM_ELSZ_SHIFT)
162#define MMU_RAM_ELSZ_16 (1 << MMU_RAM_ELSZ_SHIFT)
163#define MMU_RAM_ELSZ_32 (2 << MMU_RAM_ELSZ_SHIFT)
164#define MMU_RAM_ELSZ_NONE (3 << MMU_RAM_ELSZ_SHIFT)
165#define MMU_RAM_MIXED_SHIFT 6
166#define MMU_RAM_MIXED_MASK (1 << MMU_RAM_MIXED_SHIFT)
167#define MMU_RAM_MIXED MMU_RAM_MIXED_MASK
168
169/*
170 * utilities for super page(16MB, 1MB, 64KB and 4KB)
171 */
172
173#define iopgsz_max(bytes) \
174 (((bytes) >= SZ_16M) ? SZ_16M : \
175 ((bytes) >= SZ_1M) ? SZ_1M : \
176 ((bytes) >= SZ_64K) ? SZ_64K : \
177 ((bytes) >= SZ_4K) ? SZ_4K : 0)
178
179#define bytes_to_iopgsz(bytes) \
180 (((bytes) == SZ_16M) ? MMU_CAM_PGSZ_16M : \
181 ((bytes) == SZ_1M) ? MMU_CAM_PGSZ_1M : \
182 ((bytes) == SZ_64K) ? MMU_CAM_PGSZ_64K : \
183 ((bytes) == SZ_4K) ? MMU_CAM_PGSZ_4K : -1)
184
185#define iopgsz_to_bytes(iopgsz) \
186 (((iopgsz) == MMU_CAM_PGSZ_16M) ? SZ_16M : \
187 ((iopgsz) == MMU_CAM_PGSZ_1M) ? SZ_1M : \
188 ((iopgsz) == MMU_CAM_PGSZ_64K) ? SZ_64K : \
189 ((iopgsz) == MMU_CAM_PGSZ_4K) ? SZ_4K : 0)
190
191#define iopgsz_ok(bytes) (bytes_to_iopgsz(bytes) >= 0)
192
193/*
194 * global functions
195 */
196extern u32 omap_iommu_arch_version(void);
197
198extern void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
199
200extern int
201omap_iopgtable_store_entry(struct omap_iommu *obj, struct iotlb_entry *e);
202
203extern void omap_iommu_save_ctx(struct device *dev);
204extern void omap_iommu_restore_ctx(struct device *dev);
205
206extern int omap_foreach_iommu_device(void *data,
207 int (*fn)(struct device *, void *));
208
209extern int omap_install_iommu_arch(const struct iommu_functions *ops);
210extern void omap_uninstall_iommu_arch(const struct iommu_functions *ops);
211
212extern ssize_t
213omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len);
214extern size_t
215omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t len);
216
217/*
218 * register accessors
219 */
220static inline u32 iommu_read_reg(struct omap_iommu *obj, size_t offs)
221{
222 return __raw_readl(obj->regbase + offs);
223}
224
225static inline void iommu_write_reg(struct omap_iommu *obj, u32 val, size_t offs)
226{
227 __raw_writel(val, obj->regbase + offs);
228}
diff --git a/drivers/iommu/omap-iommu2.c b/drivers/iommu/omap-iommu2.c
new file mode 100644
index 000000000000..c02020292377
--- /dev/null
+++ b/drivers/iommu/omap-iommu2.c
@@ -0,0 +1,370 @@
1/*
2 * omap iommu: omap2/3 architecture specific functions
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
7 * Paul Mundt and Toshihiro Kobayashi
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/err.h>
15#include <linux/device.h>
16#include <linux/io.h>
17#include <linux/jiffies.h>
18#include <linux/module.h>
19#include <linux/omap-iommu.h>
20#include <linux/slab.h>
21#include <linux/stringify.h>
22#include <linux/platform_data/iommu-omap.h>
23
24#include "omap-iommu.h"
25
26/*
27 * omap2 architecture specific register bit definitions
28 */
29#define IOMMU_ARCH_VERSION 0x00000011
30
31/* SYSCONF */
32#define MMU_SYS_IDLE_SHIFT 3
33#define MMU_SYS_IDLE_FORCE (0 << MMU_SYS_IDLE_SHIFT)
34#define MMU_SYS_IDLE_NONE (1 << MMU_SYS_IDLE_SHIFT)
35#define MMU_SYS_IDLE_SMART (2 << MMU_SYS_IDLE_SHIFT)
36#define MMU_SYS_IDLE_MASK (3 << MMU_SYS_IDLE_SHIFT)
37
38#define MMU_SYS_SOFTRESET (1 << 1)
39#define MMU_SYS_AUTOIDLE 1
40
41/* SYSSTATUS */
42#define MMU_SYS_RESETDONE 1
43
44/* IRQSTATUS & IRQENABLE */
45#define MMU_IRQ_MULTIHITFAULT (1 << 4)
46#define MMU_IRQ_TABLEWALKFAULT (1 << 3)
47#define MMU_IRQ_EMUMISS (1 << 2)
48#define MMU_IRQ_TRANSLATIONFAULT (1 << 1)
49#define MMU_IRQ_TLBMISS (1 << 0)
50
51#define __MMU_IRQ_FAULT \
52 (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_EMUMISS | MMU_IRQ_TRANSLATIONFAULT)
53#define MMU_IRQ_MASK \
54 (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_TLBMISS)
55#define MMU_IRQ_TWL_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT)
56#define MMU_IRQ_TLB_MISS_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TLBMISS)
57
58/* MMU_CNTL */
59#define MMU_CNTL_SHIFT 1
60#define MMU_CNTL_MASK (7 << MMU_CNTL_SHIFT)
61#define MMU_CNTL_EML_TLB (1 << 3)
62#define MMU_CNTL_TWL_EN (1 << 2)
63#define MMU_CNTL_MMU_EN (1 << 1)
64
65#define get_cam_va_mask(pgsz) \
66 (((pgsz) == MMU_CAM_PGSZ_16M) ? 0xff000000 : \
67 ((pgsz) == MMU_CAM_PGSZ_1M) ? 0xfff00000 : \
68 ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \
69 ((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0)
70
71/* IOMMU errors */
72#define OMAP_IOMMU_ERR_TLB_MISS (1 << 0)
73#define OMAP_IOMMU_ERR_TRANS_FAULT (1 << 1)
74#define OMAP_IOMMU_ERR_EMU_MISS (1 << 2)
75#define OMAP_IOMMU_ERR_TBLWALK_FAULT (1 << 3)
76#define OMAP_IOMMU_ERR_MULTIHIT_FAULT (1 << 4)
77
78static void __iommu_set_twl(struct omap_iommu *obj, bool on)
79{
80 u32 l = iommu_read_reg(obj, MMU_CNTL);
81
82 if (on)
83 iommu_write_reg(obj, MMU_IRQ_TWL_MASK, MMU_IRQENABLE);
84 else
85 iommu_write_reg(obj, MMU_IRQ_TLB_MISS_MASK, MMU_IRQENABLE);
86
87 l &= ~MMU_CNTL_MASK;
88 if (on)
89 l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
90 else
91 l |= (MMU_CNTL_MMU_EN);
92
93 iommu_write_reg(obj, l, MMU_CNTL);
94}
95
96
97static int omap2_iommu_enable(struct omap_iommu *obj)
98{
99 u32 l, pa;
100 unsigned long timeout;
101
102 if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K))
103 return -EINVAL;
104
105 pa = virt_to_phys(obj->iopgd);
106 if (!IS_ALIGNED(pa, SZ_16K))
107 return -EINVAL;
108
109 iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG);
110
111 timeout = jiffies + msecs_to_jiffies(20);
112 do {
113 l = iommu_read_reg(obj, MMU_SYSSTATUS);
114 if (l & MMU_SYS_RESETDONE)
115 break;
116 } while (!time_after(jiffies, timeout));
117
118 if (!(l & MMU_SYS_RESETDONE)) {
119 dev_err(obj->dev, "can't take mmu out of reset\n");
120 return -ENODEV;
121 }
122
123 l = iommu_read_reg(obj, MMU_REVISION);
124 dev_info(obj->dev, "%s: version %d.%d\n", obj->name,
125 (l >> 4) & 0xf, l & 0xf);
126
127 l = iommu_read_reg(obj, MMU_SYSCONFIG);
128 l &= ~MMU_SYS_IDLE_MASK;
129 l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
130 iommu_write_reg(obj, l, MMU_SYSCONFIG);
131
132 iommu_write_reg(obj, pa, MMU_TTB);
133
134 __iommu_set_twl(obj, true);
135
136 return 0;
137}
138
139static void omap2_iommu_disable(struct omap_iommu *obj)
140{
141 u32 l = iommu_read_reg(obj, MMU_CNTL);
142
143 l &= ~MMU_CNTL_MASK;
144 iommu_write_reg(obj, l, MMU_CNTL);
145 iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG);
146
147 dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
148}
149
150static void omap2_iommu_set_twl(struct omap_iommu *obj, bool on)
151{
152 __iommu_set_twl(obj, false);
153}
154
155static u32 omap2_iommu_fault_isr(struct omap_iommu *obj, u32 *ra)
156{
157 u32 stat, da;
158 u32 errs = 0;
159
160 stat = iommu_read_reg(obj, MMU_IRQSTATUS);
161 stat &= MMU_IRQ_MASK;
162 if (!stat) {
163 *ra = 0;
164 return 0;
165 }
166
167 da = iommu_read_reg(obj, MMU_FAULT_AD);
168 *ra = da;
169
170 if (stat & MMU_IRQ_TLBMISS)
171 errs |= OMAP_IOMMU_ERR_TLB_MISS;
172 if (stat & MMU_IRQ_TRANSLATIONFAULT)
173 errs |= OMAP_IOMMU_ERR_TRANS_FAULT;
174 if (stat & MMU_IRQ_EMUMISS)
175 errs |= OMAP_IOMMU_ERR_EMU_MISS;
176 if (stat & MMU_IRQ_TABLEWALKFAULT)
177 errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT;
178 if (stat & MMU_IRQ_MULTIHITFAULT)
179 errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT;
180 iommu_write_reg(obj, stat, MMU_IRQSTATUS);
181
182 return errs;
183}
184
185static void omap2_tlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
186{
187 cr->cam = iommu_read_reg(obj, MMU_READ_CAM);
188 cr->ram = iommu_read_reg(obj, MMU_READ_RAM);
189}
190
191static void omap2_tlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
192{
193 iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM);
194 iommu_write_reg(obj, cr->ram, MMU_RAM);
195}
196
197static u32 omap2_cr_to_virt(struct cr_regs *cr)
198{
199 u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK;
200 u32 mask = get_cam_va_mask(cr->cam & page_size);
201
202 return cr->cam & mask;
203}
204
205static struct cr_regs *omap2_alloc_cr(struct omap_iommu *obj,
206 struct iotlb_entry *e)
207{
208 struct cr_regs *cr;
209
210 if (e->da & ~(get_cam_va_mask(e->pgsz))) {
211 dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__,
212 e->da);
213 return ERR_PTR(-EINVAL);
214 }
215
216 cr = kmalloc(sizeof(*cr), GFP_KERNEL);
217 if (!cr)
218 return ERR_PTR(-ENOMEM);
219
220 cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz | e->valid;
221 cr->ram = e->pa | e->endian | e->elsz | e->mixed;
222
223 return cr;
224}
225
226static inline int omap2_cr_valid(struct cr_regs *cr)
227{
228 return cr->cam & MMU_CAM_V;
229}
230
231static u32 omap2_get_pte_attr(struct iotlb_entry *e)
232{
233 u32 attr;
234
235 attr = e->mixed << 5;
236 attr |= e->endian;
237 attr |= e->elsz >> 3;
238 attr <<= (((e->pgsz == MMU_CAM_PGSZ_4K) ||
239 (e->pgsz == MMU_CAM_PGSZ_64K)) ? 0 : 6);
240 return attr;
241}
242
243static ssize_t
244omap2_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, char *buf)
245{
246 char *p = buf;
247
248 /* FIXME: Need more detail analysis of cam/ram */
249 p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram,
250 (cr->cam & MMU_CAM_P) ? 1 : 0);
251
252 return p - buf;
253}
254
255#define pr_reg(name) \
256 do { \
257 ssize_t bytes; \
258 const char *str = "%20s: %08x\n"; \
259 const int maxcol = 32; \
260 bytes = snprintf(p, maxcol, str, __stringify(name), \
261 iommu_read_reg(obj, MMU_##name)); \
262 p += bytes; \
263 len -= bytes; \
264 if (len < maxcol) \
265 goto out; \
266 } while (0)
267
268static ssize_t
269omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len)
270{
271 char *p = buf;
272
273 pr_reg(REVISION);
274 pr_reg(SYSCONFIG);
275 pr_reg(SYSSTATUS);
276 pr_reg(IRQSTATUS);
277 pr_reg(IRQENABLE);
278 pr_reg(WALKING_ST);
279 pr_reg(CNTL);
280 pr_reg(FAULT_AD);
281 pr_reg(TTB);
282 pr_reg(LOCK);
283 pr_reg(LD_TLB);
284 pr_reg(CAM);
285 pr_reg(RAM);
286 pr_reg(GFLUSH);
287 pr_reg(FLUSH_ENTRY);
288 pr_reg(READ_CAM);
289 pr_reg(READ_RAM);
290 pr_reg(EMU_FAULT_AD);
291out:
292 return p - buf;
293}
294
295static void omap2_iommu_save_ctx(struct omap_iommu *obj)
296{
297 int i;
298 u32 *p = obj->ctx;
299
300 for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
301 p[i] = iommu_read_reg(obj, i * sizeof(u32));
302 dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
303 }
304
305 BUG_ON(p[0] != IOMMU_ARCH_VERSION);
306}
307
308static void omap2_iommu_restore_ctx(struct omap_iommu *obj)
309{
310 int i;
311 u32 *p = obj->ctx;
312
313 for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
314 iommu_write_reg(obj, p[i], i * sizeof(u32));
315 dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
316 }
317
318 BUG_ON(p[0] != IOMMU_ARCH_VERSION);
319}
320
321static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
322{
323 e->da = cr->cam & MMU_CAM_VATAG_MASK;
324 e->pa = cr->ram & MMU_RAM_PADDR_MASK;
325 e->valid = cr->cam & MMU_CAM_V;
326 e->pgsz = cr->cam & MMU_CAM_PGSZ_MASK;
327 e->endian = cr->ram & MMU_RAM_ENDIAN_MASK;
328 e->elsz = cr->ram & MMU_RAM_ELSZ_MASK;
329 e->mixed = cr->ram & MMU_RAM_MIXED;
330}
331
332static const struct iommu_functions omap2_iommu_ops = {
333 .version = IOMMU_ARCH_VERSION,
334
335 .enable = omap2_iommu_enable,
336 .disable = omap2_iommu_disable,
337 .set_twl = omap2_iommu_set_twl,
338 .fault_isr = omap2_iommu_fault_isr,
339
340 .tlb_read_cr = omap2_tlb_read_cr,
341 .tlb_load_cr = omap2_tlb_load_cr,
342
343 .cr_to_e = omap2_cr_to_e,
344 .cr_to_virt = omap2_cr_to_virt,
345 .alloc_cr = omap2_alloc_cr,
346 .cr_valid = omap2_cr_valid,
347 .dump_cr = omap2_dump_cr,
348
349 .get_pte_attr = omap2_get_pte_attr,
350
351 .save_ctx = omap2_iommu_save_ctx,
352 .restore_ctx = omap2_iommu_restore_ctx,
353 .dump_ctx = omap2_iommu_dump_ctx,
354};
355
356static int __init omap2_iommu_init(void)
357{
358 return omap_install_iommu_arch(&omap2_iommu_ops);
359}
360module_init(omap2_iommu_init);
361
362static void __exit omap2_iommu_exit(void)
363{
364 omap_uninstall_iommu_arch(&omap2_iommu_ops);
365}
366module_exit(omap2_iommu_exit);
367
368MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
369MODULE_DESCRIPTION("omap iommu: omap2/3 architecture specific functions");
370MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h
new file mode 100644
index 000000000000..cd4ae9e5b0c6
--- /dev/null
+++ b/drivers/iommu/omap-iopgtable.h
@@ -0,0 +1,98 @@
1/*
2 * omap iommu: pagetable definitions
3 *
4 * Copyright (C) 2008-2010 Nokia Corporation
5 *
6 * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13/*
14 * "L2 table" address mask and size definitions.
15 */
16#define IOPGD_SHIFT 20
17#define IOPGD_SIZE (1UL << IOPGD_SHIFT)
18#define IOPGD_MASK (~(IOPGD_SIZE - 1))
19
20/*
21 * "section" address mask and size definitions.
22 */
23#define IOSECTION_SHIFT 20
24#define IOSECTION_SIZE (1UL << IOSECTION_SHIFT)
25#define IOSECTION_MASK (~(IOSECTION_SIZE - 1))
26
27/*
28 * "supersection" address mask and size definitions.
29 */
30#define IOSUPER_SHIFT 24
31#define IOSUPER_SIZE (1UL << IOSUPER_SHIFT)
32#define IOSUPER_MASK (~(IOSUPER_SIZE - 1))
33
34#define PTRS_PER_IOPGD (1UL << (32 - IOPGD_SHIFT))
35#define IOPGD_TABLE_SIZE (PTRS_PER_IOPGD * sizeof(u32))
36
37/*
38 * "small page" address mask and size definitions.
39 */
40#define IOPTE_SHIFT 12
41#define IOPTE_SIZE (1UL << IOPTE_SHIFT)
42#define IOPTE_MASK (~(IOPTE_SIZE - 1))
43
44/*
45 * "large page" address mask and size definitions.
46 */
47#define IOLARGE_SHIFT 16
48#define IOLARGE_SIZE (1UL << IOLARGE_SHIFT)
49#define IOLARGE_MASK (~(IOLARGE_SIZE - 1))
50
51#define PTRS_PER_IOPTE (1UL << (IOPGD_SHIFT - IOPTE_SHIFT))
52#define IOPTE_TABLE_SIZE (PTRS_PER_IOPTE * sizeof(u32))
53
54#define IOPAGE_MASK IOPTE_MASK
55
56/**
57 * omap_iommu_translate() - va to pa translation
58 * @d: omap iommu descriptor
59 * @va: virtual address
60 * @mask: omap iommu descriptor mask
61 *
62 * va to pa translation
63 */
64static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
65{
66 return (d & mask) | (va & (~mask));
67}
68
69/*
70 * some descriptor attributes.
71 */
72#define IOPGD_TABLE (1 << 0)
73#define IOPGD_SECTION (2 << 0)
74#define IOPGD_SUPER (1 << 18 | 2 << 0)
75
76#define iopgd_is_table(x) (((x) & 3) == IOPGD_TABLE)
77#define iopgd_is_section(x) (((x) & (1 << 18 | 3)) == IOPGD_SECTION)
78#define iopgd_is_super(x) (((x) & (1 << 18 | 3)) == IOPGD_SUPER)
79
80#define IOPTE_SMALL (2 << 0)
81#define IOPTE_LARGE (1 << 0)
82
83#define iopte_is_small(x) (((x) & 2) == IOPTE_SMALL)
84#define iopte_is_large(x) (((x) & 3) == IOPTE_LARGE)
85
86/* to find an entry in a page-table-directory */
87#define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
88#define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da))
89
90#define iopgd_page_paddr(iopgd) (*iopgd & ~((1 << 10) - 1))
91#define iopgd_page_vaddr(iopgd) ((u32 *)phys_to_virt(iopgd_page_paddr(iopgd)))
92
93/* to find an entry in the second-level page table. */
94#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
95#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da))
96
97#define to_iommu(dev) \
98 (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index 2e10c3e0a7ae..46d875690739 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -17,14 +17,58 @@
17#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/scatterlist.h> 18#include <linux/scatterlist.h>
19#include <linux/iommu.h> 19#include <linux/iommu.h>
20#include <linux/omap-iommu.h>
21#include <linux/platform_data/iommu-omap.h>
20 22
21#include <asm/cacheflush.h> 23#include <asm/cacheflush.h>
22#include <asm/mach/map.h> 24#include <asm/mach/map.h>
23 25
24#include <plat/iommu.h> 26#include "omap-iopgtable.h"
25#include <plat/iovmm.h> 27#include "omap-iommu.h"
26 28
27#include <plat/iopgtable.h> 29/*
30 * IOVMF_FLAGS: attribute for iommu virtual memory area(iovma)
31 *
32 * lower 16 bit is used for h/w and upper 16 bit is for s/w.
33 */
34#define IOVMF_SW_SHIFT 16
35
36/*
37 * iovma: h/w flags derived from cam and ram attribute
38 */
39#define IOVMF_CAM_MASK (~((1 << 10) - 1))
40#define IOVMF_RAM_MASK (~IOVMF_CAM_MASK)
41
42#define IOVMF_PGSZ_MASK (3 << 0)
43#define IOVMF_PGSZ_1M MMU_CAM_PGSZ_1M
44#define IOVMF_PGSZ_64K MMU_CAM_PGSZ_64K
45#define IOVMF_PGSZ_4K MMU_CAM_PGSZ_4K
46#define IOVMF_PGSZ_16M MMU_CAM_PGSZ_16M
47
48#define IOVMF_ENDIAN_MASK (1 << 9)
49#define IOVMF_ENDIAN_BIG MMU_RAM_ENDIAN_BIG
50
51#define IOVMF_ELSZ_MASK (3 << 7)
52#define IOVMF_ELSZ_16 MMU_RAM_ELSZ_16
53#define IOVMF_ELSZ_32 MMU_RAM_ELSZ_32
54#define IOVMF_ELSZ_NONE MMU_RAM_ELSZ_NONE
55
56#define IOVMF_MIXED_MASK (1 << 6)
57#define IOVMF_MIXED MMU_RAM_MIXED
58
59/*
60 * iovma: s/w flags, used for mapping and umapping internally.
61 */
62#define IOVMF_MMIO (1 << IOVMF_SW_SHIFT)
63#define IOVMF_ALLOC (2 << IOVMF_SW_SHIFT)
64#define IOVMF_ALLOC_MASK (3 << IOVMF_SW_SHIFT)
65
66/* "superpages" is supported just with physically linear pages */
67#define IOVMF_DISCONT (1 << (2 + IOVMF_SW_SHIFT))
68#define IOVMF_LINEAR (2 << (2 + IOVMF_SW_SHIFT))
69#define IOVMF_LINEAR_MASK (3 << (2 + IOVMF_SW_SHIFT))
70
71#define IOVMF_DA_FIXED (1 << (4 + IOVMF_SW_SHIFT))
28 72
29static struct kmem_cache *iovm_area_cachep; 73static struct kmem_cache *iovm_area_cachep;
30 74