aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubash Lakkimsetti2017-02-03 10:13:55 -0600
committerBuddy Liong2017-02-08 15:48:34 -0600
commit5fee22e43a891a715536842b489decc6541c6c51 (patch)
treee2c596316903739b21aabfd37438eababa85330e
parent11e251e17ea7b39d5a85e9f89197db073e70a93a (diff)
downloadkernel-omap-5fee22e43a891a715536842b489decc6541c6c51.tar.gz
kernel-omap-5fee22e43a891a715536842b489decc6541c6c51.tar.xz
kernel-omap-5fee22e43a891a715536842b489decc6541c6c51.zip
Late Attach: Fix for accessing second level page table
With IOMMU page table carve out crashes are seen while accessing second level page table entries due to address conversion in unmapped kernel space. Calculating the virtual address for mapping second level page table entry before accessing for late attach IOMMU page table carveout. Change-Id: I705373a731b88ba63516ae3ffa2f69841d1cf66b Signed-off-by: Subash Lakkimsetti <x0091084@ti.com>
-rw-r--r--drivers/iommu/omap-iommu-debug.c5
-rw-r--r--drivers/iommu/omap-iommu.c49
-rw-r--r--drivers/iommu/omap-iopgtable.h8
3 files changed, 51 insertions, 11 deletions
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index 505548aafeff..78cec6fd5e00 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -197,7 +197,10 @@ static void dump_ioptable(struct seq_file *s)
197 continue; 197 continue;
198 } 198 }
199 199
200 iopte = iopte_offset(iopgd, 0); 200 if (obj->late_attach)
201 iopte = iopte_offset_lateattach(obj, iopgd, 0);
202 else
203 iopte = iopte_offset(iopgd, 0);
201 for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) { 204 for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) {
202 if (!*iopte) 205 if (!*iopte)
203 continue; 206 continue;
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 15b6844a26ed..6ce7abb22732 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -539,7 +539,10 @@ static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, u32 da)
539 } 539 }
540 540
541pte_ready: 541pte_ready:
542 iopte = iopte_offset(iopgd, da); 542 if (obj->late_attach)
543 iopte = iopte_offset_lateattach(obj, iopgd, da);
544 else
545 iopte = iopte_offset(iopgd, da);
543 546
544 dev_vdbg(obj->dev, 547 dev_vdbg(obj->dev,
545 "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n", 548 "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
@@ -691,8 +694,12 @@ iopgtable_lookup_entry(struct omap_iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
691 if (!*iopgd) 694 if (!*iopgd)
692 goto out; 695 goto out;
693 696
694 if (iopgd_is_table(*iopgd)) 697 if (iopgd_is_table(*iopgd)) {
695 iopte = iopte_offset(iopgd, da); 698 if (obj->late_attach)
699 iopte = iopte_offset_lateattach(obj, iopgd, da);
700 else
701 iopte = iopte_offset(iopgd, da);
702 }
696out: 703out:
697 *ppgd = iopgd; 704 *ppgd = iopgd;
698 *ppte = iopte; 705 *ppte = iopte;
@@ -709,13 +716,23 @@ static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da)
709 716
710 if (iopgd_is_table(*iopgd)) { 717 if (iopgd_is_table(*iopgd)) {
711 int i; 718 int i;
712 u32 *iopte = iopte_offset(iopgd, da); 719 u32 *iopte;
720
721 if (obj->late_attach)
722 iopte = iopte_offset_lateattach(obj, iopgd, da);
723 else
724 iopte = iopte_offset(iopgd, da);
713 725
714 bytes = IOPTE_SIZE; 726 bytes = IOPTE_SIZE;
715 if (*iopte & IOPTE_LARGE) { 727 if (*iopte & IOPTE_LARGE) {
716 nent *= 16; 728 nent *= 16;
717 /* rewind to the 1st entry */ 729 /* rewind to the 1st entry */
718 iopte = iopte_offset(iopgd, (da & IOLARGE_MASK)); 730 if (obj->late_attach)
731 iopte = iopte_offset_lateattach(obj, iopgd,
732 (da & IOLARGE_MASK));
733 else
734 iopte = iopte_offset(iopgd,
735 (da & IOLARGE_MASK));
719 } 736 }
720 bytes *= nent; 737 bytes *= nent;
721 memset(iopte, 0, nent * sizeof(*iopte)); 738 memset(iopte, 0, nent * sizeof(*iopte));
@@ -724,7 +741,11 @@ static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da)
724 /* 741 /*
725 * do table walk to check if this table is necessary or not 742 * do table walk to check if this table is necessary or not
726 */ 743 */
727 iopte = iopte_offset(iopgd, 0); 744 if (obj->late_attach)
745 iopte = iopte_offset_lateattach(obj, iopgd, 0);
746 else
747 iopte = iopte_offset(iopgd, 0);
748
728 for (i = 0; i < PTRS_PER_IOPTE; i++) 749 for (i = 0; i < PTRS_PER_IOPTE; i++)
729 if (iopte[i]) 750 if (iopte[i])
730 goto out; 751 goto out;
@@ -781,8 +802,13 @@ static void iopgtable_clear_entry_all(struct omap_iommu *obj)
781 if (!*iopgd) 802 if (!*iopgd)
782 continue; 803 continue;
783 804
784 if (iopgd_is_table(*iopgd)) 805 if (iopgd_is_table(*iopgd)) {
785 iopte_free(iopte_offset(iopgd, 0)); 806 if (obj->late_attach)
807 iopte_free(iopte_offset_lateattach(obj,
808 iopgd, 0));
809 else
810 iopte_free(iopte_offset(iopgd, 0));
811 }
786 812
787 *iopgd = 0; 813 *iopgd = 0;
788 flush_iopgd_range(iopgd, iopgd + 1); 814 flush_iopgd_range(iopgd, iopgd + 1);
@@ -825,7 +851,10 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
825 return IRQ_NONE; 851 return IRQ_NONE;
826 } 852 }
827 853
828 iopte = iopte_offset(iopgd, da); 854 if (obj->late_attach)
855 iopte = iopte_offset_lateattach(obj, iopgd, da);
856 else
857 iopte = iopte_offset(iopgd, da);
829 858
830 dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n", 859 dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n",
831 obj->name, errs, da, iopgd, *iopgd, iopte, *iopte); 860 obj->name, errs, da, iopgd, *iopgd, iopte, *iopte);
@@ -865,7 +894,7 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd)
865 if (obj->late_attach) { 894 if (obj->late_attach) {
866 iopgd_pa = iommu_read_reg(obj, MMU_TTB); 895 iopgd_pa = iommu_read_reg(obj, MMU_TTB);
867 iopgd = devm_ioremap(obj->dev, iopgd_pa, 896 iopgd = devm_ioremap(obj->dev, iopgd_pa,
868 IOPGD_TABLE_SIZE); 897 2 * IOPGD_TABLE_SIZE);
869 if (!iopgd) 898 if (!iopgd)
870 return ERR_PTR(-ENOMEM); 899 return ERR_PTR(-ENOMEM);
871 } else { 900 } else {
diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h
index 01a315227bf0..9a6a6d228765 100644
--- a/drivers/iommu/omap-iopgtable.h
+++ b/drivers/iommu/omap-iopgtable.h
@@ -99,4 +99,12 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
99#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) 99#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
100#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) 100#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da))
101 101
102/* For late attach */
103#define iopgd_page_vaddr_lateattach(obj, iopgd) \
104 ((u32 *)((u32 *)obj->iopgd) + \
105 ((u32 *)iopgd_page_paddr(iopgd) - (u32 *)obj->iopgd_pa))
106
107/* to find an entry in the second-level page table for late attach mode*/
108#define iopte_offset_lateattach(obj, iopgd, da) \
109 (iopgd_page_vaddr_lateattach(obj, iopgd) + iopte_index(da))
102#endif /* _OMAP_IOPGTABLE_H */ 110#endif /* _OMAP_IOPGTABLE_H */