1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 */ 6 7 #include "msm_drv.h" 8 #include "msm_mmu.h" 9 10 struct msm_iommu { 11 struct msm_mmu base; 12 struct iommu_domain *domain; 13 }; 14 #define to_msm_iommu(x) container_of(x, struct msm_iommu, base) 15 16 static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, 17 unsigned long iova, int flags, void *arg) 18 { 19 struct msm_iommu *iommu = arg; 20 if (iommu->base.handler) 21 return iommu->base.handler(iommu->base.arg, iova, flags); 22 pr_warn_ratelimited("*** fault: iova=%16lx, flags=%d\n", iova, flags); 23 return 0; 24 } 25 26 static void msm_iommu_detach(struct msm_mmu *mmu) 27 { 28 struct msm_iommu *iommu = to_msm_iommu(mmu); 29 30 iommu_detach_device(iommu->domain, mmu->dev); 31 } 32 33 static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, 34 struct sg_table *sgt, size_t len, int prot) 35 { 36 struct msm_iommu *iommu = to_msm_iommu(mmu); 37 size_t ret; 38 39 ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot); 40 WARN_ON(!ret); 41 42 return (ret == len) ? 0 : -EINVAL; 43 } 44 45 static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, size_t len) 46 { 47 struct msm_iommu *iommu = to_msm_iommu(mmu); 48 49 iommu_unmap(iommu->domain, iova, len); 50 51 return 0; 52 } 53 54 static void msm_iommu_destroy(struct msm_mmu *mmu) 55 { 56 struct msm_iommu *iommu = to_msm_iommu(mmu); 57 iommu_domain_free(iommu->domain); 58 kfree(iommu); 59 } 60 61 static const struct msm_mmu_funcs funcs = { 62 .detach = msm_iommu_detach, 63 .map = msm_iommu_map, 64 .unmap = msm_iommu_unmap, 65 .destroy = msm_iommu_destroy, 66 }; 67 68 struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) 69 { 70 struct msm_iommu *iommu; 71 int ret; 72 73 if (!domain) 74 return ERR_PTR(-ENODEV); 75 76 iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); 77 if (!iommu) 78 return ERR_PTR(-ENOMEM); 79 80 iommu->domain = domain; 81 msm_mmu_init(&iommu->base, dev, &funcs); 82 iommu_set_fault_handler(domain, msm_fault_handler, iommu); 83 84 ret = iommu_attach_device(iommu->domain, dev); 85 if (ret) { 86 kfree(iommu); 87 return ERR_PTR(ret); 88 } 89 90 return &iommu->base; 91 } 92