1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2020 NVIDIA Corporation */
4 #include <linux/dma-fence-array.h>
5 #include <linux/dma-mapping.h>
6 #include <linux/file.h>
7 #include <linux/host1x.h>
8 #include <linux/iommu.h>
9 #include <linux/kref.h>
10 #include <linux/list.h>
11 #include <linux/nospec.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/scatterlist.h>
14 #include <linux/slab.h>
15 #include <linux/sync_file.h>
17 #include <drm/drm_drv.h>
18 #include <drm/drm_file.h>
19 #include <drm/drm_syncobj.h>
26 #define SUBMIT_ERR(context, fmt, ...) \
27 dev_err_ratelimited(context->client->base.dev, \
28 "%s: job submission failed: " fmt "\n", \
29 current->comm, ##__VA_ARGS__)
32 struct host1x_bo base;
38 dma_addr_t gather_data_dma;
39 size_t gather_data_words;
42 static struct host1x_bo *gather_bo_get(struct host1x_bo *host_bo)
44 struct gather_bo *bo = container_of(host_bo, struct gather_bo, base);
51 static void gather_bo_release(struct kref *ref)
53 struct gather_bo *bo = container_of(ref, struct gather_bo, ref);
55 dma_free_attrs(bo->dev, bo->gather_data_words * 4, bo->gather_data, bo->gather_data_dma,
60 static void gather_bo_put(struct host1x_bo *host_bo)
62 struct gather_bo *bo = container_of(host_bo, struct gather_bo, base);
64 kref_put(&bo->ref, gather_bo_release);
67 static struct sg_table *
68 gather_bo_pin(struct device *dev, struct host1x_bo *host_bo, dma_addr_t *phys)
70 struct gather_bo *bo = container_of(host_bo, struct gather_bo, base);
74 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
76 return ERR_PTR(-ENOMEM);
78 err = dma_get_sgtable(bo->dev, sgt, bo->gather_data, bo->gather_data_dma,
79 bo->gather_data_words * 4);
88 static void gather_bo_unpin(struct device *dev, struct sg_table *sgt)
96 static void *gather_bo_mmap(struct host1x_bo *host_bo)
98 struct gather_bo *bo = container_of(host_bo, struct gather_bo, base);
100 return bo->gather_data;
103 static void gather_bo_munmap(struct host1x_bo *host_bo, void *addr)
107 const struct host1x_bo_ops gather_bo_ops = {
108 .get = gather_bo_get,
109 .put = gather_bo_put,
110 .pin = gather_bo_pin,
111 .unpin = gather_bo_unpin,
112 .mmap = gather_bo_mmap,
113 .munmap = gather_bo_munmap,
116 static struct tegra_drm_mapping *
117 tegra_drm_mapping_get(struct tegra_drm_context *context, u32 id)
119 struct tegra_drm_mapping *mapping;
121 xa_lock(&context->mappings);
123 mapping = xa_load(&context->mappings, id);
125 kref_get(&mapping->ref);
127 xa_unlock(&context->mappings);
132 static void *alloc_copy_user_array(void __user *from, size_t count, size_t size)
137 if (check_mul_overflow(count, size, ©_len))
138 return ERR_PTR(-EINVAL);
140 if (copy_len > 0x4000)
141 return ERR_PTR(-E2BIG);
143 data = kvmalloc(copy_len, GFP_KERNEL);
145 return ERR_PTR(-ENOMEM);
147 if (copy_from_user(data, from, copy_len)) {
149 return ERR_PTR(-EFAULT);
155 static int submit_copy_gather_data(struct gather_bo **pbo, struct device *dev,
156 struct tegra_drm_context *context,
157 struct drm_tegra_channel_submit *args)
159 struct gather_bo *bo;
162 if (args->gather_data_words == 0) {
163 SUBMIT_ERR(context, "gather_data_words cannot be zero");
167 if (check_mul_overflow((size_t)args->gather_data_words, (size_t)4, ©_len)) {
168 SUBMIT_ERR(context, "gather_data_words is too large");
172 bo = kzalloc(sizeof(*bo), GFP_KERNEL);
174 SUBMIT_ERR(context, "failed to allocate memory for bo info");
178 host1x_bo_init(&bo->base, &gather_bo_ops);
182 bo->gather_data = dma_alloc_attrs(dev, copy_len, &bo->gather_data_dma,
183 GFP_KERNEL | __GFP_NOWARN, 0);
184 if (!bo->gather_data) {
185 SUBMIT_ERR(context, "failed to allocate memory for gather data");
190 if (copy_from_user(bo->gather_data, u64_to_user_ptr(args->gather_data_ptr), copy_len)) {
191 SUBMIT_ERR(context, "failed to copy gather data from userspace");
192 dma_free_attrs(dev, copy_len, bo->gather_data, bo->gather_data_dma, 0);
197 bo->gather_data_words = args->gather_data_words;
204 static int submit_write_reloc(struct tegra_drm_context *context, struct gather_bo *bo,
205 struct drm_tegra_submit_buf *buf, struct tegra_drm_mapping *mapping)
207 /* TODO check that target_offset is within bounds */
208 dma_addr_t iova = mapping->iova + buf->reloc.target_offset;
211 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
212 if (buf->flags & DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT)
216 written_ptr = iova >> buf->reloc.shift;
218 if (buf->reloc.gather_offset_words >= bo->gather_data_words) {
220 "relocation has too large gather offset (%u vs gather length %zu)",
221 buf->reloc.gather_offset_words, bo->gather_data_words);
225 buf->reloc.gather_offset_words = array_index_nospec(buf->reloc.gather_offset_words,
226 bo->gather_data_words);
228 bo->gather_data[buf->reloc.gather_offset_words] = written_ptr;
233 static int submit_process_bufs(struct tegra_drm_context *context, struct gather_bo *bo,
234 struct drm_tegra_channel_submit *args,
235 struct tegra_drm_submit_data *job_data)
237 struct tegra_drm_used_mapping *mappings;
238 struct drm_tegra_submit_buf *bufs;
242 bufs = alloc_copy_user_array(u64_to_user_ptr(args->bufs_ptr), args->num_bufs,
245 SUBMIT_ERR(context, "failed to copy bufs array from userspace");
246 return PTR_ERR(bufs);
249 mappings = kcalloc(args->num_bufs, sizeof(*mappings), GFP_KERNEL);
251 SUBMIT_ERR(context, "failed to allocate memory for mapping info");
256 for (i = 0; i < args->num_bufs; i++) {
257 struct drm_tegra_submit_buf *buf = &bufs[i];
258 struct tegra_drm_mapping *mapping;
260 if (buf->flags & ~DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT) {
261 SUBMIT_ERR(context, "invalid flag specified for buffer");
266 mapping = tegra_drm_mapping_get(context, buf->mapping);
268 SUBMIT_ERR(context, "invalid mapping ID '%u' for buffer", buf->mapping);
273 err = submit_write_reloc(context, bo, buf, mapping);
275 tegra_drm_mapping_put(mapping);
279 mappings[i].mapping = mapping;
280 mappings[i].flags = buf->flags;
283 job_data->used_mappings = mappings;
284 job_data->num_used_mappings = i;
292 tegra_drm_mapping_put(mappings[i].mapping);
295 job_data->used_mappings = NULL;
303 static int submit_get_syncpt(struct tegra_drm_context *context, struct host1x_job *job,
304 struct xarray *syncpoints, struct drm_tegra_channel_submit *args)
306 struct host1x_syncpt *sp;
308 if (args->syncpt.flags) {
309 SUBMIT_ERR(context, "invalid flag specified for syncpt");
313 /* Syncpt ref will be dropped on job release */
314 sp = xa_load(syncpoints, args->syncpt.id);
316 SUBMIT_ERR(context, "syncpoint specified in syncpt was not allocated");
320 job->syncpt = host1x_syncpt_get(sp);
321 job->syncpt_incrs = args->syncpt.increments;
326 static int submit_job_add_gather(struct host1x_job *job, struct tegra_drm_context *context,
327 struct drm_tegra_submit_cmd_gather_uptr *cmd,
328 struct gather_bo *bo, u32 *offset,
329 struct tegra_drm_submit_data *job_data,
334 if (cmd->reserved[0] || cmd->reserved[1] || cmd->reserved[2]) {
335 SUBMIT_ERR(context, "non-zero reserved field in GATHER_UPTR command");
339 /* Check for maximum gather size */
340 if (cmd->words > 16383) {
341 SUBMIT_ERR(context, "too many words in GATHER_UPTR command");
345 if (check_add_overflow(*offset, cmd->words, &next_offset)) {
346 SUBMIT_ERR(context, "too many total words in job");
350 if (next_offset > bo->gather_data_words) {
351 SUBMIT_ERR(context, "GATHER_UPTR command overflows gather data");
355 if (tegra_drm_fw_validate(context->client, bo->gather_data, *offset,
356 cmd->words, job_data, class)) {
357 SUBMIT_ERR(context, "job was rejected by firewall");
361 host1x_job_add_gather(job, &bo->base, cmd->words, *offset * 4);
363 *offset = next_offset;
368 static struct host1x_job *
369 submit_create_job(struct tegra_drm_context *context, struct gather_bo *bo,
370 struct drm_tegra_channel_submit *args, struct tegra_drm_submit_data *job_data,
371 struct xarray *syncpoints)
373 struct drm_tegra_submit_cmd *cmds;
374 u32 i, gather_offset = 0, class;
375 struct host1x_job *job;
378 /* Set initial class for firewall. */
379 class = context->client->base.class;
381 cmds = alloc_copy_user_array(u64_to_user_ptr(args->cmds_ptr), args->num_cmds,
384 SUBMIT_ERR(context, "failed to copy cmds array from userspace");
385 return ERR_CAST(cmds);
388 job = host1x_job_alloc(context->channel, args->num_cmds, 0, true);
390 SUBMIT_ERR(context, "failed to allocate memory for job");
391 job = ERR_PTR(-ENOMEM);
395 err = submit_get_syncpt(context, job, syncpoints, args);
399 job->client = &context->client->base;
400 job->class = context->client->base.class;
401 job->serialize = true;
403 for (i = 0; i < args->num_cmds; i++) {
404 struct drm_tegra_submit_cmd *cmd = &cmds[i];
407 SUBMIT_ERR(context, "unknown flags given for cmd");
412 if (cmd->type == DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR) {
413 err = submit_job_add_gather(job, context, &cmd->gather_uptr, bo,
414 &gather_offset, job_data, &class);
417 } else if (cmd->type == DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT) {
418 if (cmd->wait_syncpt.reserved[0] || cmd->wait_syncpt.reserved[1]) {
419 SUBMIT_ERR(context, "non-zero reserved value");
424 host1x_job_add_wait(job, cmd->wait_syncpt.id, cmd->wait_syncpt.value,
426 } else if (cmd->type == DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT_RELATIVE) {
427 if (cmd->wait_syncpt.reserved[0] || cmd->wait_syncpt.reserved[1]) {
428 SUBMIT_ERR(context, "non-zero reserved value");
433 if (cmd->wait_syncpt.id != args->syncpt.id) {
434 SUBMIT_ERR(context, "syncpoint ID in CMD_WAIT_SYNCPT_RELATIVE is not used by the job");
439 host1x_job_add_wait(job, cmd->wait_syncpt.id, cmd->wait_syncpt.value,
442 SUBMIT_ERR(context, "unknown cmd type");
448 if (gather_offset == 0) {
449 SUBMIT_ERR(context, "job must have at least one gather");
466 static void release_job(struct host1x_job *job)
468 struct tegra_drm_client *client = container_of(job->client, struct tegra_drm_client, base);
469 struct tegra_drm_submit_data *job_data = job->user_data;
472 for (i = 0; i < job_data->num_used_mappings; i++)
473 tegra_drm_mapping_put(job_data->used_mappings[i].mapping);
475 kfree(job_data->used_mappings);
478 if (pm_runtime_enabled(client->base.dev))
479 pm_runtime_put_autosuspend(client->base.dev);
482 int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
483 struct drm_file *file)
485 struct tegra_drm_file *fpriv = file->driver_priv;
486 struct drm_tegra_channel_submit *args = data;
487 struct tegra_drm_submit_data *job_data;
488 struct drm_syncobj *syncobj = NULL;
489 struct tegra_drm_context *context;
490 struct host1x_job *job;
491 struct gather_bo *bo;
495 mutex_lock(&fpriv->lock);
497 context = xa_load(&fpriv->contexts, args->context);
499 mutex_unlock(&fpriv->lock);
500 pr_err_ratelimited("%s: %s: invalid channel context '%#x'", __func__,
501 current->comm, args->context);
505 if (args->syncobj_in) {
506 struct dma_fence *fence;
508 err = drm_syncobj_find_fence(file, args->syncobj_in, 0, 0, &fence);
510 SUBMIT_ERR(context, "invalid syncobj_in '%#x'", args->syncobj_in);
514 err = dma_fence_wait_timeout(fence, true, msecs_to_jiffies(10000));
515 dma_fence_put(fence);
517 SUBMIT_ERR(context, "wait for syncobj_in timed out");
522 if (args->syncobj_out) {
523 syncobj = drm_syncobj_find(file, args->syncobj_out);
525 SUBMIT_ERR(context, "invalid syncobj_out '%#x'", args->syncobj_out);
531 /* Allocate gather BO and copy gather words in. */
532 err = submit_copy_gather_data(&bo, drm->dev, context, args);
536 job_data = kzalloc(sizeof(*job_data), GFP_KERNEL);
538 SUBMIT_ERR(context, "failed to allocate memory for job data");
543 /* Get data buffer mappings and do relocation patching. */
544 err = submit_process_bufs(context, bo, args, job_data);
548 /* Allocate host1x_job and add gathers and waits to it. */
549 job = submit_create_job(context, bo, args, job_data, &fpriv->syncpoints);
555 /* Map gather data for Host1x. */
556 err = host1x_job_pin(job, context->client->base.dev);
558 SUBMIT_ERR(context, "failed to pin job: %d", err);
563 if (pm_runtime_enabled(context->client->base.dev)) {
564 err = pm_runtime_resume_and_get(context->client->base.dev);
566 SUBMIT_ERR(context, "could not power up engine: %d", err);
571 job->user_data = job_data;
572 job->release = release_job;
573 job->timeout = 10000;
576 * job_data is now part of job reference counting, so don't release
581 /* Submit job to hardware. */
582 err = host1x_job_submit(job);
584 SUBMIT_ERR(context, "host1x job submission failed: %d", err);
588 /* Return postfences to userspace and add fences to DMA reservations. */
589 args->syncpt.value = job->syncpt_end;
592 struct dma_fence *fence = host1x_fence_create(job->syncpt, job->syncpt_end);
594 err = PTR_ERR(fence);
595 SUBMIT_ERR(context, "failed to create postfence: %d", err);
598 drm_syncobj_replace_fence(syncobj, fence);
604 host1x_job_unpin(job);
608 if (job_data && job_data->used_mappings) {
609 for (i = 0; i < job_data->num_used_mappings; i++)
610 tegra_drm_mapping_put(job_data->used_mappings[i].mapping);
612 kfree(job_data->used_mappings);
618 gather_bo_put(&bo->base);
621 drm_syncobj_put(syncobj);
623 mutex_unlock(&fpriv->lock);