Merge branches 'iommu/fixes', 'arm/allwinner', 'arm/exynos', 'arm/mediatek', 'arm...
[sfrench/cifs-2.6.git] / drivers / iommu / iommu-sva.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Helpers for IOMMU drivers implementing SVA
4  */
5 #include <linux/mutex.h>
6 #include <linux/sched/mm.h>
7 #include <linux/iommu.h>
8
9 #include "iommu-sva.h"
10
11 static DEFINE_MUTEX(iommu_sva_lock);
12 static DEFINE_IDA(iommu_global_pasid_ida);
13
14 /* Allocate a PASID for the mm within range (inclusive) */
15 static int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
16 {
17         int ret = 0;
18
19         if (!pasid_valid(min) || !pasid_valid(max) ||
20             min == 0 || max < min)
21                 return -EINVAL;
22
23         mutex_lock(&iommu_sva_lock);
24         /* Is a PASID already associated with this mm? */
25         if (pasid_valid(mm->pasid)) {
26                 if (mm->pasid < min || mm->pasid > max)
27                         ret = -EOVERFLOW;
28                 goto out;
29         }
30
31         ret = ida_alloc_range(&iommu_global_pasid_ida, min, max, GFP_KERNEL);
32         if (ret < min)
33                 goto out;
34         mm->pasid = ret;
35         ret = 0;
36 out:
37         mutex_unlock(&iommu_sva_lock);
38         return ret;
39 }
40
41 /**
42  * iommu_sva_bind_device() - Bind a process address space to a device
43  * @dev: the device
44  * @mm: the mm to bind, caller must hold a reference to mm_users
45  *
46  * Create a bond between device and address space, allowing the device to
47  * access the mm using the PASID returned by iommu_sva_get_pasid(). If a
48  * bond already exists between @device and @mm, an additional internal
49  * reference is taken. Caller must call iommu_sva_unbind_device()
50  * to release each reference.
51  *
52  * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
53  * initialize the required SVA features.
54  *
55  * On error, returns an ERR_PTR value.
56  */
57 struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
58 {
59         struct iommu_domain *domain;
60         struct iommu_sva *handle;
61         ioasid_t max_pasids;
62         int ret;
63
64         max_pasids = dev->iommu->max_pasids;
65         if (!max_pasids)
66                 return ERR_PTR(-EOPNOTSUPP);
67
68         /* Allocate mm->pasid if necessary. */
69         ret = iommu_sva_alloc_pasid(mm, 1, max_pasids - 1);
70         if (ret)
71                 return ERR_PTR(ret);
72
73         handle = kzalloc(sizeof(*handle), GFP_KERNEL);
74         if (!handle)
75                 return ERR_PTR(-ENOMEM);
76
77         mutex_lock(&iommu_sva_lock);
78         /* Search for an existing domain. */
79         domain = iommu_get_domain_for_dev_pasid(dev, mm->pasid,
80                                                 IOMMU_DOMAIN_SVA);
81         if (IS_ERR(domain)) {
82                 ret = PTR_ERR(domain);
83                 goto out_unlock;
84         }
85
86         if (domain) {
87                 domain->users++;
88                 goto out;
89         }
90
91         /* Allocate a new domain and set it on device pasid. */
92         domain = iommu_sva_domain_alloc(dev, mm);
93         if (!domain) {
94                 ret = -ENOMEM;
95                 goto out_unlock;
96         }
97
98         ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
99         if (ret)
100                 goto out_free_domain;
101         domain->users = 1;
102 out:
103         mutex_unlock(&iommu_sva_lock);
104         handle->dev = dev;
105         handle->domain = domain;
106
107         return handle;
108
109 out_free_domain:
110         iommu_domain_free(domain);
111 out_unlock:
112         mutex_unlock(&iommu_sva_lock);
113         kfree(handle);
114
115         return ERR_PTR(ret);
116 }
117 EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
118
119 /**
120  * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
121  * @handle: the handle returned by iommu_sva_bind_device()
122  *
123  * Put reference to a bond between device and address space. The device should
124  * not be issuing any more transaction for this PASID. All outstanding page
125  * requests for this PASID must have been flushed to the IOMMU.
126  */
127 void iommu_sva_unbind_device(struct iommu_sva *handle)
128 {
129         struct iommu_domain *domain = handle->domain;
130         ioasid_t pasid = domain->mm->pasid;
131         struct device *dev = handle->dev;
132
133         mutex_lock(&iommu_sva_lock);
134         if (--domain->users == 0) {
135                 iommu_detach_device_pasid(domain, dev, pasid);
136                 iommu_domain_free(domain);
137         }
138         mutex_unlock(&iommu_sva_lock);
139         kfree(handle);
140 }
141 EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
142
143 u32 iommu_sva_get_pasid(struct iommu_sva *handle)
144 {
145         struct iommu_domain *domain = handle->domain;
146
147         return domain->mm->pasid;
148 }
149 EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
150
151 /*
152  * I/O page fault handler for SVA
153  */
154 enum iommu_page_response_code
155 iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
156 {
157         vm_fault_t ret;
158         struct vm_area_struct *vma;
159         struct mm_struct *mm = data;
160         unsigned int access_flags = 0;
161         unsigned int fault_flags = FAULT_FLAG_REMOTE;
162         struct iommu_fault_page_request *prm = &fault->prm;
163         enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
164
165         if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
166                 return status;
167
168         if (!mmget_not_zero(mm))
169                 return status;
170
171         mmap_read_lock(mm);
172
173         vma = find_extend_vma(mm, prm->addr);
174         if (!vma)
175                 /* Unmapped area */
176                 goto out_put_mm;
177
178         if (prm->perm & IOMMU_FAULT_PERM_READ)
179                 access_flags |= VM_READ;
180
181         if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
182                 access_flags |= VM_WRITE;
183                 fault_flags |= FAULT_FLAG_WRITE;
184         }
185
186         if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
187                 access_flags |= VM_EXEC;
188                 fault_flags |= FAULT_FLAG_INSTRUCTION;
189         }
190
191         if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
192                 fault_flags |= FAULT_FLAG_USER;
193
194         if (access_flags & ~vma->vm_flags)
195                 /* Access fault */
196                 goto out_put_mm;
197
198         ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
199         status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
200                 IOMMU_PAGE_RESP_SUCCESS;
201
202 out_put_mm:
203         mmap_read_unlock(mm);
204         mmput(mm);
205
206         return status;
207 }
208
209 void mm_pasid_drop(struct mm_struct *mm)
210 {
211         if (likely(!pasid_valid(mm->pasid)))
212                 return;
213
214         ida_free(&iommu_global_pasid_ida, mm->pasid);
215 }