diff options
author | Subash Lakkimsetti | 2017-02-03 10:13:55 -0600 |
---|---|---|
committer | Buddy Liong | 2017-02-08 15:48:34 -0600 |
commit | 5fee22e43a891a715536842b489decc6541c6c51 (patch) | |
tree | e2c596316903739b21aabfd37438eababa85330e | |
parent | 11e251e17ea7b39d5a85e9f89197db073e70a93a (diff) | |
download | kernel-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.c | 5 | ||||
-rw-r--r-- | drivers/iommu/omap-iommu.c | 49 | ||||
-rw-r--r-- | drivers/iommu/omap-iopgtable.h | 8 |
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 | ||
541 | pte_ready: | 541 | pte_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 | } | ||
696 | out: | 703 | out: |
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 */ |