diff options
-rw-r--r-- | drivers/iommu/exynos-iommu.c | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 8d7c3f9632f8..aec7fd75f400 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c | |||
@@ -728,13 +728,18 @@ finish: | |||
728 | static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, | 728 | static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, |
729 | short *pgcounter) | 729 | short *pgcounter) |
730 | { | 730 | { |
731 | if (lv1ent_section(sent)) { | ||
732 | WARN(1, "Trying mapping on %#08lx mapped with 1MiB page", iova); | ||
733 | return ERR_PTR(-EADDRINUSE); | ||
734 | } | ||
735 | |||
731 | if (lv1ent_fault(sent)) { | 736 | if (lv1ent_fault(sent)) { |
732 | unsigned long *pent; | 737 | unsigned long *pent; |
733 | 738 | ||
734 | pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC); | 739 | pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC); |
735 | BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1)); | 740 | BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1)); |
736 | if (!pent) | 741 | if (!pent) |
737 | return NULL; | 742 | return ERR_PTR(-ENOMEM); |
738 | 743 | ||
739 | *sent = mk_lv1ent_page(virt_to_phys(pent)); | 744 | *sent = mk_lv1ent_page(virt_to_phys(pent)); |
740 | *pgcounter = NUM_LV2ENTRIES; | 745 | *pgcounter = NUM_LV2ENTRIES; |
@@ -745,14 +750,21 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, | |||
745 | return page_entry(sent, iova); | 750 | return page_entry(sent, iova); |
746 | } | 751 | } |
747 | 752 | ||
748 | static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt) | 753 | static int lv1set_section(unsigned long *sent, unsigned long iova, |
754 | phys_addr_t paddr, short *pgcnt) | ||
749 | { | 755 | { |
750 | if (lv1ent_section(sent)) | 756 | if (lv1ent_section(sent)) { |
757 | WARN(1, "Trying mapping on 1MiB@%#08lx that is mapped", | ||
758 | iova); | ||
751 | return -EADDRINUSE; | 759 | return -EADDRINUSE; |
760 | } | ||
752 | 761 | ||
753 | if (lv1ent_page(sent)) { | 762 | if (lv1ent_page(sent)) { |
754 | if (*pgcnt != NUM_LV2ENTRIES) | 763 | if (*pgcnt != NUM_LV2ENTRIES) { |
764 | WARN(1, "Trying mapping on 1MiB@%#08lx that is mapped", | ||
765 | iova); | ||
755 | return -EADDRINUSE; | 766 | return -EADDRINUSE; |
767 | } | ||
756 | 768 | ||
757 | kfree(page_entry(sent, 0)); | 769 | kfree(page_entry(sent, 0)); |
758 | 770 | ||
@@ -770,8 +782,10 @@ static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, | |||
770 | short *pgcnt) | 782 | short *pgcnt) |
771 | { | 783 | { |
772 | if (size == SPAGE_SIZE) { | 784 | if (size == SPAGE_SIZE) { |
773 | if (!lv2ent_fault(pent)) | 785 | if (!lv2ent_fault(pent)) { |
786 | WARN(1, "Trying mapping on 4KiB where mapping exists"); | ||
774 | return -EADDRINUSE; | 787 | return -EADDRINUSE; |
788 | } | ||
775 | 789 | ||
776 | *pent = mk_lv2ent_spage(paddr); | 790 | *pent = mk_lv2ent_spage(paddr); |
777 | pgtable_flush(pent, pent + 1); | 791 | pgtable_flush(pent, pent + 1); |
@@ -780,7 +794,10 @@ static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, | |||
780 | int i; | 794 | int i; |
781 | for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) { | 795 | for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) { |
782 | if (!lv2ent_fault(pent)) { | 796 | if (!lv2ent_fault(pent)) { |
783 | memset(pent, 0, sizeof(*pent) * i); | 797 | WARN(1, |
798 | "Trying mapping on 64KiB where mapping exists"); | ||
799 | if (i > 0) | ||
800 | memset(pent - i, 0, sizeof(*pent) * i); | ||
784 | return -EADDRINUSE; | 801 | return -EADDRINUSE; |
785 | } | 802 | } |
786 | 803 | ||
@@ -808,7 +825,7 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, | |||
808 | entry = section_entry(priv->pgtable, iova); | 825 | entry = section_entry(priv->pgtable, iova); |
809 | 826 | ||
810 | if (size == SECT_SIZE) { | 827 | if (size == SECT_SIZE) { |
811 | ret = lv1set_section(entry, paddr, | 828 | ret = lv1set_section(entry, iova, paddr, |
812 | &priv->lv2entcnt[lv1ent_offset(iova)]); | 829 | &priv->lv2entcnt[lv1ent_offset(iova)]); |
813 | } else { | 830 | } else { |
814 | unsigned long *pent; | 831 | unsigned long *pent; |
@@ -816,17 +833,16 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, | |||
816 | pent = alloc_lv2entry(entry, iova, | 833 | pent = alloc_lv2entry(entry, iova, |
817 | &priv->lv2entcnt[lv1ent_offset(iova)]); | 834 | &priv->lv2entcnt[lv1ent_offset(iova)]); |
818 | 835 | ||
819 | if (!pent) | 836 | if (IS_ERR(pent)) |
820 | ret = -ENOMEM; | 837 | ret = PTR_ERR(pent); |
821 | else | 838 | else |
822 | ret = lv2set_page(pent, paddr, size, | 839 | ret = lv2set_page(pent, paddr, size, |
823 | &priv->lv2entcnt[lv1ent_offset(iova)]); | 840 | &priv->lv2entcnt[lv1ent_offset(iova)]); |
824 | } | 841 | } |
825 | 842 | ||
826 | if (ret) { | 843 | if (ret) |
827 | pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n", | 844 | pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n", |
828 | __func__, iova, size); | 845 | __func__, iova, size); |
829 | } | ||
830 | 846 | ||
831 | spin_unlock_irqrestore(&priv->pgtablelock, flags); | 847 | spin_unlock_irqrestore(&priv->pgtablelock, flags); |
832 | 848 | ||
@@ -840,6 +856,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain, | |||
840 | struct sysmmu_drvdata *data; | 856 | struct sysmmu_drvdata *data; |
841 | unsigned long flags; | 857 | unsigned long flags; |
842 | unsigned long *ent; | 858 | unsigned long *ent; |
859 | size_t err_pgsize; | ||
843 | 860 | ||
844 | BUG_ON(priv->pgtable == NULL); | 861 | BUG_ON(priv->pgtable == NULL); |
845 | 862 | ||
@@ -848,7 +865,10 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain, | |||
848 | ent = section_entry(priv->pgtable, iova); | 865 | ent = section_entry(priv->pgtable, iova); |
849 | 866 | ||
850 | if (lv1ent_section(ent)) { | 867 | if (lv1ent_section(ent)) { |
851 | BUG_ON(size < SECT_SIZE); | 868 | if (size < SECT_SIZE) { |
869 | err_pgsize = SECT_SIZE; | ||
870 | goto err; | ||
871 | } | ||
852 | 872 | ||
853 | *ent = 0; | 873 | *ent = 0; |
854 | pgtable_flush(ent, ent + 1); | 874 | pgtable_flush(ent, ent + 1); |
@@ -879,7 +899,10 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain, | |||
879 | } | 899 | } |
880 | 900 | ||
881 | /* lv1ent_large(ent) == true here */ | 901 | /* lv1ent_large(ent) == true here */ |
882 | BUG_ON(size < LPAGE_SIZE); | 902 | if (size < LPAGE_SIZE) { |
903 | err_pgsize = LPAGE_SIZE; | ||
904 | goto err; | ||
905 | } | ||
883 | 906 | ||
884 | memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE); | 907 | memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE); |
885 | 908 | ||
@@ -893,8 +916,15 @@ done: | |||
893 | sysmmu_tlb_invalidate_entry(data->dev, iova); | 916 | sysmmu_tlb_invalidate_entry(data->dev, iova); |
894 | spin_unlock_irqrestore(&priv->lock, flags); | 917 | spin_unlock_irqrestore(&priv->lock, flags); |
895 | 918 | ||
896 | |||
897 | return size; | 919 | return size; |
920 | err: | ||
921 | spin_unlock_irqrestore(&priv->pgtablelock, flags); | ||
922 | |||
923 | WARN(1, | ||
924 | "%s: Failed due to size(%#x) @ %#08lx is smaller than page size %#x\n", | ||
925 | __func__, size, iova, err_pgsize); | ||
926 | |||
927 | return 0; | ||
898 | } | 928 | } |
899 | 929 | ||
900 | static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, | 930 | static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, |