aboutsummaryrefslogtreecommitdiffstats
path: root/omap
diff options
context:
space:
mode:
authorRob Clark2012-07-13 16:18:25 -0500
committerRob Clark2012-07-13 16:18:25 -0500
commit22574aa887efa879519328acc09cb01d03374bf4 (patch)
treeaf4cdcdf552663204fe271fd5fac884257c09050 /omap
parent42f8a68e19ba48a25f5eca2778d997f3d1ad094d (diff)
downloadexternal-libgbm-22574aa887efa879519328acc09cb01d03374bf4.tar.gz
external-libgbm-22574aa887efa879519328acc09cb01d03374bf4.tar.xz
external-libgbm-22574aa887efa879519328acc09cb01d03374bf4.zip
omap: add refcnting and handle tracking
There can be scenarios, especially when re-importing an existing buffer, where you end up with multiple 'struct omap_bo's wrapping a single GEM object handle. Which causes badness when the first of the evil-clones is omap_bo_del()'d. To do this, introduce reference counting and a hashtable to track the handles per fd. First, to avoid bo's slipping through the crack if multiple 'struct omap_device's are created for one drm fd, a hashtable mapping drm fd to omap_device, and the omap_device itself is reference counted. Per omap_device, we keep a handle_table mapping GEM handle to omap_bo. When buffers are imported from flink name or dmabuf fd, the handle table is consulted, and if an omap_bo already exists, it's refcnt is incremented and it is returned. For good measure, to avoid the handle_table being deleted before the omap_bo is freed, the omap_bo holds a reference to the omap_device. TODO: check the overhead of the hashtable. If too much we could maybe get away with only tracking exported and imported bo's in the table. TODO: all the import/export flink/dmabuf operations are generic DRM ioctls. Really all this functionality could be handled by a generic drm_bo and drm_device "base class" that could be extended by omap, exynos, etc. That would also allow more common userspace code by avoiding artificial libdrm_omap dependencies. Signed-off-by: Rob Clark <rob@ti.com>
Diffstat (limited to 'omap')
-rw-r--r--omap/omap_drm.c150
-rw-r--r--omap/omap_drmif.h2
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
52static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
53static void * dev_table;
54
49struct omap_device { 55struct 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
64struct omap_device * omap_device_new(int fd) 83static 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
94struct 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
117struct 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
73void omap_device_del(struct omap_device *dev) 123void 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: */
161static 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 */
173static 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 */
105static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, 193static 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
139fail: 222fail:
@@ -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
257struct 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 */
175static int get_buffer_info(struct omap_bo *bo) 264static 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 */
194struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name) 283struct 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 */
225struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd) 315struct 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
40struct omap_device * omap_device_new(int fd); 40struct omap_device * omap_device_new(int fd);
41struct omap_device * omap_device_ref(struct omap_device *dev);
41void omap_device_del(struct omap_device *dev); 42void omap_device_del(struct omap_device *dev);
42int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value); 43int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value);
43int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value); 44int 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);
50struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, 51struct 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);
53struct omap_bo * omap_bo_ref(struct omap_bo *bo);
52struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name); 54struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name);
53struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd); 55struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd);
54void omap_bo_del(struct omap_bo *bo); 56void omap_bo_del(struct omap_bo *bo);