aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/iommu.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 13:50:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 13:50:00 -0400
commita6f039869ff87e0a8d621e31d14bbb120c1dfa93 (patch)
treec8975a8d02893633d03efe5435aa8b0635298a93 /arch/arm/plat-omap/iommu.c
parente0bc5d4a54938eedcde14005210e6c08aa9727e4 (diff)
parentf6304f5804f228b6c2fea9e3dfac25c5b2db9b38 (diff)
Merge branch 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6
* 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6: (113 commits) omap4: Add support for i2c init omap: Fix i2c platform init code for omap4 OMAP2 clock: fix recursive spinlock attempt when CONFIG_CPU_FREQ=y OMAP powerdomain, hwmod, omap_device: add some credits OMAP4 powerdomain: Support LOWPOWERSTATECHANGE for powerdomains OMAP3 clock: add support for setting the divider for sys_clkout2 using clk_set_rate OMAP4 powerdomain: Fix pwrsts flags for ALWAYS ON domains OMAP: timers: Fix clock source names for OMAP4 OMAP4 clock: Support clk_set_parent OMAP4: PRCM: Add offset defines for all CM registers OMAP4: PRCM: Add offset defines for all PRM registers OMAP4: PRCM: Remove duplicate definition of base addresses OMAP4: PRM: Remove MPU internal code name and apply PRCM naming convention OMAP4: CM: Remove non-functional registers in ES1.0 OMAP: hwmod: Replace WARN by pr_warning for clockdomain check OMAP: hwmod: Rename hwmod name for the MPU OMAP: hwmod: Do not exit the iteration if one clock init failed OMAP: hwmod: Replace WARN by pr_warning if clock lookup failed OMAP: hwmod: Remove IS_ERR check with omap_clk_get_by_name return value OMAP: hwmod: Fix wrong pointer iteration in oh->slaves ...
Diffstat (limited to 'arch/arm/plat-omap/iommu.c')
-rw-r--r--arch/arm/plat-omap/iommu.c101
1 files changed, 66 insertions, 35 deletions
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index 0e137663349c..bc094dbacee6 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -25,6 +25,11 @@
25 25
26#include "iopgtable.h" 26#include "iopgtable.h"
27 27
28#define for_each_iotlb_cr(obj, n, __i, cr) \
29 for (__i = 0; \
30 (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \
31 __i++)
32
28/* accommodate the difference between omap1 and omap2/3 */ 33/* accommodate the difference between omap1 and omap2/3 */
29static const struct iommu_functions *arch_iommu; 34static const struct iommu_functions *arch_iommu;
30 35
@@ -172,15 +177,12 @@ static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l)
172 l->base = MMU_LOCK_BASE(val); 177 l->base = MMU_LOCK_BASE(val);
173 l->vict = MMU_LOCK_VICT(val); 178 l->vict = MMU_LOCK_VICT(val);
174 179
175 BUG_ON(l->base != 0); /* Currently no preservation is used */
176} 180}
177 181
178static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l) 182static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l)
179{ 183{
180 u32 val; 184 u32 val;
181 185
182 BUG_ON(l->base != 0); /* Currently no preservation is used */
183
184 val = (l->base << MMU_LOCK_BASE_SHIFT); 186 val = (l->base << MMU_LOCK_BASE_SHIFT);
185 val |= (l->vict << MMU_LOCK_VICT_SHIFT); 187 val |= (l->vict << MMU_LOCK_VICT_SHIFT);
186 188
@@ -214,6 +216,20 @@ static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
214 return arch_iommu->dump_cr(obj, cr, buf); 216 return arch_iommu->dump_cr(obj, cr, buf);
215} 217}
216 218
219/* only used in iotlb iteration for-loop */
220static struct cr_regs __iotlb_read_cr(struct iommu *obj, int n)
221{
222 struct cr_regs cr;
223 struct iotlb_lock l;
224
225 iotlb_lock_get(obj, &l);
226 l.vict = n;
227 iotlb_lock_set(obj, &l);
228 iotlb_read_cr(obj, &cr);
229
230 return cr;
231}
232
217/** 233/**
218 * load_iotlb_entry - Set an iommu tlb entry 234 * load_iotlb_entry - Set an iommu tlb entry
219 * @obj: target iommu 235 * @obj: target iommu
@@ -221,7 +237,6 @@ static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
221 **/ 237 **/
222int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) 238int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
223{ 239{
224 int i;
225 int err = 0; 240 int err = 0;
226 struct iotlb_lock l; 241 struct iotlb_lock l;
227 struct cr_regs *cr; 242 struct cr_regs *cr;
@@ -231,21 +246,30 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
231 246
232 clk_enable(obj->clk); 247 clk_enable(obj->clk);
233 248
234 for (i = 0; i < obj->nr_tlb_entries; i++) { 249 iotlb_lock_get(obj, &l);
250 if (l.base == obj->nr_tlb_entries) {
251 dev_warn(obj->dev, "%s: preserve entries full\n", __func__);
252 err = -EBUSY;
253 goto out;
254 }
255 if (!e->prsvd) {
256 int i;
235 struct cr_regs tmp; 257 struct cr_regs tmp;
236 258
259 for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, tmp)
260 if (!iotlb_cr_valid(&tmp))
261 break;
262
263 if (i == obj->nr_tlb_entries) {
264 dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
265 err = -EBUSY;
266 goto out;
267 }
268
237 iotlb_lock_get(obj, &l); 269 iotlb_lock_get(obj, &l);
238 l.vict = i; 270 } else {
271 l.vict = l.base;
239 iotlb_lock_set(obj, &l); 272 iotlb_lock_set(obj, &l);
240 iotlb_read_cr(obj, &tmp);
241 if (!iotlb_cr_valid(&tmp))
242 break;
243 }
244
245 if (i == obj->nr_tlb_entries) {
246 dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
247 err = -EBUSY;
248 goto out;
249 } 273 }
250 274
251 cr = iotlb_alloc_cr(obj, e); 275 cr = iotlb_alloc_cr(obj, e);
@@ -257,9 +281,11 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
257 iotlb_load_cr(obj, cr); 281 iotlb_load_cr(obj, cr);
258 kfree(cr); 282 kfree(cr);
259 283
284 if (e->prsvd)
285 l.base++;
260 /* increment victim for next tlb load */ 286 /* increment victim for next tlb load */
261 if (++l.vict == obj->nr_tlb_entries) 287 if (++l.vict == obj->nr_tlb_entries)
262 l.vict = 0; 288 l.vict = l.base;
263 iotlb_lock_set(obj, &l); 289 iotlb_lock_set(obj, &l);
264out: 290out:
265 clk_disable(obj->clk); 291 clk_disable(obj->clk);
@@ -276,20 +302,15 @@ EXPORT_SYMBOL_GPL(load_iotlb_entry);
276 **/ 302 **/
277void flush_iotlb_page(struct iommu *obj, u32 da) 303void flush_iotlb_page(struct iommu *obj, u32 da)
278{ 304{
279 struct iotlb_lock l;
280 int i; 305 int i;
306 struct cr_regs cr;
281 307
282 clk_enable(obj->clk); 308 clk_enable(obj->clk);
283 309
284 for (i = 0; i < obj->nr_tlb_entries; i++) { 310 for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
285 struct cr_regs cr;
286 u32 start; 311 u32 start;
287 size_t bytes; 312 size_t bytes;
288 313
289 iotlb_lock_get(obj, &l);
290 l.vict = i;
291 iotlb_lock_set(obj, &l);
292 iotlb_read_cr(obj, &cr);
293 if (!iotlb_cr_valid(&cr)) 314 if (!iotlb_cr_valid(&cr))
294 continue; 315 continue;
295 316
@@ -299,7 +320,6 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
299 if ((start <= da) && (da < start + bytes)) { 320 if ((start <= da) && (da < start + bytes)) {
300 dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n", 321 dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
301 __func__, start, da, bytes); 322 __func__, start, da, bytes);
302 iotlb_load_cr(obj, &cr);
303 iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); 323 iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
304 } 324 }
305 } 325 }
@@ -370,26 +390,19 @@ EXPORT_SYMBOL_GPL(iommu_dump_ctx);
370static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num) 390static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
371{ 391{
372 int i; 392 int i;
373 struct iotlb_lock saved, l; 393 struct iotlb_lock saved;
394 struct cr_regs tmp;
374 struct cr_regs *p = crs; 395 struct cr_regs *p = crs;
375 396
376 clk_enable(obj->clk); 397 clk_enable(obj->clk);
377
378 iotlb_lock_get(obj, &saved); 398 iotlb_lock_get(obj, &saved);
379 memcpy(&l, &saved, sizeof(saved));
380 399
381 for (i = 0; i < num; i++) { 400 for_each_iotlb_cr(obj, num, i, tmp) {
382 struct cr_regs tmp;
383
384 iotlb_lock_get(obj, &l);
385 l.vict = i;
386 iotlb_lock_set(obj, &l);
387 iotlb_read_cr(obj, &tmp);
388 if (!iotlb_cr_valid(&tmp)) 401 if (!iotlb_cr_valid(&tmp))
389 continue; 402 continue;
390
391 *p++ = tmp; 403 *p++ = tmp;
392 } 404 }
405
393 iotlb_lock_set(obj, &saved); 406 iotlb_lock_set(obj, &saved);
394 clk_disable(obj->clk); 407 clk_disable(obj->clk);
395 408
@@ -503,6 +516,12 @@ static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
503{ 516{
504 u32 *iopgd = iopgd_offset(obj, da); 517 u32 *iopgd = iopgd_offset(obj, da);
505 518
519 if ((da | pa) & ~IOSECTION_MASK) {
520 dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
521 __func__, da, pa, IOSECTION_SIZE);
522 return -EINVAL;
523 }
524
506 *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION; 525 *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
507 flush_iopgd_range(iopgd, iopgd); 526 flush_iopgd_range(iopgd, iopgd);
508 return 0; 527 return 0;
@@ -513,6 +532,12 @@ static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
513 u32 *iopgd = iopgd_offset(obj, da); 532 u32 *iopgd = iopgd_offset(obj, da);
514 int i; 533 int i;
515 534
535 if ((da | pa) & ~IOSUPER_MASK) {
536 dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
537 __func__, da, pa, IOSUPER_SIZE);
538 return -EINVAL;
539 }
540
516 for (i = 0; i < 16; i++) 541 for (i = 0; i < 16; i++)
517 *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER; 542 *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
518 flush_iopgd_range(iopgd, iopgd + 15); 543 flush_iopgd_range(iopgd, iopgd + 15);
@@ -542,6 +567,12 @@ static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot)
542 u32 *iopte = iopte_alloc(obj, iopgd, da); 567 u32 *iopte = iopte_alloc(obj, iopgd, da);
543 int i; 568 int i;
544 569
570 if ((da | pa) & ~IOLARGE_MASK) {
571 dev_err(obj->dev, "%s: %08x:%08x should aligned on %08lx\n",
572 __func__, da, pa, IOLARGE_SIZE);
573 return -EINVAL;
574 }
575
545 if (IS_ERR(iopte)) 576 if (IS_ERR(iopte))
546 return PTR_ERR(iopte); 577 return PTR_ERR(iopte);
547 578