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) "rga_fence: " fmt
9 
10 #include <linux/dma-fence.h>
11 #include <linux/sync_file.h>
12 #include <linux/slab.h>
13 
14 #include "rga_fence.h"
15 
rga_fence_get_name(struct dma_fence *fence)16 static const char *rga_fence_get_name(struct dma_fence *fence)
17 {
18 	return DRIVER_NAME;
19 }
20 
21 static const struct dma_fence_ops rga_fence_ops = {
22 	.get_driver_name = rga_fence_get_name,
23 	.get_timeline_name = rga_fence_get_name,
24 };
25 
rga_fence_context_alloc(void)26 struct rga_fence_context *rga_fence_context_alloc(void)
27 {
28 	struct rga_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 
rga_fence_context_free(struct rga_fence_context *fence_ctx)40 void rga_fence_context_free(struct rga_fence_context *fence_ctx)
41 {
42 	kfree(fence_ctx);
43 }
44 
rga_out_fence_alloc(struct rga_job *job)45 int rga_out_fence_alloc(struct rga_job *job)
46 {
47 	struct rga_fence_context *fence_ctx = rga_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, &rga_fence_ops, &job->fence_lock,
55 			 fence_ctx->context, ++fence_ctx->seqno);
56 
57 	job->out_fence = fence;
58 
59 	return 0;
60 }
61 
rga_out_fence_get_fd(struct rga_job *job)62 int rga_out_fence_get_fd(struct rga_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 
rga_get_input_fence(int in_fence_fd)83 struct dma_fence *rga_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 
rga_wait_input_fence(struct dma_fence *in_fence)95 int rga_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 
rga_add_dma_fence_callback(struct rga_job *job, struct dma_fence *in_fence, dma_fence_func_t func)106 int rga_add_dma_fence_callback(struct rga_job *job, struct dma_fence *in_fence,
107 				 dma_fence_func_t func)
108 {
109 	struct rga_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