hc
2024-05-16 8d2a02b24d66aa359e83eebc1ed3c0f85367a1cb
kernel/drivers/gpu/host1x/job.c
....@@ -1,24 +1,14 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Tegra host1x Job
34 *
45 * Copyright (c) 2010-2015, NVIDIA Corporation.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms and conditions of the GNU General Public License,
8
- * version 2, as published by the Free Software Foundation.
9
- *
10
- * This program is distributed in the hope it will be useful, but WITHOUT
11
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
- * more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
176 */
187
198 #include <linux/dma-mapping.h>
209 #include <linux/err.h>
2110 #include <linux/host1x.h>
11
+#include <linux/iommu.h>
2212 #include <linux/kref.h>
2313 #include <linux/module.h>
2414 #include <linux/scatterlist.h>
....@@ -37,9 +27,12 @@
3727 u32 num_cmdbufs, u32 num_relocs)
3828 {
3929 struct host1x_job *job = NULL;
40
- unsigned int num_unpins = num_cmdbufs + num_relocs;
30
+ unsigned int num_unpins = num_relocs;
4131 u64 total;
4232 void *mem;
33
+
34
+ if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
35
+ num_unpins += num_cmdbufs;
4336
4437 /* Check that we're not going to overflow */
4538 total = sizeof(struct host1x_job) +
....@@ -110,15 +103,20 @@
110103
111104 static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
112105 {
106
+ struct host1x_client *client = job->client;
107
+ struct device *dev = client->dev;
108
+ struct host1x_job_gather *g;
109
+ struct iommu_domain *domain;
113110 unsigned int i;
114111 int err;
115112
113
+ domain = iommu_get_domain_for_dev(dev);
116114 job->num_unpins = 0;
117115
118116 for (i = 0; i < job->num_relocs; i++) {
119117 struct host1x_reloc *reloc = &job->relocs[i];
118
+ dma_addr_t phys_addr, *phys;
120119 struct sg_table *sgt;
121
- dma_addr_t phys_addr;
122120
123121 reloc->target.bo = host1x_bo_get(reloc->target.bo);
124122 if (!reloc->target.bo) {
....@@ -126,7 +124,60 @@
126124 goto unpin;
127125 }
128126
129
- phys_addr = host1x_bo_pin(reloc->target.bo, &sgt);
127
+ /*
128
+ * If the client device is not attached to an IOMMU, the
129
+ * physical address of the buffer object can be used.
130
+ *
131
+ * Similarly, when an IOMMU domain is shared between all
132
+ * host1x clients, the IOVA is already available, so no
133
+ * need to map the buffer object again.
134
+ *
135
+ * XXX Note that this isn't always safe to do because it
136
+ * relies on an assumption that no cache maintenance is
137
+ * needed on the buffer objects.
138
+ */
139
+ if (!domain || client->group)
140
+ phys = &phys_addr;
141
+ else
142
+ phys = NULL;
143
+
144
+ sgt = host1x_bo_pin(dev, reloc->target.bo, phys);
145
+ if (IS_ERR(sgt)) {
146
+ err = PTR_ERR(sgt);
147
+ goto unpin;
148
+ }
149
+
150
+ if (sgt) {
151
+ unsigned long mask = HOST1X_RELOC_READ |
152
+ HOST1X_RELOC_WRITE;
153
+ enum dma_data_direction dir;
154
+
155
+ switch (reloc->flags & mask) {
156
+ case HOST1X_RELOC_READ:
157
+ dir = DMA_TO_DEVICE;
158
+ break;
159
+
160
+ case HOST1X_RELOC_WRITE:
161
+ dir = DMA_FROM_DEVICE;
162
+ break;
163
+
164
+ case HOST1X_RELOC_READ | HOST1X_RELOC_WRITE:
165
+ dir = DMA_BIDIRECTIONAL;
166
+ break;
167
+
168
+ default:
169
+ err = -EINVAL;
170
+ goto unpin;
171
+ }
172
+
173
+ err = dma_map_sgtable(dev, sgt, dir, 0);
174
+ if (err)
175
+ goto unpin;
176
+
177
+ job->unpins[job->num_unpins].dev = dev;
178
+ job->unpins[job->num_unpins].dir = dir;
179
+ phys_addr = sg_dma_address(sgt->sgl);
180
+ }
130181
131182 job->addr_phys[job->num_unpins] = phys_addr;
132183 job->unpins[job->num_unpins].bo = reloc->target.bo;
....@@ -134,26 +185,48 @@
134185 job->num_unpins++;
135186 }
136187
188
+ /*
189
+ * We will copy gathers BO content later, so there is no need to
190
+ * hold and pin them.
191
+ */
192
+ if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
193
+ return 0;
194
+
137195 for (i = 0; i < job->num_gathers; i++) {
138
- struct host1x_job_gather *g = &job->gathers[i];
139196 size_t gather_size = 0;
140197 struct scatterlist *sg;
141198 struct sg_table *sgt;
142199 dma_addr_t phys_addr;
143200 unsigned long shift;
144201 struct iova *alloc;
202
+ dma_addr_t *phys;
145203 unsigned int j;
146204
205
+ g = &job->gathers[i];
147206 g->bo = host1x_bo_get(g->bo);
148207 if (!g->bo) {
149208 err = -EINVAL;
150209 goto unpin;
151210 }
152211
153
- phys_addr = host1x_bo_pin(g->bo, &sgt);
212
+ /**
213
+ * If the host1x is not attached to an IOMMU, there is no need
214
+ * to map the buffer object for the host1x, since the physical
215
+ * address can simply be used.
216
+ */
217
+ if (!iommu_get_domain_for_dev(host->dev))
218
+ phys = &phys_addr;
219
+ else
220
+ phys = NULL;
154221
155
- if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) {
156
- for_each_sg(sgt->sgl, sg, sgt->nents, j)
222
+ sgt = host1x_bo_pin(host->dev, g->bo, phys);
223
+ if (IS_ERR(sgt)) {
224
+ err = PTR_ERR(sgt);
225
+ goto put;
226
+ }
227
+
228
+ if (host->domain) {
229
+ for_each_sgtable_sg(sgt, sg, j)
157230 gather_size += sg->length;
158231 gather_size = iova_align(&host->iova, gather_size);
159232
....@@ -162,26 +235,32 @@
162235 host->iova_end >> shift, true);
163236 if (!alloc) {
164237 err = -ENOMEM;
165
- goto unpin;
238
+ goto put;
166239 }
167240
168
- err = iommu_map_sg(host->domain,
241
+ err = iommu_map_sgtable(host->domain,
169242 iova_dma_addr(&host->iova, alloc),
170
- sgt->sgl, sgt->nents, IOMMU_READ);
243
+ sgt, IOMMU_READ);
171244 if (err == 0) {
172245 __free_iova(&host->iova, alloc);
173246 err = -EINVAL;
174
- goto unpin;
247
+ goto put;
175248 }
176249
177
- job->addr_phys[job->num_unpins] =
178
- iova_dma_addr(&host->iova, alloc);
179250 job->unpins[job->num_unpins].size = gather_size;
180
- } else {
181
- job->addr_phys[job->num_unpins] = phys_addr;
251
+ phys_addr = iova_dma_addr(&host->iova, alloc);
252
+ } else if (sgt) {
253
+ err = dma_map_sgtable(host->dev, sgt, DMA_TO_DEVICE, 0);
254
+ if (err)
255
+ goto put;
256
+
257
+ job->unpins[job->num_unpins].dir = DMA_TO_DEVICE;
258
+ job->unpins[job->num_unpins].dev = host->dev;
259
+ phys_addr = sg_dma_address(sgt->sgl);
182260 }
183261
184
- job->gather_addr_phys[i] = job->addr_phys[job->num_unpins];
262
+ job->addr_phys[job->num_unpins] = phys_addr;
263
+ job->gather_addr_phys[i] = phys_addr;
185264
186265 job->unpins[job->num_unpins].bo = g->bo;
187266 job->unpins[job->num_unpins].sgt = sgt;
....@@ -190,6 +269,8 @@
190269
191270 return 0;
192271
272
+put:
273
+ host1x_bo_put(g->bo);
193274 unpin:
194275 host1x_job_unpin(job);
195276 return err;
....@@ -197,8 +278,7 @@
197278
198279 static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g)
199280 {
200
- u32 last_page = ~0;
201
- void *cmdbuf_page_addr = NULL;
281
+ void *cmdbuf_addr = NULL;
202282 struct host1x_bo *cmdbuf = g->bo;
203283 unsigned int i;
204284
....@@ -220,28 +300,22 @@
220300 goto patch_reloc;
221301 }
222302
223
- if (last_page != reloc->cmdbuf.offset >> PAGE_SHIFT) {
224
- if (cmdbuf_page_addr)
225
- host1x_bo_kunmap(cmdbuf, last_page,
226
- cmdbuf_page_addr);
303
+ if (!cmdbuf_addr) {
304
+ cmdbuf_addr = host1x_bo_mmap(cmdbuf);
227305
228
- cmdbuf_page_addr = host1x_bo_kmap(cmdbuf,
229
- reloc->cmdbuf.offset >> PAGE_SHIFT);
230
- last_page = reloc->cmdbuf.offset >> PAGE_SHIFT;
231
-
232
- if (unlikely(!cmdbuf_page_addr)) {
306
+ if (unlikely(!cmdbuf_addr)) {
233307 pr_err("Could not map cmdbuf for relocation\n");
234308 return -ENOMEM;
235309 }
236310 }
237311
238
- target = cmdbuf_page_addr + (reloc->cmdbuf.offset & ~PAGE_MASK);
312
+ target = cmdbuf_addr + reloc->cmdbuf.offset;
239313 patch_reloc:
240314 *target = reloc_addr;
241315 }
242316
243
- if (cmdbuf_page_addr)
244
- host1x_bo_kunmap(cmdbuf, last_page, cmdbuf_page_addr);
317
+ if (cmdbuf_addr)
318
+ host1x_bo_munmap(cmdbuf, cmdbuf_addr);
245319
246320 return 0;
247321 }
....@@ -569,6 +643,8 @@
569643
570644 for (i = 0; i < job->num_unpins; i++) {
571645 struct host1x_job_unpin_data *unpin = &job->unpins[i];
646
+ struct device *dev = unpin->dev ?: host->dev;
647
+ struct sg_table *sgt = unpin->sgt;
572648
573649 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) &&
574650 unpin->size && host->domain) {
....@@ -578,7 +654,10 @@
578654 iova_pfn(&host->iova, job->addr_phys[i]));
579655 }
580656
581
- host1x_bo_unpin(unpin->bo, unpin->sgt);
657
+ if (unpin->dev && sgt)
658
+ dma_unmap_sgtable(unpin->dev, sgt, unpin->dir, 0);
659
+
660
+ host1x_bo_unpin(dev, unpin->bo, sgt);
582661 host1x_bo_put(unpin->bo);
583662 }
584663