1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) Rockchip Electronics Co., Ltd.
4 *
5 * Author: Huang Lee <Putin.li@rock-chips.com>
6 */
7
8 #define pr_fmt(fmt) "rve_fence: " fmt
9
10 #include <linux/dma-fence.h>
11 #include <linux/sync_file.h>
12 #include <linux/slab.h>
13
14 #include "rve_fence.h"
15
rve_fence_get_name(struct dma_fence * fence)16 static const char *rve_fence_get_name(struct dma_fence *fence)
17 {
18 return DRIVER_NAME;
19 }
20
21 static const struct dma_fence_ops rve_fence_ops = {
22 .get_driver_name = rve_fence_get_name,
23 .get_timeline_name = rve_fence_get_name,
24 };
25
rve_fence_context_alloc(void)26 struct rve_fence_context *rve_fence_context_alloc(void)
27 {
28 struct rve_fence_context *fence_ctx = NULL;
29
30 fence_ctx = kzalloc(sizeof(*fence_ctx), GFP_KERNEL);
31 if (!fence_ctx)
32 return ERR_PTR(-ENOMEM);
33
34 fence_ctx->context = dma_fence_context_alloc(1);
35 spin_lock_init(&fence_ctx->spinlock);
36
37 return fence_ctx;
38 }
39
rve_fence_context_free(struct rve_fence_context * fence_ctx)40 void rve_fence_context_free(struct rve_fence_context *fence_ctx)
41 {
42 kfree(fence_ctx);
43 }
44
rve_out_fence_alloc(struct rve_job * job)45 int rve_out_fence_alloc(struct rve_job *job)
46 {
47 struct rve_fence_context *fence_ctx = rve_drvdata->fence_ctx;
48 struct dma_fence *fence = NULL;
49
50 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
51 if (!fence)
52 return -ENOMEM;
53
54 dma_fence_init(fence, &rve_fence_ops, &job->fence_lock,
55 fence_ctx->context, ++fence_ctx->seqno);
56
57 job->out_fence = fence;
58
59 return 0;
60 }
61
rve_out_fence_get_fd(struct rve_job * job)62 int rve_out_fence_get_fd(struct rve_job *job)
63 {
64 struct sync_file *sync_file = NULL;
65 int fence_fd = -1;
66
67 if (!job->out_fence)
68 return -EINVAL;
69
70 fence_fd = get_unused_fd_flags(O_CLOEXEC);
71 if (fence_fd < 0)
72 return fence_fd;
73
74 sync_file = sync_file_create(job->out_fence);
75 if (!sync_file)
76 return -ENOMEM;
77
78 fd_install(fence_fd, sync_file->file);
79
80 return fence_fd;
81 }
82
rve_get_input_fence(int in_fence_fd)83 struct dma_fence *rve_get_input_fence(int in_fence_fd)
84 {
85 struct dma_fence *in_fence;
86
87 in_fence = sync_file_get_fence(in_fence_fd);
88
89 if (!in_fence)
90 pr_err("can not get in-fence from fd\n");
91
92 return in_fence;
93 }
94
rve_wait_input_fence(struct dma_fence * in_fence)95 int rve_wait_input_fence(struct dma_fence *in_fence)
96 {
97 int ret = 0;
98
99 ret = dma_fence_wait(in_fence, true);
100
101 dma_fence_put(in_fence);
102
103 return ret;
104 }
105
rve_add_dma_fence_callback(struct rve_job * job,struct dma_fence * in_fence,dma_fence_func_t func)106 int rve_add_dma_fence_callback(struct rve_job *job, struct dma_fence *in_fence,
107 dma_fence_func_t func)
108 {
109 struct rve_fence_waiter *waiter;
110 int ret;
111
112 waiter = kmalloc(sizeof(*waiter), GFP_KERNEL);
113 if (!waiter) {
114 pr_err("%s: Failed to allocate waiter\n", __func__);
115 return -ENOMEM;
116 }
117
118 waiter->job = job;
119
120 ret = dma_fence_add_callback(in_fence, &waiter->waiter, func);
121 if (ret == -ENOENT) {
122 pr_err("'input fence' has been already signaled.");
123 goto err_free_waiter;
124 } else if (ret == -EINVAL) {
125 pr_err
126 ("%s: failed to add callback to dma_fence, err: %d\n",
127 __func__, ret);
128 goto err_free_waiter;
129 }
130
131 return ret;
132
133 err_free_waiter:
134 kfree(waiter);
135 return ret;
136 }
137