1 /*
2 * Copyright © 2012-2018 Rob Clark <[email protected]>
3 * SPDX-License-Identifier: MIT
4 *
5 * Authors:
6 * Rob Clark <[email protected]>
7 */
8
9 #include "msm_priv.h"
10
11 static int
bo_allocate(struct msm_bo * msm_bo)12 bo_allocate(struct msm_bo *msm_bo)
13 {
14 struct fd_bo *bo = &msm_bo->base;
15 if (!msm_bo->offset) {
16 struct drm_msm_gem_info req = {
17 .handle = bo->handle,
18 .info = MSM_INFO_GET_OFFSET,
19 };
20 int ret;
21
22 /* if the buffer is already backed by pages then this
23 * doesn't actually do anything (other than giving us
24 * the offset)
25 */
26 ret =
27 drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req));
28 if (ret) {
29 ERROR_MSG("alloc failed: %s", strerror(errno));
30 return ret;
31 }
32
33 msm_bo->offset = req.value;
34 }
35
36 return 0;
37 }
38
39 static int
msm_bo_offset(struct fd_bo * bo,uint64_t * offset)40 msm_bo_offset(struct fd_bo *bo, uint64_t *offset)
41 {
42 struct msm_bo *msm_bo = to_msm_bo(bo);
43 int ret = bo_allocate(msm_bo);
44 if (ret)
45 return ret;
46 *offset = msm_bo->offset;
47 return 0;
48 }
49
50 static int
msm_bo_cpu_prep(struct fd_bo * bo,struct fd_pipe * pipe,uint32_t op)51 msm_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
52 {
53 struct drm_msm_gem_cpu_prep req = {
54 .handle = bo->handle,
55 .op = op,
56 };
57
58 get_abs_timeout(&req.timeout, OS_TIMEOUT_INFINITE);
59
60 return drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_CPU_PREP, &req, sizeof(req));
61 }
62
63 static int
msm_bo_madvise(struct fd_bo * bo,int willneed)64 msm_bo_madvise(struct fd_bo *bo, int willneed)
65 {
66 struct drm_msm_gem_madvise req = {
67 .handle = bo->handle,
68 .madv = willneed ? MSM_MADV_WILLNEED : MSM_MADV_DONTNEED,
69 };
70 int ret;
71
72 /* older kernels do not support this: */
73 if (bo->dev->version < FD_VERSION_MADVISE)
74 return willneed;
75
76 ret =
77 drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_MADVISE, &req, sizeof(req));
78 if (ret)
79 return ret;
80
81 return req.retained;
82 }
83
84 static uint64_t
msm_bo_iova(struct fd_bo * bo)85 msm_bo_iova(struct fd_bo *bo)
86 {
87 struct drm_msm_gem_info req = {
88 .handle = bo->handle,
89 .info = MSM_INFO_GET_IOVA,
90 };
91 int ret;
92
93 ret = drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req));
94 if (ret)
95 return 0;
96
97 return req.value;
98 }
99
100 static void
msm_bo_set_name(struct fd_bo * bo,const char * fmt,va_list ap)101 msm_bo_set_name(struct fd_bo *bo, const char *fmt, va_list ap)
102 {
103 struct drm_msm_gem_info req = {
104 .handle = bo->handle,
105 .info = MSM_INFO_SET_NAME,
106 };
107 char buf[32];
108 int sz;
109
110 if (bo->dev->version < FD_VERSION_SOFTPIN)
111 return;
112
113 sz = vsnprintf(buf, sizeof(buf), fmt, ap);
114
115 req.value = VOID2U64(buf);
116 req.len = MIN2(sz, sizeof(buf));
117
118 drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req));
119 }
120
121 static void
msm_bo_set_metadata(struct fd_bo * bo,void * metadata,uint32_t metadata_size)122 msm_bo_set_metadata(struct fd_bo *bo, void *metadata, uint32_t metadata_size)
123 {
124 struct drm_msm_gem_info req = {
125 .handle = bo->handle,
126 .info = MSM_INFO_SET_METADATA,
127 .value = (uintptr_t)(void *)metadata,
128 .len = metadata_size,
129 };
130
131 int ret = drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req));
132 if (ret) {
133 mesa_logw_once("Failed to set BO metadata with DRM_MSM_GEM_INFO: %d",
134 ret);
135 }
136 }
137
138 static int
msm_bo_get_metadata(struct fd_bo * bo,void * metadata,uint32_t metadata_size)139 msm_bo_get_metadata(struct fd_bo *bo, void *metadata, uint32_t metadata_size)
140 {
141 struct drm_msm_gem_info req = {
142 .handle = bo->handle,
143 .info = MSM_INFO_GET_METADATA,
144 .value = (uintptr_t)(void *)metadata,
145 .len = metadata_size,
146 };
147
148 int ret = drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req));
149 if (ret) {
150 mesa_logw_once("Failed to get BO metadata with DRM_MSM_GEM_INFO: %d",
151 ret);
152 }
153
154 return ret;
155 }
156
157 static const struct fd_bo_funcs funcs = {
158 .offset = msm_bo_offset,
159 .map = fd_bo_map_os_mmap,
160 .cpu_prep = msm_bo_cpu_prep,
161 .madvise = msm_bo_madvise,
162 .iova = msm_bo_iova,
163 .set_name = msm_bo_set_name,
164 .set_metadata = msm_bo_set_metadata,
165 .get_metadata = msm_bo_get_metadata,
166 .dmabuf = fd_bo_dmabuf_drm,
167 .destroy = fd_bo_fini_common,
168 };
169
170 /* allocate a buffer handle: */
171 static int
new_handle(struct fd_device * dev,uint32_t size,uint32_t flags,uint32_t * handle)172 new_handle(struct fd_device *dev, uint32_t size, uint32_t flags, uint32_t *handle)
173 {
174 struct drm_msm_gem_new req = {
175 .size = size,
176 };
177 int ret;
178
179 if (flags & FD_BO_SCANOUT)
180 req.flags |= MSM_BO_SCANOUT;
181
182 if (flags & FD_BO_GPUREADONLY)
183 req.flags |= MSM_BO_GPU_READONLY;
184
185 if (flags & FD_BO_CACHED_COHERENT)
186 req.flags |= MSM_BO_CACHED_COHERENT;
187 else
188 req.flags |= MSM_BO_WC;
189
190 ret = drmCommandWriteRead(dev->fd, DRM_MSM_GEM_NEW, &req, sizeof(req));
191 if (ret)
192 return ret;
193
194 *handle = req.handle;
195
196 return 0;
197 }
198
199 /* allocate a new buffer object */
200 struct fd_bo *
msm_bo_new(struct fd_device * dev,uint32_t size,uint32_t flags)201 msm_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
202 {
203 uint32_t handle;
204 int ret;
205
206 ret = new_handle(dev, size, flags, &handle);
207 if (ret)
208 return NULL;
209
210 return msm_bo_from_handle(dev, size, handle);
211 }
212
213 /* allocate a new buffer object from existing handle (import) */
214 struct fd_bo *
msm_bo_from_handle(struct fd_device * dev,uint32_t size,uint32_t handle)215 msm_bo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle)
216 {
217 struct msm_bo *msm_bo;
218 struct fd_bo *bo;
219
220 msm_bo = calloc(1, sizeof(*msm_bo));
221 if (!msm_bo)
222 return NULL;
223
224 bo = &msm_bo->base;
225 bo->size = size;
226 bo->handle = handle;
227 bo->funcs = &funcs;
228
229 fd_bo_init_common(bo, dev);
230
231 return bo;
232 }
233