blob: 2955899d040a7e6eb2333408e07f203e584ea40f [file] [log] [blame]
Yalong Liu1df84372018-01-24 17:10:12 +08001/*
2 * Copyright 2017 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <linux/dma-buf.h>
8#include <sys/ioctl.h>
9
10#include "bs_drm.h"
11
12#define HANDLE_EINTR(x) \
13 ({ \
14 int eintr_wrapper_counter = 0; \
15 int eintr_wrapper_result; \
16 do { \
17 eintr_wrapper_result = (x); \
18 } while (eintr_wrapper_result == -1 && errno == EINTR && \
19 eintr_wrapper_counter++ < 100); \
20 eintr_wrapper_result; \
21 })
22
23struct bs_map_info {
24 size_t plane_index;
25 void *ptr;
26 void *map_data;
27};
28
29typedef void *(*bs_map_t)(struct bs_mapper *mapper, struct gbm_bo *bo, size_t plane,
30 struct bs_map_info *info);
31typedef void (*bs_unmap_t)(struct gbm_bo *bo, struct bs_map_info *info);
32
33struct bs_mapper {
34 bs_map_t map_plane_fn;
35 bs_unmap_t unmap_plane_fn;
36 int device_fd;
37};
38
39static void *dma_buf_map(struct bs_mapper *mapper, struct gbm_bo *bo, size_t plane,
40 struct bs_map_info *info)
41{
42 int drm_prime_fd = gbm_bo_get_plane_fd(bo, plane);
43 uint32_t handle = gbm_bo_get_plane_handle(bo, plane).u32;
44 size_t length = 0;
45
46 for (size_t p = 0; p <= plane; p++) {
47 if (gbm_bo_get_plane_handle(bo, p).u32 == handle)
48 length += gbm_bo_get_plane_size(bo, p);
49 }
50
51 void *ptr = mmap(NULL, length, (PROT_READ | PROT_WRITE), MAP_SHARED, drm_prime_fd, 0);
52 if (ptr == MAP_FAILED) {
53 bs_debug_error("dma-buf mmap returned MAP_FAILED: %d", errno);
54 ptr = MAP_FAILED;
55 } else {
56 ptr += gbm_bo_get_plane_offset(bo, plane);
57 }
58
59 struct dma_buf_sync sync_start = { 0 };
60 sync_start.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
61 int ret = HANDLE_EINTR(ioctl(drm_prime_fd, DMA_BUF_IOCTL_SYNC, &sync_start));
62 if (ret)
63 bs_debug_error("DMA_BUF_IOCTL_SYNC failed");
64
65 close(drm_prime_fd);
66 return ptr;
67}
68
69static void dma_buf_unmap(struct gbm_bo *bo, struct bs_map_info *info)
70{
71 struct dma_buf_sync sync_end = { 0 };
72 sync_end.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
73 int drm_prime_fd = gbm_bo_get_plane_fd(bo, info->plane_index);
74 int ret = HANDLE_EINTR(ioctl(drm_prime_fd, DMA_BUF_IOCTL_SYNC, &sync_end));
75 close(drm_prime_fd);
76 if (ret)
77 bs_debug_error("DMA_BUF_IOCTL_SYNC failed");
78
79 void *addr = info->ptr;
80 addr -= gbm_bo_get_plane_offset(bo, info->plane_index);
81 ret = munmap(addr, gbm_bo_get_plane_size(bo, info->plane_index));
82 if (ret)
83 bs_debug_error("dma-buf unmap failed.");
84}
85
86static void *gem_map(struct bs_mapper *mapper, struct gbm_bo *bo, size_t plane,
87 struct bs_map_info *info)
88{
89 uint32_t w = gbm_bo_get_width(bo);
90 uint32_t h = gbm_bo_get_height(bo);
91 uint32_t stride;
92 void *ptr =
93 gbm_bo_map(bo, 0, 0, w, h, GBM_BO_TRANSFER_READ_WRITE, &stride, &info->map_data, plane);
94 return ptr;
95}
96
97static void gem_unmap(struct gbm_bo *bo, struct bs_map_info *info)
98{
99 gbm_bo_unmap(bo, info->map_data);
100}
101
102static void *dumb_map(struct bs_mapper *mapper, struct gbm_bo *bo, size_t plane,
103 struct bs_map_info *info)
104{
105 if (plane) {
106 bs_debug_error("dump map supports only single plane buffer.");
107 return MAP_FAILED;
108 }
109
110 int prime_fd = gbm_bo_get_fd(bo);
111 uint32_t size = gbm_bo_get_plane_size(bo, plane);
112
113 uint32_t bo_handle;
114 int ret = drmPrimeFDToHandle(mapper->device_fd, prime_fd, &bo_handle);
115 if (ret) {
116 bs_debug_error("dump map failed.");
117 return MAP_FAILED;
118 }
119
120 struct drm_mode_map_dumb mmap_arg = { 0 };
121 mmap_arg.handle = bo_handle;
122
123 ret = drmIoctl(mapper->device_fd, DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg);
124 if (ret) {
125 bs_debug_error("failed DRM_IOCTL_MODE_MAP_DUMB: %d", ret);
126 return MAP_FAILED;
127 }
128
129 if (mmap_arg.offset == 0) {
130 bs_debug_error("DRM_IOCTL_MODE_MAP_DUMB returned 0 offset");
131 return MAP_FAILED;
132 }
133
134 void *ptr = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, mapper->device_fd,
135 mmap_arg.offset);
136
137 if (ptr == MAP_FAILED) {
138 bs_debug_error("mmap returned MAP_FAILED: %d", errno);
139 return MAP_FAILED;
140 }
141
142 close(prime_fd);
143 return ptr;
144}
145
146static void dumb_unmap(struct gbm_bo *bo, struct bs_map_info *info)
147{
148 int ret = munmap(info->ptr, gbm_bo_get_plane_size(bo, info->plane_index));
149 if (ret)
150 bs_debug_error("dump unmap failed.");
151}
152
153struct bs_mapper *bs_mapper_dma_buf_new()
154{
155 struct bs_mapper *mapper = calloc(1, sizeof(struct bs_mapper));
156 assert(mapper);
157 mapper->map_plane_fn = dma_buf_map;
158 mapper->unmap_plane_fn = dma_buf_unmap;
159 mapper->device_fd = -1;
160 return mapper;
161}
162
163struct bs_mapper *bs_mapper_gem_new()
164{
165 struct bs_mapper *mapper = calloc(1, sizeof(struct bs_mapper));
166 assert(mapper);
167 mapper->map_plane_fn = gem_map;
168 mapper->unmap_plane_fn = gem_unmap;
169 mapper->device_fd = -1;
170 return mapper;
171}
172
173struct bs_mapper *bs_mapper_dumb_new(int device_fd)
174{
175 assert(device_fd >= 0);
176 struct bs_mapper *mapper = calloc(1, sizeof(struct bs_mapper));
177 assert(mapper);
178 mapper->map_plane_fn = dumb_map;
179 mapper->unmap_plane_fn = dumb_unmap;
180 mapper->device_fd = dup(device_fd);
181 assert(mapper->device_fd >= 0);
182 return mapper;
183}
184
185void bs_mapper_destroy(struct bs_mapper *mapper)
186{
187 assert(mapper);
188 if (mapper->device_fd >= 0)
189 close(mapper->device_fd);
190
191 free(mapper);
192}
193
194void *bs_mapper_map(struct bs_mapper *mapper, struct gbm_bo *bo, size_t plane, void **map_data)
195{
196 assert(mapper);
197 assert(bo);
198 assert(map_data);
199 struct bs_map_info *info = calloc(1, sizeof(struct bs_map_info));
200 info->plane_index = plane;
201 void *ptr = mapper->map_plane_fn(mapper, bo, plane, info);
202 if (ptr == MAP_FAILED) {
203 free(info);
204 return MAP_FAILED;
205 }
206
207 info->ptr = ptr;
208 *map_data = info;
209 return info->ptr;
210}
211
212void bs_mapper_unmap(struct bs_mapper *mapper, struct gbm_bo *bo, void *map_data)
213{
214 struct bs_map_info *info = map_data;
215 assert(info);
216 mapper->unmap_plane_fn(bo, info);
217 free(info);
218}