b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 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 int msm_iommu_attach(struct msm_mmu *mmu, const char * const *names, |
| 27 | int cnt) |
| 28 | { |
| 29 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 30 | |
| 31 | return iommu_attach_device(iommu->domain, mmu->dev); |
| 32 | } |
| 33 | |
| 34 | static void msm_iommu_detach(struct msm_mmu *mmu, const char * const *names, |
| 35 | int cnt) |
| 36 | { |
| 37 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 38 | |
| 39 | iommu_detach_device(iommu->domain, mmu->dev); |
| 40 | } |
| 41 | |
| 42 | static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, |
| 43 | struct sg_table *sgt, unsigned len, int prot) |
| 44 | { |
| 45 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 46 | size_t ret; |
| 47 | |
| 48 | ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot); |
| 49 | WARN_ON(!ret); |
| 50 | |
| 51 | return (ret == len) ? 0 : -EINVAL; |
| 52 | } |
| 53 | |
| 54 | static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, unsigned len) |
| 55 | { |
| 56 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 57 | |
| 58 | iommu_unmap(iommu->domain, iova, len); |
| 59 | |
| 60 | return 0; |
| 61 | } |
| 62 | |
| 63 | static void msm_iommu_destroy(struct msm_mmu *mmu) |
| 64 | { |
| 65 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 66 | iommu_domain_free(iommu->domain); |
| 67 | kfree(iommu); |
| 68 | } |
| 69 | |
| 70 | static const struct msm_mmu_funcs funcs = { |
| 71 | .attach = msm_iommu_attach, |
| 72 | .detach = msm_iommu_detach, |
| 73 | .map = msm_iommu_map, |
| 74 | .unmap = msm_iommu_unmap, |
| 75 | .destroy = msm_iommu_destroy, |
| 76 | }; |
| 77 | |
| 78 | struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) |
| 79 | { |
| 80 | struct msm_iommu *iommu; |
| 81 | |
| 82 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
| 83 | if (!iommu) |
| 84 | return ERR_PTR(-ENOMEM); |
| 85 | |
| 86 | iommu->domain = domain; |
| 87 | msm_mmu_init(&iommu->base, dev, &funcs); |
| 88 | iommu_set_fault_handler(domain, msm_fault_handler, iommu); |
| 89 | |
| 90 | return &iommu->base; |
| 91 | } |