aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCho KyongHo <pullip.cho@samsung.com>2014-05-12 02:14:49 -0400
committerJoerg Roedel <jroedel@suse.de>2014-05-13 13:12:52 -0400
commit3ad6b7f3a41ba6bf4503be442802072ca9dc8336 (patch)
tree9b6da104965f8c0ae7dc01f00d1ddb42141c7e02
parent734c3c732ca91adbe705f2a289509627810231a3 (diff)
iommu/exynos: Fix L2TLB invalidation
L2TLB is 8-way set-associative TLB with 512 entries. The number of sets is 64. A single 4KB(small page) translation information is cached only to a set whose index is the same with the lower 6 bits of the page frame number. A single 64KB(large page) translation information can be cached to any 16 sets whose top two bits of their indices are the same with the bit [5:4] of the page frame number. A single 1MB(section) or larger translation information can be cached to any set in the TLB. It is required to invalidate entire sets that may cache the target translation information to guarantee that the L2TLB has no stale data. Signed-off-by: Cho KyongHo <pullip.cho@samsung.com> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/exynos-iommu.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4ff4b0b81575..06fc70ee4389 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -226,9 +226,14 @@ static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
226} 226}
227 227
228static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, 228static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
229 unsigned long iova) 229 unsigned long iova, unsigned int num_inv)
230{ 230{
231 __raw_writel((iova & SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY); 231 unsigned int i;
232 for (i = 0; i < num_inv; i++) {
233 __raw_writel((iova & SPAGE_MASK) | 1,
234 sfrbase + REG_MMU_FLUSH_ENTRY);
235 iova += SPAGE_SIZE;
236 }
232} 237}
233 238
234static void __sysmmu_set_ptbase(void __iomem *sfrbase, 239static void __sysmmu_set_ptbase(void __iomem *sfrbase,
@@ -452,7 +457,8 @@ static bool exynos_sysmmu_disable(struct device *dev)
452 return disabled; 457 return disabled;
453} 458}
454 459
455static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova) 460static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova,
461 size_t size)
456{ 462{
457 unsigned long flags; 463 unsigned long flags;
458 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); 464 struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
@@ -460,9 +466,25 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)
460 read_lock_irqsave(&data->lock, flags); 466 read_lock_irqsave(&data->lock, flags);
461 467
462 if (is_sysmmu_active(data)) { 468 if (is_sysmmu_active(data)) {
469 unsigned int maj;
470 unsigned int num_inv = 1;
471 maj = __raw_readl(data->sfrbase + REG_MMU_VERSION);
472 /*
473 * L2TLB invalidation required
474 * 4KB page: 1 invalidation
475 * 64KB page: 16 invalidation
476 * 1MB page: 64 invalidation
477 * because it is set-associative TLB
478 * with 8-way and 64 sets.
479 * 1MB page can be cached in one of all sets.
480 * 64KB page can be one of 16 consecutive sets.
481 */
482 if ((maj >> 28) == 2) /* major version number */
483 num_inv = min_t(unsigned int, size / PAGE_SIZE, 64);
484
463 if (sysmmu_block(data->sfrbase)) { 485 if (sysmmu_block(data->sfrbase)) {
464 __sysmmu_tlb_invalidate_entry( 486 __sysmmu_tlb_invalidate_entry(
465 data->sfrbase, iova); 487 data->sfrbase, iova, num_inv);
466 sysmmu_unblock(data->sfrbase); 488 sysmmu_unblock(data->sfrbase);
467 } 489 }
468 } else { 490 } else {
@@ -915,7 +937,7 @@ done:
915 937
916 spin_lock_irqsave(&priv->lock, flags); 938 spin_lock_irqsave(&priv->lock, flags);
917 list_for_each_entry(data, &priv->clients, node) 939 list_for_each_entry(data, &priv->clients, node)
918 sysmmu_tlb_invalidate_entry(data->dev, iova); 940 sysmmu_tlb_invalidate_entry(data->dev, iova, size);
919 spin_unlock_irqrestore(&priv->lock, flags); 941 spin_unlock_irqrestore(&priv->lock, flags);
920 942
921 return size; 943 return size;