diff options
Diffstat (limited to 'omap')
-rw-r--r-- | omap/omap_drm.c | 150 | ||||
-rw-r--r-- | omap/omap_drmif.h | 2 |
2 files changed, 126 insertions, 26 deletions
diff --git a/omap/omap_drm.c b/omap/omap_drm.c index 1d37e451..cd8e8bc4 100644 --- a/omap/omap_drm.c +++ b/omap/omap_drm.c | |||
@@ -32,12 +32,15 @@ | |||
32 | 32 | ||
33 | #include <stdlib.h> | 33 | #include <stdlib.h> |
34 | #include <linux/stddef.h> | 34 | #include <linux/stddef.h> |
35 | #include <linux/types.h> | ||
35 | #include <errno.h> | 36 | #include <errno.h> |
36 | #include <sys/mman.h> | 37 | #include <sys/mman.h> |
37 | #include <fcntl.h> | 38 | #include <fcntl.h> |
38 | #include <unistd.h> | 39 | #include <unistd.h> |
40 | #include <pthread.h> | ||
39 | 41 | ||
40 | #include <xf86drm.h> | 42 | #include <xf86drm.h> |
43 | #include <xf86atomic.h> | ||
41 | 44 | ||
42 | #include "omap_drm.h" | 45 | #include "omap_drm.h" |
43 | #include "omap_drmif.h" | 46 | #include "omap_drmif.h" |
@@ -46,8 +49,23 @@ | |||
46 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) | 49 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) |
47 | #define PAGE_SIZE 4096 | 50 | #define PAGE_SIZE 4096 |
48 | 51 | ||
52 | static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; | ||
53 | static void * dev_table; | ||
54 | |||
49 | struct omap_device { | 55 | struct omap_device { |
50 | int fd; | 56 | int fd; |
57 | atomic_t refcnt; | ||
58 | |||
59 | /* The handle_table is used to track GEM bo handles associated w/ | ||
60 | * this fd. This is needed, in particular, when importing | ||
61 | * dmabuf's because we don't want multiple 'struct omap_bo's | ||
62 | * floating around with the same handle. Otherwise, when the | ||
63 | * first one is omap_bo_del()'d the handle becomes no longer | ||
64 | * valid, and the remaining 'struct omap_bo's are left pointing | ||
65 | * to an invalid handle (and possible a GEM bo that is already | ||
66 | * free'd). | ||
67 | */ | ||
68 | void *handle_table; | ||
51 | }; | 69 | }; |
52 | 70 | ||
53 | /* a GEM buffer object allocated from the DRM device */ | 71 | /* a GEM buffer object allocated from the DRM device */ |
@@ -59,19 +77,57 @@ struct omap_bo { | |||
59 | uint32_t name; /* flink global handle (DRI2 name) */ | 77 | uint32_t name; /* flink global handle (DRI2 name) */ |
60 | uint64_t offset; /* offset to mmap() */ | 78 | uint64_t offset; /* offset to mmap() */ |
61 | int fd; /* dmabuf handle */ | 79 | int fd; /* dmabuf handle */ |
80 | atomic_t refcnt; | ||
62 | }; | 81 | }; |
63 | 82 | ||
64 | struct omap_device * omap_device_new(int fd) | 83 | static struct omap_device * omap_device_new_impl(int fd) |
65 | { | 84 | { |
66 | struct omap_device *dev = calloc(sizeof(*dev), 1); | 85 | struct omap_device *dev = calloc(sizeof(*dev), 1); |
67 | if (!dev) | 86 | if (!dev) |
68 | return NULL; | 87 | return NULL; |
69 | dev->fd = fd; | 88 | dev->fd = fd; |
89 | atomic_set(&dev->refcnt, 1); | ||
90 | dev->handle_table = drmHashCreate(); | ||
91 | return dev; | ||
92 | } | ||
93 | |||
94 | struct omap_device * omap_device_new(int fd) | ||
95 | { | ||
96 | struct omap_device *dev = NULL; | ||
97 | |||
98 | pthread_mutex_lock(&table_lock); | ||
99 | |||
100 | if (!dev_table) | ||
101 | dev_table = drmHashCreate(); | ||
102 | |||
103 | if (drmHashLookup(dev_table, fd, (void **)&dev)) { | ||
104 | /* not found, create new device */ | ||
105 | dev = omap_device_new_impl(fd); | ||
106 | drmHashInsert(dev_table, fd, dev); | ||
107 | } else { | ||
108 | /* found, just incr refcnt */ | ||
109 | dev = omap_device_ref(dev); | ||
110 | } | ||
111 | |||
112 | pthread_mutex_unlock(&table_lock); | ||
113 | |||
114 | return dev; | ||
115 | } | ||
116 | |||
117 | struct omap_device * omap_device_ref(struct omap_device *dev) | ||
118 | { | ||
119 | atomic_inc(&dev->refcnt); | ||
70 | return dev; | 120 | return dev; |
71 | } | 121 | } |
72 | 122 | ||
73 | void omap_device_del(struct omap_device *dev) | 123 | void omap_device_del(struct omap_device *dev) |
74 | { | 124 | { |
125 | if (!atomic_dec_and_test(&dev->refcnt)) | ||
126 | return; | ||
127 | pthread_mutex_lock(&table_lock); | ||
128 | drmHashDestroy(dev->handle_table); | ||
129 | drmHashDelete(dev_table, dev->fd); | ||
130 | pthread_mutex_unlock(&table_lock); | ||
75 | free(dev); | 131 | free(dev); |
76 | } | 132 | } |
77 | 133 | ||
@@ -101,6 +157,38 @@ int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value) | |||
101 | return drmCommandWrite(dev->fd, DRM_OMAP_SET_PARAM, &req, sizeof(req)); | 157 | return drmCommandWrite(dev->fd, DRM_OMAP_SET_PARAM, &req, sizeof(req)); |
102 | } | 158 | } |
103 | 159 | ||
160 | /* lookup a buffer from it's handle, call w/ table_lock held: */ | ||
161 | static struct omap_bo * lookup_bo(struct omap_device *dev, | ||
162 | uint32_t handle) | ||
163 | { | ||
164 | struct omap_bo *bo = NULL; | ||
165 | if (!drmHashLookup(dev->handle_table, handle, (void **)&bo)) { | ||
166 | /* found, incr refcnt and return: */ | ||
167 | bo = omap_bo_ref(bo); | ||
168 | } | ||
169 | return bo; | ||
170 | } | ||
171 | |||
172 | /* allocate a new buffer object, call w/ table_lock held */ | ||
173 | static struct omap_bo * bo_from_handle(struct omap_device *dev, | ||
174 | uint32_t handle) | ||
175 | { | ||
176 | struct omap_bo *bo = calloc(sizeof(*bo), 1); | ||
177 | if (!bo) { | ||
178 | struct drm_gem_close req = { | ||
179 | .handle = handle, | ||
180 | }; | ||
181 | drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req); | ||
182 | return NULL; | ||
183 | } | ||
184 | bo->dev = omap_device_ref(dev); | ||
185 | bo->handle = handle; | ||
186 | atomic_set(&bo->refcnt, 1); | ||
187 | /* add ourselves to the handle table: */ | ||
188 | drmHashInsert(dev->handle_table, handle, bo); | ||
189 | return bo; | ||
190 | } | ||
191 | |||
104 | /* allocate a new buffer object */ | 192 | /* allocate a new buffer object */ |
105 | static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, | 193 | static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, |
106 | union omap_gem_size size, uint32_t flags) | 194 | union omap_gem_size size, uint32_t flags) |
@@ -115,12 +203,13 @@ static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, | |||
115 | goto fail; | 203 | goto fail; |
116 | } | 204 | } |
117 | 205 | ||
118 | bo = calloc(sizeof(*bo), 1); | 206 | if (drmCommandWriteRead(dev->fd, DRM_OMAP_GEM_NEW, &req, sizeof(req))) { |
119 | if (!bo) { | ||
120 | goto fail; | 207 | goto fail; |
121 | } | 208 | } |
122 | 209 | ||
123 | bo->dev = dev; | 210 | pthread_mutex_lock(&table_lock); |
211 | bo = bo_from_handle(dev, req.handle); | ||
212 | pthread_mutex_unlock(&table_lock); | ||
124 | 213 | ||
125 | if (flags & OMAP_BO_TILED) { | 214 | if (flags & OMAP_BO_TILED) { |
126 | bo->size = round_up(size.tiled.width, PAGE_SIZE) * size.tiled.height; | 215 | bo->size = round_up(size.tiled.width, PAGE_SIZE) * size.tiled.height; |
@@ -128,12 +217,6 @@ static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, | |||
128 | bo->size = size.bytes; | 217 | bo->size = size.bytes; |
129 | } | 218 | } |
130 | 219 | ||
131 | if (drmCommandWriteRead(dev->fd, DRM_OMAP_GEM_NEW, &req, sizeof(req))) { | ||
132 | goto fail; | ||
133 | } | ||
134 | |||
135 | bo->handle = req.handle; | ||
136 | |||
137 | return bo; | 220 | return bo; |
138 | 221 | ||
139 | fail: | 222 | fail: |
@@ -171,6 +254,12 @@ struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, | |||
171 | return omap_bo_new_impl(dev, gsize, flags); | 254 | return omap_bo_new_impl(dev, gsize, flags); |
172 | } | 255 | } |
173 | 256 | ||
257 | struct omap_bo * omap_bo_ref(struct omap_bo *bo) | ||
258 | { | ||
259 | atomic_inc(&bo->refcnt); | ||
260 | return bo; | ||
261 | } | ||
262 | |||
174 | /* get buffer info */ | 263 | /* get buffer info */ |
175 | static int get_buffer_info(struct omap_bo *bo) | 264 | static int get_buffer_info(struct omap_bo *bo) |
176 | { | 265 | { |
@@ -193,23 +282,24 @@ static int get_buffer_info(struct omap_bo *bo) | |||
193 | /* import a buffer object from DRI2 name */ | 282 | /* import a buffer object from DRI2 name */ |
194 | struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name) | 283 | struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name) |
195 | { | 284 | { |
196 | struct omap_bo *bo; | 285 | struct omap_bo *bo = NULL; |
197 | struct drm_gem_open req = { | 286 | struct drm_gem_open req = { |
198 | .name = name, | 287 | .name = name, |
199 | }; | 288 | }; |
200 | 289 | ||
201 | bo = calloc(sizeof(*bo), 1); | 290 | pthread_mutex_lock(&table_lock); |
202 | if (!bo) { | ||
203 | goto fail; | ||
204 | } | ||
205 | 291 | ||
206 | if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { | 292 | if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { |
207 | goto fail; | 293 | goto fail; |
208 | } | 294 | } |
209 | 295 | ||
210 | bo->dev = dev; | 296 | bo = lookup_bo(dev, req.handle); |
211 | bo->name = name; | 297 | if (!bo) { |
212 | bo->handle = req.handle; | 298 | bo = bo_from_handle(dev, req.handle); |
299 | bo->name = name; | ||
300 | } | ||
301 | |||
302 | pthread_mutex_unlock(&table_lock); | ||
213 | 303 | ||
214 | return bo; | 304 | return bo; |
215 | 305 | ||
@@ -224,24 +314,25 @@ fail: | |||
224 | */ | 314 | */ |
225 | struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd) | 315 | struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd) |
226 | { | 316 | { |
227 | struct omap_bo *bo; | 317 | struct omap_bo *bo = NULL; |
228 | struct drm_prime_handle req = { | 318 | struct drm_prime_handle req = { |
229 | .fd = fd, | 319 | .fd = fd, |
230 | }; | 320 | }; |
231 | int ret; | 321 | int ret; |
232 | 322 | ||
233 | bo = calloc(sizeof(*bo), 1); | 323 | pthread_mutex_lock(&table_lock); |
234 | if (!bo) { | ||
235 | goto fail; | ||
236 | } | ||
237 | 324 | ||
238 | ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &req); | 325 | ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &req); |
239 | if (ret) { | 326 | if (ret) { |
240 | goto fail; | 327 | goto fail; |
241 | } | 328 | } |
242 | 329 | ||
243 | bo->dev = dev; | 330 | bo = lookup_bo(dev, req.handle); |
244 | bo->handle = req.handle; | 331 | if (!bo) { |
332 | bo = bo_from_handle(dev, req.handle); | ||
333 | } | ||
334 | |||
335 | pthread_mutex_unlock(&table_lock); | ||
245 | 336 | ||
246 | return bo; | 337 | return bo; |
247 | 338 | ||
@@ -257,6 +348,9 @@ void omap_bo_del(struct omap_bo *bo) | |||
257 | return; | 348 | return; |
258 | } | 349 | } |
259 | 350 | ||
351 | if (!atomic_dec_and_test(&bo->refcnt)) | ||
352 | return; | ||
353 | |||
260 | if (bo->map) { | 354 | if (bo->map) { |
261 | munmap(bo->map, bo->size); | 355 | munmap(bo->map, bo->size); |
262 | } | 356 | } |
@@ -269,10 +363,14 @@ void omap_bo_del(struct omap_bo *bo) | |||
269 | struct drm_gem_close req = { | 363 | struct drm_gem_close req = { |
270 | .handle = bo->handle, | 364 | .handle = bo->handle, |
271 | }; | 365 | }; |
272 | 366 | pthread_mutex_lock(&table_lock); | |
367 | drmHashDelete(bo->dev->handle_table, bo->handle); | ||
273 | drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); | 368 | drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); |
369 | pthread_mutex_unlock(&table_lock); | ||
274 | } | 370 | } |
275 | 371 | ||
372 | omap_device_del(bo->dev); | ||
373 | |||
276 | free(bo); | 374 | free(bo); |
277 | } | 375 | } |
278 | 376 | ||
diff --git a/omap/omap_drmif.h b/omap/omap_drmif.h index 284b9ccc..e62d1278 100644 --- a/omap/omap_drmif.h +++ b/omap/omap_drmif.h | |||
@@ -38,6 +38,7 @@ struct omap_device; | |||
38 | */ | 38 | */ |
39 | 39 | ||
40 | struct omap_device * omap_device_new(int fd); | 40 | struct omap_device * omap_device_new(int fd); |
41 | struct omap_device * omap_device_ref(struct omap_device *dev); | ||
41 | void omap_device_del(struct omap_device *dev); | 42 | void omap_device_del(struct omap_device *dev); |
42 | int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value); | 43 | int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value); |
43 | int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value); | 44 | int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value); |
@@ -49,6 +50,7 @@ struct omap_bo * omap_bo_new(struct omap_device *dev, | |||
49 | uint32_t size, uint32_t flags); | 50 | uint32_t size, uint32_t flags); |
50 | struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, | 51 | struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, |
51 | uint32_t width, uint32_t height, uint32_t flags); | 52 | uint32_t width, uint32_t height, uint32_t flags); |
53 | struct omap_bo * omap_bo_ref(struct omap_bo *bo); | ||
52 | struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name); | 54 | struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name); |
53 | struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd); | 55 | struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd); |
54 | void omap_bo_del(struct omap_bo *bo); | 56 | void omap_bo_del(struct omap_bo *bo); |