aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/iommu/exynos-iommu.c58
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:
728static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, 728static 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
748static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt) 753static 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;
920err:
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
900static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, 930static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,