aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/omap-iommu.c
diff options
context:
space:
mode:
authorSuman Anna <s-anna@ti.com>2014-10-22 18:22:27 -0400
committerJoerg Roedel <jroedel@suse.de>2014-10-23 08:32:25 -0400
commitbd4396f09a4a9e77423e92ec9448217ab46f6edf (patch)
treeb437a750480b8a463b7e136a21d3a0dac7d555b2 /drivers/iommu/omap-iommu.c
parent124262a2eecc4c3e6e96e083e50ce4909b2d69d9 (diff)
iommu/omap: Consolidate OMAP IOMMU modules
The OMAP IOMMU driver was originally designed as modules, and split into a core module and a thin arch-specific module through the OMAP arch-specific struct iommu_functions, to scale for both OMAP1 and OMAP2+ IOMMU variants. The driver can only be built for OMAP2+ platforms currently, and also can only be built-in after the adaptation to generic IOMMU API. The OMAP1 variant was never added and will most probably be never added (the code for the only potential user, its parent, DSP processor has already been cleaned up). So, consolidate the OMAP2 specific omap-iommu2 module into the core OMAP IOMMU driver - this eliminates the arch-specific ops structure and simplifies the driver into a single module that only implements the generic IOMMU API's iommu_ops. The following are the main changes: - omap-iommu2 module is completely eliminated, with the common definitions moved to the internal omap-iommu.h, and the ops implementations moved into omap-iommu.c - OMAP arch-specific struct iommu_functions is also eliminated, with the ops implementations directly absorbed into the calling functions - iotlb_alloc_cr() is no longer inlined and defined only when PREFETCH_IOTLB is defined - iotlb_dump_cr() is similarly defined only when CONFIG_OMAP_IOMMU_DEBUG is defined - Elimination of the OMAP IOMMU exported functions to register the arch ops, omap_install_iommu_arch() & omap_uninstall_iommu_arch() - Any stale comments about OMAP1 are also cleaned up Signed-off-by: Suman Anna <s-anna@ti.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu/omap-iommu.c')
-rw-r--r--drivers/iommu/omap-iommu.c263
1 files changed, 188 insertions, 75 deletions
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index f9efa6ba99f5..91262fa2a351 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -76,53 +76,23 @@ struct iotlb_lock {
76 short vict; 76 short vict;
77}; 77};
78 78
79/* accommodate the difference between omap1 and omap2/3 */
80static const struct iommu_functions *arch_iommu;
81
82static struct platform_driver omap_iommu_driver; 79static struct platform_driver omap_iommu_driver;
83static struct kmem_cache *iopte_cachep; 80static struct kmem_cache *iopte_cachep;
84 81
85/** 82/**
86 * omap_install_iommu_arch - Install archtecure specific iommu functions
87 * @ops: a pointer to architecture specific iommu functions
88 *
89 * There are several kind of iommu algorithm(tlb, pagetable) among
90 * omap series. This interface installs such an iommu algorighm.
91 **/
92int omap_install_iommu_arch(const struct iommu_functions *ops)
93{
94 if (arch_iommu)
95 return -EBUSY;
96
97 arch_iommu = ops;
98 return 0;
99}
100EXPORT_SYMBOL_GPL(omap_install_iommu_arch);
101
102/**
103 * omap_uninstall_iommu_arch - Uninstall archtecure specific iommu functions
104 * @ops: a pointer to architecture specific iommu functions
105 *
106 * This interface uninstalls the iommu algorighm installed previously.
107 **/
108void omap_uninstall_iommu_arch(const struct iommu_functions *ops)
109{
110 if (arch_iommu != ops)
111 pr_err("%s: not your arch\n", __func__);
112
113 arch_iommu = NULL;
114}
115EXPORT_SYMBOL_GPL(omap_uninstall_iommu_arch);
116
117/**
118 * omap_iommu_save_ctx - Save registers for pm off-mode support 83 * omap_iommu_save_ctx - Save registers for pm off-mode support
119 * @dev: client device 84 * @dev: client device
120 **/ 85 **/
121void omap_iommu_save_ctx(struct device *dev) 86void omap_iommu_save_ctx(struct device *dev)
122{ 87{
123 struct omap_iommu *obj = dev_to_omap_iommu(dev); 88 struct omap_iommu *obj = dev_to_omap_iommu(dev);
89 u32 *p = obj->ctx;
90 int i;
124 91
125 arch_iommu->save_ctx(obj); 92 for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
93 p[i] = iommu_read_reg(obj, i * sizeof(u32));
94 dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
95 }
126} 96}
127EXPORT_SYMBOL_GPL(omap_iommu_save_ctx); 97EXPORT_SYMBOL_GPL(omap_iommu_save_ctx);
128 98
@@ -133,20 +103,75 @@ EXPORT_SYMBOL_GPL(omap_iommu_save_ctx);
133void omap_iommu_restore_ctx(struct device *dev) 103void omap_iommu_restore_ctx(struct device *dev)
134{ 104{
135 struct omap_iommu *obj = dev_to_omap_iommu(dev); 105 struct omap_iommu *obj = dev_to_omap_iommu(dev);
106 u32 *p = obj->ctx;
107 int i;
136 108
137 arch_iommu->restore_ctx(obj); 109 for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
110 iommu_write_reg(obj, p[i], i * sizeof(u32));
111 dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
112 }
138} 113}
139EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx); 114EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx);
140 115
116static void __iommu_set_twl(struct omap_iommu *obj, bool on)
117{
118 u32 l = iommu_read_reg(obj, MMU_CNTL);
119
120 if (on)
121 iommu_write_reg(obj, MMU_IRQ_TWL_MASK, MMU_IRQENABLE);
122 else
123 iommu_write_reg(obj, MMU_IRQ_TLB_MISS_MASK, MMU_IRQENABLE);
124
125 l &= ~MMU_CNTL_MASK;
126 if (on)
127 l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
128 else
129 l |= (MMU_CNTL_MMU_EN);
130
131 iommu_write_reg(obj, l, MMU_CNTL);
132}
133
134static int omap2_iommu_enable(struct omap_iommu *obj)
135{
136 u32 l, pa;
137
138 if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K))
139 return -EINVAL;
140
141 pa = virt_to_phys(obj->iopgd);
142 if (!IS_ALIGNED(pa, SZ_16K))
143 return -EINVAL;
144
145 l = iommu_read_reg(obj, MMU_REVISION);
146 dev_info(obj->dev, "%s: version %d.%d\n", obj->name,
147 (l >> 4) & 0xf, l & 0xf);
148
149 iommu_write_reg(obj, pa, MMU_TTB);
150
151 if (obj->has_bus_err_back)
152 iommu_write_reg(obj, MMU_GP_REG_BUS_ERR_BACK_EN, MMU_GP_REG);
153
154 __iommu_set_twl(obj, true);
155
156 return 0;
157}
158
159static void omap2_iommu_disable(struct omap_iommu *obj)
160{
161 u32 l = iommu_read_reg(obj, MMU_CNTL);
162
163 l &= ~MMU_CNTL_MASK;
164 iommu_write_reg(obj, l, MMU_CNTL);
165
166 dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
167}
168
141static int iommu_enable(struct omap_iommu *obj) 169static int iommu_enable(struct omap_iommu *obj)
142{ 170{
143 int err; 171 int err;
144 struct platform_device *pdev = to_platform_device(obj->dev); 172 struct platform_device *pdev = to_platform_device(obj->dev);
145 struct iommu_platform_data *pdata = pdev->dev.platform_data; 173 struct iommu_platform_data *pdata = pdev->dev.platform_data;
146 174
147 if (!arch_iommu)
148 return -ENODEV;
149
150 if (pdata && pdata->deassert_reset) { 175 if (pdata && pdata->deassert_reset) {
151 err = pdata->deassert_reset(pdev, pdata->reset_name); 176 err = pdata->deassert_reset(pdev, pdata->reset_name);
152 if (err) { 177 if (err) {
@@ -157,7 +182,7 @@ static int iommu_enable(struct omap_iommu *obj)
157 182
158 pm_runtime_get_sync(obj->dev); 183 pm_runtime_get_sync(obj->dev);
159 184
160 err = arch_iommu->enable(obj); 185 err = omap2_iommu_enable(obj);
161 186
162 return err; 187 return err;
163} 188}
@@ -167,7 +192,7 @@ static void iommu_disable(struct omap_iommu *obj)
167 struct platform_device *pdev = to_platform_device(obj->dev); 192 struct platform_device *pdev = to_platform_device(obj->dev);
168 struct iommu_platform_data *pdata = pdev->dev.platform_data; 193 struct iommu_platform_data *pdata = pdev->dev.platform_data;
169 194
170 arch_iommu->disable(obj); 195 omap2_iommu_disable(obj);
171 196
172 pm_runtime_put_sync(obj->dev); 197 pm_runtime_put_sync(obj->dev);
173 198
@@ -182,7 +207,13 @@ void omap_iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
182{ 207{
183 BUG_ON(!cr || !e); 208 BUG_ON(!cr || !e);
184 209
185 arch_iommu->cr_to_e(cr, e); 210 e->da = cr->cam & MMU_CAM_VATAG_MASK;
211 e->pa = cr->ram & MMU_RAM_PADDR_MASK;
212 e->valid = cr->cam & MMU_CAM_V;
213 e->pgsz = cr->cam & MMU_CAM_PGSZ_MASK;
214 e->endian = cr->ram & MMU_RAM_ENDIAN_MASK;
215 e->elsz = cr->ram & MMU_RAM_ELSZ_MASK;
216 e->mixed = cr->ram & MMU_RAM_MIXED;
186} 217}
187EXPORT_SYMBOL_GPL(omap_iotlb_cr_to_e); 218EXPORT_SYMBOL_GPL(omap_iotlb_cr_to_e);
188 219
@@ -191,31 +222,46 @@ static inline int iotlb_cr_valid(struct cr_regs *cr)
191 if (!cr) 222 if (!cr)
192 return -EINVAL; 223 return -EINVAL;
193 224
194 return arch_iommu->cr_valid(cr); 225 return cr->cam & MMU_CAM_V;
195}
196
197static inline struct cr_regs *iotlb_alloc_cr(struct omap_iommu *obj,
198 struct iotlb_entry *e)
199{
200 if (!e)
201 return NULL;
202
203 return arch_iommu->alloc_cr(obj, e);
204} 226}
205 227
206static u32 iotlb_cr_to_virt(struct cr_regs *cr) 228static u32 iotlb_cr_to_virt(struct cr_regs *cr)
207{ 229{
208 return arch_iommu->cr_to_virt(cr); 230 u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK;
231 u32 mask = get_cam_va_mask(cr->cam & page_size);
232
233 return cr->cam & mask;
209} 234}
210 235
211static u32 get_iopte_attr(struct iotlb_entry *e) 236static u32 get_iopte_attr(struct iotlb_entry *e)
212{ 237{
213 return arch_iommu->get_pte_attr(e); 238 u32 attr;
239
240 attr = e->mixed << 5;
241 attr |= e->endian;
242 attr |= e->elsz >> 3;
243 attr <<= (((e->pgsz == MMU_CAM_PGSZ_4K) ||
244 (e->pgsz == MMU_CAM_PGSZ_64K)) ? 0 : 6);
245 return attr;
214} 246}
215 247
216static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da) 248static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da)
217{ 249{
218 return arch_iommu->fault_isr(obj, da); 250 u32 status, fault_addr;
251
252 status = iommu_read_reg(obj, MMU_IRQSTATUS);
253 status &= MMU_IRQ_MASK;
254 if (!status) {
255 *da = 0;
256 return 0;
257 }
258
259 fault_addr = iommu_read_reg(obj, MMU_FAULT_AD);
260 *da = fault_addr;
261
262 iommu_write_reg(obj, status, MMU_IRQSTATUS);
263
264 return status;
219} 265}
220 266
221static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) 267static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l)
@@ -241,31 +287,19 @@ static void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l)
241 287
242static void iotlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr) 288static void iotlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
243{ 289{
244 arch_iommu->tlb_read_cr(obj, cr); 290 cr->cam = iommu_read_reg(obj, MMU_READ_CAM);
291 cr->ram = iommu_read_reg(obj, MMU_READ_RAM);
245} 292}
246 293
247static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr) 294static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
248{ 295{
249 arch_iommu->tlb_load_cr(obj, cr); 296 iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM);
297 iommu_write_reg(obj, cr->ram, MMU_RAM);
250 298
251 iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); 299 iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
252 iommu_write_reg(obj, 1, MMU_LD_TLB); 300 iommu_write_reg(obj, 1, MMU_LD_TLB);
253} 301}
254 302
255/**
256 * iotlb_dump_cr - Dump an iommu tlb entry into buf
257 * @obj: target iommu
258 * @cr: contents of cam and ram register
259 * @buf: output buffer
260 **/
261static inline ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr,
262 char *buf)
263{
264 BUG_ON(!cr || !buf);
265
266 return arch_iommu->dump_cr(obj, cr, buf);
267}
268
269/* only used in iotlb iteration for-loop */ 303/* only used in iotlb iteration for-loop */
270static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n) 304static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n)
271{ 305{
@@ -280,12 +314,36 @@ static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n)
280 return cr; 314 return cr;
281} 315}
282 316
317#ifdef PREFETCH_IOTLB
318static struct cr_regs *iotlb_alloc_cr(struct omap_iommu *obj,
319 struct iotlb_entry *e)
320{
321 struct cr_regs *cr;
322
323 if (!e)
324 return NULL;
325
326 if (e->da & ~(get_cam_va_mask(e->pgsz))) {
327 dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__,
328 e->da);
329 return ERR_PTR(-EINVAL);
330 }
331
332 cr = kmalloc(sizeof(*cr), GFP_KERNEL);
333 if (!cr)
334 return ERR_PTR(-ENOMEM);
335
336 cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz | e->valid;
337 cr->ram = e->pa | e->endian | e->elsz | e->mixed;
338
339 return cr;
340}
341
283/** 342/**
284 * load_iotlb_entry - Set an iommu tlb entry 343 * load_iotlb_entry - Set an iommu tlb entry
285 * @obj: target iommu 344 * @obj: target iommu
286 * @e: an iommu tlb entry info 345 * @e: an iommu tlb entry info
287 **/ 346 **/
288#ifdef PREFETCH_IOTLB
289static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) 347static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
290{ 348{
291 int err = 0; 349 int err = 0;
@@ -416,6 +474,44 @@ static void flush_iotlb_all(struct omap_iommu *obj)
416 474
417#if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) 475#if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
418 476
477#define pr_reg(name) \
478 do { \
479 ssize_t bytes; \
480 const char *str = "%20s: %08x\n"; \
481 const int maxcol = 32; \
482 bytes = snprintf(p, maxcol, str, __stringify(name), \
483 iommu_read_reg(obj, MMU_##name)); \
484 p += bytes; \
485 len -= bytes; \
486 if (len < maxcol) \
487 goto out; \
488 } while (0)
489
490static ssize_t
491omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len)
492{
493 char *p = buf;
494
495 pr_reg(REVISION);
496 pr_reg(IRQSTATUS);
497 pr_reg(IRQENABLE);
498 pr_reg(WALKING_ST);
499 pr_reg(CNTL);
500 pr_reg(FAULT_AD);
501 pr_reg(TTB);
502 pr_reg(LOCK);
503 pr_reg(LD_TLB);
504 pr_reg(CAM);
505 pr_reg(RAM);
506 pr_reg(GFLUSH);
507 pr_reg(FLUSH_ENTRY);
508 pr_reg(READ_CAM);
509 pr_reg(READ_RAM);
510 pr_reg(EMU_FAULT_AD);
511out:
512 return p - buf;
513}
514
419ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes) 515ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes)
420{ 516{
421 if (!obj || !buf) 517 if (!obj || !buf)
@@ -423,7 +519,7 @@ ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes)
423 519
424 pm_runtime_get_sync(obj->dev); 520 pm_runtime_get_sync(obj->dev);
425 521
426 bytes = arch_iommu->dump_ctx(obj, buf, bytes); 522 bytes = omap2_iommu_dump_ctx(obj, buf, bytes);
427 523
428 pm_runtime_put_sync(obj->dev); 524 pm_runtime_put_sync(obj->dev);
429 525
@@ -455,6 +551,24 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
455} 551}
456 552
457/** 553/**
554 * iotlb_dump_cr - Dump an iommu tlb entry into buf
555 * @obj: target iommu
556 * @cr: contents of cam and ram register
557 * @buf: output buffer
558 **/
559static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr,
560 char *buf)
561{
562 char *p = buf;
563
564 /* FIXME: Need more detail analysis of cam/ram */
565 p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram,
566 (cr->cam & MMU_CAM_P) ? 1 : 0);
567
568 return p - buf;
569}
570
571/**
458 * omap_dump_tlb_entries - dump cr arrays to given buffer 572 * omap_dump_tlb_entries - dump cr arrays to given buffer
459 * @obj: target iommu 573 * @obj: target iommu
460 * @buf: output buffer 574 * @buf: output buffer
@@ -1008,7 +1122,6 @@ static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz)
1008 e->da = da; 1122 e->da = da;
1009 e->pa = pa; 1123 e->pa = pa;
1010 e->valid = MMU_CAM_V; 1124 e->valid = MMU_CAM_V;
1011 /* FIXME: add OMAP1 support */
1012 e->pgsz = pgsz; 1125 e->pgsz = pgsz;
1013 e->endian = MMU_RAM_ENDIAN_LITTLE; 1126 e->endian = MMU_RAM_ENDIAN_LITTLE;
1014 e->elsz = MMU_RAM_ELSZ_8; 1127 e->elsz = MMU_RAM_ELSZ_8;